aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2013-06-08 13:04:18 +0200
committerLaurent Ghigonis <laurent@p1sec.com>2013-06-08 13:04:18 +0200
commitd65d47c4e0da83f20fa51846be1015d0be94835b (patch)
treed28b018a42f2bd4aee867e21ba5afcea283cdae1 /libglouglou
parentlibglouglou: indent (diff)
downloadglouglou-d65d47c4e0da83f20fa51846be1015d0be94835b.tar.xz
glouglou-d65d47c4e0da83f20fa51846be1015d0be94835b.zip
libglouglou: traceroute TCP working
Diffstat (limited to 'libglouglou')
-rw-r--r--libglouglou/examples/traceroute.c4
-rw-r--r--libglouglou/libggnet_traceroute.c153
-rw-r--r--libglouglou/libggnet_traceroute.h11
3 files changed, 119 insertions, 49 deletions
diff --git a/libglouglou/examples/traceroute.c b/libglouglou/examples/traceroute.c
index d78115b..504b3fc 100644
--- a/libglouglou/examples/traceroute.c
+++ b/libglouglou/examples/traceroute.c
@@ -47,7 +47,7 @@ main(int argc, char *argv[])
ggtr = ggnet_traceroute_new(_ev_base, get_iface(argv[1]));
droppriv("nobody", 1, NULL); /* bad practise, use dedicated user */
- ggnet_traceroute_trace(ggtr, &ip, TRACEMODE_ICMP,
+ ggnet_traceroute_trace(ggtr, &ip, TRACEMODE_AUTO,
_cb_traceroute, NULL, NULL);
event_base_loopexit(_ev_base, &tv);
@@ -56,7 +56,7 @@ main(int argc, char *argv[])
if (_answer) {
printf("%s:\n", addr_ntoa(&ip));
TAILQ_FOREACH(hop, &_route->hops_list, entry) {
- printf("%s (%d)\n", addr_ntoa(&hop->ip), hop->delay);
+ printf("%2.2d: %s (%d) [XXX %p]\n", hop->ttl, addr_ntoa(&hop->ip), hop->delay, hop);
}
} else {
printf("no answer\n");
diff --git a/libglouglou/libggnet_traceroute.c b/libglouglou/libggnet_traceroute.c
index 879b96c..6a635d0 100644
--- a/libglouglou/libggnet_traceroute.c
+++ b/libglouglou/libggnet_traceroute.c
@@ -78,6 +78,10 @@ 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 void _cb_trace_timeout(evutil_socket_t, short, void *);
+static struct ggnet_traceroute_hop *
+ _hop_ip_id(struct ggnet_traceroute_req *, int);
+static struct ggnet_traceroute_hop *
+ _hop_sport(struct ggnet_traceroute_req *, int);
static void _timeout_set(struct ggnet_traceroute_req *, int, int);
static int pcap_dloff(pcap_t *); // XXX move to libggnet_utils ?
@@ -167,6 +171,10 @@ ggnet_traceroute_trace(struct ggnet_traceroute *ggtr,
}
memcpy(&req->srcip, &intf_entry.intf_addr, sizeof(struct addr));
req->mode = mode;
+ if (mode == TRACEMODE_ICMP) {
+ printf("ERROR: ICMP trace not supported yet\n");
+ return NULL;
+ }
TAILQ_INIT(&req->hops_list);
req->run.ev_recv = event_new(ggtr->ev_base,
@@ -218,23 +226,19 @@ static void
_cb_recv(evutil_socket_t fd, short what, void *arg)
{
struct ggnet_traceroute_req *req;
-#if 0
struct ggnet_traceroute_hop *hop;
struct ggnet_traceroute *ggtr;
struct pcap_pkthdr ph;
- u_char *pread, *tmp;
- struct ip_hdr *ip, ip_in;
+ u_char *pread;
+ struct ip_hdr *ip, *ip_in;
struct tcp_hdr *tcp;
struct icmp_hdr *icmp;
struct addr ip_src;
- char *reply = "U!";
- char *p;
-#endif
+ char *p, *flags;
req = arg;
printf("XXX cbggnet_traceroute cb_recv %s -> %s\n",
addr_ntoa(&req->srcip), addr_ntoa(&req->target->ip));
-#if 0
// XXX call cb_hop if hop successfuly detected
// req->cb_hop(req, hop, req->data);
req = arg;
@@ -242,29 +246,40 @@ _cb_recv(evutil_socket_t fd, short what, void *arg)
if ((pread = (u_char *) pcap_next(ggtr->pcap, &ph)) == NULL) {
printf("libggnet_traceroute _cb_recv: read error\n");
- return;
+ goto reschedule_recv;
}
+ printf("XXX packet received\n");
/* 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);
+ ip = (struct ip_hdr *) (pread + ggtr->pcap_dllen);
+ if (ip->ip_v != 4)
+ goto reschedule_recv;
+ p = ip_ntoa(&ip->ip_src);
if ((addr_aton(p, &ip_src)) == -1)
- return;
+ goto reschedule_recv;
+ printf("XXX packet IP received from %s, ip_id %d\n", addr_ntoa(&ip_src), ntohs(ip->ip_id));
- switch(ip_h->ip_p) {
+ switch(ip->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);
+ goto reschedule_recv;
+ tcp = (struct tcp_hdr *)((u_char *)ip + IP_HDR_LEN);
+ printf("XXX TCP %d %d %d\n", ntohs(tcp->th_sport),
+ req->params.tcp.dport, tcp->th_seq);
if (((tcp->th_flags == TH_SYN + TH_ACK) ||
- (tcp->th_flags == TH_RST + TH_ACK)) &&
- (htons(tcp->th_sport) == ctx->dport)) {
- hop = req->target;
+ (tcp->th_flags == TH_RST + TH_ACK)) &&
+ (ntohs(tcp->th_sport) == req->params.tcp.dport)) {
+ /* target answer */
+ printf("XXX found target !\n");
+ hop = _hop_sport(req, ntohs(tcp->th_dport));
+ if (!hop) {
+ printf("libggnet_traceroute _cb_recv: WARNING: TCP answer with dport not matching sent sport (%d) not found !\n",
+ ntohs(tcp->th_dport));
+ goto reschedule_recv;
+ }
+
+ memcpy(&hop->ip, &ip_src, sizeof(struct addr));
hop->answer_count++;
flags = "SA";
if (tcp->th_flags == TH_RST + TH_ACK)
@@ -275,17 +290,19 @@ _cb_recv(evutil_socket_t fd, short what, void *arg)
break;
case IP_PROTO_ICMP:
+ printf("XXX is ICMP\n");
/* answer from a hop */
- icmp = (struct icmp_hdr *)(ip + IP_HDR_LEN);
+ icmp = (struct icmp_hdr *)((u_char *)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);
+ ip_in = (struct ip_hdr *)
+ ((u_char *)ip + IP_HDR_LEN + ICMP_LEN_MIN);
+ hop = _hop_ip_id(req, ntohs(ip_in->ip_id));
if (!hop) {
- printf("libggnet_traceroute _cb_recv: WARNING: hop ttl %d not found !",
- ip_in->ttl);
- return;
+ printf("libggnet_traceroute _cb_recv: WARNING: ICMP answer with IP ID not matching sent IP ID (%x) not found !\n",
+ ntohs(ip_in->ip_id));
+ goto reschedule_recv;
}
+ memcpy(&hop->ip, &ip_src, sizeof(struct addr));
hop->answer_count++;
if (icmp->icmp_type == ICMP_UNREACH) {
switch (icmp->icmp_code) {
@@ -305,16 +322,17 @@ _cb_recv(evutil_socket_t fd, short what, void *arg)
}
} 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++;
+ if (hop->ttl == req->run.last_ttl_sent &&
+ addr_cmp(&hop->ip, &req->target->ip)) {
+ /* send more probes */
+ event_add(req->run.ev_send, NULL);
+ }
break;
}
- fflush(stdout);
- /* do we need to send more packets ? */
-#endif // if 0
+reschedule_recv:
+ event_add(req->run.ev_recv, NULL);
}
static void
@@ -325,7 +343,7 @@ _cb_send(evutil_socket_t fd, short what, void *arg)
struct ggnet_traceroute *ggtr;
u_char buf[BUFSIZ];
struct trace_pkt *pkt;
- int len, lensent, ttl, i;
+ int len, lensent, ttl, ip_id, sport, i;
req = arg;
printf("XXX cbggnet_traceroute cb_send %s -> %s\n",
@@ -342,36 +360,42 @@ _cb_send(evutil_socket_t fd, short what, void *arg)
}
hop->ttl = ttl;
//addr_pack(hop->ip, ADDR_TYPE_IP, IP_ADDR_BITS, ip, IP_ADDR_LEN);
+ ip_id = rand_uint16(ggtr->pkt_rand);
+ sport = rand_uint16(ggtr->pkt_rand);
switch (req->mode) {
case TRACEMODE_AUTO:
case TRACEMODE_TCP:
+ req->params.tcp.dport = TRACE_DPORT;
ip_pack_hdr(&pkt->pkt_hdr_i.ip, IP_TOS_LOWDELAY, len,
- rand_uint16(ggtr->pkt_rand), 0, ttl,
- IP_PROTO_TCP,
+ ip_id, 0, ttl, IP_PROTO_TCP,
req->srcip.addr_ip, req->target->ip.addr_ip);
tcp_pack_hdr(&pkt->pkt_hdr_t.tcp,
- rand_uint16(ggtr->pkt_rand), TRACE_DPORT,
+ sport, req->params.tcp.dport,
rand_uint32(ggtr->pkt_rand), 0,
TH_SYN, rand_uint16(ggtr->pkt_rand), 0);
+ break;
case TRACEMODE_ICMP:
ip_pack_hdr(&pkt->pkt_hdr_i.ip, IP_TOS_LOWDELAY, len,
- rand_uint16(ggtr->pkt_rand), 0, ttl,
- IP_PROTO_ICMP,
+ ip_id, 0, ttl, IP_PROTO_ICMP,
req->srcip.addr_ip, req->target->ip.addr_ip);
icmp_pack_hdr(&pkt->pkt_hdr_t.icmp, ICMP_ECHO, 8);
+ break;
}
ip_checksum(pkt, len);
TAILQ_INSERT_TAIL(&req->hops_list, hop, entry);
- for (i=0; i<TRACEROUTE_NB_PROBES; i++)
+ for (i=0; i<TRACEROUTE_NB_PROBES; i++) {
+ hop->ip_ids[i] = ip_id;
+ hop->sports[i] = sport;
lensent = ip_send(ggtr->pkt_ip, pkt, len);
if (len < 0)
warn("_cb_send : ip_send error");
if (lensent < len)
warn("_cb_send : ip_send short send (%d < %d",
lensent, len);
- _timeout_set(req, TIMEOUT_TOTAL_S, 0);
+ }
}
req->run.last_ttl_sent = ttl;
+ _timeout_set(req, TIMEOUT_TOTAL_S, 0);
}
static void
@@ -384,17 +408,55 @@ _timeout_set(struct ggnet_traceroute_req *req, int sec, int usec)
}
static struct ggnet_traceroute_hop *
-_hop_last(struct ggnet_traceroute_req *req)
+_hop_ip_id(struct ggnet_traceroute_req *req, int ip_id)
+{
+ struct ggnet_traceroute_hop *h;
+ int i;
+
+ TAILQ_FOREACH_REVERSE(h, &req->hops_list, tailhead, entry) {
+ for (i = 0; i<TRACEROUTE_NB_PROBES; i++)
+ if (h->ip_ids[i] == ip_id)
+ return h;
+ }
+ return NULL;
+}
+
+static struct ggnet_traceroute_hop *
+_hop_sport(struct ggnet_traceroute_req *req, int sport)
{
struct ggnet_traceroute_hop *h;
+ int i;
TAILQ_FOREACH_REVERSE(h, &req->hops_list, tailhead, entry) {
- if (h->answer_count > 0)
- return h;
+ for (i = 0; i<TRACEROUTE_NB_PROBES; i++)
+ if (h->sports[i] == sport)
+ return h;
}
return NULL;
}
+/**
+ * Returns the target hop, and clean the hops_list before calling user callback
+ */
+static struct ggnet_traceroute_hop *
+_hop_last(struct ggnet_traceroute_req *req)
+{
+ struct ggnet_traceroute_hop *h, *ht;
+ struct ggnet_traceroute_hop *last = NULL;
+ int found = 0;
+
+ TAILQ_FOREACH_SAFE(h, &req->hops_list, entry, ht) {
+ if (found)
+ TAILQ_REMOVE(&req->hops_list, h, entry);
+ else if (addr_cmp(&h->ip, &req->target->ip) == 0) {
+ last = h;
+ found = 1;
+ }
+ }
+
+ return last;
+}
+
static void
_cb_trace_timeout(evutil_socket_t fd, short what, void *arg)
{
@@ -406,6 +468,7 @@ _cb_trace_timeout(evutil_socket_t fd, short what, void *arg)
printf("XXX cbggnet_traceroute cb_trace_timeout (%s -> %s)\n",
addr_ntoa(&req->srcip), addr_ntoa(&req->target->ip));
last = _hop_last(req);
+ printf("XXX last %p\n", last);
if (last)
req->target->ttl = last->ttl + 1;
req->cb_done(req, req->data);
diff --git a/libglouglou/libggnet_traceroute.h b/libglouglou/libggnet_traceroute.h
index e14cea7..9cd64ad 100644
--- a/libglouglou/libggnet_traceroute.h
+++ b/libglouglou/libggnet_traceroute.h
@@ -21,6 +21,8 @@ struct ggnet_traceroute_hop {
int ttl;
int answer_count; /* on TRACEROUTE_NB_PROBES sent probes */
char answer[2 * TRACEROUTE_NB_PROBES];
+ int ip_ids[TRACEROUTE_NB_PROBES];
+ int sports[TRACEROUTE_NB_PROBES];
struct addr ip;
int delay;
int delay_dev;
@@ -34,8 +36,13 @@ struct ggnet_traceroute_req {
struct ggnet_traceroute_hop *target;
struct addr srcip;
enum tracemode mode;
- int probes_count;
- int hops_count;
+ union {
+ struct {
+ int dport;
+ } tcp;
+ struct icmp {
+ } icmp;
+ } params;
TAILQ_HEAD(tailhead, ggnet_traceroute_hop) hops_list;
struct {
struct event *ev_recv;