void handle_ether(const u_char * pkt, int len, void *userdata) { struct ether_header *e = (struct ether_header *)pkt; unsigned short etype; if (len < ETHER_HDR_LEN) return; etype = nptohs(&e->ether_type); if (callback_ether) if (0 != callback_ether(pkt, len, userdata)) return; pkt += ETHER_HDR_LEN; len -= ETHER_HDR_LEN; if (ETHERTYPE_8021Q == etype) { unsigned short vlan = nptohs((unsigned short *) pkt); if (callback_vlan) if (0 != callback_vlan(vlan, userdata)) return; etype = nptohs((unsigned short *)(pkt + 2)); pkt += 4; len -= 4; } if (len < 0) return; /* fprintf(stderr, "Ethernet packet of len %d ethertype %#04x\n", len, etype); */ if (is_ethertype_ip(etype)) { handle_ip((struct ip *)pkt, len, userdata); } }
void handle_ppp(const u_char * pkt, int len, void *userdata) { char buf[PCAP_SNAPLEN]; unsigned short proto; if (len < 2) return NULL; if (*pkt == PPP_ADDRESS_VAL && *(pkt + 1) == PPP_CONTROL_VAL) { pkt += 2; /* ACFC not used */ len -= 2; } if (len < 2) return NULL; if (*pkt % 2) { proto = *pkt; /* PFC is used */ pkt++; len--; } else { proto = nptohs(pkt); pkt += 2; len -= 2; } if (is_ethertype_ip(proto)) handle_ip((struct ip *)pkt, len, userdata); }
void handle_linux_sll(const u_char * pkt, int len, void *userdata) { struct sll_header *s = (struct sll_header *)pkt; unsigned short etype, eproto; if (len < SLL_HDR_LEN) return; etype = nptohs(&s->sll_pkttype); if (etype == LINUX_SLL_BROADCAST || etype == LINUX_SLL_MULTICAST) return; eproto = nptohs(&s->sll_protocol); if (eproto != ETHERTYPE_IP) return; pkt += SLL_HDR_LEN; len -= SLL_HDR_LEN; /* fprintf(stderr, "linnux cooked packet of len %d type %#04x proto %#04x\n", len, etype, eproto); */ handle_ip((struct ip *)pkt, len, userdata); }
void handle_gre(const u_char * gre, int len, void *userdata) { int grelen = 4; unsigned short flags = nptohs(gre); unsigned short etype = nptohs(gre + 2); if (len < grelen) return; if (callback_gre) callback_gre(gre, len, userdata); if (flags & 0x0001) /* checksum present? */ grelen += 4; if (flags & 0x0004) /* key present? */ grelen += 4; if (flags & 0x0008) /* sequence number present? */ grelen += 4; if (is_ethertype_ip(etype)) handle_ip((struct ip *) (gre + grelen), len - grelen, userdata); }
static off_t grok_additional_for_opt_rr(const u_char *buf, int len, off_t offset, dns_message * m) { int x; unsigned short sometype; unsigned short someclass; unsigned short us; char somename[MAX_QNAME_SZ]; x = rfc1035NameUnpack(buf, len, &offset, somename, MAX_QNAME_SZ); if (0 != x) return 0; if (offset + 10 > len) return 0; sometype = nptohs(buf + offset); someclass = nptohs(buf + offset + 2); if (sometype == T_OPT) { m->edns.found = 1; m->edns.bufsiz = someclass; memcpy(&m->edns.version, buf + offset + 5, 1); us = nptohs(buf + offset + 6); m->edns.DO = (us >> 15) & 0x01; /* RFC 3225 */ }
static off_t grok_question(const u_char *buf, int len, off_t offset, char *qname, unsigned short *qtype, unsigned short *qclass) { char *t; int x; x = rfc1035NameUnpack(buf, len, &offset, qname, MAX_QNAME_SZ); if (0 != x) return 0; if ('\0' == *qname) strcpy(qname, "."); /* XXX remove special characters from QNAME */ while ((t = strchr(qname, '\n'))) *t = ' '; while ((t = strchr(qname, '\r'))) *t = ' '; for (t = qname; *t; t++) *t = tolower(*t); if (offset + 4 > len) return 0; *qtype = nptohs(buf + offset); *qclass = nptohs(buf + offset + 2); offset += 4; return offset; }
/* * When passing on to the next layers, use the ip_len * value for the length, unless the given len happens to * to be less for some reason. Note that ip_len might * be less than len due to Ethernet padding. */ void handle_ipv4(const struct ip *ip, int len, void *userdata) { int offset; int iplen; uint16_t ip_off; if (len < sizeof(*ip)) return; offset = ip->ip_hl << 2; iplen = XMIN(nptohs(&ip->ip_len), len); if (callback_ipv4) if (0 != callback_ipv4(ip, iplen, userdata)) return; ip_off = ntohs(ip->ip_off); if ((ip_off & (IP_OFFMASK | IP_MF)) && _reassemble_fragments) { handle_ipv4_fragment(ip, iplen, userdata); } else if (IPPROTO_UDP == ip->ip_p) { handle_udp((struct udphdr *)((char *)ip + offset), iplen - offset, userdata); } else if (IPPROTO_TCP == ip->ip_p) { handle_tcp((struct tcphdr *)((char *)ip + offset), iplen - offset, userdata); } else if (IPPROTO_GRE == ip->ip_p) { handle_gre((u_char *)ip + offset, iplen - offset, userdata); } }
static int rfc1035NameUnpack(const u_char *buf, size_t sz, off_t * off, char *name, int ns) { off_t no = 0; unsigned char c; size_t len; static int loop_detect = 0; if (loop_detect > 2) return 4; /* compression loop */ if (ns <= 0) return 4; /* probably compression loop */ do { if ((*off) >= sz) break; c = *(buf + (*off)); if (c > 191) { /* blasted compression */ int rc; unsigned short s; off_t ptr; s = nptohs(buf + (*off)); (*off) += sizeof(s); /* Sanity check */ if ((*off) >= sz) return 1; /* message too short */ ptr = s & 0x3FFF; /* Make sure the pointer is inside this message */ if (ptr >= sz) return 2; /* bad compression ptr */ if (ptr < DNS_MSG_HDR_SZ) return 2; /* bad compression ptr */ loop_detect++; rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no); loop_detect--; return rc; } else if (c > RFC1035_MAXLABELSZ) { /* * "(The 10 and 01 combinations are reserved for future use.)" */ return 3; /* reserved label/compression flags */ break; } else { (*off)++; len = (size_t) c; if (len == 0) break; if (len > (ns - 1)) len = ns - 1; if ((*off) + len > sz) return 4; /* message is too short */ if (no + len + 1 > ns) return 5; /* qname would overflow name buffer */ memcpy(name + no, buf + (*off), len); (*off) += len; no += len; *(name + (no++)) = '.'; } } while (c > 0); if (no > 0) *(name + no - 1) = '\0'; /* make sure we didn't allow someone to overflow the name buffer */ assert(no <= ns); return 0; }
x = rfc1035NameUnpack(buf, len, &offset, somename, MAX_QNAME_SZ); if (0 != x) return 0; if (offset + 10 > len) return 0; sometype = nptohs(buf + offset); someclass = nptohs(buf + offset + 2); if (sometype == T_OPT) { m->edns.found = 1; m->edns.bufsiz = someclass; memcpy(&m->edns.version, buf + offset + 5, 1); us = nptohs(buf + offset + 6); m->edns.DO = (us >> 15) & 0x01; /* RFC 3225 */ } /* get rdlength */ us = nptohs(buf + offset + 8); offset += 10; if (offset + us > len) return 0; offset += us; return offset; } void handle_dns(const u_char *buf, uint16_t len, transport_message *tm, DMC *dns_message_callback) { unsigned short us; off_t offset; int qdcount; int ancount; int nscount;
void handle_ipv6(const struct ip6_hdr *ip6, int len, void *userdata) { int offset; int nexthdr; uint16_t payload_len; if (len < sizeof(*ip6)) return; if (callback_ipv6) if (0 != callback_ipv6(ip6, len, userdata)) return; offset = sizeof(struct ip6_hdr); nexthdr = ip6->ip6_nxt; payload_len = nptohs(&ip6->ip6_plen); /* * Parse extension headers. This only handles the standard headers, as * defined in RFC 2460, correctly. Fragments are discarded. */ while ((IPPROTO_ROUTING == nexthdr) /* routing header */ ||(IPPROTO_HOPOPTS == nexthdr) /* Hop-by-Hop options. */ ||(IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */ ||(IPPROTO_DSTOPTS == nexthdr) /* destination options. */ ||(IPPROTO_AH == nexthdr) /* authentication header. */ ||(IPPROTO_ESP == nexthdr)) { /* encapsulating security payload. */ typedef struct { uint8_t nexthdr; uint8_t length; } ext_hdr_t; ext_hdr_t *ext_hdr; uint16_t ext_hdr_len; /* Catch broken packets */ if ((offset + sizeof(ext_hdr)) > len) return; /* Cannot handle fragments. */ if (IPPROTO_FRAGMENT == nexthdr) return; ext_hdr = (ext_hdr_t *) ((char *)ip6 + offset); nexthdr = ext_hdr->nexthdr; ext_hdr_len = (8 * (ext_hdr->length + 1)); /* This header is longer than the packets payload.. WTF? */ if (ext_hdr_len > payload_len) return; offset += ext_hdr_len; payload_len -= ext_hdr_len; } /* while */ /* Catch broken and empty packets */ if (((offset + payload_len) > len) || (payload_len == 0) || (payload_len > PCAP_SNAPLEN)) return; if (IPPROTO_UDP == nexthdr) { handle_udp((struct udphdr *)((char *)ip6 + offset), payload_len, userdata); } else if (IPPROTO_TCP == nexthdr) { handle_tcp((struct tcphdr *)((char *)ip6 + offset), payload_len, userdata); } else if (IPPROTO_GRE == nexthdr) { handle_gre((u_char *)ip6 + offset, payload_len, userdata); } }