Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C#

TCP Session Reconstruction Tool

Rate me:
Please Sign up or sign in to vote.
4.65/5 (17 votes)
21 Sep 2007CPOL6 min read 166K   8.2K   74  
A TCP session reconstruction tool for C#.
/*
  This file is taken from Linux 2.0.36 kernel source.
  Modified in Jun 99 by Nergal.
*/

#include <string.h>
#ifdef WIN32
	#include "nids.h"
#endif

#define __u8 unsigned char
#define __u16 unsigned short
#define __u32 unsigned int

#define IPOPT_END	0
#define IPOPT_NOOP	1
#define IPOPT_SEC	130
#define IPOPT_LSRR	131
#define IPOPT_SSRR	137
#define IPOPT_RR	7
#define IPOPT_SID	136
#define IPOPT_TIMESTAMP	68

#define MAXTTL		255

struct timestamp {
  __u8 len;
  __u8 ptr;
#if defined(LIBNET_LIL_ENDIAN)
  __u8 flags:4, overflow:4;
#elif defined(LIBNET_BIG_ENDIAN)
  __u8 overflow:4, flags:4;
#else
#error	"unknown byte ordering"
#endif
  __u32 data[9];
};

#define MAX_ROUTE	16

struct route {
  char route_size;
  char pointer;
  unsigned long route[MAX_ROUTE];
};

#define IPOPT_OPTVAL 0
#define IPOPT_OLEN   1
#define IPOPT_OFFSET 2
#define IPOPT_MINOFF 4
#define MAX_IPOPTLEN 40
#define IPOPT_NOP IPOPT_NOOP
#define IPOPT_EOL IPOPT_END
#define IPOPT_TS  IPOPT_TIMESTAMP

#define	IPOPT_TS_TSONLY		0	/* timestamps only */
#define	IPOPT_TS_TSANDADDR	1	/* timestamps and addresses */
#define	IPOPT_TS_PRESPEC	3	/* specified modules only */

struct options {
  __u32 faddr;			/* Saved first hop address */
  unsigned char optlen;
  unsigned char srr;
  unsigned char rr;
  unsigned char ts;
  unsigned char is_setbyuser:1,	/* Set by setsockopt?			 */
       is_data:1,		/* Options in __data, rather than skb	 */
       is_strictroute:1,	/* Strict source route			 */
       srr_is_hit:1,		/* Packet destination addr was our one	 */
       is_changed:1,		/* IP checksum more not valid		 */
       rr_needaddr:1,		/* Need to record addr of outgoing dev	 */
       ts_needtime:1,		/* Need to record timestamp		 */
       ts_needaddr:1;		/* Need to record addr of outgoing dev  */
  unsigned char __pad1;
  unsigned char __pad2;
  unsigned char __pad3;
  unsigned char __data[0];
};

struct iphdr {
#if defined(LIBNET_LIL_ENDIAN)
  __u8 ihl:4, version:4;
#elif defined (LIBNET_BIG_ENDIAN)
  __u8 version:4, ihl:4;
#else
#error	"unknown byte ordering"
#endif
  __u8 tos;
  __u16 tot_len;
  __u16 id;
  __u16 frag_off;
  __u8 ttl;
  __u8 protocol;
  __u16 check;
  __u32 saddr;
  __u32 daddr;
  /* The options start here. */
};

#define ip_chk_addr(x) 0

