Skip to content

Commit 924eb67

Browse files
committed
net: dns: Bind DNS server to a network interface
Allow user to specify a network interface in the DNS server list. User can append "%" and network interface name to the DNS server to use this. If the network interface is mentioned in the server list, then the DNS queries are sent via this network interface. For example setting the interfaces like this: 192.0.2.2%eth1 [2001:db8::2]:5353%ppp0 would cause the DNS queries to sent to 192.0.2.1 via eth1 in the first example, and to 2001:db8::2 via ppp0 in the second example. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent aaf68fd commit 924eb67

File tree

3 files changed

+102
-7
lines changed

3 files changed

+102
-7
lines changed

include/zephyr/net/dns_resolve.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,11 @@ struct dns_resolve_context {
344344
/** Connection to the DNS server */
345345
int sock;
346346

347+
/** Network interface index if the DNS resolving should be done
348+
* via this interface. Value 0 indicates any interface can be used.
349+
*/
350+
int if_index;
351+
347352
/** Is this server mDNS one */
348353
uint8_t is_mdns : 1;
349354

subsys/net/lib/dns/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ config DNS_SERVER1
8787
192.0.2.1:5353
8888
2001:db8::1
8989
[2001:db8::1]:5353
90+
It is possible to bind the DNS connection via a certain network
91+
interface by appending "%" and network interface name to the server
92+
address. For example: 192.0.2.1%eth1 would bind the connection socket
93+
to the network interface eth1. This is optional and by default the
94+
resolver connects to server by selecting the output network interface
95+
using normal IP routing.
9096
It is not mandatory to use this Kconfig option at all.
9197
The one calling dns_resolve_init() can use this option or not
9298
to populate the server list. If the DNS server addresses are

subsys/net/lib/dns/resolve.c

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ LOG_MODULE_REGISTER(net_dns_resolve, CONFIG_DNS_RESOLVER_LOG_LEVEL);
2727
#include <zephyr/net/net_mgmt.h>
2828
#include <zephyr/net/dns_resolve.h>
2929
#include <zephyr/net/socket_service.h>
30+
#include "../../ip/net_private.h"
3031
#include "dns_pack.h"
3132
#include "dns_internal.h"
3233
#include "dns_cache.h"
@@ -319,6 +320,31 @@ static int register_dispatcher(struct dns_resolve_context *ctx,
319320
return dns_dispatcher_register(&server->dispatcher);
320321
}
321322

323+
static int bind_to_iface(int sock, const struct sockaddr *addr, int if_index)
324+
{
325+
struct ifreq ifreq = { 0 };
326+
int ret;
327+
328+
ret = net_if_get_name(net_if_get_by_index(if_index), ifreq.ifr_name,
329+
sizeof(ifreq.ifr_name));
330+
if (ret < 0) {
331+
LOG_DBG("Cannot get interface name for %d (%d)", if_index, ret);
332+
return ret;
333+
}
334+
335+
ret = zsock_setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
336+
&ifreq, sizeof(ifreq));
337+
if (ret < 0) {
338+
ret = -errno;
339+
340+
NET_DBG("Cannot bind %s to %d (%d)",
341+
net_sprint_addr(addr->sa_family, &net_sin(addr)->sin_addr),
342+
if_index, ret);
343+
}
344+
345+
return ret;
346+
}
347+
322348
/* Must be invoked with context lock held */
323349
static int dns_resolve_init_locked(struct dns_resolve_context *ctx,
324350
const char *servers[],
@@ -363,24 +389,56 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx,
363389

364390
if (servers) {
365391
for (i = 0; idx < SERVER_COUNT && servers[i]; i++) {
392+
const char *iface_str;
393+
size_t server_len;
394+
366395
struct sockaddr *addr = &ctx->servers[idx].dns_server;
367396

397+
iface_str = strstr(servers[i], "%");
398+
if (iface_str) {
399+
server_len = iface_str - servers[i];
400+
iface_str++;
401+
402+
if (server_len == 0) {
403+
NET_DBG("Empty server name");
404+
continue;
405+
}
406+
407+
/* Skip empty interface name */
408+
if (iface_str[0] == '\0') {
409+
ctx->servers[idx].if_index = 0;
410+
iface_str = NULL;
411+
} else {
412+
ctx->servers[idx].if_index =
413+
net_if_get_by_name(iface_str);
414+
}
415+
416+
} else {
417+
server_len = strlen(servers[i]);
418+
ctx->servers[idx].if_index = 0;
419+
}
420+
368421
(void)memset(addr, 0, sizeof(*addr));
369422

370-
ret = net_ipaddr_parse(servers[i], strlen(servers[i]),
371-
addr);
423+
ret = net_ipaddr_parse(servers[i], server_len, addr);
372424
if (!ret) {
425+
if (servers[i] != NULL && servers[i][0] != '\0') {
426+
NET_DBG("Invalid server address %.*s",
427+
server_len, servers[i]);
428+
}
429+
373430
continue;
374431
}
375432

376433
dns_postprocess_server(ctx, idx);
377434

378-
NET_DBG("[%d] %s%s%s", i, servers[i],
435+
NET_DBG("[%d] %.*s%s%s%s%s", i, server_len, servers[i],
379436
IS_ENABLED(CONFIG_MDNS_RESOLVER) ?
380437
(ctx->servers[i].is_mdns ? " mDNS" : "") : "",
381438
IS_ENABLED(CONFIG_LLMNR_RESOLVER) ?
382-
(ctx->servers[i].is_llmnr ?
383-
" LLMNR" : "") : "");
439+
(ctx->servers[i].is_llmnr ? " LLMNR" : "") : "",
440+
iface_str != NULL ? " via " : "",
441+
iface_str != NULL ? iface_str : "");
384442
idx++;
385443
}
386444
}
@@ -441,14 +499,40 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx,
441499

442500
ctx->servers[i].sock = ret;
443501

502+
/* Try to bind to the interface if it is set */
503+
if (ctx->servers[i].if_index > 0) {
504+
ret = bind_to_iface(ctx->servers[i].sock,
505+
&ctx->servers[i].dns_server,
506+
ctx->servers[i].if_index);
507+
if (ret < 0) {
508+
zsock_close(ctx->servers[i].sock);
509+
ctx->servers[i].sock = -1;
510+
continue;
511+
}
512+
513+
iface = net_if_get_by_index(ctx->servers[i].if_index);
514+
NET_DBG("Binding %s to %d",
515+
net_sprint_addr(ctx->servers[i].dns_server.sa_family,
516+
&net_sin(&ctx->servers[i].dns_server)->sin_addr),
517+
ctx->servers[i].if_index);
518+
} else {
519+
iface = NULL;
520+
}
521+
444522
if (ctx->servers[i].dns_server.sa_family == AF_INET6) {
445-
iface = net_if_ipv6_select_src_iface(
523+
if (iface == NULL) {
524+
iface = net_if_ipv6_select_src_iface(
446525
&net_sin6(&ctx->servers[i].dns_server)->sin6_addr);
526+
}
527+
447528
addr6 = net_if_ipv6_select_src_addr(iface,
448529
&net_sin6(&ctx->servers[i].dns_server)->sin6_addr);
449530
} else {
450-
iface = net_if_ipv4_select_src_iface(
531+
if (iface == NULL) {
532+
iface = net_if_ipv4_select_src_iface(
451533
&net_sin(&ctx->servers[i].dns_server)->sin_addr);
534+
}
535+
452536
addr4 = net_if_ipv4_select_src_addr(iface,
453537
&net_sin(&ctx->servers[i].dns_server)->sin_addr);
454538
}

0 commit comments

Comments
 (0)