aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2012-12-04 15:44:40 +0100
committerLaurent Ghigonis <laurent@p1sec.com>2012-12-04 15:44:40 +0100
commite8946a36bc72db82e6666d1ab8f7afdee9f41824 (patch)
treec39c086d8f4c5fd7732c786cc81f6404acf7e898
parentstop the servers in the main(), not in signal handlers ! (diff)
downloadglouglou-e8946a36bc72db82e6666d1ab8f7afdee9f41824.tar.xz
glouglou-e8946a36bc72db82e6666d1ab8f7afdee9f41824.zip
handle listening on any interface, by passing to interface option to gg_sniff.
therefore, implement LINUX_SLL handling in pcap.c
-rw-r--r--gg_sniff/gg_sniff.c19
-rw-r--r--gg_sniff/pcap.c118
2 files changed, 114 insertions, 23 deletions
diff --git a/gg_sniff/gg_sniff.c b/gg_sniff/gg_sniff.c
index e35238e..91585b7 100644
--- a/gg_sniff/gg_sniff.c
+++ b/gg_sniff/gg_sniff.c
@@ -39,7 +39,7 @@ usage(void)
{
extern char *__progname;
- fprintf(stderr, "usage: %s [-hv] interface [ip [port]]", __progname);
+ fprintf(stderr, "usage: %s [-hv] [-i interface] [ip [port]]", __progname);
exit(1);
}
@@ -59,7 +59,7 @@ main(int argc, char **argv)
struct ggnet *net = NULL;
struct event *ev_sigint, *ev_sigterm, *ev_sigchld, *ev_sighup;
char ggserv_ip[30] = "127.0.0.1";
- char iface[30] = "lo";
+ char *iface = NULL;
int ggserv_port = GLOUGLOU_PROBE_DEFAULT_PORT;
int pcap_init = 0;
int dns_init = 0;
@@ -70,11 +70,14 @@ main(int argc, char **argv)
if (geteuid() != 0)
errx(1, "must be root");
- while ((op = getopt(argc, argv, "hv")) != -1) {
+ while ((op = getopt(argc, argv, "hi:v")) != -1) {
switch (op) {
case 'h':
usage();
/* NOTREACHED */
+ case 'i':
+ iface = strndup(optarg, 30);
+ break;
case 'v':
loglevel++;
break;
@@ -83,10 +86,10 @@ main(int argc, char **argv)
/* NOTREACHED */
}
}
- switch (argc) {
- case 4: ggserv_port = atoi(argv[3]);
- case 3: strncpy(ggserv_ip, argv[2], sizeof(ggserv_ip));
- case 2: strncpy(iface, argv[1], sizeof(iface));
+ switch (argc - optind) {
+ case 2: ggserv_port = atoi(argv[3]);
+ case 1: strncpy(ggserv_ip, argv[2], sizeof(ggserv_ip));
+ case 0:
break;
default:
usage();
@@ -137,7 +140,7 @@ quit:
if (net)
ggnet_free(net);
- gg_log_info("exiting");
+ gg_log_warn("exiting");
gg_log_shutdown();
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__ */