summaryrefslogtreecommitdiff
path: root/src/ra.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2013-12-24 17:22:05 +0100
committerHans Dedecker <dedeckeh@gmail.com>2013-12-24 17:22:05 +0100
commit1339588a2a1143e4029a9e7558130c9b17fd6a3e (patch)
treee37ecd3a6016ebe439a5c193a278e36f0268e7ec /src/ra.c
parent9c8875f568caade53069b10790f02364ffc007a6 (diff)
downloadodhcp6c-1339588a2a1143e4029a9e7558130c9b17fd6a3e.tar.gz
Add ICMPv6 validity check
Diffstat (limited to 'src/ra.c')
-rw-r--r--src/ra.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/src/ra.c b/src/ra.c
index de21710..58c8741 100644
--- a/src/ra.c
+++ b/src/ra.c
@@ -195,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;
@@ -226,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;
@@ -238,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