diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2006-11-15 07:32:45 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2006-11-15 07:32:45 +0000 |
commit | 25fdb1912ca9ed97492e40e08ff71d13986957fe (patch) | |
tree | 3be19deb684167a93a9135e62169f1507c6de4f4 /usr.sbin/route6d | |
parent | 6b4f71635879a1b4d279383a12bccb3e55bbd926 (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.c | 90 |
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) { |