From 7165b548cd57f4d628789f6f9097eb5f43d3ceec Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Tue, 4 Dec 2012 13:17:32 +0100 Subject: work on gg_sniff, now it compiles --- gg_sniff/pcap.c | 267 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 198 insertions(+), 69 deletions(-) (limited to 'gg_sniff/pcap.c') diff --git a/gg_sniff/pcap.c b/gg_sniff/pcap.c index 2d885bd..e66a6d5 100644 --- a/gg_sniff/pcap.c +++ b/gg_sniff/pcap.c @@ -1,37 +1,123 @@ -#define PCAP_INTERFACE "lo" +#include +#include +#include +#include + +#if !defined(__OpenBSD__) +#define __FAVOR_BSD +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + #define PCAP_SNAPLEN 100 -#define PCAP_FILTER "not port 4430 and not port 53" +#define PCAP_FILTER "not port 4430 and not port 4431 and not port 53" #define PCAP_COUNT 20 #define PCAP_TO 300 -static pcap_t *my_pcap_open_live(const char *, int, int, int, - char *, u_int, u_int) +#define NULL_HDRLEN 4 // XXX portable ? +#define NODE_MAX_WITHOUT_TIMEOUT 1000 +#define NODE_TIMEOUT 300 // XXX conf ? +#define CONN_TIMEOUT 300 // XXX conf ? +#define CONN_TIMEOUT_UDP 20 // XXX conf ? +#define CONN_TIMEOUT_ICMP 10 // XXX conf ? +#define CONNTIMER 5 // XXX conf ? + +struct phandler { + pcap_handler f; + int type; +}; + +struct _cap_t { + pcap_t *pcap; + pcap_handler handler; + struct event *ev; + struct event *conntimer_ev; + struct timeval conntimer_tv; + struct gg_client *ggcli; + struct ggnet *net; + int pinvalid; + int ptruncated; +}; -static pcap_t *_pcap; -static struct event *_pcap_ev; +static pcap_t *my_pcap_open_live(const char *, int, int, int, + char *, u_int, u_int); +static void ip_handle(struct ip *, const u_char *, u_int); +static pcap_handler lookup_phandler(int); +static void phandler_ether(u_char *, + const struct pcap_pkthdr *, const u_char *); +static void phandler_loop(u_char *, + const struct pcap_pkthdr *, const u_char *); +static void cb_pcap(int, short, void *); +static void cb_conntimer(int, short, void *); + +static struct phandler phandlers[] = { + { phandler_ether, DLT_EN10MB }, + { phandler_ether, DLT_IEEE802 }, + { phandler_loop, DLT_LOOP }, + { NULL, 0 }, +}; + +static struct _cap_t _cap; int -ggsniff_pcap_init(struct event_base *ev_base) +ggsniff_pcap_init(struct event_base *ev_base, struct gg_client *ggcli, + struct ggnet *net, char *iface) { char errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program bprog; - int pcap_fd; + pcap_t *pcap; - pcap = my_pcap_open_live(PCAP_INTERFACE, PCAP_SNAPLEN, 1, PCAP_TO, errbuf, -1, 0); + pcap = my_pcap_open_live(iface, PCAP_SNAPLEN, 1, PCAP_TO, + errbuf, -1, 0); if (pcap == NULL) gg_log_fatal("capture: pcap_open_live failed on interface %s\n" "with snaplen %d : %s", - PCAP_INTERFACE, PCAP_SNAPLEN, errbuf); + iface, PCAP_SNAPLEN, errbuf); if (pcap_compile(pcap, &bprog, PCAP_FILTER, 0, 0) < 0) gg_log_fatal("capture: pcap_compile failed with filter %s : %s", PCAP_FILTER, pcap_geterr(pcap)); if (pcap_setfilter(pcap, &bprog) < 0) gg_log_fatal("capture: pcap_setfilter failed : %s", pcap_geterr(pcap)); - pcap_fd = pcap_fileno(_pcap); - _pcap_ev = event_new(ev_base, pcap_fd, EV_READ|EV_PERSIST, cb_pcap, NULL); - event_add(_pcap_ev, NULL); + _cap.pcap = pcap; + _cap.handler = lookup_phandler(pcap_datalink(pcap)); + //_cap.tv.tv_sec = 0; + //_cap.tv.tv_usec = PCAP_TO; + fd_nonblock(pcap_fileno(pcap)); + _cap.ev = event_new(ev_base, pcap_fileno(pcap), EV_READ|EV_PERSIST, + cb_pcap, NULL); + //event_add(_cap.ev, &_cap->tv); + event_add(_cap.ev, NULL); + + _cap.conntimer_tv.tv_sec = CONNTIMER; + _cap.conntimer_tv.tv_usec = 0; + _cap.conntimer_ev = evtimer_new(ev_base, cb_conntimer, NULL); + if (evtimer_add(_cap.conntimer_ev, &_cap.conntimer_tv) == -1) + gg_log_fatal("user: event_add conntimer failed: %s", strerror(errno)); + + _cap.ggcli = ggcli; + _cap.net = net; return 1; } @@ -39,8 +125,8 @@ ggsniff_pcap_init(struct event_base *ev_base) void ggsniff_pcap_shutdown(void) { - event_del(_pcap_ev); - pcap_close(_pcap); + event_del(_cap.ev); + pcap_close(_cap.pcap); } /* @@ -169,14 +255,56 @@ my_pcap_open_live(const char *dev, int slen, int promisc, int to_ms, } static void -ev_pcap(int fd, short why, void *data) +cb_pcap(int fd, short why, void *data) { - log_tmp("ev_pcap"); - pcap_dispatch(cap->pcap, PCAP_COUNT, cap->pcap_handler, NULL); + gg_log_tmp("cb_pcap"); + pcap_dispatch(_cap.pcap, PCAP_COUNT, _cap.handler, NULL); - /* reschedule */ - if (event_add(&cap->pcap_ev, &cap->pcap_tv) == -1) - fatal("user: event_add pcap failed : %s", strerror(errno)); + /* reschedule */ + //if (event_add(&_cap->ev, &_cap->tv) == -1) + // gg_log_fatal("user: event_add pcap failed : %s", strerror(errno)); +} + +static void +cb_conntimer(int fd, short why, void *data) +{ + struct ggnet_conn *c, *ctmp; + struct ggnet_node *n, *ntmp; + int i, to; + + gg_log_debug("ev_timer"); + ggnet_time_update(_cap.net, time(NULL)); + + i = 0; + LIST_FOREACH_SAFE(c, &_cap.net->conn_list, entry, ctmp) { + switch (c->proto) { + case IPPROTO_UDP: + to = CONN_TIMEOUT_UDP; + break; + case IPPROTO_ICMP: + to = CONN_TIMEOUT_ICMP; + break; + default: + to = CONN_TIMEOUT; + break; + } + if (_cap.net->time > c->lastseen + to) + ggnet_conn_del(_cap.net, c); + else + i++; + } + + if (_cap.net->node_count > NODE_MAX_WITHOUT_TIMEOUT) { + LIST_FOREACH_SAFE(n, &_cap.net->node_list, entry, ntmp) { + if (n->used == 0 && + _cap.net->time > n->lastseen + NODE_TIMEOUT) + ggnet_node_del(_cap.net, n); + } + } + + gg_log_debug("user: ev_timer leaving with %d active connections and %d active nodes", i, _cap.net->node_count); + if (event_add(_cap.conntimer_ev, &_cap.conntimer_tv) == -1) + gg_log_fatal("user: event_add conntimer failed : %s", strerror(errno)); } /* @@ -187,6 +315,8 @@ ev_pcap(int fd, short why, void *data) */ #define NOTCAPTURED(v) ((u_char *)v > (u_char *)pend - sizeof(*v)) #define NOTRECEIVED(v) (wirelen < sizeof(v)) +#define log_pinvalid(fmt, ...) \ + gg_log_info("ggsniff pinvalid: " fmt, ##__VA_ARGS__) static void ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) { @@ -197,33 +327,35 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) struct icmp *icmp; struct in_addr src, dst; u_int src_port, dst_port; - u_int size, proto, close, response; - struct conn *c, *conn; + u_int size, proto, close; + int response; + struct ggnet_conn *conn; + struct gg_packet pkt; if (NOTCAPTURED(ip)) { log_pinvalid("user: ip truncated (ip %x pend %x sizeof(ip) %d", ip, pend, sizeof(ip)); - cap->ptruncated++; + _cap.ptruncated++; return; } if (ip->ip_v != IPVERSION) { log_pinvalid("user: invalid ip version"); - cap->pinvalid++; + _cap.pinvalid++; return; } len = ntohs(ip->ip_len); if (wirelen < len) { log_pinvalid("user: ip too small"); - cap->pinvalid++; + _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++; + _cap.pinvalid++; return; } len -= ip_hlen; @@ -245,12 +377,12 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) tcph = (struct tcphdr *)cp; if (NOTCAPTURED(&tcph->th_flags)) { log_pinvalid("user: tcp truncated"); - cap->ptruncated++; + _cap.ptruncated++; return; } if (NOTRECEIVED(*tcph)) { log_pinvalid("user: tcp too small"); - cap->pinvalid++; + _cap.pinvalid++; return; } src_port = ntohs(tcph->th_sport); @@ -268,12 +400,12 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) 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++; + _cap.ptruncated++; return; } if (NOTRECEIVED(*udph)) { log_pinvalid("user: udp too small"); - cap->pinvalid++; + _cap.pinvalid++; return; } src_port = ntohs(udph->uh_sport); @@ -286,7 +418,7 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) icmp = (struct icmp *)cp; if (NOTRECEIVED(*icmp)) { log_pinvalid("user: icmp too small"); - cap->pinvalid++; + _cap.pinvalid++; return; } proto = IPPROTO_ICMP; @@ -294,7 +426,7 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) break; default: - log_warn("user: unknown ip protocol !"); + gg_log_warn("user: unknown ip protocol !"); break; } } else { @@ -302,40 +434,37 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) * 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; - } + gg_log_tmp("user: got a fragmented ip packet !"); } + pkt.ver = PACKET_VERSION; + conn = ggnet_conn_find(_cap.net, &src, src_port, &dst, dst_port, + proto, &response); if (conn) { if (!close) { - conn_data(conn, size, response); + pkt.type = PACKET_DATA; + pkt.data_connid = conn->id; + pkt.data_size = size << 8 | response; + gg_client_send(_cap.ggcli, &pkt); + ggnet_conn_data(_cap.net, conn, size, response); } else { - conn_del(conn); + pkt.type = PACKET_DELCONN; + pkt.delconn_id = conn->id; + gg_client_send(_cap.ggcli, &pkt); + ggnet_conn_del(_cap.net, conn); } } else { if (!close) { - conn_add(&src, src_port, &dst, dst_port, proto, size); + conn = ggnet_conn_add(_cap.net, &src, src_port, &dst, dst_port, proto, size); + pkt.type = PACKET_NEWCONN; + pkt.newconn_id = conn->id; + pkt.newconn_src = src.s_addr; + pkt.newconn_dst = dst.s_addr; + pkt.newconn_proto = proto; + pkt.newconn_size = size << 8; + gg_client_send(_cap.ggcli, &pkt); } else { - log_warn("user: captured connection close w/o open !"); + gg_log_warn("user: captured connection close w/o open !"); } } } @@ -349,7 +478,7 @@ lookup_phandler(int type) if (type == p->type) return p->f; } - fatal("user: unknown data link type 0x%x", type); + gg_log_fatal("user: unknown data link type 0x%x", type); /* NOTREACHED */ return NULL; } @@ -363,7 +492,7 @@ phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p) const u_char *pend; u_int len; - log_debug("user: pcap handler ethernet !"); + gg_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 */ @@ -375,16 +504,16 @@ phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p) ether_type = ntohs(ep->ether_type); if (ether_type <= ETHERMTU) - log_tmp("llc packet !"); + gg_log_tmp("llc packet !"); else { switch (ether_type) { case ETHERTYPE_IP: - log_tmp("ether IP"); + gg_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 !"); + gg_log_tmp("non ip packet !"); break; } } @@ -400,7 +529,7 @@ phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) const u_char *pend; u_int len; - log_debug("user: pcap handler loop !"); + gg_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 */ @@ -412,7 +541,7 @@ phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) family = ntohl(family); switch (family) { case AF_INET: - log_tmp("loop family AF_INET"); + gg_log_tmp("loop family AF_INET"); ip = (struct ip *)(p + NULL_HDRLEN); len -= NULL_HDRLEN; ip_handle(ip, pend, len); @@ -425,22 +554,22 @@ phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) ep = (struct ether_header *)(p + NULL_HDRLEN); ether_type = ntohs(ep->ether_type); if (ether_type <= ETHERMTU) - log_tmp("llc packet !"); + gg_log_tmp("llc packet !"); else { switch (ether_type) { case ETHERTYPE_IP: - log_tmp("loop family AF_LINK IP"); + gg_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 !"); + gg_log_tmp("loop non ip packet !"); break; } } default: - log_tmp("unknown family %x !", family); + gg_log_tmp("unknown family %x !", family); break; } } -- cgit v1.2.3-59-g8ed1b