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.c267
1 files changed, 198 insertions, 69 deletions
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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#if !defined(__OpenBSD__)
+#define __FAVOR_BSD
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include <pcap.h>
+#include <event.h>
+
+#include <libglouglou.h>
+#include <libggnet.h>
+
#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;
}
}