aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2013-01-12 23:37:32 +0100
committerLaurent Ghigonis <laurent@p1sec.com>2013-01-12 23:37:32 +0100
commit8aa15027443ef20e1d65c127f882511c2ee2e7ab (patch)
treec61672acb42d88065242ea324f56c7a6b3d065af /libglouglou
parentupdate requirements (diff)
downloadglouglou-8aa15027443ef20e1d65c127f882511c2ee2e7ab.tar.xz
glouglou-8aa15027443ef20e1d65c127f882511c2ee2e7ab.zip
work in progress on traceroute and it's integration in gg_sniff
Diffstat (limited to 'libglouglou')
-rw-r--r--libglouglou/libggnet_traceroute.c261
-rw-r--r--libglouglou/libggnet_traceroute.h26
2 files changed, 275 insertions, 12 deletions
diff --git a/libglouglou/libggnet_traceroute.c b/libglouglou/libggnet_traceroute.c
index f00fd72..af0d0ce 100644
--- a/libglouglou/libggnet_traceroute.c
+++ b/libglouglou/libggnet_traceroute.c
@@ -1,13 +1,60 @@
/*
- * Traceroute using libevent, libdnet and libpcap
+ * Traceroute library using libevent, libdnet and libpcap
*
* 2012 Laurent Ghigonis <laurent@p1sec.com>
*
- * Inspired from jtrace (http://monkey.org/~jose/software/jtrace/)
+ * Inspired from jtrace
+ * http://monkey.org/~jose/software/jtrace/
* Copyright (c) 2003-2004 Jose Nazario <jose@monkey.org>
* All rights reserved.
+ * Inspired from OpenBSD's traceroute
+ * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/traceroute/traceroute.c?rev=HEAD
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson.
+ * Inspired from netsniff-ng's astraceroute
+ * http://www.netsniff-ng.org/
+ * https://github.com/gnumaniacs/netsniff-ng/blob/master/src/astraceroute.c
+ * By Daniel Borkmann <daniel@netsniff-ng.org>
+ * Copyright 2011 Daniel Borkmann.
*/
+/*
+ * Traceroute algorithm
+ *
+ * Send algo (_cb_send) :
+ *
+ * send 3 * 15 packets to next 15 ttls
+ * add packets in hops_list
+ * set recv timeout in 3s
+ *
+ * Recv algo (_cb_recv) :
+ *
+ * check if dst IP is for us
+ * check if src IP is for us in hop_list
+ * tcp / udp
+ * is it answer from the target ?
+ XXX we might still want to continue a few hops after target
+ * target info write in hop_list
+ * recv timeout in 0.5s
+ * icmp unreach / exceed :
+ * did we send the inner pkt ?
+ * hop info write in hop_list
+ * which ttl ?
+ * is it answer from the target ?
+ * recv timeout in 0.5s
+ * did we receive all answers ?
+ * send more !
+ */
+
+/* TODO
+ * * hop store 3 answer results
+ * * send more packets of 15th answer
+ * * LATER hability to intrace all captured TCP session
+ * check for no incidence on the TCP connection
+ * can do on UDP ?
+ */
#include <sys/param.h>
#include <sys/time.h>
@@ -23,11 +70,24 @@
#include "libggnet_traceroute.h"
+#define TRACE_DPORT 80
+#define TIMEOUT_TOTAL_S 3
+#define TIMEOUT_AFTERTARGET_US 500000
+
static void _req_free(struct ggnet_traceroute_req *);
static void _cb_recv(evutil_socket_t, short, void *);
static void _cb_send(evutil_socket_t, short, void *);
static int pcap_dloff(pcap_t *); // XXX move to libggnet_utils ?
+struct trace_pkt {
+ union {
+ struct ip_hdr ip;
+ } pkt_hdr_i;
+ union {
+ struct tcp_hdr tcp;
+ } pkt_hdr_t;
+};
+
struct ggnet_traceroute *
ggnet_traceroute_new(struct event_base *ev_base, char *iface)
{
@@ -48,7 +108,6 @@ ggnet_traceroute_new(struct event_base *ev_base, char *iface)
}
ggtr->pkt_rand = rand_open();
-
/* XXX get iface from route_open, route_get and pcap_lookupnet.
* will need to do so in ggnet_traceroute_trace() so user privs, so will need
* to prefetch the routes / interfaces, maybe */
@@ -85,15 +144,21 @@ ggnet_traceroute_trace(struct ggnet_traceroute *ggtr,
void *data)
{
struct ggnet_traceroute_req *req;
+ struct ggnet_traceroute_hop *target;
req = calloc(1, sizeof(struct ggnet_traceroute_req));
if (!req) {
printf("could not allocate ggnet_traceroute_req\n");
exit(1);
}
+ target = calloc(1, sizeof(struct ggnet_traceroute_hop));
+ if (!target) {
+ printf("cannot allocate ggnet_traceroute_hop\n");
+ exit(1);
+ }
+ addr_aton("127.0.0.1", &req->target->ip);
addr_aton("127.0.0.1", &req->srcip);
- addr_aton("127.0.0.1", &req->ip);
req->ev_recv = event_new(ggtr->ev_base,
ggtr->pcap_fd, EV_READ, _cb_recv, req);
@@ -102,6 +167,9 @@ ggnet_traceroute_trace(struct ggnet_traceroute *ggtr,
ggtr->pcap_fd, EV_WRITE, _cb_send, req);
event_add(req->ev_send, NULL);
+ // XXX evtimer timeout !!!
+ evtimer_new(ggtr->ev_base, _cb_trace_timeout, req);
+
LIST_INSERT_HEAD(&ggtr->req_list, req, entry);
return req;
}
@@ -128,19 +196,168 @@ _req_free(struct ggnet_traceroute_req *req)
static void
_cb_recv(evutil_socket_t fd, short what, void *arg)
{
+ struct ggnet_traceroute_hop *hop;
struct ggnet_traceroute_req *req;
+ struct ggnet_traceroute *ggtr;
+ struct pcap_pkthdr ph;
+ u_char *pread, *tmp;
+ struct ip_hdr *ip, ip_in;
+ struct tcp_hdr *tcp;
+ struct icmp_hdr *icmp;
+ struct addr ip_src;
+ char *reply = "U!";
+ char *p;
+ printf("cbggnet_traceroute cb_recv %s\n", addr_ntoa(&req->target->ip));
req = arg;
- printf("cbggnet_traceroute cb_recv %s\n", addr_ntoa(&req->ip));
+ ggtr = req->ggtr;
+
+ if ((pread = (u_char *) pcap_next(ggtr->pcap, &ph)) == NULL) {
+ printf("libggnet_traceroute _cb_recv: read error\n");
+ return;
+ }
+
+ /* decode the current packet : ttl, ip, ... */
+ tmp = pread + ctx->dl_len;
+ ip = (struct ip_hdr *) tmp;
+ if (ip_h->ip_v != 4)
+ return;
+ p = inet_ntoasc(ip_h->ip_src);
+ if ((addr_aton(p, &ip_src)) == -1)
+ return;
+
+ switch(ip_h->ip_p) {
+
+ case IP_PROTO_TCP:
+ /* should be our target */
+ if (addr_cmp(&ip_src, &(req->target->ip)) != 0)
+ return;
+ tcp = (struct tcp_hdr *)(ip + IP_HDR_LEN);
+ if (((tcp->th_flags == TH_SYN + TH_ACK) ||
+ (tcp->th_flags == TH_RST + TH_ACK)) &&
+ (htons(tcp->th_sport) == ctx->dport)) {
+ hop = req->target;
+ hop->answer_count++;
+ flags = "SA";
+ if (tcp->th_flags == TH_RST + TH_ACK)
+ flags = "R";
+ strncpy(hop->answer, flags, sizeof(hop->answer));
+ _timeout_set(req, 0, TIMEOUT_AFTERTARGET_US);
+ }
+ break;
+
+ case IP_PROTO_ICMP:
+ /* answer from a hop */
+ icmp = (struct icmp_hdr *)(ip + IP_HDR_LEN);
+ /* XXX ? look for TTL_EXPIRED, PROHIBITED msgs */
+ ip_in = (struct iphdr *) (ip + sizeof(struct iphdr) +
+ sizeof(struct icmphdr));
+ hop = _hop_ttl(req, ip_in->ttl);
+ if (!hop) {
+ printf("libggnet_traceroute _cb_recv: WARNING: hop ttl %d not found !",
+ ip_in->ttl);
+ return;
+ }
+ hop->answer_count++;
+ if (icmp->icmp_type == ICMP_UNREACH) {
+ switch (icmp->icmp_code) {
+ case ICMP_UNREACH_NET:
+ strncpy(hop->answer, "N!", sizeof(hop->answer));
+ break;
+ case ICMP_UNREACH_HOST:
+ strncpy(hop->answer, "H!", sizeof(hop->answer));
+ break;
+ case ICMP_UNREACH_PROTO:
+ strncpy(hop->answer, "P!", sizeof(hop->answer));
+ break;
+ case ICMP_UNREACH_NET_PROHIB:
+ case ICMP_UNREACH_HOST_PROHIB:
+ strncpy(hop->answer, "A!", sizeof(hop->answer));
+ break;
+ }
+ } else if (icmp->icmp_type == ICMP_TIMEXCEED) {
+ strncpy(hop->answer, "A!", sizeof(hop->answer));
+ reply = "X!";
+ event_add(&ctx->send_ev, &ctx->tv);
+ }
+ ctx->hop++;
+ break;
+ }
+ fflush(stdout);
+
+ /* do we need to send more packets ? */
}
static void
_cb_send(evutil_socket_t fd, short what, void *arg)
{
struct ggnet_traceroute_req *req;
+ struct ggnet_traceroute *ggtr;
+ u_char buf[BUFSIZ];
+ struct trace_pkt *pkt;
+ int len;
+ int ttl;
- req = arg;
printf("cbggnet_traceroute cb_send %s\n", addr_ntoa(&req->ip));
+ req = arg;
+ ggtr = req->ggtr;
+ pkt = (struct trace_pkt *)buf;
+ len = IP_HDR_LEN + TCP_HDR_LEN;
+
+ for (ttl=req->ttl_sent; i<15; i++) {
+ hop = calloc(1, sizeof(struct ggnet_traceroute_hop));
+ if (!hop) {
+ printf("cannot allocate ggnet_traceroute_hop\n");
+ exit(1);
+ }
+ hop->ttl = ttl;
+ //addr_pack(hop->ip, ADDR_TYPE_IP, IP_ADDR_BITS, ip, IP_ADDR_LEN);
+ ip_pack_hdr(&pkt->pkt_hdr_i.ip, IP_TOS_LOWDELAY, len,
+ rand_uint16(ggtr->pkt_rand), 0, ttl, IP_PROTO_TCP,
+ req->src.addr_ip, req->dst.addr_ip);
+ tcp_pack_hdr(&pkt->pkt_hdr_t.tcp, rand_uint16(ggtr->pkt_rand), TRACE_DPORT,
+ rand_uint32(ggtr->pkt_rand), rand_uint32(ggtr->pkt_rand),
+ TH_SYN, rand_uint16(ggtr->pkt_rand), 0);
+ ip_checksum(pkt, len);
+ TAILQ_INSERT_TAIL(&req->hops_list, hop, entry);
+ for (i=0; i<TRACEROUTE_NB_PROBES; i++)
+ if (ip_send(ggtr->pkt_ip, pkt, len) < 0)
+ warn("_cb_send : ip_send short send");
+ _timeout_set(req, TIMEOUT_TOTAL_S, 0);
+ }
+ req->ttl_sent = ttl;
+}
+
+static void
+_timeout_set(struct ggnet_traceroute_req *req, int sec, int usec)
+{
+ evtimer_del(req->run.ev_timeout);
+ req->run.tv_timeout.secs = sec;
+ req->run.tv_timeout.usecs = usec;
+ evtimer_add(req->run.ev_timeout, req->run.tv_timeout);
+}
+
+static ggnet_traceroute_hop *
+_hop_last(ggnet_traceroute_req *req)
+{
+ struct ggnet_traceroute_hop *h;
+
+ TAILQ_FOREACH_REVERSE(h, req->hop_list, entry) {
+ if (h->answer_count > 0)
+ return h;
+ }
+ return NULL;
+}
+
+void _cb_trace_timeout(evutil_socket_t fd, short what, void *arg)
+{
+ struct ggnet_traceroute_req *req;
+
+ req = arg;
+
+ // XXX IN PROGRESS
+ last = _hop_last(req);
+ req->target->ttl = last->ttl + 1;
}
static int
@@ -169,3 +386,35 @@ pcap_dloff(pcap_t *pd)
}
return (i);
}
+
+/* XXX do it with evdns
+static int
+get_asn(struct in_addr in)
+{
+ const u_char *uaddr = (const u_char *)&in.s_addr;
+ int i, counter;
+ struct rrsetinfo *answers = NULL;
+ char qbuf[MAXDNAME];
+ int asn = -1;
+
+ if (snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u.origin.asn.cymru.com",
+ (uaddr[3] & 0xff), (uaddr[2] & 0xff),
+ (uaddr[1] & 0xff), (uaddr[0] & 0xff)) >= sizeof (qbuf))
+ return;
+ if (getrrsetbyname(qbuf, C_IN, T_TXT, 0, &answers) != 0)
+ return;
+ for (counter = 0; counter < answers->rri_nrdatas; counter++) {
+ char *p, *as = answers->rri_rdatas[counter].rdi_data;
+ as++; // skip first byte, it contains length
+ if (p = strchr(as,'|')) {
+ p[-1] = 0;
+ asn = atoi(as);
+ goto ret;
+ }
+ }
+
+ret:
+ freerrset(answers);
+ return asn;
+}
+*/
diff --git a/libglouglou/libggnet_traceroute.h b/libglouglou/libggnet_traceroute.h
index 0c19bea..833705b 100644
--- a/libglouglou/libggnet_traceroute.h
+++ b/libglouglou/libggnet_traceroute.h
@@ -8,21 +8,35 @@
#include <bsd/sys/queue.h>
#endif
+#define TRACEROUTE_NB_PROBES 3
+
struct ggnet_traceroute_hop {
- LIST_ENTRY(ggnet_traceroute_hop) entry;
- struct in_addr ip;
+ TAILQ_ENTRY(ggnet_traceroute_hop) entry;
+ int ttl;
+ int answer_count; /* on TRACEROUTE_NB_PROBES sent probes */
+ char answer[2 * TRACEROUTE_NB_PROBES];
+ struct addr ip;
int delay;
+ int delay_dev;
int loss;
+ int loss_dev;
+ int asn;
};
struct ggnet_traceroute_req {
LIST_ENTRY(ggnet_traceroute_req) entry;
- struct event *ev_recv;
- struct event *ev_send;
- struct addr ip;
+ struct ggnet_traceroute_hop *target;
struct addr srcip;
+ int probes_count;
int hops_count;
- LIST_HEAD(, ggnet_traceroute_hop) hops;
+ TAILQ_HEAD(, ggnet_traceroute_hop) hops_list;
+ struct {
+ struct event *ev_recv;
+ struct event *ev_send;
+ struct evtimer *ev_timeout;
+ struct timeval tv_timeout;
+ int last_ttl_sent;
+ } run;
void (*cb_usr)(struct in_addr *, char *, void *);
void *data;
};