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");