int 
ip_options_compile(unsigned char *iph)
{
  int l;
  unsigned char *optptr;
  int optlen;
  unsigned char *pp_ptr = 0;
  char optholder[16];
  struct options *opt;
  int skb = 1;
  int skb_pa_addr = 314159;

  opt = (struct options *) optholder;
  memset(opt, 0, sizeof(struct options));
  opt->optlen = ((struct iphdr *) iph)->ihl * 4 - sizeof(struct iphdr);
  optptr = iph + sizeof(struct iphdr);
  opt->is_data = 0;

  for (l = opt->optlen; l > 0;) {
    switch (*optptr) {
    case IPOPT_END:
      for (optptr++, l--; l > 0; l--) {
	if (*optptr != IPOPT_END) {
	  *optptr = IPOPT_END;
	  opt->is_changed = 1;
	}
      }
      goto eol;
    case IPOPT_NOOP:
      l--;
      optptr++;
      continue;
    }
    optlen = optptr[1];
    if (optlen < 2 || optlen > l) {
      pp_ptr = optptr;
      goto error;
    }
    switch (*optptr) {
    case IPOPT_SSRR:
    case IPOPT_LSRR:
      if (optlen < 3) {
	pp_ptr = optptr + 1;
	goto error;
      }
      if (optptr[2] < 4) {
	pp_ptr = optptr + 2;
	goto error;
      }
      /* NB: cf RFC-1812 5.2.4.1 */
      if (opt->srr) {
	pp_ptr = optptr;
	goto error;
      }
      if (!skb) {
	if (optptr[2] != 4 || optlen < 7 || ((optlen - 3) & 3)) {
	  pp_ptr = optptr + 1;
	  goto error;
	}
	memcpy(&opt->faddr, &optptr[3], 4);
	if (optlen > 7)
	  memmove(&optptr[3], &optptr[7], optlen - 7);
      }
      opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
      opt->srr = optptr - iph;
      break;
    case IPOPT_RR:
      if (opt->rr) {
	pp_ptr = optptr;
	goto error;
      }
      if (optlen < 3) {
	pp_ptr = optptr + 1;
	goto error;
      }
      if (optptr[2] < 4) {
	pp_ptr = optptr + 2;
	goto error;
      }
      if (optptr[2] <= optlen) {
	if (optptr[2] + 3 > optlen) {
	  pp_ptr = optptr + 2;
	  goto error;
	}
	if (skb) {
	  memcpy(&optptr[optptr[2] - 1], &skb_pa_addr, 4);
	  opt->is_changed = 1;
	}
	optptr[2] += 4;
	opt->rr_needaddr = 1;
      }
      opt->rr = optptr - iph;
      break;
    case IPOPT_TIMESTAMP:
      if (opt->ts) {
	pp_ptr = optptr;
	goto error;
      }
      if (optlen < 4) {
	pp_ptr = optptr + 1;
	goto error;
      }
      if (optptr[2] < 5) {
	pp_ptr = optptr + 2;
	goto error;
      }
      if (optptr[2] <= optlen) {
	struct timestamp *ts = (struct timestamp *) (optptr + 1);
	__u32 *timeptr = 0;

	if (ts->ptr + 3 > ts->len) {
	  pp_ptr = optptr + 2;
	  goto error;
	}
	switch (ts->flags) {
	case IPOPT_TS_TSONLY:
	  opt->ts = optptr - iph;
	  if (skb)
	    timeptr = (__u32 *) & optptr[ts->ptr - 1];
	  opt->ts_needtime = 1;
	  ts->ptr += 4;
	  break;
	case IPOPT_TS_TSANDADDR:
	  if (ts->ptr + 7 > ts->len) {
	    pp_ptr = optptr + 2;
	    goto error;
	  }
	  opt->ts = optptr - iph;
	  if (skb) {
	    memcpy(&optptr[ts->ptr - 1], &skb_pa_addr, 4);
	    timeptr = (__u32 *) & optptr[ts->ptr + 3];
	  }
	  opt->ts_needaddr = 1;
	  opt->ts_needtime = 1;
	  ts->ptr += 8;
	  break;
	case IPOPT_TS_PRESPEC:
	  if (ts->ptr + 7 > ts->len) {
	    pp_ptr = optptr + 2;
	    goto error;
	  }
	  opt->ts = optptr - iph;
	  {
	    __u32 addr;

	    memcpy(&addr, &optptr[ts->ptr - 1], 4);
	    if (ip_chk_addr(addr) == 0)
	      break;
	    if (skb)
	      timeptr = (__u32 *) & optptr[ts->ptr + 3];
	  }
	  opt->ts_needaddr = 1;
	  opt->ts_needtime = 1;
	  ts->ptr += 8;
	  break;
	default:
	  pp_ptr = optptr + 3;
	  goto error;
	}
	if (timeptr) {
	  //struct timeval tv;
	  __u32 midtime = 1;

	  //do_gettimeofday(&tv);
	  //midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
	  memcpy(timeptr, &midtime, sizeof(__u32));
	  opt->is_changed = 1;
	}
      }
      else {
	struct timestamp *ts = (struct timestamp *) (optptr + 1);

	if (ts->overflow == 15) {
	  pp_ptr = optptr + 3;
	  goto error;
	}
	opt->ts = optptr - iph;
	if (skb) {
	  ts->overflow++;
	  opt->is_changed = 1;
	}
      }
      break;
    case IPOPT_SEC:
    case IPOPT_SID:
    default:
      if (!skb) {
	pp_ptr = optptr;
	goto error;
      }
      break;
    }
    l -= optlen;
    optptr += optlen;
  }

eol:
  if (!pp_ptr)
    if (!((struct options *) optholder)->srr)
      return 0;

error:
  return -1;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Microsoft
Israel Israel
Saar, has been programing since 1997. He enjoys taking things a part and designing simple solutions to complex problems. Currently, works for Microsoft writing in a variety of languages and flavors. During the last year he is taking a closer look into mobile and web development.

Comments and Discussions