diff options
-rw-r--r-- | astraceroute.8 | 4 | ||||
-rw-r--r-- | 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 <device>, -d <device>, --dev <device> Networking device to start the trace route from, e.g. eth0, wlan0. .PP +.SS -b <IP>, --bind <IP> +IP address to bind to other than the network device's address. You must specify +''\-6'' for an IPv6 address. +.PP .SS -f <ttl>, --init-ttl <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> Host/IPv4/IPv6 to lookup AS route to\n" " -p|--port <port> Hosts port to lookup AS route to\n" " -i|-d|--dev <device> Networking device, e.g. eth0\n" + " -b|--bind <IP> IP address to bind to, Must specify -6 for an IPv6 address\n" " -f|--init-ttl <ttl> Set initial TTL\n" " -m|--max-ttl <ttl> Set maximum TTL (def: 30)\n" " -q|--num-probes <num> 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; |