From 2b575ec093dcd84d8d5c816fe41dd5b7363228e6 Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Sat, 6 Jul 2013 02:27:56 +0200 Subject: WIP traceroute integration, disabled by default gg_map is not graphing correctly the route for now --- gg_map/gg_map.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++ gg_sniff/pcap.c | 45 ++++++++++++++++++---------- libglouglou/libggnet.c | 68 ++++++++++++++++++++++++++++++++++++++++++ libglouglou/libggnet.h | 37 +++++++++++++++++++++-- libglouglou/libggnet_dns.c | 5 ++++ libglouglou/libglouglou.c | 40 +++++++++++++++++++++++-- libglouglou/libglouglou.h | 16 ++++++++++ 7 files changed, 265 insertions(+), 20 deletions(-) diff --git a/gg_map/gg_map.c b/gg_map/gg_map.c index 221b915..511d791 100644 --- a/gg_map/gg_map.c +++ b/gg_map/gg_map.c @@ -73,6 +73,37 @@ _cb_ggnet_delgroup(struct ggnet *net, struct ggnet_nodegroup *group) egraph_vertice_del(_egraph, vgroup); } +void +_cb_ggnet_link(struct ggnet *net, struct ggnet_node *a, struct ggnet_node *b) +{ + Egraph_Edge *e; + + e = egraph_edge_add(_egraph, ggnet_node_usrdata_get(a), + ggnet_node_usrdata_get(b), NULL); + if (!e) { + printf("gg_map: WARNING: _cb_link cannot create edge !\n"); + return; + } + egraph_edge_type_set(_egraph, e, "edge_group"); +} + +void +_cb_ggnet_unlink(struct ggnet *net, struct ggnet_node *a, struct ggnet_node *b) +{ + Egraph_Edge *e; + const char *type; + + e = egraph_edge_find(_egraph, ggnet_node_usrdata_get(a), ggnet_node_usrdata_get(b)); + if (!e) { + printf("gg_map: WARNING: _cb_unlink on non existing edge !\n"); + return; + } + egraph_edge_type_get(_egraph, e, &type); + if (strncmp(type, "edge_group", EGRAPH_TYPE_MAXLEN)) + return; + egraph_edge_del(_egraph, e); +} + static Egraph_Vertice * _node_to_vertice(struct ggnet_node *n) { @@ -230,6 +261,37 @@ _conn_name(u_int32_t addr, u_int8_t pktsize, u_char *fqdn) { egraph_vertice_rename(_egraph, ggnet_node_usrdata_get(n), (char *)fqdn); } +static void +_conn_trace(u_int32_t addr, u_int8_t hopcount, struct gg_packet *pkt) { + struct gg_packet_tracehop *h; + struct ggnet_node *n, *np; + struct in_addr ip; + Egraph_Vertice *v; + int i; + + ip.s_addr = addr; + np = ggnet_node_find(_ggnet, &ip); + if (!np) + return; + for (i=0; itrace_hops[i]; + ip.s_addr = h->addr; + n = ggnet_node_find(_ggnet, &ip); + if (!n) { + n = ggnet_node_add(_ggnet, &ip); + v = _node_to_vertice(n); + if (v) + egraph_vertice_type_set(_egraph, v, + "vertice_group"); + else + printf("gg_map: ERROR: could not create trace vertice !\n"); + + } + ggnet_node_path_link(np, n); + np = n; + } +} + static int _cb_packet(struct gg_client *cli, struct gg_packet *pkt) { @@ -278,6 +340,16 @@ _cb_packet(struct gg_client *cli, struct gg_packet *pkt) _conn_name(pkt->name_addr, pkt->name_len, pkt->name_fqdn); break; + + case PACKET_TRACE: + if (_loglevel >= 1) { + printf(" type PACKET_TRACE\n"); + printf(" trace_addr %4x\n", pkt->trace_addr); + printf(" trace_hopcount %d\n", pkt->trace_hopcount); + } + + _conn_trace(pkt->trace_addr, pkt->trace_hopcount, pkt); + break; } return 0; @@ -482,6 +554,8 @@ elm_main(int argc, char **argv) goto quit; ggnet_set_grouping(_ggnet, GGNET_GROUPING_TRUE, _cb_ggnet_addgroup, _cb_ggnet_delgroup); + ggnet_setcb_traceroute(_ggnet, + _cb_ggnet_link, _cb_ggnet_unlink); _ev_base = event_base_new(); ggcli = gg_client_connect(_ev_base, gg_serv_ip, gg_serv_port, diff --git a/gg_sniff/pcap.c b/gg_sniff/pcap.c index 78c7211..d0b326a 100644 --- a/gg_sniff/pcap.c +++ b/gg_sniff/pcap.c @@ -80,7 +80,7 @@ static void phandler_sll(u_char *, static void cb_pcap(int, short, void *); static void cb_conntimer(int, short, void *); static void cb_nodename(struct ggnet *, struct ggnet_node *); -static void cb_nodetraceroute(struct ggnet *, struct ggnet_node *); +static void cb_nodetraceroute(struct ggnet *, struct ggnet_traceroute_req *); static struct phandler phandlers[] = { { phandler_ether, DLT_EN10MB }, @@ -140,8 +140,11 @@ ggsniff_pcap_init(struct event_base *ev_base, struct gg_client *ggcli, gg_log_fatal("user: event_add conntimer failed: %s", strerror(errno)); if (active) { + gg_log_info("active mode"); ggnet_set_dns(net, 1, ev_base, cb_nodename); - //ggnet_set_traceroute(net, 1, ev_base, cb_nodetraceroute); + // XXX IN PROGRESS traceroute, disabled for now, 20130705 + // laurent + //ggnet_set_traceroute(net, 1, iface, ev_base, cb_nodetraceroute); } _cap.ggcli = ggcli; @@ -341,6 +344,7 @@ cb_nodename(struct ggnet *net, struct ggnet_node *n) struct gg_packet pkt; int len; + gg_log_debug("cb_nodename"); len = strnlen(n->fqdn, GGNET_DNSNAME_MAX); if (len > 0) { pkt.ver = PACKET_VERSION; @@ -353,21 +357,30 @@ cb_nodename(struct ggnet *net, struct ggnet_node *n) } static void -cb_nodetraceroute(struct ggnet *net, struct ggnet_node *n) +cb_nodetraceroute(struct ggnet *net, struct ggnet_traceroute_req *req) { + struct ggnet_traceroute_hop *h; struct gg_packet pkt; - int len; + int i; - len = strnlen(n->fqdn, GGNET_DNSNAME_MAX); - if (len > 0) { - pkt.ver = PACKET_VERSION; - pkt.type = PACKET_TRACE; - pkt.name_addr = n->addr.s_addr; - // XXX IN PROGRESS - //pkt.name_len = len; - //strncpy((char *)pkt.name_fqdn, n->fqdn, sizeof(pkt.name_fqdn)); - gg_client_send(_cap.ggcli, &pkt); + if (req->hopcount_answering == 0) + return; + + gg_log_debug("cb_nodetraceroute"); + pkt.ver = PACKET_VERSION; + pkt.type = PACKET_TRACE; + pkt.trace_addr = req->target->ip.addr_ip; + pkt.trace_hopcount = req->hopcount_total; + i = 0; + TAILQ_FOREACH(h, &req->hops_list, entry) { + pkt.trace_hops[i].addr = h->ip.addr_ip; + pkt.trace_hops[i].delay = h->delay; + pkt.trace_hops[i].loss = h->loss; + pkt.trace_hops[i].asn = h->asn; + i++; } + gg_client_send(_cap.ggcli, &pkt); + ggnet_traceroute_trace_free(req); } /* @@ -387,7 +400,7 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) const u_char *cp; struct tcphdr *tcph; struct udphdr *udph; - struct icmp *icmp; + struct icmp_hdr *icmp; struct in_addr src, dst; u_int src_port, dst_port; u_int proto, close; @@ -475,12 +488,14 @@ ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) break; case IPPROTO_ICMP: - icmp = (struct icmp *)cp; + icmp = (struct icmp_hdr *)cp; if (NOTRECEIVED(*icmp)) { log_pinvalid("user: icmp too small"); _cap.pinvalid++; return; } + if (icmp->icmp_type == ICMP_TIMEXCEED) + return; /* not considered real node */ proto = IPPROTO_ICMP; break; diff --git a/libglouglou/libggnet.c b/libglouglou/libggnet.c index 832de54..5f9810b 100644 --- a/libglouglou/libggnet.c +++ b/libglouglou/libggnet.c @@ -4,6 +4,7 @@ #include "libggnet.h" #include "libggnet_dns.h" +#include "libggnet_traceroute.h" static struct ggnet_nodegroup * nodegroup_add(struct ggnet *, @@ -17,6 +18,7 @@ static struct ggnet_nodegroup * static void nodegroup_set(struct ggnet *, struct ggnet_node *); static void nodegroup_unset(struct ggnet *, struct ggnet_node *); static void _cb_dns_reverse(struct in_addr *, char *, void *); +static void _cb_traceroute_trace(struct ggnet_traceroute_req *req, void *data); struct ggnet * ggnet_new(int manage_connid) @@ -52,13 +54,26 @@ ggnet_set_grouping(struct ggnet *net, int set, net->cb_delgroup = cb_delgroup; } +void +ggnet_setcb_traceroute(struct ggnet *net, + void (*cb_link)(struct ggnet *, + struct ggnet_node *, struct ggnet_node *), + void (*cb_unlink)(struct ggnet *, + struct ggnet_node *, struct ggnet_node *)) +{ + net->cb_traceroute_link = cb_link; + net->cb_traceroute_unlink = cb_unlink; +} + void ggnet_set_dns(struct ggnet *net, int set, struct event_base *ev_base, void (*cb_nodename)(struct ggnet *, struct ggnet_node *)) { + printf("XXX ggnet_set_dns %d\n", set); net->use_dns = set; if (set) { + printf("XXX calling ggnet_dns_new\n"); net->ggdns = ggnet_dns_new(ev_base); net->cb_nodename = cb_nodename; } @@ -66,6 +81,20 @@ ggnet_set_dns(struct ggnet *net, int set, ggnet_dns_free(net->ggdns); } +void +ggnet_set_traceroute(struct ggnet *net, int set, char *iface, + struct event_base *ev_base, + void (*cb_traceroute)(struct ggnet *, struct ggnet_traceroute_req *)) +{ + net->use_traceroute = set; + if (set) { + net->ggtraceroute = ggnet_traceroute_new(ev_base, iface, net->debug); + net->cb_traceroute = cb_traceroute; + } + else if (net->use_traceroute) + ggnet_traceroute_free(net->ggtraceroute); +} + void ggnet_debug_set(struct ggnet *net, int set) { @@ -110,6 +139,12 @@ ggnet_node_add(struct ggnet *net, struct in_addr *addr) nodegroup_set(net, n); if (net->use_dns) n->dns_req = ggnet_dns_reverse(net->ggdns, &n->addr, _cb_dns_reverse, n); + if (net->use_traceroute) { + struct addr ip; + addr_aton(inet_ntoa(*addr), &ip); + printf("XXX calling trace on %s\n", inet_ntoa(*addr)); + n->traceroute_req = ggnet_traceroute_trace_tcp(net->ggtraceroute, &ip, 80, _cb_traceroute_trace, NULL, n); + } return n; } @@ -163,6 +198,26 @@ ggnet_node_group_get(struct ggnet_node *n) return n->group; } +int +ggnet_node_path_link(struct ggnet_node *a, struct ggnet_node *b) +{ + if (b->path_parent) { + if (b->path_parent == a) + return 0; /* already path connected */ + /* remove old path link */ + LIST_REMOVE(b, entry_path); + b->path_parent = NULL; + if (a->net->cb_traceroute_unlink) + a->net->cb_traceroute_unlink(a->net, a, b); + } + LIST_INSERT_HEAD(&a->path_to, b, entry_path); + b->path_parent = a; + if (a->net->cb_traceroute_link) + a->net->cb_traceroute_link(a->net, a, b); + + return 1; +} + struct ggnet_conn * ggnet_conn_add(struct ggnet *net, struct in_addr *src, int src_port, struct in_addr *dst, int dst_port, int proto, int size, @@ -487,6 +542,7 @@ _cb_dns_reverse(struct in_addr *ip, char *name, void *data) struct ggnet *net; struct ggnet_node *n; + printf("XXX _cb_dns_reverse %s\n", name); n = data; net = n->net; n->dns_req = NULL; @@ -496,3 +552,15 @@ _cb_dns_reverse(struct in_addr *ip, char *name, void *data) } } +static void +_cb_traceroute_trace(struct ggnet_traceroute_req *req, void *data) +{ + struct ggnet *net; + struct ggnet_node *n; + + printf("XXX _cb_traceroute_trace %p\n", req); + n = data; + net = n->net; + n->traceroute_req = NULL; + net->cb_traceroute(net, req); +} diff --git a/libglouglou/libggnet.h b/libglouglou/libggnet.h index 794639b..fecf2bb 100644 --- a/libglouglou/libggnet.h +++ b/libglouglou/libggnet.h @@ -14,6 +14,8 @@ #include #endif +#include "libggnet_traceroute.h" + #define GGNET_DNSNAME_MAX 60 #define GGNET_CONN_FREEIDS_COUNT 65536 /* 2^16 as freeids are u_int16_t */ @@ -43,13 +45,17 @@ struct ggnet_nodegroup { struct ggnet_node { LIST_ENTRY(ggnet_node) entry; + LIST_ENTRY(ggnet_node) entry_path; struct ggnet *net; struct in_addr addr; + LIST_HEAD(, ggnet_node) path_to; /* traceroute childs */ + struct ggnet_node *path_parent; /* traceroute parent */ time_t lastseen; - int used; + int used; /* by ggnet_conn */ + struct ggnet_nodegroup *group; /* XXX for now only one group */ char fqdn[GGNET_DNSNAME_MAX]; - struct ggnet_nodegroup *group; /* XXX for now we support only one group */ struct ggnet_dns_req *dns_req; + struct ggnet_traceroute_req *traceroute_req; void *usrdata; }; @@ -82,7 +88,7 @@ struct ggnet { int node_count; u_int16_t conn_freeids[GGNET_CONN_FREEIDS_COUNT]; int conn_freeids_ptr; - int manage_connid; + int manage_connid; /* XXX rename to active / passive */ time_t time; int debug; /* grouping */ @@ -93,6 +99,18 @@ struct ggnet { int use_dns; struct ggnet_dns *ggdns; void (*cb_nodename)(struct ggnet *, struct ggnet_node *); + /* traceroute */ + int use_traceroute; + struct ggnet_traceroute *ggtraceroute; + void (*cb_traceroute)(struct ggnet *, struct ggnet_traceroute_req *); + /* traceroute callbacks */ + void (*cb_traceroute_link)(struct ggnet *, + struct ggnet_node *, + struct ggnet_node *); + void (*cb_traceroute_unlink)(struct ggnet *, + struct ggnet_node *, + struct ggnet_node *); + }; struct ggnet *ggnet_new(int); @@ -102,10 +120,21 @@ void ggnet_set_grouping(struct ggnet *, int, struct ggnet_nodegroup *), void (*cb_delgroup)(struct ggnet *, struct ggnet_nodegroup *)); +void ggnet_setcb_traceroute(struct ggnet *, + void (*cb_link)(struct ggnet *, + struct ggnet_node *, + struct ggnet_node *), + void (*cb_unlink)(struct ggnet *, + struct ggnet_node *, + struct ggnet_node *)); void ggnet_set_dns(struct ggnet *net, int set, struct event_base *ev_base, void (*cb_nodename)(struct ggnet *, struct ggnet_node *)); +void ggnet_set_traceroute(struct ggnet *, int, char *, + struct event_base *, + void (*cb_traceroute)(struct ggnet *, + struct ggnet_traceroute_req *)); void ggnet_debug_set(struct ggnet *, int); void ggnet_free(struct ggnet *); struct ggnet_node *ggnet_node_add(struct ggnet *, struct in_addr *); @@ -114,6 +143,8 @@ struct ggnet_node *ggnet_node_find(struct ggnet *, struct in_addr *); void *ggnet_node_usrdata_get(struct ggnet_node *); void ggnet_node_usrdata_set(struct ggnet_node *, void *); struct ggnet_nodegroup *ggnet_node_group_get(struct ggnet_node *); +int ggnet_node_path_link(struct ggnet_node *a, + struct ggnet_node *b); struct ggnet_conn *ggnet_conn_add(struct ggnet *, struct in_addr *, int, struct in_addr *, int, int, int, int); void ggnet_conn_data(struct ggnet *, struct ggnet_conn *, diff --git a/libglouglou/libggnet_dns.c b/libglouglou/libggnet_dns.c index c6f8cce..66292b1 100644 --- a/libglouglou/libggnet_dns.c +++ b/libglouglou/libggnet_dns.c @@ -18,6 +18,8 @@ ggnet_dns_new(struct event_base *ev_base) { struct ggnet_dns *ggdns = NULL; + printf("XXX ggnet_dns_new\n"); + ggdns = calloc(1, sizeof(struct ggnet_dns)); if (!ggdns) { printf("could not allocate ggnet_dns\n"); @@ -53,6 +55,8 @@ ggnet_dns_reverse(struct ggnet_dns *ggdns, struct evdns_request *ereq; struct in_addr nip; + printf("XXX ggnet_dns_reverse %d\n", ip->s_addr); + memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = EVUTIL_AI_CANONNAME; @@ -105,6 +109,7 @@ _cb_evdns_reverse(int result, char type, int count, req = arg; name = addresses; + printf("XXX _cb_evdns_reverse %p\n", name); if (result != DNS_ERR_NONE || count == 0) req->cb_usr(&req->ip, NULL, req->data); else diff --git a/libglouglou/libglouglou.c b/libglouglou/libglouglou.c index f702d2a..9f41313 100644 --- a/libglouglou/libglouglou.c +++ b/libglouglou/libglouglou.c @@ -50,6 +50,8 @@ gg_packet_props_t gg_packet_props[] = { { (PACKET_HEADER_SIZE + sizeof((struct gg_packet *)0)->pdat.data) }, [PACKET_NAME] = \ { ((PACKET_HEADER_SIZE + sizeof((struct gg_packet *)0)->pdat.name) - GG_PKTARG_MAX) }, + [PACKET_TRACE] = \ + { ((PACKET_HEADER_SIZE + sizeof((struct gg_packet *)0)->pdat.trace) - (sizeof(struct gg_packet_tracehop) * GG_PKTARG_MAX)) }, [PACKET_FORK] = \ { (PACKET_HEADER_SIZE + sizeof((struct gg_packet *)0)->pdat.fork) }, [PACKET_EXEC] = \ @@ -514,8 +516,7 @@ pkt_decode(char **buf, int *buf_len) { static struct gg_packet newpkt; struct gg_packet *pkt; - int len; - int packet_len; + int i, len, packet_len; len = *buf_len; @@ -566,6 +567,22 @@ pkt_decode(char **buf, int *buf_len) strncpy((char *)newpkt.name_fqdn, (char *)pkt->name_fqdn, newpkt.name_len); break; + case PACKET_TRACE: + newpkt.trace_addr = ntohl(pkt->trace_addr); + newpkt.trace_hopcount = pkt->trace_hopcount; + if (newpkt.trace_hopcount > GG_PKTARG_MAX) + invalid("type trace hopcount"); + packet_len = packet_len \ + + newpkt.trace_hopcount * sizeof(struct gg_packet_tracehop); + if (len < packet_len) + goto incomplete; + for (i=0; itrace_hops[i].addr); + newpkt.trace_hops[i].delay = ntohs(pkt->trace_hops[i].delay); + newpkt.trace_hops[i].loss = pkt->trace_hops[i].loss; + newpkt.trace_hops[i].asn = pkt->trace_hops[i].asn; + } + break; case PACKET_FORK: newpkt.fork_pid = ntohl(pkt->fork_pid); newpkt.fork_ppid = ntohl(pkt->fork_ppid); @@ -615,6 +632,8 @@ invalid: int pkt_encode(struct gg_packet *pkt, struct gg_packet *newpkt) { + int i; + if (pkt->type < PACKET_TYPE_MIN || pkt->type > PACKET_TYPE_MAX) invalid("type"); @@ -643,6 +662,18 @@ pkt_encode(struct gg_packet *pkt, struct gg_packet *newpkt) strncpy((char *)newpkt->name_fqdn, (char *)pkt->name_fqdn, pkt->name_len); break; + case PACKET_TRACE: + if (pkt->trace_hopcount > GG_PKTARG_MAX) + goto invalid; + newpkt->trace_addr = htonl(pkt->trace_addr); + newpkt->trace_hopcount = pkt->trace_hopcount; + for (i=0; itrace_hopcount; i++) { + newpkt->trace_hops[i].addr = htonl(pkt->trace_hops[i].addr); + newpkt->trace_hops[i].delay = htons(pkt->trace_hops[i].delay); + newpkt->trace_hops[i].loss = pkt->trace_hops[i].loss; + newpkt->trace_hops[i].asn = pkt->trace_hops[i].asn; + } + break; case PACKET_FORK: newpkt->fork_pid = htonl(pkt->fork_pid); newpkt->fork_ppid = htonl(pkt->fork_ppid); @@ -691,6 +722,11 @@ pkt_getsize(struct gg_packet *pkt) goto invalid; packet_len = packet_len + pkt->name_len; break; + case PACKET_TRACE: + if (pkt->trace_hopcount > GG_PKTARG_MAX) + goto invalid; + packet_len = packet_len + pkt->trace_hopcount * sizeof(struct gg_packet_tracehop); + break; case PACKET_EXEC: if (pkt->exec_cmdlen > GG_PKTARG_MAX) goto invalid; diff --git a/libglouglou/libglouglou.h b/libglouglou/libglouglou.h index fb755a7..ac57595 100644 --- a/libglouglou/libglouglou.h +++ b/libglouglou/libglouglou.h @@ -35,11 +35,19 @@ enum gg_packet_type { /* u_int8_t */ PACKET_DELCONN = 0x01, PACKET_DATA = 0x02, PACKET_NAME = 0x03, + PACKET_TRACE = 0x04, PACKET_FORK = 0x10, PACKET_EXEC = 0x11, PACKET_EXIT = 0x12, }; +struct __attribute__((packed)) gg_packet_tracehop { + u_int32_t addr; + u_int16_t delay; + u_int8_t loss; + u_int8_t asn; +}; + /* XXX is packed needed everywhere ? */ struct __attribute__((packed)) gg_packet { u_int8_t ver; @@ -64,6 +72,11 @@ struct __attribute__((packed)) gg_packet { u_int8_t len; u_char fqdn[GG_PKTARG_MAX]; } name; + struct __attribute__((packed)) trace { + u_int32_t addr; + u_int8_t hopcount; + struct gg_packet_tracehop hops[GG_PKTARG_MAX]; + } trace; struct __attribute__((packed)) fork { u_int32_t pid; u_int32_t ppid; @@ -92,6 +105,9 @@ struct __attribute__((packed)) gg_packet { #define name_addr pdat.name.addr #define name_len pdat.name.len #define name_fqdn pdat.name.fqdn +#define trace_addr pdat.trace.addr +#define trace_hopcount pdat.trace.hopcount +#define trace_hops pdat.trace.hops #define fork_pid pdat.fork.pid #define fork_ppid pdat.fork.ppid #define fork_cpid pdat.fork.cpid -- cgit v1.2.3-59-g8ed1b