From 534ae7240bc5cad6edb9fd160cdb0ff0eb4778de Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 26 Jan 2014 09:23:00 +0100 Subject: Add support for link-local bind addresses --- src/config.c | 2 +- src/config.y | 4 ++++ src/fastd.h | 4 ++++ src/log.c | 8 ++++---- src/socket.c | 16 ++++++++++++++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/config.c b/src/config.c index 66b69c7..1793b7b 100644 --- a/src/config.c +++ b/src/config.c @@ -112,7 +112,7 @@ void fastd_config_mac(fastd_context_t *ctx, fastd_config_t *conf, const char *na void fastd_config_bind_address(fastd_context_t *ctx UNUSED, fastd_config_t *conf, const fastd_peer_address_t *address, const char *bindtodev, bool default_v4, bool default_v6) { #ifndef USE_BINDTODEVICE - if (bindtodev) + if (bindtodev && !fastd_peer_address_is_v6_ll(address)) exit_error(ctx, "config error: device bind configuration not supported on this system"); #endif diff --git a/src/config.y b/src/config.y index b7243a5..878f6e7 100644 --- a/src/config.y +++ b/src/config.y @@ -292,6 +292,10 @@ interface: TOK_STRING { free(conf->ifname); conf->ifname = strdup($1->str); } bind: bind_address maybe_bind_interface maybe_bind_default { fastd_config_bind_address(ctx, conf, &$1, $2 ? $2->str : NULL, $3 == AF_UNSPEC || $3 == AF_INET, $3 == AF_UNSPEC || $3 == AF_INET6); } + | TOK_ADDR6_SCOPED maybe_port maybe_bind_default { + fastd_peer_address_t addr = { .in6 = { .sin6_family = AF_INET6, .sin6_addr = $1.addr, .sin6_port = htons($2) } }; + fastd_config_bind_address(ctx, conf, &addr, $1.ifname, $3 == AF_UNSPEC || $3 == AF_INET, $3 == AF_UNSPEC || $3 == AF_INET6); + } ; bind_address: diff --git a/src/fastd.h b/src/fastd.h index ddd05a3..219dc2e 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -363,6 +363,10 @@ static inline size_t fastd_max_outer_packet(const fastd_context_t *ctx) { return PACKET_TYPE_LEN + fastd_max_inner_packet(ctx) + ctx->conf->max_overhead; } +static inline bool fastd_peer_address_is_v6_ll(const fastd_peer_address_t *addr) { + return (addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr)); +} + static inline fastd_string_stack_t* fastd_string_stack_dup(const char *str) { fastd_string_stack_t *ret = malloc(alignto(sizeof(fastd_string_stack_t) + strlen(str) + 1, 8)); ret->next = NULL; diff --git a/src/log.c b/src/log.c index 81dfb20..fb3a8af 100644 --- a/src/log.c +++ b/src/log.c @@ -68,11 +68,11 @@ static size_t snprint_peer_address(const fastd_context_t *ctx, char *buffer, siz if (inet_ntop(AF_INET6, &address->in6.sin6_addr, addr_buf, sizeof(addr_buf))) { if (IN6_IS_ADDR_LINKLOCAL(&address->in6.sin6_addr)) { char ifname_buf[IF_NAMESIZE]; - return snprintf_safe(buffer, size, "[%s%%%s]:%u", addr_buf, if_indextoname(address->in6.sin6_scope_id, ifname_buf), ntohs(address->in6.sin6_port)); - } - else { - return snprintf_safe(buffer, size, "[%s]:%u", addr_buf, ntohs(address->in6.sin6_port)); + if (if_indextoname(address->in6.sin6_scope_id, ifname_buf)) + return snprintf_safe(buffer, size, "[%s%%%s]:%u", addr_buf, if_indextoname(address->in6.sin6_scope_id, ifname_buf), ntohs(address->in6.sin6_port)); } + + return snprintf_safe(buffer, size, "[%s]:%u", addr_buf, ntohs(address->in6.sin6_port)); } else return 0; diff --git a/src/socket.c b/src/socket.c index af99894..25f50e7 100644 --- a/src/socket.c +++ b/src/socket.c @@ -77,7 +77,7 @@ static int bind_socket(fastd_context_t *ctx, const fastd_bind_address_t *addr, b } #ifdef USE_BINDTODEVICE - if (addr->bindtodev) { + if (addr->bindtodev && !fastd_peer_address_is_v6_ll(&addr->addr)) { if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) { if (warn) pr_warn_errno(ctx, "setsockopt: unable to bind to device"); @@ -107,6 +107,18 @@ static int bind_socket(fastd_context_t *ctx, const fastd_bind_address_t *addr, b fastd_peer_address_t bind_address = addr->addr; + if (fastd_peer_address_is_v6_ll(&addr->addr) && addr->bindtodev) { + bind_address.in6.sin6_scope_id = atoi(addr->bindtodev); + + if (!bind_address.in6.sin6_scope_id) + bind_address.in6.sin6_scope_id = if_nametoindex(addr->bindtodev); + + if (!bind_address.in6.sin6_scope_id) { + pr_warn_errno(ctx, "if_nametoindex"); + goto error; + } + } + if (bind_address.sa.sa_family == AF_UNSPEC) { memset(&bind_address, 0, sizeof(bind_address)); bind_address.sa.sa_family = af; @@ -180,7 +192,7 @@ bool fastd_socket_handle_binds(fastd_context_t *ctx) { if (!ctx->socks[i].addr->addr.sa.sa_family) bound_addr.sa.sa_family = AF_UNSPEC; - if (ctx->socks[i].addr->bindtodev) + if (ctx->socks[i].addr->bindtodev && !fastd_peer_address_is_v6_ll(&bound_addr)) pr_info(ctx, "successfully bound to %B on `%s'", &bound_addr, ctx->socks[i].addr->bindtodev); else pr_info(ctx, "successfully bound to %B", &bound_addr); -- cgit v1.2.3