diff options
author | Laurent Ghigonis <laurent@p1sec.com> | 2013-01-12 23:37:32 +0100 |
---|---|---|
committer | Laurent Ghigonis <laurent@p1sec.com> | 2013-01-12 23:37:32 +0100 |
commit | 8aa15027443ef20e1d65c127f882511c2ee2e7ab (patch) | |
tree | c61672acb42d88065242ea324f56c7a6b3d065af /libglouglou | |
parent | update requirements (diff) | |
download | glouglou-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.c | 261 | ||||
-rw-r--r-- | libglouglou/libggnet_traceroute.h | 26 |
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; }; |