From 4e7694d7107d2299f4aaededf8917fceb5dfb924 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Wed, 22 Mar 2017 21:32:50 +0000 Subject: [PATCH] Allow binding to both source address and interface in server specs. The current --server syntax allows for binding to interface or address. However, in some (admittedly special) cases it is useful to be able to specify both. This commit introduces the following syntax to support binding to both interface and address: --server X.X.X.X@IP@interface#port Based on my tests, the syntax is backwards compatible with the current @IP/interface#port. The code will fail if two interface names are given. v1->v2: * Add man page description of the extended server syntax (thanks Simon Kelley) Signed-off-by: Kristian Evensen --- man/dnsmasq.8 | 16 ++++++++-------- src/option.c | 22 +++++++++++++++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 059eafc..2e5ef21 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -467,14 +467,14 @@ to make configuration files clearer in this case. IPv6 addresses may include a %interface scope-id, eg fe80::202:a412:4512:7bbf%eth0. -The optional string after the @ character tells -dnsmasq how to set the source of the queries to this -nameserver. It should be an ip-address, which should belong to the machine on which -dnsmasq is running otherwise this server line will be logged and then -ignored, or an interface name. If an interface name is given, then -queries to the server will be forced via that interface; if an -ip-address is given then the source address of the queries will be set -to that address. +The optional string after the @ character tells dnsmasq how to set the source of +the queries to this nameserver. It can either be an ip-address, an interface +name or both. The ip-address should belong to the machine on which dnsmasq is +running, otherwise this server line will be logged and then ignored. If an +interface name is given, then queries to the server will be forced via that +interface; if an ip-address is given then the source address of the queries will +be set to that address; and if both are given then a combination of ip-address +and interface name will be used to steer requests to the server. The query-port flag is ignored for any servers which have a source address specified but the port may be specified directly as part of the source address. Forcing queries to an interface is not diff --git a/src/option.c b/src/option.c index 31c8cb9..0c38db3 100644 --- a/src/option.c +++ b/src/option.c @@ -757,6 +757,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a { int source_port = 0, serv_port = NAMESERVER_PORT; char *portno, *source; + char *interface_opt = NULL; #ifdef HAVE_IPV6 int scope_index = 0; char *scope_id; @@ -782,6 +783,19 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a scope_id = split_chr(arg, '%'); #endif + if (source) { + interface_opt = split_chr(source, '@'); + + if (interface_opt) + { +#if defined(SO_BINDTODEVICE) + strncpy(interface, interface_opt, IF_NAMESIZE - 1); +#else + return _("interface binding not supported"); +#endif + } + } + if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) { addr->in.sin_port = htons(serv_port); @@ -800,6 +814,9 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0)) { #if defined(SO_BINDTODEVICE) + if (interface_opt) + return _("interface can only be specified once"); + source_addr->in.sin_addr.s_addr = INADDR_ANY; strncpy(interface, source, IF_NAMESIZE - 1); #else @@ -832,7 +849,10 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0) { #if defined(SO_BINDTODEVICE) - source_addr->in6.sin6_addr = in6addr_any; + if (interface_opt) + return _("interface can only be specified once"); + + source_addr->in6.sin6_addr = in6addr_any; strncpy(interface, source, IF_NAMESIZE - 1); #else return _("interface binding not supported");