summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Smith <oliver@zerolag.com>2013-08-20 07:19:14 -0700
committerDaniel Borkmann <dborkman@redhat.com>2013-08-21 00:32:27 +0200
commit5e739dd87b4f08f9ff7144c66c14e1d8e8bdef1c (patch)
tree3f939709b2a927b8042449007378644c0c24a071
parentb67df4299c18ba3f3fb30a2e3488873bd49d4153 (diff)
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 <oliver@zerolag.com> Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
-rw-r--r--astraceroute.84
-rw-r--r--astraceroute.c32
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;