static void decode_icmp(const uint8_t *packet, size_t pk_len, int pk_layer) { union { const struct myicmphdr *i; const uint8_t *d; } ic_u; /* ;] */ uint8_t type=0, code=0; uint16_t chksum=0; ic_u.d=packet; if (pk_len < 4) { ERR("short icmp header"); return; } type=ic_u.i->type; code=ic_u.i->code; chksum=ntohs(ic_u.i->checksum); if (ISDBG(M_PKT) || GET_SNIFF()) { INF("ICMP: type %u code %u chksum %04x%s", type, code, chksum, "[?]"); } if (type == 3 || type == 5 || type == 11) { /* * dest unreachable, the packet that generated this error should be after the icmpheader * redirect message, same as with unreachable * time exceeded, same as with above */ if (pk_len > sizeof(struct myicmphdr)) { /* there _could_ be data there, try to process it */ const uint8_t *newpacket=NULL; size_t newpk_len=0; newpacket=packet + sizeof(struct myicmphdr); newpk_len=pk_len - sizeof(struct myicmphdr); decode_ip(newpacket, newpk_len, (pk_layer + 1)); } } else if (type == 0 || type == 8) { /* pings ignore */ DBG(M_PKT, "Ignoring ping request or response"); } if (pk_layer == 2) { r_u.i.type=type; r_u.i.subtype=code; report_push(); } return; }
static void slice_icmp(const uint8_t *packet, size_t pk_len, packetlayers_t *plz, int pk_layer) { union { const struct myicmphdr *i; const uint8_t *d; } ic_u; /* ;] */ uint8_t type=0, code=0; uint16_t chksum=0; assert(plz != NULL); assert(packet != NULL); ic_u.d=packet; if (pk_len < 4) { return; } type=ic_u.i->type; code=ic_u.i->code; chksum=ntohs(ic_u.i->checksum); if (type == 3 || type == 5 || type == 11) { /* dest unreachable, the packet that generated this error should be after the icmpheader */ /* redirect message, same as with unreachable */ /* time exceeded, same as with above */ if (pk_len > sizeof(struct myicmphdr)) { /* there _could_ be data there, try to process it */ const uint8_t *newpacket=NULL; size_t newpk_len=0; newpacket=packet + sizeof(struct myicmphdr); newpk_len=pk_len - sizeof(struct myicmphdr); decode_ip(newpacket, newpk_len, (pk_layer + 1)); } } else if (type == 0 || type == 8) { /* pings ignore */ } if (pk_layer == 2) { r_u.i.type=type; r_u.i.subtype=code; report_push(); } return; }
static void decode_tcp (const uint8_t *packet, size_t pk_len, int pk_layer) { union { const struct mytcphdr *t; const uint8_t *d; } t_u; uint16_t sport=0, dport=0; uint32_t seq=0, ackseq=0; uint8_t doff=0, res1=0; uint16_t window=0, chksum=0, c_chksum=0, urgptr=0; size_t data_len=0, tcpopt_len=0; int bad_cksum=0; union { const ip_pseudo_t *ipph_ptr; const uint8_t *ptr; } ipph_u; struct chksumv c[2]; t_u.d=packet; if (pk_layer == 4) { /* this is inside an icmp error reflection, check that */ if (r_u.i.proto != IPPROTO_ICMP) { ERR("FIXME in TCP not inside an ICMP error?"); return; } /* * ok so why the special treatment? well the packet may be incomplete, so its ok if we dont have * a full udp header, we really are only looking for the source and dest ports, we _need_ those * everything else is optional at this point */ if (pk_len < 4) { ERR("TCP header too incomplete to get source and dest ports, halting processing"); return; } if (pk_len >= 4 && pk_len < sizeof(struct mytcphdr)) { /* * this is reversed from a response, the host never responded so flip src/dest ports */ r_u.i.sport=ntohs(t_u.t->dest); r_u.i.dport=ntohs(t_u.t->source); return; } } if (pk_len < sizeof(struct mytcphdr)) { ERR("short tcp header"); return; } sport=ntohs(t_u.t->source); dport=ntohs(t_u.t->dest); seq=ntohl(t_u.t->seq); ackseq=ntohl(t_u.t->ack_seq); doff=t_u.t->doff; res1=t_u.t->res1; window=ntohs(t_u.t->window); chksum=ntohs(t_u.t->check); urgptr=ntohs(t_u.t->urg_ptr); if (pk_layer == 2) { uint32_t eackseq=0, high=0; TCPHASHTRACK(eackseq, r_u.i.host_addr, sport, dport, s->ss->syn_key); if (GET_LDOCONNECT()) { DBG(M_PKT, "window size is %u or whatever", s->ss->window_size); high=eackseq + s->ss->window_size; } else { high=eackseq + 2; /* should always be +1, but lets just accept someone who didnt inc th seq */ } if (SEQ_WITHIN(ackseq, eackseq, high)) { DBG(M_PKT, "packet within my %08x-%08x window, with %08x expecting %08x", eackseq, high, ackseq, eackseq); } else if (! GET_SNIFF() && ! GET_IGNORESEQ() && ! (GET_IGNORERSEQ() && t_u.t->rst)) { DBG(M_PKT, "not my packet ackseq %08x expecting somewhere around %08x-%08x", ackseq, eackseq, high); return; } } /* layer 3 seq checking */ if (doff && ((size_t)(doff * 4) > pk_len)) { ERR("datalength exceeds capture length, truncating to zero (doff %u bytes pk_len " STFMT ")", doff * 4, pk_len); doff=0; } if (doff && (size_t )(doff * 4) < sizeof(struct mytcphdr)) { ERR("doff is too small, increasing to min size and hoping for no tcpoptions"); doff=sizeof(struct mytcphdr) / 4; } if (doff) { tcpopt_len=((doff * 4) - sizeof(struct mytcphdr)); data_len=pk_len - (doff * 4); } else { tcpopt_len=pk_len - sizeof(struct mytcphdr); data_len=0; } ipph_u.ipph_ptr=&ipph; /* its not natural to use _this_ size... */ ipph.len=ntohs(pk_len); c[0].len=sizeof(ipph); c[0].ptr=ipph_u.ptr; c[1].len=pk_len; c[1].ptr=packet; c_chksum=do_ipchksumv((const struct chksumv *)&c[0], 2); if (c_chksum != 0) { DBG(M_PKT, "bad tcp checksum, ipchksumv returned 0x%04x", c_chksum); bad_cksum=1; } if (ISDBG(M_PKT) || GET_SNIFF()) { char tcpflags[16]; memset(tcpflags, '-', sizeof(tcpflags)); tcpflags[8]='\0'; if (t_u.t->fin) tcpflags[0]='F'; if (t_u.t->syn) tcpflags[1]='S'; if (t_u.t->rst) tcpflags[2]='R'; if (t_u.t->psh) tcpflags[3]='P'; if (t_u.t->ack) tcpflags[4]='A'; if (t_u.t->urg) tcpflags[5]='U'; if (t_u.t->ece) tcpflags[6]='E'; if (t_u.t->cwr) tcpflags[7]='C'; INF("TCP : size " STFMT " sport %u dport %u seq 0x%08x ack_seq 0x%08x window %u", pk_len, sport, dport, seq, ackseq, window); INF("TCP : doff %u res1 %u flags `%s' chksum 0x%04x%s urgptr 0x%04x", doff, res1, tcpflags, chksum, (bad_cksum != 0 ? " [bad cksum]" : " [cksum ok]"), urgptr); INF("TCP : options length " STFMT " data length " STFMT, tcpopt_len, data_len); } packet += sizeof(struct mytcphdr); pk_len -= sizeof(struct mytcphdr); if (tcpopt_len && (ISDBG(M_PKT) || GET_SNIFF())) { decode_tcpopts(packet, tcpopt_len); } if (data_len && (ISDBG(M_PKT) || GET_SNIFF())) { INF("TCP : dumping packet data"); hexdump(packet + tcpopt_len, data_len); } if (pk_layer == 2) { r_u.i.sport=sport; r_u.i.dport=dport; r_u.i.type=0; r_u.i.tseq=seq; r_u.i.mseq=ackseq; r_u.i.window_size=window; if (t_u.t->fin) r_u.i.type |= TH_FIN; if (t_u.t->syn) r_u.i.type |= TH_SYN; if (t_u.t->rst) r_u.i.type |= TH_RST; if (t_u.t->psh) r_u.i.type |= TH_PSH; if (t_u.t->ack) r_u.i.type |= TH_ACK; if (t_u.t->urg) r_u.i.type |= TH_URG; if (t_u.t->ece) r_u.i.type |= TH_ECE; if (t_u.t->cwr) r_u.i.type |= TH_CWR; r_u.i.subtype=0; if (bad_cksum) { r_u.i.flags |= REPORT_BADTRANSPORT_CKSUM; } if (GET_WATCHERRORS() || GET_LDOCONNECT()) { report_push(); } else if (t_u.t->syn /* close enough */) { report_push(); } } else if (pk_layer == 4) { r_u.i.sport=dport; r_u.i.dport=sport; r_u.i.mseq=ackseq; r_u.i.tseq=seq; r_u.i.window_size=0; } else { ERR("fixme"); return; } return; }
static void decode_udp (const uint8_t *packet, size_t pk_len, int pk_layer) { union { const struct myudphdr *u; const uint8_t *d; } u_u; uint16_t sport=0, dport=0, len=0, chksum=0, c_chksum=0; int bad_cksum=0; union { const ip_pseudo_t *ipph_ptr; const uint8_t *ptr; } ipph_u; struct chksumv c[2]; u_u.d=packet; if (pk_layer == 4) { /* this is inside an icmp error reflection, check that */ if (r_u.i.proto != IPPROTO_ICMP) { ERR("FIXME in UDP not inside a ICMP error?"); return; } /* see TCP comment above about special treatment */ if (pk_len < 4) { ERR("UDP header too short to get source and dest ports"); return; } if (pk_len >= 4 && pk_len < sizeof(struct myudphdr)) { /* this is reversed from a response, the host never responded so flip src/dest ports */ r_u.i.sport=ntohs(u_u.u->dest); r_u.i.dport=ntohs(u_u.u->source); r_u.i.tseq=0; r_u.i.mseq=0; return; } } if (pk_len < sizeof(struct myudphdr)) { ERR("short udp header"); return; } sport=ntohs(u_u.u->source); dport=ntohs(u_u.u->dest); len=ntohs(u_u.u->len); chksum=ntohs(u_u.u->check); ipph_u.ipph_ptr=&ipph; ipph.len=ntohs(pk_len); c[0].len=sizeof(ipph); c[0].ptr=ipph_u.ptr; c[1].len=pk_len; c[1].ptr=packet; c_chksum=do_ipchksumv((const struct chksumv *)&c[0], 2); if (c_chksum != 0) { DBG(M_PKT, "bad udp checksum, ipchksumv returned 0x%x", c_chksum); bad_cksum=1; } if (ISDBG(M_PKT) || GET_SNIFF()) { INF("UDP : pklen " STFMT " sport %u dport %u len %u checksum %04x%s", pk_len, sport, dport, len, chksum, bad_cksum == 0 ? " [bad cksum]" : " [cksum ok]"); } if (pk_layer == 2) { r_u.i.sport=sport; r_u.i.dport=dport; r_u.i.type=0; r_u.i.subtype=0; r_u.i.tseq=0; r_u.i.mseq=0; report_push(); } else if (pk_layer == 4) { /* this is reversed from a response, the host never responded so flip src/dest ports */ r_u.i.sport=dport; r_u.i.dport=sport; r_u.i.tseq=0; r_u.i.mseq=0; } else { ERR("FIXME at decode UDP at layer %d", pk_layer); return; } pk_len -= sizeof(struct myudphdr); packet += sizeof(struct myudphdr); if (pk_len && (ISDBG(M_PKT) || GET_SNIFF())) { INF("UDP : dumping UDP payload"); hexdump(packet, pk_len); } return; }
static void decode_arp (const uint8_t *packet, size_t pk_len, int pk_layer) { union { const struct myetherarphdr *a; const uint8_t *d; } a_u; uint16_t hwtype=0, opcode=0; a_u.d=packet; r_u.a.flags=0; if (pk_len < sizeof(struct myetherarphdr)) { ERR("short arp packet"); return; } hwtype=ntohs(a_u.a->hw_type); opcode=ntohs(a_u.a->opcode); if (a_u.a->protosize != 4 || a_u.a->hwsize != 6) { DBG(M_PKT, "arp packet isnt 6:4, giving up"); return; } if (opcode != ARPOP_REPLY) { return; } if (memcmp(s->vi[0]->hwaddr, a_u.a->smac, 6) == 0) { return; /* we sent this */ } if (ISDBG(M_PKT) || GET_SNIFF()) { char srcip[32], srcmac[32]; struct in_addr ia; ia.s_addr=a_u.a->sip; sprintf(srcip, "%s", inet_ntoa(ia)); ia.s_addr=a_u.a->dip; sprintf(srcmac, "%s", decode_6mac(a_u.a->smac)); INF("ARP : hw_type `%s' protocol `%s' hwsize %d protosize %d opcode `%s'", str_hwtype(hwtype), str_hwproto(a_u.a->protocol), a_u.a->hwsize, a_u.a->protosize, str_opcode(opcode)); INF("ARP : SRC HW %s SRC IP -> %s DST HW %s DST IP %s", srcmac, srcip, decode_6mac(a_u.a->dmac), inet_ntoa(ia)); } pk_len -= sizeof(struct myetherarphdr); memcpy(r_u.a.hwaddr, a_u.a->smac, THE_ONLY_SUPPORTED_HWADDR_LEN); memcpy(&r_u.a.ipaddr, &a_u.a->sip, sizeof(r_u.a.ipaddr)); report_push(); if (pk_len) { /* frame padding ;] */ pk_layer++; packet += sizeof(struct myetherarphdr); decode_junk(packet, pk_len, pk_layer); } return; }