From e8946a36bc72db82e6666d1ab8f7afdee9f41824 Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Tue, 4 Dec 2012 15:44:40 +0100 Subject: handle listening on any interface, by passing to interface option to gg_sniff. therefore, implement LINUX_SLL handling in pcap.c --- gg_sniff/pcap.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 15 deletions(-) (limited to 'gg_sniff/pcap.c') diff --git a/gg_sniff/pcap.c b/gg_sniff/pcap.c index 4d62791..89f9f2a 100644 --- a/gg_sniff/pcap.c +++ b/gg_sniff/pcap.c @@ -22,8 +22,12 @@ #include #include #include +#include #include +#if defined(__linux__) +#include +#endif #include #include @@ -34,7 +38,6 @@ #define PCAP_COUNT 20 #define PCAP_TO 300 -#define NULL_HDRLEN 4 // XXX portable ? #define NODE_MAX_WITHOUT_TIMEOUT 1000 #define NODE_TIMEOUT 300 // XXX conf ? #define CONN_TIMEOUT 300 // XXX conf ? @@ -65,15 +68,26 @@ 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 *); +#if defined(__OpenBSD__) static void phandler_loop(u_char *, const struct pcap_pkthdr *, const u_char *); +#endif +#if defined(__linux__) +static void phandler_sll(u_char *, + const struct pcap_pkthdr *, const u_char *); +#endif 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 }, +#if defined(__OpenBSD__) { phandler_loop, DLT_LOOP }, +#endif +#if defined(__linux__) + { phandler_sll, DLT_LINUX_SLL }, +#endif { NULL, 0 }, }; @@ -87,17 +101,21 @@ ggsniff_pcap_init(struct event_base *ev_base, struct gg_client *ggcli, struct bpf_program bprog; pcap_t *pcap; +#if defined(__OpenBSD__) + if (!iface) + err(1, "On OpenBSD you cannot listen on ANY interface"); +#endif 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" + err(1, "capture: pcap_open_live failed on interface %s\n" "with snaplen %d : %s", 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", + err(1, "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", + err(1, "capture: pcap_setfilter failed : %s", pcap_geterr(pcap)); _cap.pcap = pcap; @@ -472,15 +490,15 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) static pcap_handler lookup_phandler(int type) { - struct phandler *p; - - for (p = phandlers; p->f; ++p) { - if (type == p->type) - return p->f; - } - gg_log_fatal("user: unknown data link type 0x%x", type); - /* NOTREACHED */ - return NULL; + struct phandler *p; + + for (p = phandlers; p->f; ++p) { + if (type == p->type) + return p->f; + } + err(1, "user: unknown data link type 0x%x", type); + /* NOTREACHED */ + return NULL; } static void @@ -501,7 +519,6 @@ phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p) pend = p + h->caplen; len = h->len - sizeof(struct ether_header); - ether_type = ntohs(ep->ether_type); if (ether_type <= ETHERMTU) gg_log_tmp("llc packet !"); @@ -519,6 +536,76 @@ phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p) } } +/* + * Handler for Linux cooked, used when capturing on any interface + */ +#if defined(__linux__) +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_ETHERNET 0x0003 /* Ethernet */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_PPPHDLC 0x0007 /* PPP HDLC frames */ +#define LINUX_SLL_P_CAN 0x000C /* Controller Area Network */ +#define LINUX_SLL_P_IRDA_LAP 0x0017 /* IrDA Link Access Protocol */ + +static void +phandler_sll(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; + + gg_log_debug("user: phandler_sll !"); + + /* 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; + + family = ntohs(p[14]); + if (family < 1536) { /* linux and wireshark are good for you */ + switch (family) { + case LINUX_SLL_P_ETHERNET: + ep = (struct ether_header *)(p + SLL_HDR_LEN); + // XXX call phandler_ether instead + ether_type = ntohs(ep->ether_type); + if (ether_type <= ETHERMTU) + gg_log_tmp("llc packet !"); + else { + switch (ether_type) { + case ETHERTYPE_IP: + gg_log_tmp("loop family AF_LINK IP"); + ip = (struct ip *)((u_char *)ep + sizeof(*ep)); + len -= SLL_HDR_LEN + sizeof(*ep); + ip_handle(ip, pend, len); + break; + default: + gg_log_tmp("loop non ip packet !"); + break; + } + } + default: + gg_log_tmp("unknown family %x !", family); + break; + } + } else { + struct ip *ip; + ip = (struct ip *)((u_char *)p + SLL_HDR_LEN); + len -= SLL_HDR_LEN; + ip_handle(ip, pend, len); + } +} +#endif /* __linux__ */ + +/* + * Handler for OpenBSD Loopback + */ +#if defined(__OpenBSD__) +#define NULL_HDRLEN 4 + static void phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { @@ -552,6 +639,7 @@ phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) case AF_LOCAL: #endif ep = (struct ether_header *)(p + NULL_HDRLEN); + // XXX call phandler_ether instead ether_type = ntohs(ep->ether_type); if (ether_type <= ETHERMTU) gg_log_tmp("llc packet !"); @@ -573,4 +661,4 @@ phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) break; } } - +#endif /* __OpenBSD__ */ -- cgit v1.2.3-59-g8ed1b