treewide: add netlink file
[project/odhcpd.git] / src / ndp.c
index 8378ebff8eb135cad964f8e4ee5212f1daa70a78..460d5fc9e8edbacb089174fa8b179546becd1990 100644 (file)
--- a/src/ndp.c
+++ b/src/ndp.c
@@ -74,11 +74,11 @@ static const struct sock_fprog bpf_prog = {sizeof(bpf) / sizeof(*bpf), bpf};
 
 
 // Initialize NDP-proxy
-int init_ndp(void)
+int ndp_init(void)
 {
        int val = 2;
 
-       rtnl_event.sock = odhcpd_create_nl_socket(NETLINK_ROUTE);
+       rtnl_event.sock = netlink_create_socket(NETLINK_ROUTE);
        if (!rtnl_event.sock)
                goto err;
 
@@ -95,7 +95,7 @@ int init_ndp(void)
        // Receive IPv4 address, IPv6 address, IPv6 routes and neighbor events
        if (nl_socket_add_memberships(rtnl_event.sock, RTNLGRP_IPV4_IFADDR,
                                RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE,
-                               RTNLGRP_NEIGH, 0))
+                               RTNLGRP_NEIGH, RTNLGRP_LINK, 0))
                goto err;
 
        odhcpd_register(&rtnl_event.ev);
@@ -168,7 +168,7 @@ static void dump_addr_table(bool v6)
        nlmsg_free(msg);
 }
 
-int setup_ndp_interface(struct interface *iface, bool enable)
+int ndp_setup_interface(struct interface *iface, bool enable)
 {
        int ret = 0, procfd;
        bool dump_neigh = false;
@@ -187,13 +187,13 @@ int setup_ndp_interface(struct interface *iface, bool enable)
                close(iface->ndp_event.uloop.fd);
                iface->ndp_event.uloop.fd = -1;
 
-               if (!enable || iface->ndp != RELAYD_RELAY)
+               if (!enable || iface->ndp != MODE_RELAY)
                        if (write(procfd, "0\n", 2) < 0) {}
 
                dump_neigh = true;
        }
 
-       if (enable && iface->ndp == RELAYD_RELAY) {
+       if (enable && iface->ndp == MODE_RELAY) {
                if (write(procfd, "1\n", 2) < 0) {}
 
                int sock = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IPV6));
@@ -265,9 +265,9 @@ static void ping6(struct in6_addr *addr,
        inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf));
        syslog(LOG_NOTICE, "Pinging for %s%%%s", ipbuf, iface->ifname);
 
-       odhcpd_setup_route(addr, 128, iface, NULL, 128, true);
+       netlink_setup_route(addr, 128, iface, NULL, 128, true);
        odhcpd_send(ping_socket, &dest, &iov, 1, iface);
-       odhcpd_setup_route(addr, 128, iface, NULL, 128, false);
+       netlink_setup_route(addr, 128, iface, NULL, 128, false);
 }
 
 // Handle solicitations
@@ -286,7 +286,7 @@ static void handle_solicit(void *addr, void *data, size_t len,
        // Don't process solicit messages on non relay interfaces
        // Don't forward any non-DAD solicitation for external ifaces
        // TODO: check if we should even forward DADs for them
-       if (iface->ndp != RELAYD_RELAY || (iface->external && !ns_is_dad))
+       if (iface->ndp != MODE_RELAY || (iface->external && !ns_is_dad))
                return;
 
        if (len < sizeof(*ip6) + sizeof(*req))
@@ -306,7 +306,7 @@ static void handle_solicit(void *addr, void *data, size_t len,
 
        struct interface *c;
        list_for_each_entry(c, &interfaces, head)
-               if (iface != c && c->ndp == RELAYD_RELAY &&
+               if (iface != c && c->ndp == MODE_RELAY &&
                                (ns_is_dad || !c->external))
                        ping6(&req->nd_ns_target, c);
 }
@@ -321,33 +321,36 @@ static void setup_route(struct in6_addr *addr, struct interface *iface, bool add
                        (add) ? "Learned" : "Forgot", ipbuf, iface->ifname);
 
        if (iface->learn_routes)
-               odhcpd_setup_route(addr, 128, iface, NULL, 1024, add);
+               netlink_setup_route(addr, 128, iface, NULL, 1024, add);
 }
 
 // Check address update
 static void check_addr_updates(struct interface *iface)
 {
        struct odhcpd_ipaddr *addr = NULL;
-       ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, false, &addr);
+       ssize_t len = netlink_get_interface_addrs(iface->ifindex, false, &addr);
 
        if (len < 0)
                return;
 
        bool change = len != (ssize_t)iface->addr4_len;
        for (ssize_t i = 0; !change && i < len; ++i)
-               if (addr[i].addr.in.s_addr != iface->ia_addr[i].addr.in.s_addr)
+               if (addr[i].addr.in.s_addr != iface->addr4[i].addr.in.s_addr)
                        change = true;
 
        free(iface->addr4);
        iface->addr4 = addr;
        iface->addr4_len = len;
+
+       if (change)
+               dhcpv4_addr_update(iface);
 }
 
 // Check v6 address update
 static void check_addr6_updates(struct interface *iface)
 {
        struct odhcpd_ipaddr *addr = NULL;
-       ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, true, &addr);
+       ssize_t len = netlink_get_interface_addrs(iface->ifindex, true, &addr);
 
        if (len < 0)
                return;
