diff options
Diffstat (limited to 'interface-ip.c')
-rw-r--r-- | interface-ip.c | 73 |
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); |