aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou/libggnet_traceroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'libglouglou/libggnet_traceroute.c')
-rw-r--r--libglouglou/libggnet_traceroute.c135
1 files changed, 90 insertions, 45 deletions
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