aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/ARCHITECTURE.txt20
-rw-r--r--gg_sniff/README.txt3
-rw-r--r--gg_sniff/pcap.c23
-rw-r--r--libglouglou/Makefile6
-rw-r--r--libglouglou/README.txt24
-rw-r--r--libglouglou/examples/Makefile1
-rw-r--r--libglouglou/examples/traceroute.c103
-rw-r--r--libglouglou/libggnet_traceroute.c420
-rw-r--r--libglouglou/libggnet_traceroute.h62
9 files changed, 657 insertions, 5 deletions
diff --git a/doc/ARCHITECTURE.txt b/doc/ARCHITECTURE.txt
index 721b094..70b32ab 100644
--- a/doc/ARCHITECTURE.txt
+++ b/doc/ARCHITECTURE.txt
@@ -1,4 +1,24 @@
===============================================================================
+2012-12-18_20-36
+
+After Json talk:
+
+Probe
+* sends packets / connections about nodes that are around
+* sends informations about nodes that are around distance, path ...
+* forwards informations about other probes
+
+Processing server
+* a graph out of network informations, which nodes are connected to which
+* has the state of all the network
+
+Visualisation client (small, no processing)
+* transfers full graph on connection
+* then graph updates, about nodes
+* push / pull ?
+
+
+===============================================================================
2012-11-06_00-19
refer to architecture.xoj for big picture
diff --git a/gg_sniff/README.txt b/gg_sniff/README.txt
index 8d71005..2a43d02 100644
--- a/gg_sniff/README.txt
+++ b/gg_sniff/README.txt
@@ -36,6 +36,9 @@ Note that gg_sniff activates extra protections on libpcap file descriptor, by
setting it to readonly, for now on OpenBSD only.
It does so by reimplementing some of libpcap functions, see
pcap.c my_pcap_open_live()
+If you run gg_sniff in active mode (-a), it will open a readwrite raw socket
+(with libpcap) and a readwrite ip socket (with libdnet) which render the
+previous protection useless.
Limitations
===========
diff --git a/gg_sniff/pcap.c b/gg_sniff/pcap.c
index 72b9133..fc5b978 100644
--- a/gg_sniff/pcap.c
+++ b/gg_sniff/pcap.c
@@ -81,6 +81,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 struct phandler phandlers[] = {
{ phandler_ether, DLT_EN10MB },
@@ -137,8 +138,10 @@ ggsniff_pcap_init(struct event_base *ev_base, struct gg_client *ggcli,
if (evtimer_add(_cap.conntimer_ev, &_cap.conntimer_tv) == -1)
gg_log_fatal("user: event_add conntimer failed: %s", strerror(errno));
- if (active)
+ if (active) {
ggnet_set_dns(net, 1, ev_base, cb_nodename);
+ ggnet_set_traceroute(net, 1, ev_base, cb_nodetraceroute);
+ }
_cap.ggcli = ggcli;
_cap.net = net;
@@ -348,6 +351,24 @@ cb_nodename(struct ggnet *net, struct ggnet_node *n)
}
}
+static void
+cb_nodetraceroute(struct ggnet *net, struct ggnet_node *n)
+{
+ struct gg_packet pkt;
+ int len;
+
+ 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);
+ }
+}
+
/*
* Parse an IP packet and descide what to do with it.
* 'ip' is a pointer the the captured IP packet
diff --git a/libglouglou/Makefile b/libglouglou/Makefile
index 0343e6f..2065315 100644
--- a/libglouglou/Makefile
+++ b/libglouglou/Makefile
@@ -6,8 +6,10 @@ LIBDIR=$(PREFIX)/lib
LIBNAME=libglouglou
TARGET = ${LIBNAME}.so
-SOURCES = libglouglou.c sendbuf.c utils.c libggnet.c libggnet_dns.c
-HEADERS = libglouglou.h libggnet.h libggnet_dns.h
+SOURCES = libglouglou.c sendbuf.c utils.c \
+ libggnet.c libggnet_dns.c libggnet_traceroute.c
+HEADERS = libglouglou.h \
+ libggnet.h libggnet_dns.h libggnet_traceroute.h
OBJECTS = $(SOURCES:.c=.o)
all: $(TARGET)
diff --git a/libglouglou/README.txt b/libglouglou/README.txt
index 003db0a..577d7e8 100644
--- a/libglouglou/README.txt
+++ b/libglouglou/README.txt
@@ -3,15 +3,35 @@ libglouglou - underlaying library for glougloud and glouglou clients
Requirements
============
-* libevent2
+* libevent
+* libpcap
+* libdnet
* libbsd (linux only)
+Fedora 17:
+sudo yum install libevent-devel libpcap-devel libdnet-devel libbsd-devel
+
libggnet
========
-libglouglou includes libggnet a helper to keep track of network nodes and
+libglouglou includes libggnet, a helper to keep track of network nodes and
connections.
+libggnet_dns
+============
+
+libglouglou includes libggnet_dns, a wrapper around evdns to do asyncronous
+DNS reverse resolving with a simple API.
+It can be reused independently by using libggnet_dns.c and libggnet_dns.h.
+
+libggnet_traceroute
+===================
+
+libglouglou includes libggnet_traceroute, a library to do asyncronous traceroute
+based on libevent, libpcap and libdnet.
+It can be reused independently by using libggnet_traceroute.c and
+libggnet_traceroute.h.
+
sendbuf
=======
diff --git a/libglouglou/examples/Makefile b/libglouglou/examples/Makefile
index 5dc4bd5..d09388d 100644
--- a/libglouglou/examples/Makefile
+++ b/libglouglou/examples/Makefile
@@ -1,4 +1,5 @@
CFLAGS += -Wall -g -levent -lglouglou
+CFLAGS += -ldnet -lpcap # for libggnet_traceroute
SOURCES = $(shell echo *.c)
OBJECTS = $(SOURCES:.c=.o)
diff --git a/libglouglou/examples/traceroute.c b/libglouglou/examples/traceroute.c
new file mode 100644
index 0000000..080274f
--- /dev/null
+++ b/libglouglou/examples/traceroute.c
@@ -0,0 +1,103 @@
+#include <sys/types.h>
+
+#if !defined(__OpenBSD__)
+#define __USE_GNU
+#define _GNU_SOURCE
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <err.h>
+
+#include <libggnet_traceroute.h>
+
+static void _droppriv(char *, int, char *);
+static void _cb_traceroute(struct in_addr *,
+ struct ggnet_traceroute_req *, void *);
+
+struct event_base *_ev_base;
+struct ggnet_traceroute_req *_route = NULL;
+int _answer = 0;
+
+int
+main(int argc, char *argv[])
+{
+ struct ggnet_traceroute *ggtr;
+ struct ggnet_traceroute_hop *hop;
+ struct in_addr ip;
+ struct timeval tv;
+
+ if (argc < 2) {
+ printf("usage: traceroute <ip>\n");
+ exit(1);
+ }
+ inet_aton(argv[1], &ip);
+ ip.s_addr = ntohl(ip.s_addr);
+
+ bzero(&tv, sizeof(struct timeval));
+ tv.tv_sec = 10;
+
+ _ev_base = event_base_new();
+
+ ggtr = ggnet_traceroute_new(_ev_base, "lo"); // XXX rm iface
+ _droppriv("nobody", 1, NULL); /* bad practise you should use dedicated user */
+ ggnet_traceroute_trace(ggtr, &ip, _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);
+ }
+ } else {
+ printf("no answer\n");
+ }
+ return 0;
+}
+
+/* from libglouglou utils.c */
+static void
+_droppriv(char *user, int do_chroot, char *chroot_path)
+{
+ struct passwd *pw;
+
+ pw = getpwnam(user);
+ if (!pw)
+ err(1, "unknown user %s", user);
+ if (do_chroot) {
+ if (!chroot_path)
+ chroot_path = pw->pw_dir;
+ if (chroot(chroot_path) != 0)
+ err(1, "unable to chroot");
+ }
+ if (chdir("/") != 0)
+ err(1, "unable to chdir");
+ if (setgroups(1, &pw->pw_gid) == -1)
+ err(1, "setgroups() failed");
+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
+ err(1, "setresgid failed");
+ if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
+ err(1, "setresuid() failed");
+ endpwent();
+ printf("droppriv done\n");
+}
+
+
+static void
+_cb_traceroute(struct in_addr *ip,
+ struct ggnet_traceroute_req *route, void *data)
+{
+ _route = route;
+ _answer = 1;
+ event_base_loopexit(_ev_base, NULL);
+}
diff --git a/libglouglou/libggnet_traceroute.c b/libglouglou/libggnet_traceroute.c
new file mode 100644
index 0000000..af0d0ce
--- /dev/null
+++ b/libglouglou/libggnet_traceroute.c
@@ -0,0 +1,420 @@
+/*
+ * Traceroute library using libevent, libdnet and libpcap
+ *
+ * 2012 Laurent Ghigonis <laurent@p1sec.com>
+ *
+ * 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>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#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)
+{
+ struct ggnet_traceroute *ggtr;
+ char ebuff[PCAP_ERRBUF_SIZE];
+
+ ggtr = calloc(1, sizeof(struct ggnet_traceroute));
+ if (!ggtr) {
+ printf("could not allocate ggnet_traceroute\n");
+ exit(1);
+ }
+ ggtr->ev_base = ev_base;
+ ggtr->pkt_ip = ip_open();
+ if (!ggtr->pkt_ip) {
+ printf("ip_open() failed\n");
+ ggnet_traceroute_free(ggtr);
+ return NULL;
+ }
+ 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 */
+
+ ggtr->pcap = pcap_open_live(iface, 1500, 1, 500, ebuff);
+ if (ggtr->pcap == NULL)
+ err(1, "pcap_open_live()");
+ ggtr->pcap_dllen = pcap_dloff(ggtr->pcap);
+ ggtr->pcap_fd = pcap_fileno(ggtr->pcap);
+
+ return ggtr;
+}
+
+void
+ggnet_traceroute_free(struct ggnet_traceroute *ggtr)
+{
+ struct ggnet_traceroute_req *req;
+
+ if (ggtr->pcap)
+ pcap_close(ggtr->pcap);
+ if (ggtr->pkt_ip)
+ ip_close(ggtr->pkt_ip);
+ if (ggtr->pkt_rand)
+ rand_close(ggtr->pkt_rand);
+ LIST_FOREACH(req, &ggtr->req_list, entry)
+ _req_free(req);
+ free(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 *),
+ 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);
+
+ req->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,
+ 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;
+}
+
+void
+ggnet_traceroute_cancel(struct ggnet_traceroute *ggtr,
+ struct ggnet_traceroute_req *req)
+{
+ LIST_REMOVE(req, entry);
+ ggtr->req_pending--;
+ _req_free(req);
+}
+
+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);
+ free(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;
+ 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;
+
+ 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
+pcap_dloff(pcap_t *pd)
+{
+ int i;
+
+ i = pcap_datalink(pd);
+
+ switch (i) {
+ case DLT_EN10MB:
+ i = 14;
+ break;
+ case DLT_IEEE802:
+ i = 22;
+ break;
+ case DLT_FDDI:
+ i = 21;
+ break;
+ case DLT_NULL:
+ i = 4;
+ break;
+ default:
+ i = -1;
+ break;
+ }
+ 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
new file mode 100644
index 0000000..833705b
--- /dev/null
+++ b/libglouglou/libggnet_traceroute.h
@@ -0,0 +1,62 @@
+#include <event.h>
+#include <dnet.h>
+#include <pcap.h>
+
+#if defined(__OpenBSD__)
+#include <sys/queue.h>
+#else
+#include <bsd/sys/queue.h>
+#endif
+
+#define TRACEROUTE_NB_PROBES 3
+
+struct ggnet_traceroute_hop {
+ 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 ggnet_traceroute_hop *target;
+ struct addr srcip;
+ int probes_count;
+ int hops_count;
+ 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;
+};
+
+struct ggnet_traceroute {
+ struct event_base *ev_base;
+ pcap_t *pcap;
+ ip_t *pkt_ip;
+ rand_t *pkt_rand;
+ int pcap_fd;
+ int pcap_dllen; /* datalink layer hdr len */
+ int req_pending;
+ LIST_HEAD(, ggnet_traceroute_req) req_list;
+};
+
+struct ggnet_traceroute *ggnet_traceroute_new(struct event_base *, char *);
+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 *),
+ void *);
+void ggnet_traceroute_cancel(struct ggnet_traceroute *,
+ struct ggnet_traceroute_req *);