]> git.decadent.org.uk Git - odhcp6c.git/blobdiff - src/ra.c
Whitespace fixes
[odhcp6c.git] / src / ra.c
index c8ccb888f8856172ff58f280625b5005b61ab356..ceded54ab9340c90be76b19b3802c0bad576bfa9 100644 (file)
--- a/src/ra.c
+++ b/src/ra.c
@@ -59,13 +59,23 @@ int ra_init(const char *ifname, const struct in6_addr *ifid)
 {
        const pid_t ourpid = getpid();
        sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
+       if (sock < 0)
+               return -1;
+
        if_index = if_nametoindex(ifname);
+       if (!if_index)
+               return -1;
+
        strncpy(if_name, ifname, sizeof(if_name) - 1);
        lladdr = *ifid;
 
        rtnl = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
+       if (rtnl < 0)
+               return -1;
+
        struct sockaddr_nl rtnl_kernel = { .nl_family = AF_NETLINK };
-       connect(rtnl, (const struct sockaddr*)&rtnl_kernel, sizeof(rtnl_kernel));
+       if (connect(rtnl, (const struct sockaddr*)&rtnl_kernel, sizeof(rtnl_kernel)) < 0)
+               return -1;
 
        int val = RTNLGRP_LINK;
        setsockopt(rtnl, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &val, sizeof(val));
@@ -185,6 +195,32 @@ bool ra_link_up(void)
        return ret;
 }
 
+static bool ra_icmpv6_valid(struct sockaddr_in6 *source, int hlim, uint8_t *data, size_t len)
+{
+       struct icmp6_hdr *hdr = (struct icmp6_hdr*)data;
+       struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len];
+
+       if (hlim != 255 || len < sizeof(*hdr) || hdr->icmp6_code)
+               return false;
+
+       switch (hdr->icmp6_type) {
+       case ND_ROUTER_ADVERT:
+               if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr))
+                       return false;
+
+               opt = (struct icmpv6_opt*)((struct nd_router_advert*)data + 1);
+               break;
+
+       default:
+               return false;
+       }
+
+       icmpv6_for_each_option(opt, opt, end)
+               ;
+
+       return opt == end;
+}
+
 bool ra_process(void)
 {
        bool found = false;
@@ -216,10 +252,8 @@ bool ra_process(void)
                                cmsg_buf, sizeof(cmsg_buf), 0};
 
                ssize_t len = recvmsg(sock, &msg, MSG_DONTWAIT);
-               if (len < 0)
+               if (len <= 0)
                        break;
-               else if (len < (ssize_t)sizeof(*adv))
-                       continue;
 
                int hlim = 0;
                for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL;
@@ -228,7 +262,7 @@ bool ra_process(void)
                                        ch->cmsg_type == IPV6_HOPLIMIT)
                                memcpy(&hlim, CMSG_DATA(ch), sizeof(hlim));
 
-               if (hlim != 255)
+               if (!ra_icmpv6_valid(&from, hlim, buf, len))
                        continue;
 
                // Stop sending solicits
@@ -254,6 +288,10 @@ bool ra_process(void)
                entry.preferred = entry.valid;
                changed |= odhcp6c_update_entry(STATE_RA_ROUTE, &entry);
 
+               // Parse hoplimit
+               if (adv->nd_ra_curhoplimit)
+                       update_proc("conf", "hop_limit", adv->nd_ra_curhoplimit);
+
                // Parse ND parameters
                if (ntohl(adv->nd_ra_reachable) <= 3600000)
                        update_proc("neigh", "base_reachable_time_ms", ntohl(adv->nd_ra_reachable));