summaryrefslogtreecommitdiff
path: root/usr.sbin/route6d
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2006-11-15 07:32:45 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2006-11-15 07:32:45 +0000
commit25fdb1912ca9ed97492e40e08ff71d13986957fe (patch)
tree3be19deb684167a93a9135e62169f1507c6de4f4 /usr.sbin/route6d
parent6b4f71635879a1b4d279383a12bccb3e55bbd926 (diff)
validate response packet more carefully. kame revision 1.109->1.111
Diffstat (limited to 'usr.sbin/route6d')
-rw-r--r--usr.sbin/route6d/route6d.c90
1 files changed, 82 insertions, 8 deletions
diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c
index 27c39c118ff..f73ad3b6807 100644
--- a/usr.sbin/route6d/route6d.c
+++ b/usr.sbin/route6d/route6d.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: route6d.c,v 1.45 2006/06/16 13:51:21 claudio Exp $ */
-/* $KAME: route6d.c,v 1.94 2002/10/26 20:08:55 itojun Exp $ */
+/* $OpenBSD: route6d.c,v 1.46 2006/11/15 07:32:44 itojun Exp $ */
+/* $KAME: route6d.c,v 1.111 2006/10/25 06:38:13 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -31,7 +31,7 @@
*/
#if 0
-static char _rcsid[] = "$OpenBSD: route6d.c,v 1.45 2006/06/16 13:51:21 claudio Exp $";
+static char _rcsid[] = "$OpenBSD: route6d.c,v 1.46 2006/11/15 07:32:44 itojun Exp $";
#endif
#include <stdio.h>
@@ -644,7 +644,21 @@ init(void)
fatal("rip IPV6_PKTINFO");
/*NOTREACHED*/
}
-#endif
+#endif
+
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+ &int1, sizeof(int1)) < 0) {
+ fatal("rip IPV6_RECVHOPLIMIT");
+ /*NOTREACHED*/
+ }
+#else /* old adv. API */
+ if (setsockopt(ripsock, IPPROTO_IPV6, IPV6_HOPLIMIT,
+ &int1, sizeof(int1)) < 0) {
+ fatal("rip IPV6_HOPLIMIT");
+ /*NOTREACHED*/
+ }
+#endif
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_INET6;
@@ -1060,7 +1074,8 @@ riprecv(void)
struct cmsghdr *cm;
struct iovec iov[2];
u_char cmsgbuf[256];
- struct in6_pktinfo *pi;
+ struct in6_pktinfo *pi = NULL;
+ int *hlimp = NULL;
struct iff *iffp;
struct in6_addr ia;
int ok;
@@ -1085,11 +1100,26 @@ riprecv(void)
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
- if (cm->cmsg_level == IPPROTO_IPV6 &&
- cm->cmsg_type == IPV6_PKTINFO) {
+ if (cm->cmsg_level != IPPROTO_IPV6)
+ continue;
+ switch (cm->cmsg_type) {
+ case IPV6_PKTINFO:
+ if (cm->cmsg_len != CMSG_LEN(sizeof(*pi))) {
+ trace(1,
+ "invalid cmsg length for IPV6_PKTINFO\n");
+ return;
+ }
pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
idx = pi->ipi6_ifindex;
break;
+ case IPV6_HOPLIMIT:
+ if (cm->cmsg_len != CMSG_LEN(sizeof(int))) {
+ trace(1,
+ "invalid cmsg length for IPV6_HOPLIMIT\n");
+ return;
+ }
+ hlimp = (int *)CMSG_DATA(cm);
+ break;
}
}
if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
@@ -1100,6 +1130,18 @@ riprecv(void)
return;
}
+ if (pi == NULL || hlimp == NULL) {
+ /*
+ * This can happen when the kernel failed to allocate memory
+ * for the ancillary data. Although we might be able to handle
+ * some cases without this info, those are minor and not so
+ * important, so it's better to discard the packet for safer
+ * operation.
+ */
+ trace(1, "IPv6 packet information cannot be retrieved\n");
+ return;
+ }
+
nh = fsock.sin6_addr;
nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
sizeof(struct netinfo6);
@@ -1121,10 +1163,42 @@ riprecv(void)
}
if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
- trace(1, "Packets from non-ll addr: %s\n",
+ trace(1, "Response from non-ll addr: %s\n",
inet6_n2p(&fsock.sin6_addr));
return; /* Ignore packets from non-link-local addr */
}
+ if (ntohs(fsock.sin6_port) != RIP6_PORT) {
+ trace(1, "Response from non-rip port from %s\n",
+ inet6_n2p(&fsock.sin6_addr));
+ return;
+ }
+ if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && *hlimp != 255) {
+ trace(1,
+ "Response packet with a smaller hop limit (%d) from %s\n",
+ *hlimp, inet6_n2p(&fsock.sin6_addr));
+ return;
+ }
+ /*
+ * Further validation: since this program does not send off-link
+ * requests, an incoming response must always come from an on-link
+ * node. Although this is normally ensured by the source address
+ * check above, it may not 100% be safe because there are router
+ * implementations that (invalidly) allow a packet with a link-local
+ * source address to be forwarded to a different link.
+ * So we also check whether the destination address is a link-local
+ * address or the hop limit is 255. Note that RFC2080 does not require
+ * the specific hop limit for a unicast response, so we cannot assume
+ * the limitation.
+ */
+ if (!IN6_IS_ADDR_LINKLOCAL(&pi->ipi6_addr) && *hlimp != 255) {
+ trace(1,
+ "Response packet possibly from an off-link node: "
+ "from %s to %s hlim=%d\n",
+ inet6_n2p(&fsock.sin6_addr), inet6_n2p(&pi->ipi6_addr),
+ *hlimp);
+ return;
+ }
+
idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
if (!ifcp) {