Skip to content

net: Cherry-pick DHCP/DNS improvements #3062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion drivers/modem/hl7800.c
Original file line number Diff line number Diff line change
Expand Up @@ -1966,7 +1966,8 @@ static void dns_work_cb(struct k_work *work)
}
} else {
LOG_DBG("Reconfiguring DNS resolver");
ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL);
ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL,
DNS_SOURCE_MANUAL);
if (ret < 0) {
LOG_ERR("dns_resolve_reconfigure fail (%d)", ret);
retry = true;
Expand Down
10 changes: 8 additions & 2 deletions drivers/wifi/esp_at/esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,18 +490,24 @@
struct dns_resolve_context *dnsctx;
struct sockaddr_in *addrs = data->dns_addresses;
const struct sockaddr *dns_servers[ESP_MAX_DNS + 1] = {};
int interfaces[ESP_MAX_DNS];
size_t i;
int err;
int err, ifindex;

ifindex = net_if_get_by_ifindex(data->net_iface);

for (i = 0; i < ESP_MAX_DNS; i++) {
if (!addrs[i].sin_addr.s_addr) {
break;
}
dns_servers[i] = (struct sockaddr *) &addrs[i];
interfaces[i] = ifindex;
}

dnsctx = dns_resolve_get_default();
err = dns_resolve_reconfigure(dnsctx, NULL, dns_servers);
err = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers,
interfaces,
DNS_SOURCE_MANUAL);

Check notice on line 510 in drivers/wifi/esp_at/esp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/wifi/esp_at/esp.c:510 - err = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers, - interfaces, + err = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers, interfaces,
if (err) {
LOG_ERR("Could not set DNS servers: %d", err);
}
Expand Down
86 changes: 85 additions & 1 deletion include/zephyr/net/dns_resolve.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@
DNS_QUERY_TYPE_AAAA = 28
};

/**
* Entity that added the DNS server.
*/
enum dns_server_source {
/** Source is unknown */
DNS_SOURCE_UNKNOWN = 0,
/** Server information is added manually, for example by an application */
DNS_SOURCE_MANUAL,
/** Server information is from DHCPv4 server */
DNS_SOURCE_DHCPV4,
/** Server information is from DHCPv6 server */
DNS_SOURCE_DHCPV6,
/** Server information is from IPv6 SLAAC (router advertisement) */
DNS_SOURCE_IPV6_RA,
/** Server information is from PPP */
DNS_SOURCE_PPP,
};

/** Max size of the resolved name. */
#ifndef DNS_MAX_NAME_SIZE
#define DNS_MAX_NAME_SIZE 20
Expand Down Expand Up @@ -320,6 +338,7 @@
/** @cond INTERNAL_HIDDEN */

enum dns_resolve_context_state {
DNS_RESOLVE_CONTEXT_UNINITIALIZED = 0,
DNS_RESOLVE_CONTEXT_ACTIVE,
DNS_RESOLVE_CONTEXT_DEACTIVATING,
DNS_RESOLVE_CONTEXT_INACTIVE,
Expand All @@ -344,6 +363,9 @@
*/
int if_index;

/** Source of the DNS server, e.g., manual, DHCPv4/6, etc. */
enum dns_server_source source;

/** Is this server mDNS one */
uint8_t is_mdns : 1;

Expand Down Expand Up @@ -517,12 +539,65 @@
* @param servers_sa DNS server addresses as struct sockaddr. The array
* is NULL terminated. Port numbers are optional in struct sockaddr, the
* default will be used if set to 0.
* @param source Source of the DNS servers, e.g., manual, DHCPv4/6, etc.
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_reconfigure(struct dns_resolve_context *ctx,
const char *servers_str[],
const struct sockaddr *servers_sa[]);
const struct sockaddr *servers_sa[],
enum dns_server_source source);

