aboutsummaryrefslogtreecommitdiffstats
path: root/gg_sniff/pcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'gg_sniff/pcap.c')
-rw-r--r--gg_sniff/pcap.c118
1 files changed, 103 insertions, 15 deletions
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 <string.h>
#include <errno.h>
#include <time.h>
+#include <err.h>
#include <pcap.h>
+#if defined(__linux__)
+#include <pcap/sll.h>
+#endif
#include <event.h>
#include <libglouglou.h>
@@ -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__ */