aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2013-06-07 03:06:21 +0200
committerLaurent Ghigonis <laurent@p1sec.com>2013-06-07 03:07:16 +0200
commit6f633aa1891f631b11ca5b23ea92c7311d0f0adf (patch)
treeb729fbeb0e5fc134caa733bf643ac4794c75638b /libglouglou
parentlibglouglou: missing var declaration (diff)
downloadglouglou-6f633aa1891f631b11ca5b23ea92c7311d0f0adf.tar.xz
glouglou-6f633aa1891f631b11ca5b23ea92c7311d0f0adf.zip
libggnet: traceroute sends packets in TCP and ICMP
Diffstat (limited to 'libglouglou')
-rw-r--r--libglouglou/examples/traceroute.c20
-rw-r--r--libglouglou/libggnet_traceroute.c135
-rw-r--r--libglouglou/libggnet_traceroute.h23
-rw-r--r--libglouglou/utils.c4
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 <string.h>
#include <err.h>
+#include <libglouglou.h> /* for get_iface */
#include <libggnet_traceroute.h>
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 <ip>\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; i<TRACEROUTE_NB_PROBES; i++)
- if (ip_send(ggtr->pkt_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);
}