remove obsolete /opt/local prefix on Mac OS X
[project/netifd.git] / interface-ip.c
index 919c8cc..24ea054 100644 (file)
@@ -366,7 +366,7 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6)
                const char *mask = strtok_r(NULL, "/", &saveptr);
 
                if (!addr || inet_pton(af, addr, &route->source) < 1) {
-                       DPRINTF("Failed to parse route source: %s\n", addr);
+                       DPRINTF("Failed to parse route source: %s\n", addr ? addr : "NULL");
                        goto error;
                }
 
@@ -857,6 +857,9 @@ static void interface_update_prefix_assignments(struct device_prefix *prefix, bo
 
        // End-of-assignment sentinel
        c = malloc(sizeof(*c) + 1);
+       if (!c)
+               return;
+
        c->assigned = 1 << (64 - prefix->length);
        c->length = 64;
        c->name[0] = 0;
@@ -867,12 +870,14 @@ static void interface_update_prefix_assignments(struct device_prefix *prefix, bo
        if (prefix->excl_length > 0) {
                const char name[] = "!excluded";
                c = malloc(sizeof(*c) + sizeof(name));
-               c->assigned = ntohl(prefix->excl_addr.s6_addr32[1]) &
-                               ((1 << (64 - prefix->length)) - 1);
-               c->length = prefix->excl_length;
-               c->addr = in6addr_any;
-               memcpy(c->name, name, sizeof(name));
-               list_add(&c->head, &prefix->assignments);
+               if (c) {
+                       c->assigned = ntohl(prefix->excl_addr.s6_addr32[1]) &
+                                       ((1 << (64 - prefix->length)) - 1);
+                       c->length = prefix->excl_length;
+                       c->addr = in6addr_any;
+                       memcpy(c->name, name, sizeof(name));
+                       list_add(&c->head, &prefix->assignments);
+               }
        }
 
        bool assigned_any = false;
@@ -900,6 +905,9 @@ static void interface_update_prefix_assignments(struct device_prefix *prefix, bo
 
                size_t namelen = strlen(iface->name) + 1;
                c = malloc(sizeof(*c) + namelen);
+               if (!c)
+                       continue;
+
                c->length = iface->assignment_length;
                c->assigned = iface->assignment_hint;
                c->addr = in6addr_any;
@@ -1033,6 +1041,9 @@ interface_ip_add_device_prefix(struct interface *iface, struct in6_addr *addr,
                pclass = (iface) ? iface->name : "local";
 
        struct device_prefix *prefix = calloc(1, sizeof(*prefix) + strlen(pclass) + 1);
+       if (!prefix)
+               return NULL;
+
        prefix->length = length;
        prefix->addr = *addr;
        prefix->preferred_until = preferred_until;
@@ -1186,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)
@@ -1208,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);
@@ -1253,6 +1311,9 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
        vlist_for_each_element(&ip->addr, addr, node) {
                bool v6 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET6) ? true : false;
 
+               if (addr->flags & DEVADDR_EXTERNAL)
+                       continue;
+
                if (addr->enabled == enabled)
                        continue;
 
@@ -1278,6 +1339,9 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
        vlist_for_each_element(&ip->route, route, node) {
                bool _enabled = enabled;
 
+               if (route->flags & DEVADDR_EXTERNAL)
+                       continue;
+
                if (!enable_route(ip, route))
                        _enabled = false;