{
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));
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;
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;
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
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));