implemented more validation checks about incoming responses per RFC2080, and one additional heuristic check for safer operation.
Obtained from: KAME MFC after: 1 week
This commit is contained in:
parent
3bea4efeb1
commit
5e5792a887
@ -656,6 +656,20 @@ init()
|
|||||||
}
|
}
|
||||||
#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));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_family = PF_INET6;
|
hints.ai_family = PF_INET6;
|
||||||
hints.ai_socktype = SOCK_DGRAM;
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
@ -1082,7 +1096,8 @@ riprecv()
|
|||||||
struct cmsghdr *cm;
|
struct cmsghdr *cm;
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
u_char cmsgbuf[256];
|
u_char cmsgbuf[256];
|
||||||
struct in6_pktinfo *pi;
|
struct in6_pktinfo *pi = NULL;
|
||||||
|
int *hlimp = NULL;
|
||||||
struct iff *iffp;
|
struct iff *iffp;
|
||||||
struct in6_addr ia;
|
struct in6_addr ia;
|
||||||
int ok;
|
int ok;
|
||||||
@ -1107,11 +1122,26 @@ riprecv()
|
|||||||
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
|
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
|
||||||
cm;
|
cm;
|
||||||
cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
|
cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
|
||||||
if (cm->cmsg_level == IPPROTO_IPV6 &&
|
if (cm->cmsg_level != IPPROTO_IPV6)
|
||||||
cm->cmsg_type == IPV6_PKTINFO) {
|
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));
|
pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
|
||||||
idx = pi->ipi6_ifindex;
|
idx = pi->ipi6_ifindex;
|
||||||
break;
|
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))
|
if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr))
|
||||||
@ -1122,6 +1152,18 @@ riprecv()
|
|||||||
return;
|
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;
|
nh = fsock.sin6_addr;
|
||||||
nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
|
nn = (len - sizeof(struct rip6) + sizeof(struct netinfo6)) /
|
||||||
sizeof(struct netinfo6);
|
sizeof(struct netinfo6);
|
||||||
@ -1143,10 +1185,42 @@ riprecv()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) {
|
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));
|
inet6_n2p(&fsock.sin6_addr));
|
||||||
return; /* Ignore packets from non-link-local 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);
|
idx = IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr);
|
||||||
ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
|
ifcp = (idx < nindex2ifc) ? index2ifc[idx] : NULL;
|
||||||
if (!ifcp) {
|
if (!ifcp) {
|
||||||
|
Loading…
Reference in New Issue
Block a user