summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2014-04-05 18:32:40 +0000
committermarcel <marcel@FreeBSD.org>2014-04-05 18:32:40 +0000
commit2688b2b8a5002b6963d98e63bdda572263b02f31 (patch)
tree0d8cf8cca7ea8c7549da9492eadaa32686f3e409
parent444c6d535441b4e9fa84e03b16c59fd1345459b8 (diff)
downloadFreeBSD-src-2688b2b8a5002b6963d98e63bdda572263b02f31.zip
FreeBSD-src-2688b2b8a5002b6963d98e63bdda572263b02f31.tar.gz
Accept RFC 2292 option values so that RFC 2292 compliant programs that
are unaware of RFC 3542 can construct control messages. The kernel disallows mixing RFC 2292 behaviour with RFC 3542 behaviour. Only sockets that have specifically been marked as using the RFC 2292 API can use RFC 2292 specific options. This is all good and well, but libc itself seems inconsistent with this. The root cause of this inconsistency seems to relate to the definitions of IPV6_HOPOPTS and IPV6_DSTOPTS. They are defined in RFC 2292 and re-used in RFC 3542, yet have distinct values in the kernel. It's for this reason that the kernel also has definitions for IPV6_2292HOPOPTS and IPV6_2292DSTOPTS. Not so in libc. For example: some program calls inet6_option_init() (defined by RFC 2292) with the RFC 2292 defined IPV6_HOPOPTS and IPV6_DSTOPTS. Before RFC 3542, this was translated to values of 22 and 23 (resp.) The libc implementation correctly checks that only options IPV6_HOPOPTS and IPV6_DSTOPTS are given (as per RFC 2292) but since these defines have taken on the values defined by RFC 3542 (values 49 and 50 resp,) rejects the correct option values (22 and 23) passed said program and returns -1. The precisie fix is to have inet6_option_init() and friends only accept the RFC 2292 defined IPV6_HOPOPTS & IPV6_DSTOPTS, but that breaks other code (like mld6query(8)), which seem to not be aware of RFC 3542 and how it hi-jacked the option names. So the best fix is to accept the options from both. Obtained from: Juniper Networks, Inc. MFC after: 1 week
-rw-r--r--lib/libc/net/ip6opt.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c
index e39808c..a467758 100644
--- a/lib/libc/net/ip6opt.c
+++ b/lib/libc/net/ip6opt.c
@@ -45,6 +45,18 @@ __FBSDID("$FreeBSD$");
static int ip6optlen(u_int8_t *opt, u_int8_t *lim);
static void inet6_insert_padopt(u_char *p, int len);
+#ifndef IPV6_2292HOPOPTS
+#define IPV6_2292HOPOPTS 22
+#endif
+#ifndef IPV6_2292DSTOPTS
+#define IPV6_2292DSTOPTS 23
+#endif
+
+#define is_ipv6_hopopts(x) \
+ ((x) == IPV6_HOPOPTS || (x) == IPV6_2292HOPOPTS)
+#define is_ipv6_dstopts(x) \
+ ((x) == IPV6_DSTOPTS || (x) == IPV6_2292DSTOPTS)
+
/*
* This function returns the number of bytes required to hold an option
* when it is stored as ancillary data, including the cmsghdr structure
@@ -72,9 +84,9 @@ inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type)
struct cmsghdr *ch = (struct cmsghdr *)bp;
/* argument validation */
- if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
+ if (!is_ipv6_hopopts(type) && !is_ipv6_dstopts(type))
return(-1);
-
+
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = type;
ch->cmsg_len = CMSG_LEN(0);
@@ -234,8 +246,8 @@ inet6_option_next(const struct cmsghdr *cmsg, u_int8_t **tptrp)
u_int8_t *lim;
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
- (cmsg->cmsg_type != IPV6_HOPOPTS &&
- cmsg->cmsg_type != IPV6_DSTOPTS))
+ (!is_ipv6_hopopts(cmsg->cmsg_type) &&
+ !is_ipv6_dstopts(cmsg->cmsg_type)))
return(-1);
/* message length validation */
@@ -290,8 +302,8 @@ inet6_option_find(const struct cmsghdr *cmsg, u_int8_t **tptrp, int type)
u_int8_t *optp, *lim;
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
- (cmsg->cmsg_type != IPV6_HOPOPTS &&
- cmsg->cmsg_type != IPV6_DSTOPTS))
+ (!is_ipv6_hopopts(cmsg->cmsg_type) &&
+ !is_ipv6_dstopts(cmsg->cmsg_type)))
return(-1);
/* message length validation */
OpenPOWER on IntegriCloud