Check notice on line 550 in include/zephyr/net/dns_resolve.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/net/dns_resolve.h:550 -int dns_resolve_reconfigure(struct dns_resolve_context *ctx, - const char *servers_str[], - const struct sockaddr *servers_sa[], - enum dns_server_source source); +int dns_resolve_reconfigure(struct dns_resolve_context *ctx, const char *servers_str[], + const struct sockaddr *servers_sa[], enum dns_server_source source);
/**
* @brief Reconfigure DNS resolving context with new server list and
* allowing servers to be specified to a specific network interface.
*
* @param ctx DNS context
* @param servers_str DNS server addresses using textual strings. The
* array is NULL terminated. The port number can be given in the string.
* Syntax for the server addresses with or without port numbers:
* IPv4 : 10.0.9.1
* IPv4 + port : 10.0.9.1:5353
* IPv6 : 2001:db8::22:42
* IPv6 + port : [2001:db8::22:42]:5353
* @param servers_sa DNS server addresses as struct sockaddr. The array
* is NULL terminated. Port numbers are optional in struct sockaddr, the
* default will be used if set to 0.
* @param interfaces Network interfaces to which the DNS servers are bound.
* This is an array of network interface indices. The array must be
* the same length as the servers_str and servers_sa arrays.
* @param source Source of the DNS servers, e.g., manual, DHCPv4/6, etc.
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_reconfigure_with_interfaces(struct dns_resolve_context *ctx,
const char *servers_str[],
const struct sockaddr *servers_sa[],
int interfaces[],
enum dns_server_source source);

Check notice on line 577 in include/zephyr/net/dns_resolve.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/net/dns_resolve.h:577 - const struct sockaddr *servers_sa[], - int interfaces[], + const struct sockaddr *servers_sa[], int interfaces[],

/**
* @brief Remove servers from the DNS resolving context.
*
* @param ctx DNS context
* @param if_index Network interface from which the DNS servers are removed.
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_remove(struct dns_resolve_context *ctx, int if_index);

/**
* @brief Remove servers from the DNS resolving context that were added by
* a specific source.
*
* @param ctx DNS context
* @param if_index Network interface from which the DNS servers are removed.
* @param source Source of the DNS servers, e.g., manual, DHCPv4/6, etc.
*
* @return 0 if ok, <0 if error.
*/
int dns_resolve_remove_source(struct dns_resolve_context *ctx, int if_index,
enum dns_server_source source);

/**
* @brief Cancel a pending DNS query.
Expand Down Expand Up @@ -664,6 +739,15 @@

/** @cond INTERNAL_HIDDEN */

/**
* @brief Get string representation of the DNS server source.
*
* @param source Source of the DNS server.
*
* @return String representation of the DNS server source.
*/
const char *dns_get_source_str(enum dns_server_source source);

/**
* @brief Initialize DNS subsystem.
*/
Expand Down
1 change: 1 addition & 0 deletions subsys/net/ip/Kconfig.stack
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ config NET_TX_STACK_SIZE

config NET_RX_STACK_SIZE
int "RX thread stack size"
default 1792 if DNS_RESOLVER
default 1500
help
Set the RX thread stack size in bytes. The RX thread is waiting
Expand Down
7 changes: 6 additions & 1 deletion subsys/net/ip/ipv6_nbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2469,7 +2469,10 @@
const struct sockaddr *dns_servers[] = {
(struct sockaddr *)&dns, NULL
};
int interfaces[] = {
net_if_get_by_iface(net_pkt_iface(pkt))
};
size_t rdnss_size;

Check notice on line 2475 in subsys/net/ip/ipv6_nbr.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/ipv6_nbr.c:2475 - int interfaces[] = { - net_if_get_by_iface(net_pkt_iface(pkt)) - }; + int interfaces[] = {net_if_get_by_iface(net_pkt_iface(pkt))};
int ret;

rdnss = (struct net_icmpv6_nd_opt_rdnss *) net_pkt_get_data(pkt, &rdnss_access);
Expand Down Expand Up @@ -2505,7 +2508,9 @@

/* TODO: Handle lifetime. */
ctx = dns_resolve_get_default();
ret = dns_resolve_reconfigure(ctx, NULL, dns_servers);
ret = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers,
interfaces,
DNS_SOURCE_IPV6_RA);

Check notice on line 2513 in subsys/net/ip/ipv6_nbr.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/ip/ipv6_nbr.c:2513 - ret = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers, - interfaces, + ret = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers, interfaces,
if (ret < 0) {
NET_DBG("Failed to set RDNSS resolve address: %d", ret);
}
Expand Down
6 changes: 5 additions & 1 deletion subsys/net/l2/ppp/ipcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@
(struct sockaddr *) &dns2,
NULL
};
int ifindex = net_if_get_by_iface(ctx->iface);
int interfaces[2] = { ifindex, ifindex };
int ret;

Check notice on line 332 in subsys/net/l2/ppp/ipcp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/l2/ppp/ipcp.c:332 - int interfaces[2] = { ifindex, ifindex }; + int interfaces[2] = {ifindex, ifindex};

if (!dns1.sin_addr.s_addr) {
return;
Expand All @@ -338,7 +340,9 @@
}

dnsctx = dns_resolve_get_default();
ret = dns_resolve_reconfigure(dnsctx, NULL, dns_servers);
ret = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers,
interfaces,
DNS_SOURCE_PPP);

