summaryrefslogtreecommitdiffhomepage
path: root/interface-ip.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2016-09-13 14:33:39 +0200
committerFelix Fietkau <nbd@nbd.name>2016-09-14 13:01:29 +0200
commit7f6be657e2dabc185417520de4d0d0de2580c27d (patch)
tree69952ac03877a4f0a2ac7ae90481b725a6a0cb2f /interface-ip.c
parent83d3a901d3178a8840092b6e4f7f829b89da4ba0 (diff)
interface-ip: DNS name server sorting support in resolv.conf.auto
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>
Diffstat (limited to 'interface-ip.c')
-rw-r--r--interface-ip.c73
1 files changed, 60 insertions, 13 deletions
diff --git a/interface-ip.c b/interface-ip.c
index 26a2865..24ea054 100644
--- a/interface-ip.c
+++ b/interface-ip.c
@@ -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);