From 6f633aa1891f631b11ca5b23ea92c7311d0f0adf Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Fri, 7 Jun 2013 03:06:21 +0200 Subject: libggnet: traceroute sends packets in TCP and ICMP --- libglouglou/examples/traceroute.c | 20 +++--- libglouglou/libggnet_traceroute.c | 135 +++++++++++++++++++++++++------------- libglouglou/libggnet_traceroute.h | 23 +++++-- libglouglou/utils.c | 4 +- 4 files changed, 117 insertions(+), 65 deletions(-) diff --git a/libglouglou/examples/traceroute.c b/libglouglou/examples/traceroute.c index b5d89b1..9d76a7d 100644 --- a/libglouglou/examples/traceroute.c +++ b/libglouglou/examples/traceroute.c @@ -17,10 +17,11 @@ #include #include +#include /* for get_iface */ #include static void _droppriv(char *, int, char *); -static void _cb_traceroute(struct in_addr *, +static void _cb_traceroute(struct addr *, struct ggnet_traceroute_req *, void *); struct event_base *_ev_base; @@ -32,32 +33,31 @@ main(int argc, char *argv[]) { struct ggnet_traceroute *ggtr; struct ggnet_traceroute_hop *hop; - struct in_addr ip; + struct addr ip; struct timeval tv; if (argc < 2) { printf("usage: traceroute \n"); exit(1); } - inet_aton(argv[1], &ip); - ip.s_addr = ntohl(ip.s_addr); + addr_aton(argv[1], &ip); bzero(&tv, sizeof(struct timeval)); tv.tv_sec = 10; _ev_base = event_base_new(); - ggtr = ggnet_traceroute_new(_ev_base, "lo"); // XXX rm iface + ggtr = ggnet_traceroute_new(_ev_base, get_iface(argv[1])); _droppriv("nobody", 1, NULL); /* bad practise you should use dedicated user */ - ggnet_traceroute_trace(ggtr, &ip, _cb_traceroute, NULL); + ggnet_traceroute_trace(ggtr, &ip, TRACEMODE_ICMP, _cb_traceroute, NULL); event_base_loopexit(_ev_base, &tv); event_base_dispatch(_ev_base); if (_answer) { - printf("%x:\n", ip.s_addr); - LIST_FOREACH(hop, &_route->hops, entry) { - printf("%x (%d)\n", hop->ip.s_addr, hop->delay); + printf("%s:\n", addr_ntoa(&ip)); + TAILQ_FOREACH(hop, &_route->hops_list, entry) { + printf("%s (%d)\n", addr_ntoa(&hop->ip), hop->delay); } } else { printf("no answer\n"); @@ -94,7 +94,7 @@ _droppriv(char *user, int do_chroot, char *chroot_path) static void -_cb_traceroute(struct in_addr *ip, +_cb_traceroute(struct addr *ip, struct ggnet_traceroute_req *route, void *data) { _route = route; diff --git a/libglouglou/libggnet_traceroute.c b/libglouglou/libggnet_traceroute.c index 077d237..561f0aa 100644 --- a/libglouglou/libggnet_traceroute.c +++ b/libglouglou/libggnet_traceroute.c @@ -77,6 +77,8 @@ 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 void _timeout_set(struct ggnet_traceroute_req *, int, int); static int pcap_dloff(pcap_t *); // XXX move to libggnet_utils ? struct trace_pkt { @@ -85,6 +87,7 @@ struct trace_pkt { } pkt_hdr_i; union { struct tcp_hdr tcp; + struct icmp_hdr icmp; } pkt_hdr_t; }; @@ -107,14 +110,11 @@ ggnet_traceroute_new(struct event_base *ev_base, char *iface) return NULL; } ggtr->pkt_rand = rand_open(); - - /* XXX - * Get iface/route from route_open, route_get and pcap_lookupnet. - * DNS server cannot be changed to another interface after this. */ + ggtr->intf = intf_open(); ggtr->pcap = pcap_open_live(iface, 1500, 1, 500, ebuff); if (ggtr->pcap == NULL) - err(1, "pcap_open_live()"); + err(1, "pcap_open_live(%s)", iface); ggtr->pcap_dllen = pcap_dloff(ggtr->pcap); ggtr->pcap_fd = pcap_fileno(ggtr->pcap); @@ -139,39 +139,55 @@ ggnet_traceroute_free(struct ggnet_traceroute *ggtr) struct ggnet_traceroute_req * ggnet_traceroute_trace(struct ggnet_traceroute *ggtr, - struct in_addr *ip, - void (*cb_usr)(struct in_addr *, struct ggnet_traceroute_req *, void *), + struct addr *ip, enum tracemode mode, + void (*cb_usr)(struct addr *, struct ggnet_traceroute_req *, void *), void *data) { struct ggnet_traceroute_req *req; - struct ggnet_traceroute_hop *target; + struct intf_entry intf_entry; 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) { + req->target = calloc(1, sizeof(struct ggnet_traceroute_hop)); + if (!req->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); + memcpy(&req->target->ip, ip, sizeof(struct addr)); + if (intf_get_dst(ggtr->intf, &intf_entry, &req->target->ip) < 0) { + printf("error getting source IP for dest IP %s\n", + addr_ntoa(ip)); + goto err; + } + memcpy(&req->srcip, &intf_entry.intf_addr, sizeof(struct addr)); + req->mode = mode; + TAILQ_INIT(&req->hops_list); - req->ev_recv = event_new(ggtr->ev_base, + req->run.ev_recv = event_new(ggtr->ev_base, ggtr->pcap_fd, EV_READ, _cb_recv, req); - event_add(req->ev_recv, NULL); - req->ev_send = event_new(ggtr->ev_base, + event_add(req->run.ev_recv, NULL); + req->run.ev_send = event_new(ggtr->ev_base, ggtr->pcap_fd, EV_WRITE, _cb_send, req); - event_add(req->ev_send, NULL); + event_add(req->run.ev_send, NULL); + req->run.ev_timeout = evtimer_new(ggtr->ev_base, + _cb_trace_timeout, req); + event_add(req->run.ev_timeout, NULL); - // XXX evtimer timeout !!! - evtimer_new(ggtr->ev_base, _cb_trace_timeout, req); + req->cb_usr = cb_usr; + req->data = data; + req->ggtr = ggtr; LIST_INSERT_HEAD(&ggtr->req_list, req, entry); return req; + +err: + if (req) + _req_free(req); + return NULL; } void @@ -186,18 +202,21 @@ ggnet_traceroute_cancel(struct ggnet_traceroute *ggtr, static void _req_free(struct ggnet_traceroute_req *req) { - if (req->ev_recv) - event_free(req->ev_recv); - if (req->ev_send) - event_free(req->ev_send); + if (req->target) + free(req->target); + if (req->run.ev_recv) + event_free(req->run.ev_recv); + if (req->run.ev_send) + event_free(req->run.ev_send); free(req); } static void _cb_recv(evutil_socket_t fd, short what, void *arg) { - struct ggnet_traceroute_hop *hop; struct ggnet_traceroute_req *req; +#if 0 + struct ggnet_traceroute_hop *hop; struct ggnet_traceroute *ggtr; struct pcap_pkthdr ph; u_char *pread, *tmp; @@ -207,8 +226,12 @@ _cb_recv(evutil_socket_t fd, short what, void *arg) struct addr ip_src; char *reply = "U!"; char *p; +#endif - printf("cbggnet_traceroute cb_recv %s\n", addr_ntoa(&req->target->ip)); + req = arg; + printf("XXX cbggnet_traceroute cb_recv %s -> %s\n", + addr_ntoa(&req->srcip), addr_ntoa(&req->target->ip)); +#if 0 req = arg; ggtr = req->ggtr; @@ -286,25 +309,27 @@ _cb_recv(evutil_socket_t fd, short what, void *arg) fflush(stdout); /* do we need to send more packets ? */ +#endif // if 0 } static void _cb_send(evutil_socket_t fd, short what, void *arg) { struct ggnet_traceroute_req *req; + struct ggnet_traceroute_hop *hop; struct ggnet_traceroute *ggtr; u_char buf[BUFSIZ]; struct trace_pkt *pkt; - int len; - int ttl; + int len, lensent, ttl, i; - printf("cbggnet_traceroute cb_send %s\n", addr_ntoa(&req->ip)); req = arg; + printf("XXX cbggnet_traceroute cb_send %s -> %s\n", + addr_ntoa(&req->srcip), addr_ntoa(&req->target->ip)); ggtr = req->ggtr; pkt = (struct trace_pkt *)buf; len = IP_HDR_LEN + TCP_HDR_LEN; - for (ttl=req->ttl_sent; i<15; i++) { + for (ttl=req->run.last_ttl_sent; ttl<15; ttl++) { hop = calloc(1, sizeof(struct ggnet_traceroute_hop)); if (!hop) { printf("cannot allocate ggnet_traceroute_hop\n"); @@ -312,53 +337,73 @@ _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_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), + switch (req->mode) { + case TRACEMODE_AUTO: + case TRACEMODE_TCP: + ip_pack_hdr(&pkt->pkt_hdr_i.ip, IP_TOS_LOWDELAY, len, + rand_uint16(ggtr->pkt_rand), 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, + rand_uint32(ggtr->pkt_rand), 0, TH_SYN, rand_uint16(ggtr->pkt_rand), 0); + 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, + req->srcip.addr_ip, req->target->ip.addr_ip); + icmp_pack_hdr(&pkt->pkt_hdr_t.icmp, ICMP_ECHO, 8); + } ip_checksum(pkt, len); TAILQ_INSERT_TAIL(&req->hops_list, hop, entry); for (i=0; ipkt_ip, pkt, len) < 0) - warn("_cb_send : ip_send short send"); + 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->ttl_sent = ttl; + req->run.last_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); + req->run.tv_timeout.tv_sec = sec; + req->run.tv_timeout.tv_usec = usec; + evtimer_add(req->run.ev_timeout, &req->run.tv_timeout); } -static ggnet_traceroute_hop * -_hop_last(ggnet_traceroute_req *req) +static struct ggnet_traceroute_hop * +_hop_last(struct ggnet_traceroute_req *req) { struct ggnet_traceroute_hop *h; - TAILQ_FOREACH_REVERSE(h, req->hop_list, entry) { + TAILQ_FOREACH_REVERSE(h, &req->hops_list, tailhead, entry) { if (h->answer_count > 0) return h; } return NULL; } -void +static void _cb_trace_timeout(evutil_socket_t fd, short what, void *arg) { struct ggnet_traceroute_req *req; + struct ggnet_traceroute_hop *last; req = arg; - // XXX IN PROGRESS + printf("XXX cbggnet_traceroute cb_trace_timeout (%s -> %s)\n", + addr_ntoa(&req->srcip), addr_ntoa(&req->target->ip)); last = _hop_last(req); - req->target->ttl = last->ttl + 1; + if (last) + req->target->ttl = last->ttl + 1; + req->cb_usr(&req->srcip, req, req->data); } static int diff --git a/libglouglou/libggnet_traceroute.h b/libglouglou/libggnet_traceroute.h index 92b2d43..5699bfb 100644 --- a/libglouglou/libggnet_traceroute.h +++ b/libglouglou/libggnet_traceroute.h @@ -10,6 +10,12 @@ #define TRACEROUTE_NB_PROBES 3 +enum tracemode { + TRACEMODE_AUTO = 0, + TRACEMODE_ICMP = 1, + TRACEMODE_TCP = 2, +}; + struct ggnet_traceroute_hop { TAILQ_ENTRY(ggnet_traceroute_hop) entry; int ttl; @@ -25,25 +31,28 @@ struct ggnet_traceroute_hop { struct ggnet_traceroute_req { LIST_ENTRY(ggnet_traceroute_req) entry; - struct ggnet_traceroute_hop *target; - struct addr srcip; + struct ggnet_traceroute_hop *target; + struct addr srcip; + enum tracemode mode; int probes_count; int hops_count; - TAILQ_HEAD(, ggnet_traceroute_hop) hops_list; + TAILQ_HEAD(tailhead, ggnet_traceroute_hop) hops_list; struct { struct event *ev_recv; struct event *ev_send; - struct evtimer *ev_timeout; + struct event *ev_timeout; struct timeval tv_timeout; int last_ttl_sent; } run; - void (*cb_usr)(struct in_addr *, char *, void *); + void (*cb_usr)(struct addr *, struct ggnet_traceroute_req *, void *); void *data; + struct ggnet_traceroute *ggtr; }; struct ggnet_traceroute { struct event_base *ev_base; pcap_t *pcap; + intf_t *intf; ip_t *pkt_ip; rand_t *pkt_rand; int pcap_fd; @@ -57,8 +66,8 @@ struct ggnet_traceroute * void ggnet_traceroute_free(struct ggnet_traceroute *); struct ggnet_traceroute_req * ggnet_traceroute_trace(struct ggnet_traceroute *, - struct in_addr *ip, - void (*cb_usr)(struct in_addr *, struct ggnet_traceroute_req *, void *), + struct addr *ip, enum tracemode, + void (*cb_usr)(struct addr *, struct ggnet_traceroute_req *, void *), void *); void ggnet_traceroute_cancel(struct ggnet_traceroute *, struct ggnet_traceroute_req *); diff --git a/libglouglou/utils.c b/libglouglou/utils.c index 2f5f710..a7ceffd 100644 --- a/libglouglou/utils.c +++ b/libglouglou/utils.c @@ -205,14 +205,12 @@ get_iface(char *ip) { struct addr dst; struct intf_entry entry; intf_t *intf; - char *iface; intf = intf_open(); addr_aton(ip, &dst); if (intf_get_dst(intf, &entry, &dst) < 0) return NULL; - iface = addr_ntoa(&entry.intf_addr); intf_close(intf); - return iface; + return strdup(entry.intf_name); } -- cgit v1.2.3-59-g8ed1b