Check notice on line 345 in subsys/net/l2/ppp/ipcp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/l2/ppp/ipcp.c:345 - ret = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers, - interfaces, + ret = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers, interfaces,
if (ret < 0) {
NET_ERR("Could not set DNS servers");
return;
Expand Down
17 changes: 17 additions & 0 deletions subsys/net/lib/dhcpv4/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,23 @@ config NET_DHCPV4_OPTION_PRINT_IGNORED
received and ignored. If this is not set, then we print these as unknown
options.

config NET_DHCPV4_DNS_SERVER_VIA_INTERFACE
bool "Make DNS servers specific to the network interface"
depends on NET_DHCPV4_OPTION_DNS_ADDRESS
default y
help
If this is set, then if the system has multiple network interfaces
and each has DHCP enabled, then assign DNS servers received from that
network interface, to that specific interface.
If this option is not set, then any interface can be used for all
the configured DNS server addresses when doing DNS queries.
Example: We receive DNS server 192.0.2.53 DHCPv4 option from Wi-Fi
interface and DNS server 198.51.100.53 from Ethernet interface.
When this option is set, the DNS resolver will use DNS server
192.0.2.53 when sending DNS query to the Wi-Fi interface and DNS
server 198.51.100.53 when sending DNS query to the Ethernet
interface.

endif # NET_DHCPV4

config NET_DHCPV4_SERVER
Expand Down
39 changes: 38 additions & 1 deletion subsys/net/lib/dhcpv4/dhcpv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,27 @@
for (uint8_t i = 0; i < dns_servers_cnt; i++) {
dnses[i].sin_family = AF_INET;
}
status = dns_resolve_reconfigure(ctx, NULL, dns_servers);

if (IS_ENABLED(CONFIG_NET_DHCPV4_DNS_SERVER_VIA_INTERFACE)) {
/* If we are using the interface to resolve DNS servers,
* we need to save the interface index.
*/
int ifindex = net_if_get_by_iface(iface);
int interfaces[MAX_DNS_SERVERS];

for (uint8_t i = 0; i < dns_servers_cnt; i++) {
interfaces[i] = ifindex;
}

status = dns_resolve_reconfigure_with_interfaces(ctx, NULL,
dns_servers,
interfaces,
DNS_SOURCE_DHCPV4);
} else {

Check notice on line 1190 in subsys/net/lib/dhcpv4/dhcpv4.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/lib/dhcpv4/dhcpv4.c:1190 - status = dns_resolve_reconfigure_with_interfaces(ctx, NULL, - dns_servers, - interfaces, - DNS_SOURCE_DHCPV4); + status = dns_resolve_reconfigure_with_interfaces( + ctx, NULL, dns_servers, interfaces, DNS_SOURCE_DHCPV4);
status = dns_resolve_reconfigure(ctx, NULL, dns_servers,
DNS_SOURCE_DHCPV4);
}

if (status < 0) {
NET_DBG("options_dns, failed to set "
"resolve address: %d", status);
Expand Down Expand Up @@ -1650,6 +1670,17 @@
if (!net_if_ipv4_addr_rm(iface, &iface->config.dhcpv4.requested_ip)) {
NET_DBG("Failed to remove addr from iface");
}

/* Remove DNS servers as interface is gone. We only need to
* do this for this interface. If using global setting, the
* DNS servers are removed automatically when the interface
* comes back up.
*/
if (IS_ENABLED(CONFIG_NET_DHCPV4_DNS_SERVER_VIA_INTERFACE)) {
dns_resolve_remove_source(dns_resolve_get_default(),
net_if_get_by_iface(iface),
DNS_SOURCE_DHCPV4);
}
}
} else if (mgmt_event == NET_EVENT_IF_UP) {
NET_DBG("Interface %p coming up", iface);
Expand Down Expand Up @@ -1914,6 +1945,12 @@
NET_DBG("state=%s",
net_dhcpv4_state_name(iface->config.dhcpv4.state));

if (IS_ENABLED(CONFIG_NET_DHCPV4_DNS_SERVER_VIA_INTERFACE)) {
dns_resolve_remove_source(dns_resolve_get_default(),
net_if_get_by_iface(iface),
DNS_SOURCE_DHCPV4);
}

Check notice on line 1952 in subsys/net/lib/dhcpv4/dhcpv4.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/lib/dhcpv4/dhcpv4.c:1952 - net_if_get_by_iface(iface), - DNS_SOURCE_DHCPV4); + net_if_get_by_iface(iface), DNS_SOURCE_DHCPV4);

sys_slist_find_and_remove(&dhcpv4_ifaces,
&iface->config.dhcpv4.node);

Expand Down
17 changes: 17 additions & 0 deletions subsys/net/lib/dhcpv6/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ config NET_DHCPV6_OPTION_DNS_ADDRESS
option from the server, and if available, use obtained information
to configure DNS resolver.

