@@ -1197,21 +1197,33 @@ write_resolv_conf_entries(FILE *f, struct interface_ip_settings *ip, const char
}
}
-void
-interface_write_resolv_conf(void)
+/* Sorting of interface resolver entries : */
+/* Primary on interface dns_metric : lowest metric first */
+/* Secondary on interface metric : lowest metric first */
+/* Finally alphabetical order of interface names */
+static int resolv_conf_iface_cmp(const void *k1, const void *k2, void *ptr)
+{
+ const struct interface *iface1 = k1, *iface2 = k2;
+
+ if (iface1->dns_metric != iface2->dns_metric)
+ return iface1->dns_metric - iface2->dns_metric;
+
+ if (iface1->metric != iface2->metric)
+ return iface1->metric - iface2->metric;
+
+ return strcmp(iface1->name, iface2->name);
+}
+
+static void
+__interface_write_dns_entries(FILE *f)
{
struct interface *iface;
- char *path = alloca(strlen(resolv_conf) + 5);
- FILE *f;
- uint32_t crcold, crcnew;
+ struct {
+ struct avl_node node;
+ } *entry, *n_entry;
+ struct avl_tree resolv_conf_iface_entries;
- sprintf(path, "%s.tmp", resolv_conf);
- unlink(path);
- f = fopen(path, "w+");
- if (!f) {
- D(INTERFACE, "Failed to open %s for writing\n", path);
- return;
- }
+ avl_init(&resolv_conf_iface_entries, resolv_conf_iface_cmp, false, NULL);
vlist_for_each_element(&interfaces, iface, node) {
if (iface->state != IFS_UP)
@@ -1219,15 +1231,50 @@ interface_write_resolv_conf(void)
if (vlist_simple_empty(&iface->proto_ip.dns_search) &&
vlist_simple_empty(&iface->proto_ip.dns_servers) &&
- vlist_simple_empty(&iface->config_ip.dns_search) &&
+ vlist_simple_empty(&iface->config_ip.dns_search) &&
vlist_simple_empty(&iface->config_ip.dns_servers))
continue;
+ entry = calloc(1, sizeof(*entry));
+ if (!entry)
+ continue;
+
+ entry->node.key = iface;
+ avl_insert(&resolv_conf_iface_entries, &entry->node);
+ }
+
+ avl_for_each_element(&resolv_conf_iface_entries, entry, node) {
+ iface = (struct interface *)entry->node.key;
+
fprintf(f, "# Interface %s\n", iface->name);
+
write_resolv_conf_entries(f, &iface->config_ip, iface->ifname);
+
if (!iface->proto_ip.no_dns)
write_resolv_conf_entries(f, &iface->proto_ip, iface->ifname);
}
+
+ avl_remove_all_elements(&resolv_conf_iface_entries, entry, node, n_entry)
+ free(entry);
+}
+
+void
+interface_write_resolv_conf(void)
+{
+ char *path = alloca(strlen(resolv_conf) + 5);
+ FILE *f;
+ uint32_t crcold, crcnew;
+
+ sprintf(path, "%s.tmp", resolv_conf);
+ unlink(path);
+ f = fopen(path, "w+");
+ if (!f) {
+ D(INTERFACE, "Failed to open %s for writing\n", path);
+ return;
+ }
+
+ __interface_write_dns_entries(f);
+
fflush(f);
rewind(f);
crcnew = crc32_file(f);
@@ -35,6 +35,7 @@ enum {
IFACE_ATTR_PEERDNS,
IFACE_ATTR_DNS,
IFACE_ATTR_DNS_SEARCH,
+ IFACE_ATTR_DNS_METRIC,
IFACE_ATTR_METRIC,
IFACE_ATTR_INTERFACE,
IFACE_ATTR_IP6ASSIGN,
@@ -57,6 +58,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
[IFACE_ATTR_METRIC] = { .name = "metric", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
[IFACE_ATTR_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY },
+ [IFACE_ATTR_DNS_METRIC] = { .name = "dns_metric", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_IP6ASSIGN] = { .name = "ip6assign", .type = BLOBMSG_TYPE_INT32 },
[IFACE_ATTR_IP6HINT] = { .name = "ip6hint", .type = BLOBMSG_TYPE_STRING },
@@ -795,6 +797,9 @@ interface_alloc(const char *name, struct blob_attr *config)
if ((cur = tb[IFACE_ATTR_DNS_SEARCH]))
interface_add_dns_search_list(&iface->config_ip, cur);
+ if ((cur = tb[IFACE_ATTR_DNS_METRIC]))
+ iface->dns_metric = blobmsg_get_u32(cur);
+
if ((cur = tb[IFACE_ATTR_METRIC]))
iface->metric = blobmsg_get_u32(cur);
@@ -1185,6 +1190,7 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
if_old->parent_ifname = if_new->parent_ifname;
if_old->proto_handler = if_new->proto_handler;
if_old->force_link = if_new->force_link;
+ if_old->dns_metric = if_new->dns_metric;
if_old->proto_ip.no_dns = if_new->proto_ip.no_dns;
interface_replace_dns(&if_old->config_ip, &if_new->config_ip);
@@ -145,6 +145,7 @@ struct interface {
struct vlist_tree host_routes;
int metric;
+ int dns_metric;
unsigned int ip4table;
unsigned int ip6table;
@@ -687,6 +687,7 @@ netifd_dump_status(struct interface *iface)
if (iface->ip6table)
blobmsg_add_u32(&b, "ip6table", iface->ip6table);
blobmsg_add_u32(&b, "metric", iface->metric);
+ blobmsg_add_u32(&b, "dns_metric", iface->dns_metric);
blobmsg_add_u8(&b, "delegation", !iface->proto_ip.no_delegation);
a = blobmsg_open_array(&b, "ipv4-address");
interface_ip_dump_address_list(&iface->config_ip, false, true);
Interface name servers when being written to resolv.conf.auto are sorted based on the following parameters: -Primary sorting key is interface dns_metric; name servers having lowest interface dns_metric are listed first -Secondary sorting key is interface metric; in case of equal interface dns_metric name servers having lowest interface metric are listed first -Finally alphabetical order of the interface names in case of equal interface dns_metric and metric In case the resolver queries the multiple servers in the order listed; sorting is usefull in the following scenarios : -Name resolving over a main and backup interface -Assign priority to IPv6 name servers over IPv4 or vice versa Signed-off-by: Hans Dedecker <dedeckeh@gmail.com> --- interface-ip.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++----------- interface.c | 6 +++++ interface.h | 1 + ubus.c | 1 + 4 files changed, 68 insertions(+), 13 deletions(-)