예제 #1
0
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(&eth_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(&eth_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(&eth_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);
}
예제 #2
0
파일: snoop.c 프로젝트: bricsuc/tcptracelib
/* 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);
    }
}