config NET_DHCPV6_DNS_SERVER_VIA_INTERFACE
bool "Make DNS servers specific to the network interface"
depends on NET_DHCPV6_OPTION_DNS_ADDRESS
default y
help
If this is set, then if the system has multiple network interfaces
and each has DHCP enabled, then assign DNS servers received from that
network interface, to that specific interface.
If this option is not set, then any interface can be used for all
the configured DNS server addresses when doing DNS queries.
Example: We receive DNS server 2001:db8::1:53 DHCPv6 option from Wi-Fi
interface and DNS server 2001:db8::2:53 from Ethernet interface.
When this option is set, the DNS resolver will use DNS server
2001:db8::1:53 when sending DNS query to the Wi-Fi interface and DNS
server 2001:db8::2:53 when sending DNS query to the Ethernet
interface.

if NET_DHCPV6
module = NET_DHCPV6
module-dep = NET_LOG
Expand Down
39 changes: 38 additions & 1 deletion subsys/net/lib/dhcpv6/dhcpv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,7 +1412,27 @@
}

ctx = dns_resolve_get_default();
status = dns_resolve_reconfigure(ctx, NULL, dns_servers);

if (IS_ENABLED(CONFIG_NET_DHCPV6_DNS_SERVER_VIA_INTERFACE)) {
/* If we are using the interface to resolve DNS servers,
* we need to save the interface index.
*/
int ifindex = net_if_get_by_iface(net_pkt_iface(pkt));
int interfaces[MAX_DNS_SERVERS];

for (uint8_t i = 0; i < server_count; i++) {
interfaces[i] = ifindex;
}

status = dns_resolve_reconfigure_with_interfaces(ctx, NULL,
dns_servers,
interfaces,
DNS_SOURCE_DHCPV6);
} else {
status = dns_resolve_reconfigure(ctx, NULL, dns_servers,
DNS_SOURCE_DHCPV6);
}

Check notice on line 1434 in subsys/net/lib/dhcpv6/dhcpv6.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/lib/dhcpv6/dhcpv6.c:1434 - status = dns_resolve_reconfigure_with_interfaces(ctx, NULL, - dns_servers, - interfaces, + status = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers, interfaces, DNS_SOURCE_DHCPV6); } else { - status = dns_resolve_reconfigure(ctx, NULL, dns_servers, - DNS_SOURCE_DHCPV6); + status = dns_resolve_reconfigure(ctx, NULL, dns_servers, DNS_SOURCE_DHCPV6);

if (status < 0) {
NET_DBG("Failed to reconfigure DNS resolver from DHCPv6 "
"option: %d", status);
Expand Down Expand Up @@ -2199,6 +2219,17 @@
if (mgmt_event == NET_EVENT_IF_DOWN) {
NET_DBG("Interface %p going down", iface);
dhcpv6_set_timeout(iface, UINT64_MAX);

/* Remove DNS servers as interface is gone. We only need to
* do this for this interface. If using global setting, the
* DNS servers are removed automatically when the interface
* comes back up.
*/
if (IS_ENABLED(CONFIG_NET_DHCPV6_DNS_SERVER_VIA_INTERFACE)) {
dns_resolve_remove_source(dns_resolve_get_default(),
net_if_get_by_iface(iface),
DNS_SOURCE_DHCPV6);
}
} else if (mgmt_event == NET_EVENT_IF_UP) {
NET_DBG("Interface %p coming up", iface);
dhcpv6_enter_state(iface, NET_DHCPV6_INIT);
Expand Down Expand Up @@ -2293,6 +2324,12 @@

(void)dhcpv6_enter_state(iface, NET_DHCPV6_DISABLED);

if (IS_ENABLED(CONFIG_NET_DHCPV6_DNS_SERVER_VIA_INTERFACE)) {
dns_resolve_remove_source(dns_resolve_get_default(),
net_if_get_by_iface(iface),
DNS_SOURCE_DHCPV6);
}

sys_slist_find_and_remove(&dhcpv6_ifaces,
&iface->config.dhcpv6.node);

Expand Down
13 changes: 13 additions & 0 deletions subsys/net/lib/dns/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ config DNS_SERVER5

endif # DNS_SERVER_IP_ADDRESSES

config DNS_RECONFIGURE_CLEANUP
bool "Cleanup old DNS server entries when reconfiguring"
help
If calling dns_resolve_reconfigure() when new DNS servers
are being set, for example if receiving new ones from DHCP server,
remove the old entries before setting up the new ones.
If you have only one network interface, then this can be enabled.
If you have multiple network interfaces, then this should be disabled
because the later configuration update would remove the entries
set by the other network interface configuration.
The previous default in Zephyr 4.1 or earlier was to have this enabled.
The current default in Zephyr 4.2 is to disable this option.

config DNS_NUM_CONCUR_QUERIES
int "Number of simultaneous DNS queries per one DNS context"
default 1
Expand Down
Loading
Loading