@@ -382,12 +385,12 @@ static void setup_addr_for_relaying(struct in6_addr *addr, struct interface *ifa
        inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf));
 
        list_for_each_entry(c, &interfaces, head) {
-               if (iface == c || (c->ndp != RELAYD_RELAY && !add))
+               if (iface == c || (c->ndp != MODE_RELAY && !add))
                        continue;
 
-               bool neigh_add = (c->ndp == RELAYD_RELAY ? add : false);
+               bool neigh_add = (c->ndp == MODE_RELAY ? add : false);
 
-               if (odhcpd_setup_proxy_neigh(addr, c, neigh_add))
+               if (netlink_setup_proxy_neigh(addr, c, neigh_add))
                        syslog(LOG_DEBUG, "Failed to %s proxy neighbour entry %s%%%s",
                                neigh_add ? "add" : "delete", ipbuf, c->ifname);
                else
@@ -415,6 +418,29 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
        char ipbuf[INET6_ADDRSTRLEN];
 
        switch (hdr->nlmsg_type) {
+       case RTM_NEWLINK: {
+               struct ifinfomsg *ifi = nlmsg_data(hdr);
+               struct nlattr *nla[__IFLA_MAX];
+
+               if (!nlmsg_valid_hdr(hdr, sizeof(*ifi)) ||
+                               ifi->ifi_family != AF_UNSPEC)
+                       return NL_SKIP;
+
+               nlmsg_parse(hdr, sizeof(struct ifinfomsg), nla, __IFLA_MAX - 1, NULL);
+               if (!nla[IFLA_IFNAME])
+                       return NL_SKIP;
+
+               struct interface *iface = odhcpd_get_interface_by_name(nla_data(nla[IFLA_IFNAME]));
+               if (!iface)
+                       return NL_SKIP;
+
+               if (iface->ifindex != ifi->ifi_index) {
+                       iface->ifindex = ifi->ifi_index;
+                       check_addr_updates(iface);
+               }
+               break;
+       }
+
        case RTM_NEWROUTE:
        case RTM_DELROUTE: {
                struct rtmsg *rtm = nlmsg_data(hdr);
@@ -427,7 +453,7 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
                        syslog(LOG_INFO, "Raising SIGUSR1 due to default route change");
                        raise(SIGUSR1);
                }
-               return NL_OK;
+               break;
        }
 
        case RTM_NEWADDR:
@@ -463,7 +489,7 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
 
                        check_addr6_updates(iface);
 
-                       if (iface->ndp != RELAYD_RELAY)
+                       if (iface->ndp != MODE_RELAY)
                                break;
 
                        /* handle the relay logic below */
@@ -498,7 +524,7 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
                        return NL_SKIP;
 
                iface = odhcpd_get_interface_by_index(ndm->ndm_ifindex);
-               if (!iface || iface->ndp != RELAYD_RELAY)
+               if (!iface || iface->ndp != MODE_RELAY)
                        return (iface ? NL_OK : NL_SKIP);
 
                nlmsg_parse(hdr, sizeof(*ndm), nla, __NDA_MAX - 1, NULL);
@@ -517,7 +543,7 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg)
                if (ndm->ndm_flags & NTF_PROXY) {
                        /* Dump and flush proxy entries */
                        if (hdr->nlmsg_type == RTM_NEWNEIGH) {
-                               odhcpd_setup_proxy_neigh(addr6, iface, false);
+                               netlink_setup_proxy_neigh(addr6, iface, false);
                                setup_route(addr6, iface, false);
                                dump_neigh_table(false);
                        }