From 23f7c78663e37c7061d7b13a4d96015ae6012528 Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Tue, 4 Dec 2012 01:08:55 +0100 Subject: add functions from old/glougloud --- gg_sniff/pcap.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) (limited to 'gg_sniff/pcap.c') diff --git a/gg_sniff/pcap.c b/gg_sniff/pcap.c index 4a2d6fb..2d885bd 100644 --- a/gg_sniff/pcap.c +++ b/gg_sniff/pcap.c @@ -167,3 +167,281 @@ my_pcap_open_live(const char *dev, int slen, int promisc, int to_ms, return pcap_open_live(dev, slen, promisc, to_ms, ebuf); #endif } + +static void +ev_pcap(int fd, short why, void *data) +{ + log_tmp("ev_pcap"); + pcap_dispatch(cap->pcap, PCAP_COUNT, cap->pcap_handler, NULL); + + /* reschedule */ + if (event_add(&cap->pcap_ev, &cap->pcap_tv) == -1) + fatal("user: event_add pcap failed : %s", strerror(errno)); +} + +/* + * Parse an IP packet and descide what to do with it. + * 'ip' is a pointer the the captured IP packet + * 'pend' is a pointer to the end of the captured IP packet + * 'wirelen' is the size of the IP packet off the wire + */ +#define NOTCAPTURED(v) ((u_char *)v > (u_char *)pend - sizeof(*v)) +#define NOTRECEIVED(v) (wirelen < sizeof(v)) +static void +ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) +{ + u_int len, ip_hlen, off; + const u_char *cp; + struct tcphdr *tcph; + struct udphdr *udph; + struct icmp *icmp; + struct in_addr src, dst; + u_int src_port, dst_port; + u_int size, proto, close, response; + struct conn *c, *conn; + + if (NOTCAPTURED(ip)) { + log_pinvalid("user: ip truncated (ip %x pend %x sizeof(ip) %d", + ip, pend, sizeof(ip)); + cap->ptruncated++; + return; + } + + if (ip->ip_v != IPVERSION) { + log_pinvalid("user: invalid ip version"); + cap->pinvalid++; + return; + } + + len = ntohs(ip->ip_len); + if (wirelen < len) { + log_pinvalid("user: ip too small"); + cap->pinvalid++; + len = wirelen; + } + + ip_hlen = ip->ip_hl * 4; + if (ip_hlen < sizeof(struct ip) || ip_hlen > len) { + log_pinvalid("user: ip_hlen invalid, %d", ip_hlen); + cap->pinvalid++; + return; + } + len -= ip_hlen; + + src.s_addr = ntohl(ip->ip_src.s_addr); + dst.s_addr = ntohl(ip->ip_dst.s_addr); + src_port = 0; + dst_port = 0; + proto = IPPROTO_IP; + size = len; + close = 0; + + off = ntohs(ip->ip_off); + if ((off & IP_OFFMASK) == 0) { + cp = (const u_char *)ip + ip_hlen; + switch (ip->ip_p) { + + case IPPROTO_TCP: + tcph = (struct tcphdr *)cp; + if (NOTCAPTURED(&tcph->th_flags)) { + log_pinvalid("user: tcp truncated"); + cap->ptruncated++; + return; + } + if (NOTRECEIVED(*tcph)) { + log_pinvalid("user: tcp too small"); + cap->pinvalid++; + return; + } + src_port = ntohs(tcph->th_sport); + dst_port = ntohs(tcph->th_dport); + proto = IPPROTO_TCP; + size = len - sizeof(*tcph); + if ((tcph->th_flags & TH_FIN) && + (tcph->th_flags & TH_ACK)) + close = 1; + break; + + case IPPROTO_UDP: + udph = (struct udphdr *)cp; + if (NOTCAPTURED(&udph->uh_dport)) { + log_pinvalid("user: udp truncated, " + "ip %x, udph %x, uh_port %x, pend %x, ip_hlen %d", + ip, udph, &udph->uh_dport, pend, ip_hlen); + cap->ptruncated++; + return; + } + if (NOTRECEIVED(*udph)) { + log_pinvalid("user: udp too small"); + cap->pinvalid++; + return; + } + src_port = ntohs(udph->uh_sport); + dst_port = ntohs(udph->uh_dport); + proto = IPPROTO_UDP; + size = len - sizeof(*udph); + break; + + case IPPROTO_ICMP: + icmp = (struct icmp *)cp; + if (NOTRECEIVED(*icmp)) { + log_pinvalid("user: icmp too small"); + cap->pinvalid++; + return; + } + proto = IPPROTO_ICMP; + size = len - sizeof(*icmp); + break; + + default: + log_warn("user: unknown ip protocol !"); + break; + } + } else { + /* + * if this isn't the first frag, we're missing the + * next level protocol header. + */ + log_tmp("user: got a fragmented ip packet !"); + } + + conn = NULL; + LIST_FOREACH(c, &cap->conn_list, entry) { + if (((c->src->addr.s_addr == src.s_addr && + c->src_port == src_port && + c->dst->addr.s_addr == dst.s_addr && + c->dst_port == dst_port) || + (c->src->addr.s_addr == dst.s_addr && + c->src_port == dst_port && + c->dst->addr.s_addr == src.s_addr && + c->dst_port == src_port)) && + c->proto == proto) { + conn = c; + if (c->src->addr.s_addr == src.s_addr) + response = 0; + else + response = 1; + break; + } + } + + if (conn) { + if (!close) { + conn_data(conn, size, response); + } else { + conn_del(conn); + } + } else { + if (!close) { + conn_add(&src, src_port, &dst, dst_port, proto, size); + } else { + log_warn("user: captured connection close w/o open !"); + } + } +} + +static pcap_handler +lookup_phandler(int type) +{ + struct phandler *p; + + for (p = phandlers; p->f; ++p) { + if (type == p->type) + return p->f; + } + fatal("user: unknown data link type 0x%x", type); + /* NOTREACHED */ + return NULL; +} + +static void +phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p) +{ + struct ether_header *ep; + struct ip *ip; + u_short ether_type; + const u_char *pend; + u_int len; + + log_debug("user: pcap handler ethernet !"); + + /* XXX here i assume that packets are alligned, which might not + * be the case when using dump files, says tcpdump sources */ + + ep = (struct ether_header *)p; + pend = p + h->caplen; + len = h->len - sizeof(struct ether_header); + + + ether_type = ntohs(ep->ether_type); + if (ether_type <= ETHERMTU) + log_tmp("llc packet !"); + else { + switch (ether_type) { + case ETHERTYPE_IP: + log_tmp("ether IP"); + ip = (struct ip *)((u_char *)ep + sizeof(struct ether_header)); + ip_handle(ip, pend, len); + break; + default: + log_tmp("non ip packet !"); + break; + } + } +} + +static void +phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) +{ + struct ip *ip; + struct ether_header *ep; + u_short ether_type; + u_int family; + const u_char *pend; + u_int len; + + log_debug("user: pcap handler loop !"); + + /* XXX here i assume that packets are alligned, which might not + * be the case when using dump files, says tcpdump sources */ + + pend = p + h->caplen; + len = h->len; + + memcpy((char *)&family, (char *)p, sizeof(family)); + family = ntohl(family); + switch (family) { + case AF_INET: + log_tmp("loop family AF_INET"); + ip = (struct ip *)(p + NULL_HDRLEN); + len -= NULL_HDRLEN; + ip_handle(ip, pend, len); + break; +#if defined(__OpenBSD__) + case AF_LINK: +#else + case AF_LOCAL: +#endif + ep = (struct ether_header *)(p + NULL_HDRLEN); + ether_type = ntohs(ep->ether_type); + if (ether_type <= ETHERMTU) + log_tmp("llc packet !"); + else { + switch (ether_type) { + case ETHERTYPE_IP: + log_tmp("loop family AF_LINK IP"); + ip = (struct ip *)((u_char *)ep + sizeof(*ep)); + len -= NULL_HDRLEN + sizeof(*ep); + ip_handle(ip, pend, len); + break; + default: + log_tmp("loop non ip packet !"); + break; + } + } + default: + log_tmp("unknown family %x !", family); + break; + } +} + -- cgit v1.2.3-59-g8ed1b