diff options
author | Laurent Ghigonis <laurent@p1sec.com> | 2012-12-16 16:04:41 +0100 |
---|---|---|
committer | Laurent Ghigonis <laurent@p1sec.com> | 2012-12-16 16:04:41 +0100 |
commit | c33819056af9c8908068164a50ee98d6b78f66c0 (patch) | |
tree | 9a132bd70edba599e8c57497b683d4d63cd29cef /libglouglou | |
parent | link to libpcap and libdnet (diff) | |
download | glouglou-c33819056af9c8908068164a50ee98d6b78f66c0.tar.xz glouglou-c33819056af9c8908068164a50ee98d6b78f66c0.zip |
work on traceroute, initialisation code is there now
Diffstat (limited to 'libglouglou')
-rw-r--r-- | libglouglou/examples/traceroute.c | 55 | ||||
-rw-r--r-- | libglouglou/libggnet_traceroute.c | 121 | ||||
-rw-r--r-- | libglouglou/libggnet_traceroute.h | 29 |
3 files changed, 186 insertions, 19 deletions
diff --git a/libglouglou/examples/traceroute.c b/libglouglou/examples/traceroute.c index 9d3e218..080274f 100644 --- a/libglouglou/examples/traceroute.c +++ b/libglouglou/examples/traceroute.c @@ -1,11 +1,25 @@ +#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 *); @@ -29,20 +43,21 @@ main(int argc, char *argv[]) ip.s_addr = ntohl(ip.s_addr); bzero(&tv, sizeof(struct timeval)); - tv.tv_sec = 5; + tv.tv_sec = 10; _ev_base = event_base_new(); - ggtr = ggnet_traceroute_new(_ev_base); - ggnet_traceroute_reverse(ggtr, &ip, _cb_traceroute, NULL); + 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(&_route->hops, h, entry) { - printf("%x (%d)\n", h->ip.s_addr, h->delay); + LIST_FOREACH(hop, &_route->hops, entry) { + printf("%x (%d)\n", hop->ip.s_addr, hop->delay); } } else { printf("no answer\n"); @@ -50,9 +65,37 @@ main(int argc, char *argv[]) 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); + struct ggnet_traceroute_req *route, void *data) { _route = route; _answer = 1; diff --git a/libglouglou/libggnet_traceroute.c b/libglouglou/libggnet_traceroute.c index 3b8e6ed..f00fd72 100644 --- a/libglouglou/libggnet_traceroute.c +++ b/libglouglou/libggnet_traceroute.c @@ -8,10 +8,31 @@ * All rights reserved. */ + +#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" + +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 ggnet_traceroute * -ggnet_traceroute_new(struct event_base *ev_base) +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) { @@ -19,18 +40,47 @@ ggnet_traceroute_new(struct event_base *ev_base) exit(1); } ggtr->ev_base = ev_base; - return ggdns; + 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_iddr *ip, + struct in_addr *ip, void (*cb_usr)(struct in_addr *, struct ggnet_traceroute_req *, void *), void *data) { @@ -42,6 +92,16 @@ ggnet_traceroute_trace(struct ggnet_traceroute *ggtr, exit(1); } + addr_aton("127.0.0.1", &req->srcip); + addr_aton("127.0.0.1", &req->ip); + + 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); + LIST_INSERT_HEAD(&ggtr->req_list, req, entry); return req; } @@ -52,5 +112,60 @@ ggnet_traceroute_cancel(struct ggnet_traceroute *ggtr, { 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_req *req; + + req = arg; + printf("cbggnet_traceroute cb_recv %s\n", addr_ntoa(&req->ip)); +} + +static void +_cb_send(evutil_socket_t fd, short what, void *arg) +{ + struct ggnet_traceroute_req *req; + + req = arg; + printf("cbggnet_traceroute cb_send %s\n", addr_ntoa(&req->ip)); +} + +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); +} diff --git a/libglouglou/libggnet_traceroute.h b/libglouglou/libggnet_traceroute.h index 24aea02..0c19bea 100644 --- a/libglouglou/libggnet_traceroute.h +++ b/libglouglou/libggnet_traceroute.h @@ -1,6 +1,6 @@ -#include <event2/dns.h> -#include <event2/util.h> -#include <event2/event.h> +#include <event.h> +#include <dnet.h> +#include <pcap.h> #if defined(__OpenBSD__) #include <sys/queue.h> @@ -17,7 +17,11 @@ struct ggnet_traceroute_hop { struct ggnet_traceroute_req { LIST_ENTRY(ggnet_traceroute_req) entry; - struct event *ev; + struct event *ev_recv; + struct event *ev_send; + struct addr ip; + struct addr srcip; + int hops_count; LIST_HEAD(, ggnet_traceroute_hop) hops; void (*cb_usr)(struct in_addr *, char *, void *); void *data; @@ -25,15 +29,20 @@ struct ggnet_traceroute_req { 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; /* XXX for now unused. remove ? */ + LIST_HEAD(, ggnet_traceroute_req) req_list; }; -struct ggnet_traceroute *ggnet_traceroute_new(struct event_base *); -void ggnet_traceroute_free(struct ggnet_dns *); -struct ggnet_traceroute_req *ggnet_traceroute_trace(struct ggnet_traceroute *ggtr, - struct in_iddr *ip, +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 *data) + void *); void ggnet_traceroute_cancel(struct ggnet_traceroute *, struct ggnet_traceroute_req *); |