static int callback( char *user, struct pcap_pkthdr *phdr, char *buf) { int type; int iplen; static int offset = -1; struct vlanh{ tt_uint16 vlan_num; tt_uint16 vlan_proto; } *vlanhptr; iplen = phdr->caplen; if (iplen > IP_MAXPACKET) iplen = IP_MAXPACKET; type = pcap_datalink(pcap); /* remember the stuff we always save */ callback_phdr = phdr; /* kindof ugly, but about the only way to make them fit together :-( */ switch (type) { case 100: /* for some reason, the windows version of tcpdump is using */ /* this. It looks just like ethernet to me */ case PCAP_DLT_EN10MB: offset = find_ip_eth(buf); /* Here we check if we are dealing with Straight Ethernet encapsulation or PPPoE */ memcpy(ð_header, buf, EH_SIZE); /* save ether header */ switch (offset) { case EH_SIZE: /* straight Ethernet encapsulation */ memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PPPOE_SIZE: /* PPPoE encapsulation */ /* we use a fake ether type here */ eth_header.ether_type = htons(ETHERTYPE_IP); memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case -1: /* Not an IP packet */ /* Let's check if it is a VLAN header that * caused us to receive -1, and if we had an IP * packet buried inside */ if (eth_header.ether_type == htons(ETHERTYPE_VLAN)) { vlanhptr=(struct vlanh*) (buf+EH_SIZE); if ( (ntohs(vlanhptr->vlan_proto) == ETHERTYPE_IP) || (ntohs(vlanhptr->vlan_proto) == ETHERTYPE_IPV6) ) { offset=EH_SIZE+sizeof(struct vlanh); memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; /* Set ethernet type as whatever followed the dumb * VLAN header to prevent the rest of the code * from ignoring us. */ eth_header.ether_type=vlanhptr->vlan_proto; break; } } return (-1); default: /* should not be used, but we never know ... */ return (-1); } break; case PCAP_DLT_IEEE802: /* just pretend it's "normal" ethernet */ offset = 14; /* 22 bytes of IEEE cruft */ memcpy(ð_header,buf,EH_SIZE); /* save ether header */ memcpy(ip_buf,buf+offset,iplen-offset); callback_plast = (char *)ip_buf+iplen-offset-1; break; case PCAP_DLT_SLIP: memcpy(ip_buf,buf+16,iplen-16); callback_plast = (char *)ip_buf+iplen-16-1; break; case PCAP_DLT_PPP: /* deals with raw PPP and also with HDLC PPP frames */ offset = find_ip_ppp(buf); if (offset < 0) /* Not an IP packet */ return (-1); memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_FDDI: if (offset < 0) offset = find_ip_fddi(buf,iplen); if (offset < 0) return(-1); memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_NULL: /* no phys header attached */ offset = 4; memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_ATM_RFC1483: /* ATM RFC1483 - LLC/SNAP ecapsulated atm */ memcpy((char*)ip_buf,buf+8,iplen-8); callback_plast = ip_buf+iplen-8-1; break; case PCAP_DLT_RAW: /* raw IP */ offset = 0; memcpy((char *)ip_buf,buf+offset,iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_LINUX_SLL: /* linux cooked socket */ offset = 16; memcpy((char *)ip_buf, buf+offset, iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; // Patch sent by Brandon Eisenamann to passby 802.11, LLC/SNAP // and Prism2 headers to get to the IP packet. case PCAP_DLT_IEEE802_11: offset=24+8;// 802.11 header + LLC/SNAP header memcpy((char *)ip_buf, buf+offset, iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_IEEE802_11_RADIO: offset=64+24;//WLAN header + 802.11 header memcpy(ð_header,buf,EH_SIZE); // save ethernet header memcpy((char *)ip_buf, buf+offset, iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_PRISM2: offset=144+24+8; // PRISM2+IEEE 802.11+ LLC/SNAP headers memcpy((char *)ip_buf, buf+offset, iplen-offset); callback_plast = ip_buf+iplen-offset-1; break; case PCAP_DLT_C_HDLC: offset=4; memcpy((char *)ip_buf, buf+offset, iplen-offset); callback_plast = (char *)ip_buf+iplen-offset-1; break; default: fprintf(stderr,"Don't understand link-level format (%d)\n", type); exit(1); } return(0); }
/* currently only works for ETHERNET and FDDI */ static int pread_snoop( tcptrace_context_t *context, struct timeval *ptime, int *plen, int *ptlen, void **pphys, int *pphystype, struct ip **ppip, void **pplast) { int packlen; int rlen; int len; struct snoop_packet_header hdr; int hlen; while (1) { hlen = sizeof(struct snoop_packet_header); /* read the packet header */ if ((rlen=fread(&hdr,1,hlen,SYS_STDIN)) != hlen) { if (rlen != 0) fprintf(stderr,"Bad snoop packet header\n"); return(0); } /* convert some stuff to host byte order */ hdr.tlen = ntohl(hdr.tlen); hdr.len = ntohl(hdr.len); hdr.blen = ntohl(hdr.blen); hdr.secs = ntohl(hdr.secs); hdr.usecs = ntohl(hdr.usecs); /* truncated packet length */ packlen = hdr.tlen; /* bug fix from Brian Utterback */ /* "blen" is the "total length of the packet", header+data+padding */ len = hdr.blen - hlen; if (snoop_mac_type == SNOOP_DL_ETHER) { /* read the ethernet header */ rlen=fread(pep,1,sizeof(struct ether_header),SYS_STDIN); if (rlen != sizeof(struct ether_header)) { fprintf(stderr,"Couldn't read ether header\n"); return(0); } /* read the rest of the packet */ len -= sizeof(struct ether_header); if (len >= IP_MAXPACKET) { /* sanity check */ fprintf(stderr, "pread_snoop: invalid next packet, IP len is %d, return EOF\n", len); return(0); } /* add VLAN support for John Tysko */ if ((ntohs(pep->ether_type) == ETHERTYPE_VLAN) && (len >= 4)){ struct { tt_uint16 vlan_num; tt_uint16 vlan_proto; } vlanh; /* adjust packet length */ len -= 4; /* read the vlan header */ if ((rlen=fread(&vlanh,1,sizeof(vlanh),SYS_STDIN)) != sizeof(vlanh)) { perror("pread_snoop: seek past vlan header"); } if ((ntohs(vlanh.vlan_proto) == ETHERTYPE_IP) || (ntohs(vlanh.vlan_proto) == ETHERTYPE_IPV6)) { /* make it appear to have been IP all along */ /* (note that both fields are still in N.B.O. */ pep->ether_type = vlanh.vlan_proto; if (tcptrace_debuglevel > 2) printf("Removing VLAN header (vlan:%x)\n", vlanh.vlan_num); } else { if (tcptrace_debuglevel > 2) printf("Skipping a VLAN packet (num:%x proto:%x)\n", vlanh.vlan_num, vlanh.vlan_proto); } } /* if it's not IP, then skip it */ if ((ntohs(pep->ether_type) != ETHERTYPE_IP) && (ntohs(pep->ether_type) != ETHERTYPE_IPV6)) { if (tcptrace_debuglevel > 2) fprintf(stderr, "pread_snoop: not an IP packet (ethertype 0x%x)\n", ntohs(pep->ether_type)); /* discard the remainder */ /* N.B. fseek won't work - it could be a pipe! */ if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) { perror("pread_snoop: seek past non-IP"); } continue; } if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) { if (rlen != 0 && tcptrace_debuglevel) fprintf(stderr, "Couldn't read %d more bytes, skipping last packet\n", len); return(0); } *ppip = (struct ip *) pip_buf; /* last byte in the IP packet */ *pplast = (char *)pip_buf+packlen-sizeof(struct ether_header)-1; } else if (snoop_mac_type == SNOOP_DL_FDDI) { /* FDDI is different */ int offset; /* read in the whole frame and search for IP header */ /* (assumes sizeof(fddi frame) < IP_MAXPACKET, should be true) */ if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) { if (tcptrace_debuglevel && rlen != 0) fprintf(stderr, "Couldn't read %d more bytes, skipping last packet\n", len); return(0); } /* find the offset of the IP header inside the FDDI frame */ if ((offset = find_ip_fddi((void *)pip_buf,len)) == -1) { /* not found */ if (tcptrace_debuglevel) printf("snoop.c: couldn't find next IP within FDDI\n"); return(-1); } /* copy to avoid alignment problems later (yucc) */ /* (we use memmove to make overlaps work) */ memmove(pip_buf,(char *)pip_buf+offset,len-offset); /* point to first and last char in IP packet */ *ppip = (struct ip *) ((void *)pip_buf); *pplast = (char *)pip_buf+len-offset-1; /* assume it's IP (else find_ip_fddi would have failed) */ pep->ether_type = htons(ETHERTYPE_IP); } else if (snoop_mac_type == SNOOP_DL_ATM) { /* there's a 12 byte header that we don't care about */ /* the last 2 of those 12 bytes are the packet type */ /* we don't care about hardware header, so we just discard */ struct atm_header { u_char junk[10]; u_short type; } atm_header; /* grab the 12-byte header */ rlen=fread(&atm_header,1,sizeof(struct atm_header),SYS_STDIN); if (rlen != sizeof(struct atm_header)) { fprintf(stderr,"Couldn't read ATM header\n"); return(0); } /* fill in the ethernet type */ /* we'll just assume that they're both in the same network byte order */ pep->ether_type = atm_header.type; /* read the rest of the packet */ len -= sizeof(struct atm_header); if (len >= IP_MAXPACKET) { /* sanity check */ fprintf(stderr, "pread_snoop: invalid next packet, IP len is %d, return EOF\n", len); return(0); } /* if it's not IP, then skip it */ if ((ntohs(pep->ether_type) != ETHERTYPE_IP) && (ntohs(pep->ether_type) != ETHERTYPE_IPV6)) { if (tcptrace_debuglevel > 2) fprintf(stderr, "pread_snoop: not an IP packet (ethertype 0x%x)\n", ntohs(pep->ether_type)); /* discard the remainder */ /* N.B. fseek won't work - it could be a pipe! */ if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) { perror("pread_snoop: seek past non-IP"); } continue; } if ((rlen=fread(pip_buf,1,len,SYS_STDIN)) != len) { if (rlen != 0 && tcptrace_debuglevel) fprintf(stderr, "Couldn't read %d more bytes, skipping last packet\n", len); return(0); } *ppip = (struct ip *) pip_buf; /* last byte in the IP packet */ *pplast = (char *)pip_buf+packlen-sizeof(struct ether_header)-1; } else { printf("snoop hardware type %d not understood\n", snoop_mac_type); exit(-1); } /* save pointer to physical header (always ethernet) */ *pphys = pep; *pphystype = PHYS_ETHER; ptime->tv_sec = hdr.secs; ptime->tv_usec = hdr.usecs; *plen = hdr.len; *ptlen = hdr.tlen; return(1); } }