From 5e739dd87b4f08f9ff7144c66c14e1d8e8bdef1c Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Tue, 20 Aug 2013 07:19:14 -0700 Subject: astraceroute: Support binding to a specific IP address. In a situation where the IP that you wish to use as the source address differs from the interface it needs to be sent from, it is now possible to manually specify an address to bind to whilst still being able to specify the physical interface to send from. [Fixed up whitespace, minor coding style and added man-page entry --DB] Signed-off-by: Oliver Smith Signed-off-by: Daniel Borkmann --- astraceroute.8 | 4 ++++ astraceroute.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/astraceroute.8 b/astraceroute.8 index 41d0320..dd33985 100644 --- a/astraceroute.8 +++ b/astraceroute.8 @@ -43,6 +43,10 @@ port used is 80. .SS -i , -d , --dev Networking device to start the trace route from, e.g. eth0, wlan0. .PP +.SS -b , --bind +IP address to bind to other than the network device's address. You must specify +''\-6'' for an IPv6 address. +.PP .SS -f , --init-ttl Initial TTL value to be used. This option might be useful if you are not interested in the first n hops, but only the following ones. The default diff --git a/astraceroute.c b/astraceroute.c index b546943..84c6649 100644 --- a/astraceroute.c +++ b/astraceroute.c @@ -48,7 +48,7 @@ #include "built_in.h" struct ctx { - char *host, *port, *dev, *payload; + char *host, *port, *dev, *payload, *bind_addr; size_t totlen, rcvlen; int init_ttl, max_ttl, dns_resolv, queries, timeout; int syn, ack, ecn, fin, psh, rst, urg, tos, nofrag, proto, show; @@ -85,12 +85,13 @@ static int check_ipv6(uint8_t *packet, size_t len, int ttl, int id, static void handle_ipv6(uint8_t *packet, size_t len, int dns_resolv, int latitude); -static const char *short_options = "H:p:nNf:m:i:d:q:x:SAEFPURt:Gl:hv46X:ZuL"; +static const char *short_options = "H:p:nNf:m:b:i:d:q:x:SAEFPURt:Gl:hv46X:ZuL"; static const struct option long_options[] = { {"host", required_argument, NULL, 'H'}, {"port", required_argument, NULL, 'p'}, {"init-ttl", required_argument, NULL, 'f'}, {"max-ttl", required_argument, NULL, 'm'}, + {"bind", required_argument, NULL, 'b'}, {"dev", required_argument, NULL, 'd'}, {"num-probes", required_argument, NULL, 'q'}, {"timeout", required_argument, NULL, 'x'}, @@ -182,6 +183,7 @@ static void __noreturn help(void) " -H|--host Host/IPv4/IPv6 to lookup AS route to\n" " -p|--port Hosts port to lookup AS route to\n" " -i|-d|--dev Networking device, e.g. eth0\n" + " -b|--bind IP address to bind to, Must specify -6 for an IPv6 address\n" " -f|--init-ttl Set initial TTL\n" " -m|--max-ttl Set maximum TTL (def: 30)\n" " -q|--num-probes Number of max probes for each hop (def: 2)\n" @@ -583,8 +585,9 @@ static void show_trace_info(struct ctx *ctx, const struct sockaddr_storage *ss, static int get_remote_fd(struct ctx *ctx, struct sockaddr_storage *ss, struct sockaddr_storage *sd) { - int fd = -1, ret, one = 1; + int fd = -1, ret, one = 1, af = AF_INET; struct addrinfo hints, *ahead, *ai; + unsigned char bind_ip[sizeof(struct in6_addr)]; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; @@ -607,9 +610,25 @@ static int get_remote_fd(struct ctx *ctx, struct sockaddr_storage *ss, memset(ss, 0, sizeof(*ss)); ret = device_address(ctx->dev, ai->ai_family, ss); - if (ret < 0) + if (ret < 0 && !ctx->bind_addr) panic("Cannot get own device address!\n"); + if (ctx->bind_addr) { + if (ctx->proto == IPPROTO_IPV6) + af = AF_INET6; + + if (inet_pton(af, ctx->bind_addr, &bind_ip) != 1) + panic("Address is invalid!\n"); + + if (af == AF_INET6) { + struct sockaddr_in6 *ss6 = (struct sockaddr_in6 *) ss; + memcpy(&ss6->sin6_addr.s6_addr, &bind_ip, sizeof(struct in6_addr)); + } else { + struct sockaddr_in *ss4 = (struct sockaddr_in *) ss; + memcpy(&ss4->sin_addr.s_addr, &bind_ip, sizeof(struct in_addr)); + } + } + ret = bind(fd, (struct sockaddr *) ss, sizeof(*ss)); if (ret < 0) panic("Cannot bind socket!\n"); @@ -927,6 +946,7 @@ int main(int argc, char **argv) ctx.payload = NULL; ctx.dev = xstrdup("eth0"); ctx.port = xstrdup("80"); + ctx.bind_addr = NULL; while ((c = getopt_long(argc, argv, short_options, long_options, &opt_index)) != EOF) { @@ -974,6 +994,9 @@ int main(int argc, char **argv) if (ctx.max_ttl <= 0) help(); break; + case 'b': + ctx.bind_addr = xstrdup(optarg); + break; case 'i': case 'd': free(ctx.dev); @@ -1078,6 +1101,7 @@ int main(int argc, char **argv) free(ctx.dev); free(ctx.host); free(ctx.port); + free(ctx.bind_addr); free(ctx.payload); return ret; -- cgit v1.2.3-54-g00ecf