www.pudn.com > ids_snort.zip > decode.c
/* $Id: decode.c,v 1.26 2001/01/26 16:40:44 roesch Exp $ */ /* ** Copyright (C) 1998,1999,2000,2001 Martin Roesch** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "decode.h" /* * Function: DecodeEthPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decode those fun loving ethernet packets, one at a time! * * Arguments: p => pointer to the decoded packet struct * user => Utility pointer (unused) * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeEthPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { u_int32_t pkt_len; /* suprisingly, the length of the packet */ u_int32_t cap_len; /* caplen value */ bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; /* set the lengths we need */ pkt_len = pkthdr->len; /* total packet length */ cap_len = pkthdr->caplen; /* captured packet length */ if(snaplen < pkt_len) pkt_len = cap_len; #ifdef DEBUG printf("Packet!\n"); printf("caplen: %lu pktlen: %lu\n", (unsigned long)cap_len, (unsigned long)pkt_len); #endif /* do a little validation */ if(p->pkth->caplen < ETHERNET_HEADER_LEN) { if(pv.verbose_flag) { ErrorMessage("Captured data length < Ethernet header length! (%d bytes)\n", p->pkth->caplen); } return; } /* lay the ethernet structure over the packet data */ p->eh = (EtherHdr *) pkt; #ifdef DEBUG ErrorMessage("%X %X\n", *p->eh->ether_src, *p->eh->ether_dst); #endif /* grab out the network type */ switch(ntohs(p->eh->ether_type)) { case ETHERNET_TYPE_IP: #ifdef DEBUG printf("IP datagram size calculated to be %lu bytes\n",(unsigned long)(cap_len - ETHERNET_HEADER_LEN)); #endif DecodeIP(p->pkt + ETHERNET_HEADER_LEN, cap_len - ETHERNET_HEADER_LEN, p); /* DecodeIP(p->pkt+ETHERNET_HEADER_LEN, cap_len, p); */ return; case ETHERNET_TYPE_ARP: case ETHERNET_TYPE_REVARP: pc.arp++; if(pv.showarp_flag) { DecodeARP(p->pkt + ETHERNET_HEADER_LEN, cap_len - ETHERNET_HEADER_LEN, p); } return; case ETHERNET_TYPE_IPV6: pc.ipv6++; if(pv.showipv6_flag) DecodeIPV6(p->pkt + ETHERNET_HEADER_LEN, (cap_len - ETHERNET_HEADER_LEN)); return; case ETHERNET_TYPE_IPX: pc.ipx++; if(pv.showipx_flag) DecodeIPX(p->pkt + ETHERNET_HEADER_LEN, (cap_len - ETHERNET_HEADER_LEN)); return; default: pc.other++; return; } return; } /* * Function: DecodeNullPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decoding on loopback devices. * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeNullPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { u_int32_t len; u_int32_t cap_len; bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; len = pkthdr->len; cap_len = pkthdr->caplen; #ifdef DEBUG printf("Packet!\n"); #endif /* do a little validation */ if(cap_len < NULL_HDRLEN) { if(pv.verbose_flag) { ErrorMessage("NULL header length < captured len! (%d bytes)\n", cap_len); } return; } DecodeIP(p->pkt + NULL_HDRLEN, cap_len - NULL_HDRLEN, p); } /* * Function: DecodeTRPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decode Token Ring packets! * * Arguments: p=> pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeTRPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { u_int32_t pkt_len; /* suprisingly, the length of the packet */ u_int32_t cap_len; /* caplen value */ u_int32_t dataoff; /* data offset is variable here */ bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; /* set the lengths we need */ pkt_len = pkthdr->len; /* total packet length */ cap_len = pkthdr->caplen; /* captured packet length */ if(snaplen < pkt_len) pkt_len = cap_len; #ifdef DEBUG printf("Packet!\n"); printf("caplen: %lu pktlen: %lu\n",(unsigned long)cap_len,(unsigned long) pkt_len); #endif /* do a little validation */ if(p->pkth->caplen < TR_HLEN) { if(pv.verbose_flag) ErrorMessage("Captured data length < Token Ring header length! (%d < %d bytes)\n", p->pkth->caplen, TR_HLEN); return; } /* lay the tokenring header structure over the packet data */ p->trh = (Trh_hdr *) pkt; /* * according to rfc 1042: The presence of a Routing Information Field is indicated by the Most Significant Bit (MSB) of the source address, called the Routing Information Indicator (RII). If the RII equals zero, a RIF is not present. If the RII equals 1, the RIF is present. .. However the MSB is already zeroed by this moment, so there's no real way to figure out whether RIF is presented in packet, so we are doing some tricks to find IPARP signature.. */ /* * first I assume that we have single-ring network with no RIF * information presented in frame */ p->trhllc = (Trh_llc *) (pkt + sizeof(Trh_hdr)); if(p->trhllc->dsap != IPARP_SAP && p->trhllc->ssap != IPARP_SAP) { /* * DSAP != SSAP != 0xAA .. either we are having frame which doesn't * carry IP datagrams or has RIF information present. We assume * lattest ... */ p->trhmr = (Trh_mr *) (pkt + sizeof(Trh_hdr)); p->trhllc = (Trh_llc *) (pkt + sizeof(Trh_hdr) + p->trhmr->len); dataoff = sizeof(Trh_hdr) + p->trhmr->len + sizeof(Trh_llc); } else { p->trhllc = (Trh_llc *) (pkt + sizeof(Trh_hdr)); dataoff = sizeof(Trh_hdr) + sizeof(Trh_llc); } /* * ideally we would need to check both SSAP, DSAP, and protoid fields: IP * datagrams and ARP requests and replies are transmitted in standard * 802.2 LLC Type 1 Unnumbered Information format, control code 3, with * the DSAP and the SSAP fields of the 802.2 header set to 170, the * assigned global SAP value for SNAP [6]. The 24-bit Organization Code * in the SNAP is zero, and the remaining 16 bits are the EtherType from * Assigned Numbers [7] (IP = 2048, ARP = 2054). .. but we would check * SSAP and DSAP and assume this would be enough to trust. */ if(p->trhllc->dsap != IPARP_SAP && p->trhllc->ssap != IPARP_SAP) { #ifdef DEBUG ErrorMessage("DSAP and SSAP arent set to SNAP\n"); #endif p->trhllc = NULL; return; } pkt_len -= dataoff; cap_len -= dataoff; switch(htons(p->trhllc->ethertype)) { case ETHERNET_TYPE_IP: #ifdef DEBUG printf("Decoding IP\n"); #endif DecodeIP(p->pkt + dataoff, cap_len, p); return; case ETHERNET_TYPE_ARP: case ETHERNET_TYPE_REVARP: #ifdef DEBUG printf("Decoding ARP\n"); #endif pc.arp++; return; default: #ifdef DEBUG printf("Unknown network protocol: %d\n", htons(p->trhllc->ethertype)); #endif pc.other++; return; } return; } /* * Function: DecodeFDDIPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Mainly taken from CyberPsycotic's Token Ring Code -worm5er * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeFDDIPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { u_int32_t pkt_len; /* length of the packet */ u_int32_t cap_len; /* capture length variable */ u_int32_t dataoff; /* data offset is variable here */ bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; pkt_len = pkthdr->len; cap_len = pkthdr->caplen; if(snaplen < pkt_len) { pkt_len = cap_len; } #ifdef DEBUG printf("Packet!\n"); printf("caplen: %lu pktlen: %lu\n",(unsigned long) cap_len,(unsigned long) pkt_len); #endif /* Bounds checking (might not be right yet -worm5er) */ if(p->pkth->caplen < FDDI_MIN_HLEN) { if(pv.verbose_flag) { ErrorMessage("Captured data length < FDDI header length! " "(%d %d bytes)\n", p->pkth->caplen, FDDI_MIN_HLEN); return; } } /* let's put this in as the fddi header structure */ p->fddihdr = (Fddi_hdr *) pkt; p->fddisaps = (Fddi_llc_saps *) (pkt + sizeof(Fddi_hdr)); /* First we'll check and see if it's an IP/ARP Packet... */ /* Then we check to see if it's a SNA packet */ /* * Lastly we'll declare it none of the above and just slap something * generic on it to discard it with (I know that sucks, but heck we're * only looking for IP/ARP type packets currently... -worm5er */ if((p->fddisaps->dsap == FDDI_DSAP_IP) && (p->fddisaps->ssap == FDDI_SSAP_IP)) { p->fddiiparp = (Fddi_llc_iparp *) (pkt + sizeof(Fddi_hdr) + sizeof(Fddi_llc_saps)); dataoff = sizeof(Fddi_hdr) + sizeof(Fddi_llc_saps) + sizeof(Fddi_llc_iparp); } else if((p->fddisaps->dsap == FDDI_DSAP_SNA) && (p->fddisaps->ssap == FDDI_SSAP_SNA)) { p->fddisna = (Fddi_llc_sna *) (pkt + sizeof(Fddi_hdr) + sizeof(Fddi_llc_saps)); dataoff = sizeof(Fddi_hdr) + sizeof(Fddi_llc_saps) + sizeof(Fddi_llc_sna); } else { p->fddiother = (Fddi_llc_other *) (pkt + sizeof(Fddi_hdr) + sizeof(Fddi_llc_other)); dataoff = sizeof(Fddi_hdr) + sizeof(Fddi_llc_saps) + sizeof(Fddi_llc_other); } /* * Now let's see if we actually care about the packet... If we don't, * throw it out!!! */ if((p->fddisaps->dsap != FDDI_DSAP_IP) && (p->fddisaps->ssap != FDDI_SSAP_IP)) { #ifdef DEBUG ErrorMessage("This FDDI Packet isn't an IP/ARP packet...\n"); #endif return; } pkt_len -= dataoff; cap_len -= dataoff; switch(htons(p->fddiiparp->ethertype)) { case ETHERNET_TYPE_IP: #ifdef DEBUG printf("Decoding IP\n"); #endif DecodeIP(p->pkt + dataoff, cap_len, p); return; case ETHERNET_TYPE_ARP: case ETHERNET_TYPE_REVARP: #ifdef DEBUG printf("Decoding ARP\n"); #endif pc.arp++; return; default: #ifdef DEBUG printf("Unknown network protocol: %d\n", htons(p->fddiiparp->ethertype)); #endif pc.other++; return; } return; } /* * Function: DecodePppPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decoded PPP traffic * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodePppPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { static int had_vj = 0; u_int32_t len; u_int32_t cap_len; struct ppp_header *ppphdr; bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; ppphdr = (struct ppp_header *)pkt; len = pkthdr->len; cap_len = pkthdr->caplen; #ifdef DEBUG printf("Packet!\n"); #endif /* do a little validation */ if(cap_len < PPP_HDRLEN) { ErrorMessage("PPP header length < captured len! (%d bytes)\n", cap_len); return; } /* * We only handle uncompressed packets. Handling VJ compression would mean * to implement a PPP state machine. */ switch (ntohs(ppphdr->protocol)) { case PPP_VJ_COMP: if (!had_vj) ErrorMessage("PPP link seems to use VJ compression, cannot handle compressed packets!\n"); had_vj = 1; break; case PPP_VJ_UCOMP: /* VJ compression modifies the protocol field. It must be set * to tcp (only TCP packets can be VJ compressed) */ if(cap_len < PPP_HDRLEN + IP_HEADER_LEN) { ErrorMessage("PPP VJ min packet length > captured len! (%d bytes)\n", cap_len); return; } ((IPHdr *)(p->pkt + PPP_HDRLEN))->ip_proto = IPPROTO_TCP; /* fall through */ case PPP_IP: DecodeIP(p->pkt + PPP_HDRLEN, cap_len - PPP_HDRLEN, p); break; case PPP_IPX: DecodeIPX(p->pkt + PPP_HDRLEN, cap_len - PPP_HDRLEN); break; } } /* * Function: DecodeSlipPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decode SLIP traffic * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeSlipPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { u_int32_t len; u_int32_t cap_len; bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; len = pkthdr->len; cap_len = pkthdr->caplen; #ifdef DEBUG printf("Packet!\n"); #endif /* do a little validation */ if(cap_len < SLIP_HEADER_LEN) { ErrorMessage("SLIP header length < captured len! (%d bytes)\n", cap_len); return; } DecodeIP(p->pkt + SLIP_HEADER_LEN, cap_len - SLIP_HEADER_LEN, p); } /* * Function: DecodeRawPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decodes packets coming in raw on layer 2, like PPP. Coded and * in by Jed Pickle (thanks Jed!) and modified for a few little tweaks * by me. * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeRawPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; #ifdef DEBUG printf("Packet!\n"); #endif DecodeIP(pkt, p->pkth->caplen, p); return; } /* * Function: DecodeI4LRawIPPkt(Packet *, char *, struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decodes packets coming in raw on layer 2, like PPP. Coded and * in by Jed Pickle (thanks Jed!) and modified for a few little tweaks * by me. * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeI4LRawIPPkt(Packet * p, struct pcap_pkthdr * pkthdr, u_int8_t * pkt) { bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; #ifdef DEBUG printf("Packet!\n"); #endif DecodeIP(pkt + 2, p->pkth->len - 2, p); return; } /* * Function: DecodeI4LCiscoIPPkt(Packet *, char *, * struct pcap_pkthdr*, u_int8_t*) * * Purpose: Decodes packets coming in raw on layer 2, like PPP. Coded and * in by Jed Pickle (thanks Jed!) and modified for a few little tweaks * by me. * * Arguments: p => pointer to decoded packet struct * user => Utility pointer, unused * pkthdr => ptr to the packet header * pkt => pointer to the real live packet data * * Returns: void function */ void DecodeI4LCiscoIPPkt(Packet *p, struct pcap_pkthdr *pkthdr, u_int8_t *pkt) { bzero((char *) p, sizeof(Packet)); p->pkth = pkthdr; p->pkt = pkt; #ifdef DEBUG printf("Packet!\n"); #endif DecodeIP(pkt + 4, p->pkth->caplen - 4, p); return; } /* * Function: DecodeIP(u_int8_t *, const u_int32_t, Packet *) * * Purpose: Decode the IP network layer * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * p => pointer to the packet decode struct * * Returns: void function */ void DecodeIP(u_int8_t * pkt, const u_int32_t len, Packet * p) { u_int32_t ip_len; /* length from the start of the ip hdr to the * pkt end */ u_int32_t hlen; /* ip header length */ u_int16_t csum; /* checksum */ /* lay the IP struct over the raw data */ p->iph = (IPHdr *) pkt; #ifdef DEBUG printf("ip header starts at: %p, length is %lu\n", p->iph, (unsigned long) len); #endif /* do a little validation */ if(len < IP_HEADER_LEN) { if(pv.verbose_flag) { ErrorMessage("IP header truncated! (%d bytes)\n", len); } p->iph = NULL; return; } /* * with datalink DLT_RAW it's impossible to differ ARP datagrams from IP. * So we are just ignoring non IP datagrams */ if(p->iph->ip_ver != 4) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: Not IPv4 datagram! ([ver: 0x%x][len: 0x%x])\n", p->iph->ip_ver, p->iph->ip_len); } if(pv.logbin_flag) LogBin(p, NULL, NULL); p->iph = NULL; pc.discards++; return; } /* set the IP datagram length */ ip_len = ntohs(p->iph->ip_len); /* set the IP header length */ hlen = p->iph->ip_hlen << 2; if (ip_len != len) { if (ip_len > len) { #ifdef DEBUG if (pv.verbose_flag) ErrorMessage("[!] WARNING: IP Len field is %d bytes bigger than captured length.\n" " (ip.len: %lu, cap.len: %lu)\n", ip_len - len, ip_len, len); #endif ip_len = len; } else { #ifdef DEBUG if (pv.verbose_flag) ErrorMessage("[!] WARNING: IP Len field is %d bytes smaller than captured length.\n" " (ip.len: %lu, cap.len: %lu)\n", len - ip_len, ip_len, len); #endif } } if(ip_len < hlen) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: IP dgm len (%d bytes) < IP hdr len (%d bytes), packet discarded\n", ip_len, hlen); } if(pv.logbin_flag) LogBin(p, NULL, NULL); p->iph = NULL; pc.discards++; return; } csum = checksum((u_short *)p->iph, hlen, (u_short *)NULL, 0); if(csum) { p->csum_flags |= CSE_IP; #ifdef DEBUG printf("Bad IP checksum\n"); #endif } #ifdef DEBUG else { printf("IP Checksum: OK\n"); } #endif /* test for IP options */ if(p->iph->ip_hlen > 5) { DecodeIPOptions((pkt + IP_HEADER_LEN), hlen - IP_HEADER_LEN, p); } else { p->ip_option_count = 0; } /* set the remaining packet length */ ip_len -= hlen; /* check for fragmented packets */ p->frag_offset = ntohs(p->iph->ip_off); /* get the values of the reserved, more fragments and don't fragment flags */ p->rf = (p->frag_offset & 0x8000) >> 15; p->df = (p->frag_offset & 0x4000) >> 14; p->mf = (p->frag_offset & 0x2000) >> 13; /* mask off the high bits in the fragment offset field */ p->frag_offset &= 0x1FFF; if(p->frag_offset || p->mf) { /* set the packet fragment flag */ p->frag_flag = 1; pc.frags++; } /* if this packet isn't a fragment */ if(!(p->frag_flag)) { /* set the packet fragment flag */ p->frag_flag = 0; #ifdef DEBUG printf("IP header length: %lu\n", (unsigned long)hlen); #endif switch(p->iph->ip_proto) { case IPPROTO_TCP: pc.tcp++; DecodeTCP(pkt + hlen, ip_len, p); ClearDumpBuf(); return; case IPPROTO_UDP: pc.udp++; DecodeUDP(pkt + hlen, ip_len, p); ClearDumpBuf(); return; case IPPROTO_ICMP: pc.icmp++; DecodeICMP(pkt + hlen, ip_len, p); ClearDumpBuf(); return; default: pc.other++; p->data = pkt + hlen; p->dsize = ip_len; ClearDumpBuf(); return; } } else { /* set the payload pointer and payload size */ p->data = pkt + hlen; p->dsize = ip_len; } } /* * Function: DecodeIPOnly(u_int8_t *, const u_int32_t, Packet *) * * Purpose: Decode the IP network layer but not recurse * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * p => pointer to dummy packet decode struct * * Returns: void function */ int DecodeIPOnly(u_int8_t * pkt, const u_int32_t len, Packet * p) { u_int32_t ip_len; /* length from the start of the ip hdr to the * pkt end */ u_int32_t hlen; /* ip header length */ /* lay the IP struct over the raw data */ p->iph = (IPHdr *) pkt; #ifdef DEBUG printf("DecodeIPOnly: ip header starts at: %p, length is %lu\n", p->iph, (unsigned long) len); #endif /* do a little validation */ if(len < IP_HEADER_LEN) { ErrorMessage("ICMP Unreachable IP short header (%d bytes)\n", len); p->iph = NULL; return(0); } /* * with datalink DLT_RAW it's impossible to differ ARP datagrams from IP. * So we are just ignoring non IP datagrams */ if(p->iph->ip_ver != 4) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: ICMP Unreachable not IPv4 datagram ([ver: 0x%x][len: 0x%x])\n", p->iph->ip_ver, p->iph->ip_len); } p->iph = NULL; return(0); } /* set the IP datagram length */ ip_len = ntohs(p->iph->ip_len); /* set the IP header length */ hlen = p->iph->ip_hlen << 2; if(len < hlen) { ErrorMessage("[!] WARNING: ICMP Unreachable IP len (%d bytes) < IP hdr len (%d bytes), packet discarded\n", ip_len, hlen); p->iph = NULL; return(0); } /* don't try to recalculate the checksum of the encapsulated packet, * it will almost always be wrong and we already tested it on the * packet that spawned this UNREACH packet -MFR */ /*csum = checksum((u_short *)p->iph, hlen, (u_short *)NULL, 0); if(csum) { p->csum_flags |= CSE_IP; #ifdef DEBUG printf("Bad IP checksum\n"); #endif } #ifdef DEBUG else { printf("IP Checksum: OK\n"); } #endif*/ /* we probably aren't real interested in IP options, we already put them * out for the originating packet so it'd probably be best to advance the * packet pointer up to the next layer if it's available -MFR */ /* test for IP options */ /*if(p->iph->ip_hlen > 5) { DecodeIPOptions((pkt + IP_HEADER_LEN), hlen - IP_HEADER_LEN, p); } else {*/ p->ip_option_count = 0; /*}*/ /* set the remaining packet length */ ip_len = len - hlen; /* check for fragmented packets */ p->frag_offset = ntohs(p->iph->ip_off); /* get the values of the reserved, more fragments and don't fragment flags */ p->rf = (p->frag_offset & 0x8000) >> 15; p->df = (p->frag_offset & 0x4000) >> 14; p->mf = (p->frag_offset & 0x2000) >> 13; /* mask off the high bits in the fragment offset field */ p->frag_offset &= 0x1FFF; if(p->frag_offset || p->mf) { /* set the packet fragment flag */ p->frag_flag = 1; /* set the payload pointer and payload size */ p->data = pkt + hlen; p->dsize = ip_len; } else { p->frag_flag = 0; #ifdef DEBUG printf("ICMP Unreachable IP header length: %lu\n", (unsigned long)hlen); #endif switch(p->iph->ip_proto) { case IPPROTO_TCP: /* decode the interesting part of the header */ if(ip_len > 4) { p->tcph =(TCPHdr *)(pkt + hlen); /* stuff more data into the printout data struct */ p->sp = ntohs(p->tcph->th_sport); p->dp = ntohs(p->tcph->th_dport); } break; case IPPROTO_UDP: if(ip_len > 4) { p->udph = (UDPHdr *)(pkt + hlen); /* fill in the printout data structs */ p->sp = ntohs(p->udph->uh_sport); p->dp = ntohs(p->udph->uh_dport); } break; } } return(1); } /* * Function: DecodeTCP(u_int8_t *, const u_int32_t, Packet *) * * Purpose: Decode the TCP transport layer * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * p => Pointer to packet decode struct * * Returns: void function */ void DecodeTCP(u_int8_t * pkt, const u_int32_t len, Packet * p) { struct pseudoheader /* pseudo header for TCP checksum calculations */ { u_int32_t sip, dip; /* IP addr */ u_int8_t zero; /* checksum placeholder */ u_int8_t protocol; /* protocol number */ u_int16_t tcplen; /* tcp packet length */ }; u_int32_t hlen; /* TCP header length */ u_short csum; /* checksum */ struct pseudoheader ph; /* pseudo header declaration */ if(len < 20) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: TCP packet (len = %d) cannot contain 20 byte header\n", len); } if(pv.logbin_flag) LogBin(p, NULL, NULL); p->tcph = NULL; pc.discards++; } /* lay TCP on top of the data cause there is enough of it! */ p->tcph = (TCPHdr *) pkt; /* multiply the payload offset value by 4 */ hlen = p->tcph->th_off << 2; #ifdef DEBUG printf("TCP th_off is %d, passed len is %lu\n", p->tcph->th_off, (unsigned long)len); #endif if(hlen < 20) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: TCP Data Offset %d < 5 \n", p->tcph->th_off); } if(pv.logbin_flag) LogBin(p, NULL, NULL); hlen = 20; } /* setup the pseudo header for checksum calculation */ ph.sip = (u_int32_t)(p->iph->ip_src.s_addr); ph.dip = (u_int32_t)(p->iph->ip_dst.s_addr); ph.zero = 0; ph.protocol = p->iph->ip_proto; ph.tcplen = htons((unsigned short)len); /* calculate the checksum */ csum = checksum((u_int16_t *)&ph, 12, (u_int16_t *)(p->tcph), len); if(csum) { p->csum_flags |= CSE_TCP; #ifdef DEBUG printf("Bad TCP checksum\n"); #endif } #ifdef DEBUG else { printf("TCP Checksum: OK\n"); } #endif #ifdef DEBUG printf("tcp header starts at: %p\n", p->tcph); #endif /* if options are present, decode them */ if(hlen > 20) { #ifdef DEBUG printf("%lu bytes of tcp options....\n", (unsigned long)(hlen - 20)); #endif DecodeTCPOptions((u_int8_t *) (pkt + 20), (hlen - 20), p); } else { p->tcp_option_count = 0; } /* stuff more data into the printout data struct */ p->sp = ntohs(p->tcph->th_sport); p->dp = ntohs(p->tcph->th_dport); /* set the data pointer and size */ p->data = (u_int8_t *) (pkt + hlen); if(hlen < len) { p->dsize = len - hlen; } else { p->dsize = 0; } } /* * Function: DecodeUDP(u_int8_t *, const u_int32_t, Packet *) * * Purpose: Decode the UDP transport layer * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * p => pointer to decoded packet struct * * Returns: void function */ void DecodeUDP(u_int8_t * pkt, const u_int32_t len, Packet * p) { struct pseudoheader { u_int32_t sip, dip; u_int8_t zero; u_int8_t protocol; u_int16_t udplen; }; u_short csum; struct pseudoheader ph; if(len < sizeof(UDPHdr)) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: Truncated UDP header (%d bytes)\n", len); } if(pv.logbin_flag) LogBin(p, NULL, NULL); p->udph = NULL; pc.discards++; return; } /* set the ptr to the start of the UDP header */ p->udph = (UDPHdr *) pkt; /* look at the UDP checksum to make sure we've got a good packet */ ph.sip = (u_int32_t)(p->iph->ip_src.s_addr); ph.dip = (u_int32_t)(p->iph->ip_dst.s_addr); ph.zero = 0; ph.protocol = p->iph->ip_proto; ph.udplen = htons((unsigned short)len); csum = checksum((u_short *)&ph, 12, (u_short *)(p->udph), len); if(csum) { p->csum_flags |= CSE_UDP; #ifdef DEBUG printf("Bad UDP Checksum\n"); #endif } #ifdef DEBUG else { printf("UDP Checksum: OK\n"); } #endif #ifdef DEBUG printf("UDP header starts at: %p\n", p->udph); #endif /* fill in the printout data structs */ p->sp = ntohs(p->udph->uh_sport); p->dp = ntohs(p->udph->uh_dport); p->data = (u_int8_t *) (pkt + UDP_HEADER_LEN); if((len - UDP_HEADER_LEN) > 0) { p->dsize = len - UDP_HEADER_LEN; } else { p->dsize = 0; } } /* * Function: DecodeICMP(u_int8_t *, const u_int32_t, Packet *) * * Purpose: Decode the ICMP transport layer * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * p => pointer to the decoded packet struct * * Returns: void function */ void DecodeICMP(u_int8_t * pkt, const u_int32_t len, Packet * p) { u_int16_t csum; if(len < sizeof(ICMPHdr)) { if(pv.verbose_flag) { ErrorMessage("[!] WARNING: Truncated ICMP header(%d bytes)\n", len); } if(pv.logbin_flag) LogBin(p, NULL, NULL); p->icmph = NULL; pc.discards++; return; } /* set the header ptr first */ p->icmph = (ICMPHdr *) pkt; csum = checksum((u_int16_t *)p->icmph, len, NULL, 0); if(csum) { p->csum_flags |= CSE_ICMP; #ifdef DEBUG printf("Bad ICMP Checksum\n"); #endif } #ifdef DEBUG else { printf("ICMP Checksum: OK\n"); } #endif p->dsize = len - ICMP_HEADER_LEN; p->data = pkt + ICMP_HEADER_LEN; #ifdef DEBUG printf("ICMP type: %d code: %d\n", p->icmph->code, p->icmph->type); #endif switch(p->icmph->type) { case ICMP_ECHOREPLY: /* setup the pkt id ans seq numbers */ p->ext = (echoext *) (pkt + ICMP_HEADER_LEN); p->dsize -= sizeof(echoext); p->data += sizeof(echoext); break; case ICMP_ECHO: /* setup the pkt id ans seq numbers */ p->ext = (echoext *) (pkt + ICMP_HEADER_LEN); p->dsize -= 4; /* add the size of the echo ext to the data * ptr and subtract it from the data size */ p->data += 4; break; case ICMP_DEST_UNREACH: { Packet orig_p; /* if unreach packet is smaller than expected! */ if(len < 16) { if(pv.verbose_flag) ErrorMessage("[!] WARNING: Truncated ICMP-UNREACH header (%d bytes)\n", len); /* if it is less than 8 we are in trouble */ if(len < 8) break; } bzero((char *)&orig_p, sizeof(Packet)); orig_p.caplen = len - 8; if(DecodeIPOnly(pkt + 8, orig_p.caplen, &orig_p)) { /* * that's probably what we need to know about an original * datagram */ p->orig_iph = orig_p.iph; p->orig_tcph = orig_p.tcph; p->orig_udph = orig_p.udph; p->orig_icmph = orig_p.icmph; p->orig_sp = orig_p.sp; p->orig_dp = orig_p.dp; } else { if(pv.logbin_flag) LogBin(p, NULL, NULL); } break; } } return; } /* * Function: DecodeARP(u_int8_t *, u_int32_t, Packet *) * * Purpose: Decode ARP stuff * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * p => pointer to decoded packet struct * * Returns: void function */ void DecodeARP(u_int8_t * pkt, u_int32_t len, Packet * p) { p->ah = (EtherARP *) pkt; if(len < sizeof(EtherARP)) { if(pv.verbose_flag) printf("Truncated packet\n"); if(pv.logbin_flag) LogBin(p, NULL, NULL); pc.discards++; return; } return; } /* * Function: DecodeIPV6(u_int8_t *, u_int32_t) * * Purpose: Just like IPX, it's just for counting. * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * * Returns: void function */ void DecodeIPV6(u_int8_t *pkt, u_int32_t len) { if(pv.verbose_flag) { puts("IPV6 packet"); } return; } /* * Function: DecodeIPX(u_int8_t *, u_int32_t) * * Purpose: Well, it doesn't do much of anything right now... * * Arguments: pkt => ptr to the packet data * len => length from here to the end of the packet * * Returns: void function * */ void DecodeIPX(u_int8_t *pkt, u_int32_t len) { if(pv.verbose_flag) { puts("IPX packet"); } return; } /* * Function: DecodeTCPOptions(u_int8_t *, u_int32_t, Packet *) * * Purpose: Fairly self explainatory name, don't you think? * * Arguments: o_list => ptr to the option list * o_len => length of the option list * p => pointer to decoded packet struct * * Returns: void function */ void DecodeTCPOptions(u_int8_t *o_list, u_int32_t o_len, Packet *p) { u_int8_t *option_ptr; u_int32_t bytes_processed; u_int32_t current_option; u_char done = 0; option_ptr = o_list; bytes_processed = 0; current_option = 0; while((bytes_processed < o_len) && (current_option < 40) && !done) { p->tcp_options[current_option].code = *option_ptr; switch(*option_ptr) { case TCPOPT_NOP: case TCPOPT_EOL: if(*option_ptr == TCPOPT_EOL) done = 1; p->tcp_options[current_option].len = 0; p->tcp_options[current_option].data = NULL; bytes_processed++; current_option++; option_ptr++; break; case TCPOPT_SACKOK: p->tcp_options[current_option].len = 0; p->tcp_options[current_option].data = NULL; bytes_processed += 2; option_ptr += 2; current_option++; break; case TCPOPT_WSCALE: p->tcp_options[current_option].len = 3; p->tcp_options[current_option].data = option_ptr + 2; option_ptr += 3; bytes_processed += 3; current_option++; break; default: p->tcp_options[current_option].len = *(option_ptr + 1); if(p->tcp_options[current_option].len > 40) { p->tcp_options[current_option].len = 40; } else if( p->tcp_options[current_option].len == 0) { /* got a bad option, we're all done */ done = 1; p->tcp_lastopt_bad = 1; } p->tcp_options[current_option].data = option_ptr + 2; option_ptr += p->tcp_options[current_option].len; bytes_processed += p->tcp_options[current_option].len; current_option++; break; } } if(bytes_processed > o_len) { p->tcp_options[current_option].len = p->tcp_options[current_option].len - (bytes_processed - o_len); /* * in reality shouldn't happen until we got the option type and len * on the packet header boundary.. then we just drop last option (as * it is corrupted anyway). */ if(p->tcp_options[current_option].len < 0) current_option--; } p->tcp_option_count = current_option; return; } /* * Function: DecodeIPOptions(u_int8_t *, u_int32_t, Packet *) * * Purpose: Once again, a fairly self-explainatory name * * Arguments: o_list => ptr to the option list * o_len => length of the option list * p => pointer to decoded packet struct * * Returns: void function */ void DecodeIPOptions(u_int8_t *o_list, u_int32_t o_len, Packet *p) { u_int8_t *option_ptr; u_int32_t bytes_processed; u_int32_t current_option; u_char done = 0; option_ptr = o_list; bytes_processed = 0; current_option = 0; #ifdef DEBUG printf("Decoding %d bytes of IP options\n", o_len); #endif while((bytes_processed < o_len) && (current_option < 40) && !done) { #ifdef DEBUG printf(" => %d bytes processed\n", bytes_processed); #endif p->ip_options[current_option].code = *option_ptr; switch(*option_ptr) { case IPOPT_RTRALT: case IPOPT_NOP: case IPOPT_EOL: /* if we hit an EOL, we're done */ if(*option_ptr == IPOPT_EOL) done = 1; p->ip_options[current_option].len = 0; p->ip_options[current_option].data = NULL; bytes_processed++; current_option++; option_ptr++; break; default: p->ip_options[current_option].len = *(option_ptr + 1); if(p->ip_options[current_option].len > 40) { p->ip_options[current_option].len = 40; } else if(p->ip_options[current_option].len == 0) { /* * this shouldn't happen, indicates a bad option list * so we bail */ done = 1; p->ip_lastopt_bad = 1; } p->ip_options[current_option].data = option_ptr + 2; option_ptr += p->ip_options[current_option].len; #ifdef DEBUG printf(" => Adding %d bytes\n", p->ip_options[current_option].len); #endif bytes_processed += p->ip_options[current_option].len; current_option++; break; } } #ifdef DEBUG printf(" => %d total bytes processed\n", bytes_processed); #endif if(bytes_processed > o_len) { p->ip_options[current_option].len = p->ip_options[current_option].len - (bytes_processed - o_len); /* * in reality shouldn't happen until we got the option type and len * on the packet header boundary.. then we just drop last option (as * it is corrupted anyway). */ if(p->ip_options[current_option].len < 0) current_option--; } p->ip_option_count = current_option; return; }