From d65d47c4e0da83f20fa51846be1015d0be94835b Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Sat, 8 Jun 2013 13:04:18 +0200 Subject: libglouglou: traceroute TCP working --- libglouglou/examples/traceroute.c | 4 +- libglouglou/libggnet_traceroute.c | 153 +++++++++++++++++++++++++++----------- libglouglou/libggnet_traceroute.h | 11 ++- 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; iip_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; iip_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; isports[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; -- cgit v1.2.3-59-g8ed1b