X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=src%2Fra.c;h=58c87417e2929ca91ee0cd23403462b05d44c2db;hb=68ac18ed5d5b4c2d403396764f08c92a160b4a18;hp=aa03ff4d3ab8f6235b38aa8f069c785d3486a10e;hpb=4a9de784477a0f0dbc04ff890e35adae02ee6e8b;p=odhcp6c.git diff --git a/src/ra.c b/src/ra.c index aa03ff4..58c8741 100644 --- 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)); @@ -150,6 +160,7 @@ static void update_proc(const char *sect, const char *opt, uint32_t value) bool ra_link_up(void) { + static bool firstcall = true; struct { struct nlmsghdr hdr; struct ifinfomsg msg; @@ -161,19 +172,22 @@ bool ra_link_up(void) do { read = recv(rtnl, &resp, sizeof(resp), MSG_DONTWAIT); - if (!NLMSG_OK(&resp.hdr, read) || resp.hdr.nlmsg_type != RTM_NEWLINK || + if (read < 0 || !NLMSG_OK(&resp.hdr, (size_t)read) || + resp.hdr.nlmsg_type != RTM_NEWLINK || resp.msg.ifi_index != if_index) continue; bool hascarrier = resp.msg.ifi_flags & IFF_LOWER_UP; - if (nocarrier && hascarrier) + if (!firstcall && nocarrier != !hascarrier) ret = true; nocarrier = !hascarrier; + firstcall = false; } while (read > 0); if (ret) { - syslog(LOG_NOTICE, "carrier up event on %s", if_name); + syslog(LOG_NOTICE, "carrier => %i event on %s", (int)!nocarrier, if_name); + rs_attempt = 0; ra_send_rs(SIGALRM); } @@ -181,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; @@ -212,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; @@ -224,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 @@ -250,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));