#include #include #include #include #include "extra-ipprotos.h" #include "icmp.h" #include "ip.h" #include "main.h" #include "tcp.h" #include "udp.h" #include "util.h" #include "vars.h" /* bits in the one-octet quantity at offset 1 */ #define IP_TOS_PREC 0xe0 #define IP_TOS_PREC_ROUTINE 0x00 #define IP_TOS_PREC_PRIORITY 0x20 #define IP_TOS_PREC_IMMEDIATE 0x40 #define IP_TOS_PREC_FLASH 0x60 #define IP_TOS_PREC_FLASH_OVR 0x80 #define IP_TOS_PREC_CRITIC_ECP 0xa0 #define IP_TOS_PREC_INTNET_CTL 0xc0 #define IP_TOS_PREC_NET_CTL 0xe0 #define IP_TOS_D 0x10 #define IP_TOS_T 0x08 #define IP_TOS_R 0x04 #define IP_TOS_RES2 0x02 #define IP_TOS_RES1 0x01 /* bits in the two-octet quantity at offset 6 */ #define IP_OFF_OFF 0x1fff #define IP_OFF_MF 0x2000 #define IP_OFF_DF 0x4000 #define IP_OFF_RESV 0x8000 unsigned long int ip_src; unsigned long int ip_dst; typedef struct reass_id REASS_ID; typedef struct reass_frag REASS_FRAG; typedef struct reass REASS; struct reass_id { unsigned long int hash; unsigned short int id; unsigned long int src; unsigned long int dst; unsigned char proto; } ; struct reass_frag { REASS_FRAG *link; unsigned int off; unsigned int len; unsigned char *data; } ; struct reass { REASS *flink; REASS *blink; REASS_ID id; REASS_FRAG *frags; unsigned char *hdr; unsigned int sawlast : 1; } ; static REASS *reass_head; static void hash_id(REASS_ID *id) { id->hash = id->src ^ (id->dst << 3) ^ (id->dst >> 29) ^ (id->id << 13) ^ (id->proto << 5); } static void link_reass(REASS *r) { r->flink = reass_head; r->blink = 0; if (reass_head) reass_head->blink = r; reass_head = r; } static void unlink_reass(REASS *r) { REASS *f; REASS *b; f = r->flink; b = r->blink; if (f) f->blink = b; if (b) { b->flink = f; } else { reass_head = f; } r->flink = 0; r->blink = 0; } static REASS *find_reass(REASS_ID *id, int alloc) { REASS *r; for (r=reass_head;r;r=r->flink) { if ( (r->id.hash == id->hash) && (r->id.id == id->id) && (r->id.src == id->src) && (r->id.dst == id->dst) && (r->id.proto == id->proto) ) { if (r->blink) { REASS *b; REASS *bb; REASS *f; f = r->flink; b = r->blink; bb = b->blink; if (f) f->blink = b; b->blink = r; r->blink = bb; if (bb) { bb->flink = r; } else { reass_head = r; } r->flink = b; b->flink = f; } return(r); } } if (alloc) { r = malloc(sizeof(REASS)); r->id = *id; r->frags = 0; r->hdr = 0; r->sawlast = 0; link_reass(r); } return(r); } static void free_reass(REASS *r) { while (r->frags) { REASS_FRAG *rf; rf = r->frags; r->frags = rf->link; free(rf->data); free(rf); } free(r->hdr); free(r); } static void add_reass_data(REASS *r, unsigned int off, const unsigned char *data, int len) { REASS_FRAG *f; REASS_FRAG **fp; REASS_FRAG *n; unsigned char *d; fp = &r->frags; while (1) { f = *fp; if (f == 0) { n = malloc(sizeof(REASS_FRAG)); n->link = 0; *fp = n; n->off = off; n->len = len; n->data = malloc(len); bcopy(data,n->data,len); return; } if (f->off+f->len >= off) break; fp = &f->link; } if (off+len < f->off) { n = malloc(sizeof(REASS_FRAG)); n->link = f; *fp = n; n->off = off; n->len = len; n->data = malloc(len); bcopy(data,n->data,len); } else if (off+len <= f->off+f->len) { if (off < f->off) { d = malloc((f->off-off)+f->len); bcopy(f->data,d+(f->off-off),f->len); bcopy(data,d,len); free(f->data); f->data = d; f->len += f->off - off; f->off = off; } else { bcopy(data,f->data+(off-f->off),len); } } else { if (off <= f->off) { d = malloc(len); bcopy(data,d,len); free(f->data); f->data = d; f->off = off; f->len = len; } else { f->len = off + len - f->off; f->data = realloc(f->data,f->len); bcopy(data,f->data+(off-f->off),len); } n = f->link; while (n && (off+len >= n->off+n->len)) { f->link = n->link; free(n->data); free(n); } if (n && (off+len >= n->off)) { f->link = n->link; f->len = n->off + n->len - f->off; f->data = realloc(f->data,f->len); bcopy(n->data+((off+len)-n->off),f->data+((off+len)-f->off),(n->off+n->len)-(off+len)); free(n->data); free(n); } } } static int reass_add_frag(void) { int hl; REASS_ID id; REASS *r; int alloc; unsigned short int off; id.id = get16(4); id.src = get32(12); id.dst = get32(16); id.proto = get8(9); hash_id(&id); off = get16(6); alloc = ((off & (IP_OFF_MF|IP_OFF_OFF)) != 0); r = find_reass(&id,alloc); if (! r) return(0); if (! alloc) { unlink_reass(r); free_reass(r); return(0); } hl = get8(0) & 0x0f; if (! (off & IP_OFF_MF)) r->sawlast = 1; if (! (off & IP_OFF_OFF)) { free(r->hdr); r->hdr = malloc(hl*4); bcopy(pkt,r->hdr,hl*4); } add_reass_data(r,(off&IP_OFF_OFF)*8,pkt+(hl*4),pktleft-(hl*4)); return(1); } int print_ip_header(const char *tag, int mainhdr) { int ip_hl; int ip_v; unsigned char ip_tos; short int ip_len; unsigned short int ip_id; short int ip_off; unsigned char ip_ttl; unsigned char ip_p; unsigned short int ip_sum; unsigned long int ip__src; unsigned long int ip__dst; int ip_optlen; int n; unsigned char *pkt0; int pktleft0; pkt0 = pkt; pktleft0 = pktleft; need(20,"minimum IP header"); printx(pkt,1); ip_hl = get8(0) & 0xf; ip_v = get8(0) >> 4; printf("%sip_hl=%d %sip_v=%d\n",tag,ip_hl,tag,ip_v); if (ip_v != 4) { printf("*** IP version not equal to 4\n"); dumpabort(); } if (ip_hl < 5) { printf("*** Claimed header size too small\n"); dumpabort(); } consume(1); printx(pkt,1); ip_tos = get8(0); printf("%sip_tos [",tag); switch (ip_tos & IP_TOS_PREC) { case IP_TOS_PREC_ROUTINE : printf("Routine"); break; case IP_TOS_PREC_PRIORITY : printf("Priority"); break; case IP_TOS_PREC_IMMEDIATE : printf("Immediate"); break; case IP_TOS_PREC_FLASH : printf("Flash"); break; case IP_TOS_PREC_FLASH_OVR : printf("Flash Override"); break; case IP_TOS_PREC_CRITIC_ECP: printf("CRITIC/ECP"); break; case IP_TOS_PREC_INTNET_CTL: printf("Internetwork Control"); break; case IP_TOS_PREC_NET_CTL : printf("Network Control"); break; } if (ip_tos & IP_TOS_D) printf(", Low Delay"); if (ip_tos & IP_TOS_T) printf(", High Throughput"); if (ip_tos & IP_TOS_R) printf(", High Reliability"); if (ip_tos & IP_TOS_RES2) printf(", Reserved 0x02"); if (ip_tos & IP_TOS_RES1) printf(", Reserved 0x01"); printf("]\n"); consume(1); printx(pkt,2); ip_len = get16(0); printf("%sip_len [%d]",tag,ip_len); if (mainhdr && (ip_len < pktleft+2)) { printf(" (dropping %d trailing byte%s)",pktleft+2-ip_len,((pktleft+2-ip_len)==1)?"":"s"); pktleft0 -= pktleft - (ip_len - 2); pktleft = ip_len - 2; } printf("\n"); consume(2); if (mainhdr && (ip_len > pktleft+4)) { printf("*** IP header claims %d bytes in packet but have only %d\n",ip_len,pktleft+4); dumpabort(); } printx(pkt,2); ip_id = get16(0); printf("%sip_id\n",tag); consume(2); printx(pkt,2); ip_off = get16(0); printf("%sip_off [%d",tag,ip_off&IP_OFF_OFF); if (ip_off & IP_OFF_MF) printf(", MF"); if (ip_off & IP_OFF_DF) printf(", DF"); if (ip_off & IP_OFF_RESV) printf(", reserved flag"); printf("]\n"); consume(2); printx(pkt,1); ip_ttl = get8(0); printf("%sip_ttl [%d]\n",tag,ip_ttl); consume(1); printx(pkt,1); ip_p = get8(0); printf("%sip_p",tag); switch (ip_p) { case IPPROTO_ICMP: printf(" [ICMP]"); break; case IPPROTO_IGMP: printf(" [IGMP]"); break; case IPPROTO_GGP: printf(" [GGP]"); break; case IPPROTO_TCP: printf(" [TCP]"); break; case IPPROTO_EGP: printf(" [EGP]"); break; case IPPROTO_PUP: printf(" [PUP]"); break; case IPPROTO_UDP: printf(" [UDP]"); break; case IPPROTO_IDP: printf(" [IDP]"); break; case IPPROTO_HELLO: printf(" [HELLO]"); break; case IPPROTO_ND: printf(" [ND]"); break; } printf("\n"); consume(1); printx(pkt,2); ip_sum = get16(0); printf("%sip_sum\n",tag); consume(2); printx(pkt,4); ip__src = get32(0); printf("%sip_src [%lu.%lu.%lu.%lu]\n",tag,ip__src>>24,(ip__src>>16)&0xff,(ip__src>>8)&0xff,ip__src&0xff); consume(4); printx(pkt,4); ip__dst = get32(0); printf("%sip_dst [%lu.%lu.%lu.%lu]\n",tag,ip__dst>>24,(ip__dst>>16)&0xff,(ip__dst>>8)&0xff,ip__dst&0xff); consume(4); if (mainhdr) { ip_src = ip__src; ip_dst = ip__dst; } ip_optlen = (ip_hl - 5) * 4; need(ip_optlen,"IP options"); while (ip_optlen > 0) { switch (*pkt) { case 0x00: printx(pkt,1); printf("%sipopt: end-of-list\n",tag); n = 1; break; case 0x01: printx(pkt,1); printf("%sipopt: No-op\n",tag); n = 1; break; case 0x82: n = get8(1); need(n,"IP option (Security)"); printx(pkt,n); if (n != 11) { printf("%sipopt: Security (bad length)\n",tag); } else { printf("%sipopt: Security\n",tag); } break; case 0x83: n = get8(1); need(n,"IP option (LSRR)"); printx(pkt,n); printf("%sipopt: LSRR\n",tag); break; case 0x89: n = get8(1); need(n,"IP option (SSRR)"); printx(pkt,n); printf("%sipopt: SSRR\n",tag); break; case 0x07: n = get8(1); need(n,"IP option (RR)"); printx(pkt,n); printf("%sipopt: RR\n",tag); break; case 0x88: n = get8(1); need(n,"IP option (Stream ID)"); printx(pkt,n); if (n != 4) { printf("%sipopt: Stream ID (bad length)\n",tag); } else { printf("%sipopt: Stream ID\n",tag); } break; case 0x44: n = get8(1); need(n,"IP option (Timestamp)"); printx(pkt,n); printf("%sipopt: Timestamp\n",tag); break; default: n = 1; printx(pkt,1); printf("%sipopt: unrecognized\n",tag); break; } consume(n); ip_optlen -= n; } n = pkt - pkt0; if (n != pktleft0-pktleft) { printf("print_ip_header mismatch"); abort(); } pkt = pkt0; pktleft = pktleft0; if (reass_add_frag()) return(-1); pkt += n; pktleft -= n; return(ip_p); } void dump_ip(void) { int ip_p; ip_p = print_ip_header("",1); switch (ip_p) { case -1: printf("*** Packet fragment\n"); pktleft = 0; break; case IPPROTO_TCP: dump_tcp(); break; case IPPROTO_UDP: dump_udp(); break; case IPPROTO_ICMP: dump_icmp(); break; } } void ip_flush_reass(void) { REASS *r; REASS *r2; static unsigned char *rpkt = 0; static int rplen = 0; int len; int hl; for (r=reass_head;r;r=r2) { r2 = r->flink; if (! r->frags) { fprintf(stderr,"Reassembly item with no frags?"); abort(); } if ( r->sawlast && !r->frags->link && (r->frags->off == 0) ) { if (! r->hdr) { fprintf(stderr,"Reassembly done without header?"); abort(); } unlink_reass(r); pkt = r->hdr; pktleft = 20; hl = get8(0) & 0x0f; len = (hl * 4) + r->frags->len; if (len > rplen) { free(rpkt); rpkt = malloc(len); rplen = len; } bcopy(r->hdr,rpkt,hl*4); bcopy(r->frags->data,rpkt+(hl*4),r->frags->len); pkt = rpkt; pktleft = (hl * 4) + r->frags->len; pkt[6] &= ~0x3f; pkt[7] = 0; /* MF = 0, frag off = 0 */ pkt[2] = pktleft >> 8; pkt[3] = pktleft & 0xff; /* reset length */ pkt[10] = 0; pkt[11] = 0; /* checksum = 0 */ free_reass(r); printf("\n Reassembled packet (%d bytes):\n",pktleft); dump_ip(); dump_data(); } } }