summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-11-01 11:04:39 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-11-01 11:04:39 +0100
commit80cbd0c9bd83fd0501b505f54ec8e29028894af5 (patch)
tree1ed94db626c470b9d468a61b3d84a88aafd9c233
parent921485a5bc0c8448bcc23ae5587777e762473dd2 (diff)
downloadfastd-80cbd0c9bd83fd0501b505f54ec8e29028894af5.tar
fastd-80cbd0c9bd83fd0501b505f54ec8e29028894af5.zip
Refactor bind address configuration
-rw-r--r--src/config.c43
-rw-r--r--src/config.l4
-rw-r--r--src/config.y77
-rw-r--r--src/fastd.c191
-rw-r--r--src/fastd.h3
5 files changed, 151 insertions, 167 deletions
diff --git a/src/config.c b/src/config.c
index be67e2b..b0f4754 100644
--- a/src/config.c
+++ b/src/config.c
@@ -224,6 +224,22 @@ bool fastd_config_crypto(fastd_context *ctx, fastd_config *conf, const char *alg
return false;
}
+void fastd_config_bind_address(fastd_context *ctx, fastd_config *conf, const fastd_peer_address *address, const char *bindtodev, bool default_v4, bool default_v6) {
+ fastd_bind_address *addr = malloc(sizeof(fastd_bind_address));
+ addr->next = conf->bind_addrs;
+ conf->bind_addrs = addr;
+ conf->n_bind_addrs++;
+
+ addr->addr = *address;
+ addr->bindtodev = bindtodev ? strdup(bindtodev) : NULL;
+
+ if (address->sa.sa_family != AF_INET6 && (default_v4 || !conf->bind_addr_default_v4))
+ conf->bind_addr_default_v4 = addr;
+
+ if (address->sa.sa_family != AF_INET && (default_v6 || !conf->bind_addr_default_v6))
+ conf->bind_addr_default_v6 = addr;
+}
+
bool fastd_config_add_log_file(fastd_context *ctx, fastd_config *conf, const char *name, int level) {
char *name2 = strdup(name);
char *name3 = strdup(name);
@@ -418,6 +434,7 @@ bool fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filen
}
static void count_peers(fastd_context *ctx, fastd_config *conf) {
+ conf->n_peers = 0;
conf->n_floating = 0;
conf->n_v4 = 0;
conf->n_v6 = 0;
@@ -427,6 +444,8 @@ static void count_peers(fastd_context *ctx, fastd_config *conf) {
fastd_peer_config *peer;
for (peer = conf->peers; peer; peer = peer->next) {
+ conf->n_peers++;
+
switch (peer->address.sa.sa_family) {
case AF_UNSPEC:
if (peer->hostname)
@@ -629,35 +648,29 @@ static void option_bind(fastd_context *ctx, fastd_config *conf, const char *arg)
l = 0;
}
- fastd_bind_address *addr = calloc(1, sizeof(fastd_bind_address));
- addr->next = conf->bind_addrs;
- conf->bind_addrs = addr;
+ fastd_peer_address addr = {};
if (strcmp(addrstr, "any") == 0) {
/* nothing to do */
}
else if (arg[0] == '[') {
- addr->addr.in6.sin6_family = AF_INET6;
- addr->addr.in6.sin6_port = htons(l);
+ addr.in6.sin6_family = AF_INET6;
+ addr.in6.sin6_port = htons(l);
- if (inet_pton(AF_INET6, addrstr, &addr->addr.in6.sin6_addr) != 1)
+ if (inet_pton(AF_INET6, addrstr, &addr.in6.sin6_addr) != 1)
exit_error(ctx, "invalid bind address `%s'", addrstr);
}
else {
- addr->addr.in.sin_family = AF_INET;
- addr->addr.in.sin_port = htons(l);
+ addr.in.sin_family = AF_INET;
+ addr.in.sin_port = htons(l);
- if (inet_pton(AF_INET, addrstr, &addr->addr.in.sin_addr) != 1)
+ if (inet_pton(AF_INET, addrstr, &addr.in.sin_addr) != 1)
exit_error(ctx, "invalid bind address `%s'", addrstr);
}
- if (!conf->bind_addr_default_v4 && addr->addr.sa.sa_family != AF_INET6)
- conf->bind_addr_default_v4 = addr;
-
- if (!conf->bind_addr_default_v6 && addr->addr.sa.sa_family != AF_INET)
- conf->bind_addr_default_v6 = addr;
-
free(addrstr);
+
+ fastd_config_bind_address(ctx, conf, &addr, NULL, false, false);
}
static void option_protocol(fastd_context *ctx, fastd_config *conf, const char *arg) {
diff --git a/src/config.l b/src/config.l
index 404384e..9e82239 100644
--- a/src/config.l
+++ b/src/config.l
@@ -104,12 +104,12 @@ default { TOKEN(TOK_DEFAULT); }
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} {
UPDATE_LOCATION;
- if (!inet_pton(AF_INET, yytext, &yylval->addr)) {
+ if (!inet_pton(AF_INET, yytext, &yylval->addr4)) {
yylval->error = "invalid address";
return -1;
}
- return TOK_ADDR;
+ return TOK_ADDR4;
}
[;:\{\}] { UPDATE_LOCATION; return yytext[0]; }
diff --git a/src/config.y b/src/config.y
index 59fc296..5bf374e 100644
--- a/src/config.y
+++ b/src/config.y
@@ -45,8 +45,9 @@
fastd_string_stack *str;
char *error;
bool boolean;
- struct in_addr addr;
+ struct in_addr addr4;
struct in6_addr addr6;
+ fastd_peer_address addr;
}
%token START_CONFIG
@@ -99,7 +100,7 @@
%token TOK_USE
%token TOK_DEFAULT
-%token <addr> TOK_ADDR
+%token <addr4> TOK_ADDR4
%token <addr6> TOK_ADDR6
@@ -121,6 +122,10 @@
%type <str> maybe_as
%type <num> maybe_af
%type <boolean> maybe_float
+%type <addr> bind_address
+%type <str> maybe_bind_interface
+%type <num> maybe_bind_default
+%type <num> bind_default
%%
start: START_CONFIG config
@@ -188,70 +193,50 @@ log_level: TOK_FATAL { $$ = LOG_CRIT; }
interface: TOK_STRING { free(conf->ifname); conf->ifname = strdup($1->str); }
;
-bind_new: {
- fastd_bind_address *addr = calloc(1, sizeof(fastd_bind_address));
- addr->next = conf->bind_addrs;
- conf->bind_addrs = addr;
+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);
}
;
-bind: bind_new TOK_ADDR maybe_port maybe_bind_to_device maybe_bind_default {
- conf->bind_addrs->addr.in.sin_family = AF_INET;
- conf->bind_addrs->addr.in.sin_addr = $2;
- conf->bind_addrs->addr.in.sin_port = htons($3);
- if (!conf->bind_addr_default_v4)
- conf->bind_addr_default_v4 = conf->bind_addrs;
+bind_address:
+ TOK_ADDR4 maybe_port {
+ $$ = (fastd_peer_address){ .in = { .sin_family = AF_INET, .sin_addr = $1, .sin_port = htons($2) } };
}
- | bind_new TOK_ADDR6 maybe_port maybe_bind_to_device maybe_bind_default {
- conf->bind_addrs->addr.in6.sin6_family = AF_INET6;
- conf->bind_addrs->addr.in6.sin6_addr = $2;
- conf->bind_addrs->addr.in6.sin6_port = htons($3);
- if (!conf->bind_addr_default_v6)
- conf->bind_addr_default_v6 = conf->bind_addrs;
+ | TOK_ADDR6 maybe_port {
+ $$ = (fastd_peer_address){ .in6 = { .sin6_family = AF_INET6, .sin6_addr = $1, .sin6_port = htons($2) } };
}
- | bind_new TOK_ANY maybe_port maybe_bind_to_device maybe_bind_default {
- conf->bind_addrs->addr.in.sin_port = htons($3);
- if (!conf->bind_addr_default_v4)
- conf->bind_addr_default_v4 = conf->bind_addrs;
- if (!conf->bind_addr_default_v6)
- conf->bind_addr_default_v6 = conf->bind_addrs;
+ | TOK_ANY maybe_port {
+ $$ = (fastd_peer_address){ .in = { .sin_family = AF_UNSPEC, .sin_port = htons($2) } };
}
;
-maybe_bind_to_device:
+maybe_bind_interface:
TOK_INTERFACE TOK_STRING {
- conf->bind_addrs->bindtodev = strdup($2->str);
+ $$ = $2;
+ }
+ | {
+ $$ = NULL;
}
- |
;
maybe_bind_default:
- TOK_DEFAULT bind_default
- |
+ TOK_DEFAULT bind_default {
+ $$ = $2;
+ }
+ | {
+ $$ = -1;
+ }
;
bind_default:
TOK_IPV4 {
- if (conf->bind_addrs->addr.sa.sa_family == AF_INET6) {
- fastd_config_error(&@$, ctx, conf, filename, depth, "tried to set IPv6 bind as IPv4 default");
- YYERROR;
- }
-
- conf->bind_addr_default_v4 = conf->bind_addrs;
+ $$ = AF_INET;
}
| TOK_IPV6 {
- if (conf->bind_addrs->addr.sa.sa_family == AF_INET) {
- fastd_config_error(&@$, ctx, conf, filename, depth, "tried to set IPv4 bind as IPv6 default");
- YYERROR;
- }
-
- conf->bind_addr_default_v6 = conf->bind_addrs;
+ $$ = AF_INET6;
}
| {
- if (conf->bind_addrs->addr.sa.sa_family != AF_INET6)
- conf->bind_addr_default_v4 = conf->bind_addrs;
- if (conf->bind_addrs->addr.sa.sa_family != AF_INET)
- conf->bind_addr_default_v6 = conf->bind_addrs;
+ $$ = AF_UNSPEC;
}
;
@@ -340,7 +325,7 @@ peer_statement: TOK_REMOTE peer_remote ';'
| TOK_INCLUDE peer_include ';'
;
-peer_remote: TOK_ADDR port {
+peer_remote: TOK_ADDR4 port {
free(conf->peers->hostname);
conf->peers->hostname = NULL;
diff --git a/src/fastd.c b/src/fastd.c
index 88e7401..a117b1e 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -147,140 +147,114 @@ static void crypto_free(fastd_context *ctx) {
}
-static unsigned max_sockets(const fastd_config *conf) {
- unsigned n = 0;
- fastd_bind_address *addr;
-
- for (addr = conf->bind_addrs; addr; addr = addr->next)
- n++;
-
- return n;
-}
-
static void init_sockets(fastd_context *ctx) {
- static const fastd_bind_address bind_any = {};
+ ctx->socks = malloc(ctx->conf->n_bind_addrs * sizeof(fastd_socket));
- const fastd_bind_address *addr = ctx->conf->bind_addrs;
- const fastd_bind_address *default_v4 = ctx->conf->bind_addr_default_v4;
- const fastd_bind_address *default_v6 = ctx->conf->bind_addr_default_v6;
-
- if (!addr)
- addr = default_v4 = default_v6 = &bind_any;
+ unsigned i;
+ fastd_bind_address *addr = ctx->conf->bind_addrs;
+ for (i = 0; i < ctx->conf->n_bind_addrs; i++) {
+ ctx->socks[i] = (fastd_socket){-2, addr};
- unsigned n_v4 = 0, n_v6 = 0;
- bool info_ipv6 = true;
+ if (addr == ctx->conf->bind_addr_default_v4)
+ ctx->sock_default_v4 = &ctx->socks[i];
- ctx->socks = calloc(max_sockets(ctx->conf), sizeof(fastd_socket));
+ if (addr == ctx->conf->bind_addr_default_v6)
+ ctx->sock_default_v6 = &ctx->socks[i];
- while (addr) {
- int fd = -1;
- int af = AF_UNSPEC;
+ addr = addr->next;
+ }
- if (addr->addr.sa.sa_family != AF_INET) {
- fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0) {
- if (info_ipv6) {
- pr_warn(ctx, "there seems to be no IPv6 support; explicitely bind to an IPv4 address (or 0.0.0.0) to disable this warning");
- info_ipv6 = false;
- }
- }
- else {
- af = AF_INET6;
+ ctx->n_socks = ctx->conf->n_bind_addrs;
+}
- int val = (addr->addr.sa.sa_family == AF_INET6);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
- pr_warn_errno(ctx, "setsockopt");
- goto error;
- }
- }
- }
- if (fd < 0 && addr->addr.sa.sa_family != AF_INET6) {
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0)
- exit_errno(ctx, "unable to create socket");
- else
- af = AF_INET;
- }
+static int bind_socket(fastd_context *ctx, const fastd_bind_address *addr, bool warn) {
+ int fd = -1;
+ int af = AF_UNSPEC;
- if (fd < 0)
- goto error;
+ if (addr->addr.sa.sa_family != AF_INET) {
+ fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd >= 0) {
+ af = AF_INET6;
- if (addr->bindtodev) {
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) {
- pr_warn_errno(ctx, "setsockopt: unable to bind to device");
+ int val = (addr->addr.sa.sa_family == AF_INET6);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
+ if (warn)
+ pr_warn_errno(ctx, "setsockopt");
goto error;
}
}
+ }
+ if (fd < 0 && addr->addr.sa.sa_family != AF_INET6) {
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd < 0)
+ exit_errno(ctx, "unable to create socket");
+ else
+ af = AF_INET;
+ }
- fastd_peer_address bind_address = addr->addr;
-
- if (bind_address.sa.sa_family == AF_UNSPEC) {
- memset(&bind_address, 0, sizeof(bind_address));
- bind_address.sa.sa_family = af;
-
- if (af == AF_INET6)
- bind_address.in6.sin6_port = addr->addr.in.sin_port;
- else
- bind_address.in.sin_port = addr->addr.in.sin_port;
- }
+ if (fd < 0)
+ goto error;
- if (bind(fd, (struct sockaddr*)&bind_address, af == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
- pr_warn(ctx, "bind");
+ if (addr->bindtodev) {
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) {
+ if (warn)
+ pr_warn_errno(ctx, "setsockopt: unable to bind to device");
goto error;
}
+ }
- ctx->socks[ctx->n_socks] = (fastd_socket){fd, addr};
-
- if (af == AF_INET6) {
- if (addr == default_v6)
- ctx->sock_default_v6 = &ctx->socks[ctx->n_socks];
-
- n_v6++;
-
- if (addr->addr.sa.sa_family == AF_UNSPEC) {
- if (addr == default_v4)
- ctx->sock_default_v4 = &ctx->socks[ctx->n_socks];
+ fastd_peer_address bind_address = addr->addr;
- n_v4++;
- }
- }
- else {
- if (addr == default_v4)
- ctx->sock_default_v4 = &ctx->socks[ctx->n_socks];
+ if (bind_address.sa.sa_family == AF_UNSPEC) {
+ memset(&bind_address, 0, sizeof(bind_address));
+ bind_address.sa.sa_family = af;
- n_v4++;
- }
+ if (af == AF_INET6)
+ bind_address.in6.sin6_port = addr->addr.in.sin_port;
+ else
+ bind_address.in.sin_port = addr->addr.in.sin_port;
+ }
- ctx->n_socks++;
+ if (bind(fd, (struct sockaddr*)&bind_address, af == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) {
+ if (warn)
+ pr_warn(ctx, "bind");
+ goto error;
+ }
- addr = addr->next;
- continue;
+ return fd;
- error:
- if (fd >= 0) {
- if (close(fd))
- pr_error_errno(ctx, "close");
- }
+ error:
+ if (fd >= 0) {
+ if (close(fd))
+ pr_error_errno(ctx, "close");
+ }
+ if (warn) {
if (addr->bindtodev)
pr_warn(ctx, "unable to bind to %I on `%s'", &addr->addr, addr->bindtodev);
- else
+ else
pr_warn(ctx, "unable to bind to %I", &addr->addr);
+ }
- if (addr == default_v4 || addr == default_v6)
- exit_error(ctx, "unable to bind to default address");
+ return -1;
+}
- addr = addr->next;
- }
+static void bind_sockets(fastd_context *ctx) {
+ unsigned i;
- if (!ctx->n_socks)
- exit_error(ctx, "all bind attempts failed");
+ for (i = 0; i < ctx->n_socks; i++) {
+ if (ctx->socks[i].fd >= 0)
+ continue;
- if (!n_v4 && ctx->conf->n_v4)
- pr_warn(ctx, "there are IPv4 peers defined, but there was no successful IPv4 bind");
+ ctx->socks[i].fd = bind_socket(ctx, ctx->socks[i].addr, ctx->socks[i].fd < -1);
- if (!n_v6 && ctx->conf->n_v6)
- pr_warn(ctx, "there are IPv6 peers defined, but there was no successful IPv4 bind");
+ if (ctx->socks[i].fd >= 0) {
+ if (ctx->socks[i].addr->bindtodev)
+ pr_info(ctx, "successfully bound to %I on `%s'", &ctx->socks[i].addr->addr, ctx->socks[i].addr->bindtodev);
+ else
+ pr_info(ctx, "successfully bound to %I", &ctx->socks[i].addr->addr);
+ }
+ }
}
static void init_tuntap(fastd_context *ctx) {
@@ -315,12 +289,17 @@ static void init_tuntap(fastd_context *ctx) {
ctx->ifname = strndup(ifr.ifr_name, IFNAMSIZ);
- int ctl_sock = ctx->socks[0].fd;
+ int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (ctl_sock < 0)
+ exit_errno(ctx, "socket");
ifr.ifr_mtu = ctx->conf->mtu;
if (ioctl(ctl_sock, SIOCSIFMTU, &ifr) < 0)
exit_errno(ctx, "SIOCSIFMTU ioctl failed");
+ if (close(ctl_sock))
+ pr_error_errno(ctx, "close");
+
pr_debug(ctx, "tun/tap device initialized.");
}
@@ -924,6 +903,8 @@ int main(int argc, char *argv[]) {
pr_info(&ctx, "fastd " FASTD_VERSION " starting");
init_sockets(&ctx);
+ bind_sockets(&ctx);
+
init_tuntap(&ctx);
init_peers(&ctx);
@@ -949,6 +930,8 @@ int main(int argc, char *argv[]) {
while (!terminate) {
handle_tasks(&ctx);
+
+ bind_sockets(&ctx);
handle_input(&ctx);
maintenance(&ctx);
diff --git a/src/fastd.h b/src/fastd.h
index cf5aaf1..9f84ae7 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -160,6 +160,7 @@ struct _fastd_config {
char *ifname;
+ unsigned n_bind_addrs;
fastd_bind_address *bind_addrs;
fastd_bind_address *bind_addr_default_v4;
@@ -187,6 +188,7 @@ struct _fastd_config {
fastd_string_stack *peer_dirs;
fastd_peer_config *peers;
+ unsigned n_peers;
unsigned n_floating;
unsigned n_v4;
unsigned n_v6;
@@ -277,6 +279,7 @@ bool fastd_config_protocol(fastd_context *ctx, fastd_config *conf, const char *n
bool fastd_config_method(fastd_context *ctx, fastd_config *conf, const char *name);
bool fastd_config_crypto(fastd_context *ctx, fastd_config *conf, const char *alg, const char *impl);
bool fastd_config_add_log_file(fastd_context *ctx, fastd_config *conf, const char *name, int level);
+void fastd_config_bind_address(fastd_context *ctx, fastd_config *conf, const fastd_peer_address *address, const char *bindtodev, bool default_v4, bool default_v6);
void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *const argv[]);
void fastd_reconfigure(fastd_context *ctx, fastd_config *conf);
void fastd_config_release(fastd_context *ctx, fastd_config *conf);