summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordd193516 <none@none>2006-05-17 16:43:08 -0700
committerdd193516 <none@none>2006-05-17 16:43:08 -0700
commitb94bb0f0e78c11b6013e1a33c11fd73901947bfc (patch)
treeaf2f1566808ba423371b1f4a361c6f041e284562
parent43fb4b48d7d5ba4ce77cb215445844e34af5848b (diff)
downloadillumos-joyent-b94bb0f0e78c11b6013e1a33c11fd73901947bfc.tar.gz
6204066 Neighbor Solicitation w/ SRC=::, DST=all-nodes-multicast should be ignored during DAD
6281202 Neighbor Solicitation w/ SRC=:: and SLLA option should be ignored during DAD
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/dupl_addr.c49
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/dupl_addr.c51
-rw-r--r--usr/src/uts/common/inet/ip/ip_ndp.c14
-rw-r--r--usr/src/uts/common/netinet/in.h22
4 files changed, 91 insertions, 45 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/dupl_addr.c b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/dupl_addr.c
index 937546d1d7..8c81c13901 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/dupl_addr.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/dupl_addr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -58,8 +57,8 @@ static int send_dad_probe(int s, char *phyname,
struct sockaddr_in6 *solicited_mc);
static int recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr,
int ifindex);
-static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen,
- struct sockaddr_in6 *from);
+static boolean_t verify_opts(struct nd_opt_hdr *opt, int optlen,
+ struct sockaddr_in6 *from, boolean_t reject_dad_slla);
static void dad_failed(char *phyname, struct sockaddr_in6 *testaddr,
int code);
static void print_na(char *str, char *phyname,
@@ -312,8 +311,9 @@ run_dad(int s, char *phyname, struct sockaddr_in6 *testaddr,
while (1) {
(void) gettimeofday(&curtime, NULL);
time_left = RetransTimer -
- (curtime.tv_sec - starttime.tv_sec) * 1000 -
- (curtime.tv_usec - starttime.tv_usec) / 1000;
+ (curtime.tv_sec - starttime.tv_sec) * 1000 -
+ (curtime.tv_usec - starttime.tv_usec) / 1000;
+
if (debug & D_DAD) {
logmsg(LOG_DEBUG, "run_dad: time_left %d ms\n",
@@ -556,14 +556,22 @@ recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr, int ifindex)
}
if (len > sizeof (struct nd_neighbor_solicit)) {
- if (!verify_opt_len((struct nd_opt_hdr *)&ns[1],
- len - sizeof (struct nd_neighbor_solicit), &from))
+ /*
+ * For DAD neighbor solicitation type message,
+ * we need to further verify if SLLA option is present
+ * in received options,
+ * so we pass TRUE to reject_dad_slla argument.
+ */
+ if (!verify_opts((struct nd_opt_hdr *)&ns[1],
+ len - sizeof (struct nd_neighbor_solicit),
+ &from, _B_TRUE))
return (0);
}
if (debug & D_DAD)
print_ns("Received valid NS", phyname, ns, len, &from);
- if (!IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
+ if (!IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ||
+ !IN6_IS_ADDR_MC_SOLICITEDNODE(&dst)) {
/* Sender is doing address resolution */
return (0);
}
@@ -642,8 +650,14 @@ recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr, int ifindex)
}
if (len > sizeof (struct nd_neighbor_advert)) {
- if (!verify_opt_len((struct nd_opt_hdr *)&na[1],
- len - sizeof (struct nd_neighbor_advert), &from))
+ /*
+ * Since this is a Neighbor advertisement
+ * we unset the reject_dad_slla flag, thus
+ * there is no need to verify the SLLA options.
+ */
+ if (!verify_opts((struct nd_opt_hdr *)&na[1],
+ len - sizeof (struct nd_neighbor_advert),
+ &from, _B_FALSE))
return (0);
}
@@ -667,9 +681,12 @@ recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr, int ifindex)
/*
* Verify that all options have a non-zero length and that
* the options fit within the total length of the packet (optlen).
+ * If reject_dad_slla is set, we also verify that no SLLA option is present
+ * as mandated by section 7.1.1 of RFC 2461.
*/
static boolean_t
-verify_opt_len(struct nd_opt_hdr *opt, int optlen, struct sockaddr_in6 *from)
+verify_opts(struct nd_opt_hdr *opt, int optlen, struct sockaddr_in6 *from,
+ boolean_t reject_dad_slla)
{
while (optlen > 0) {
if (opt->nd_opt_len == 0) {
@@ -700,6 +717,10 @@ verify_opt_len(struct nd_opt_hdr *opt, int optlen, struct sockaddr_in6 *from)
}
return (_B_FALSE);
}
+ if (reject_dad_slla &&
+ opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR) {
+ return (_B_FALSE);
+ }
opt = (struct nd_opt_hdr *)((char *)opt +
8 * opt->nd_opt_len);
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/dupl_addr.c b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/dupl_addr.c
index 27d74f788a..3fc32c67a7 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/dupl_addr.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/dupl_addr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,10 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1995-1999 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
-
/*
* Perform IPv6 duplicate address detection for a given interface
* and IPv6 address.
@@ -56,8 +54,8 @@ static int send_dad_probe(int s, char *phyname,
struct sockaddr_in6 *solicited_mc);
static int recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr,
int ifindex);
-static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen,
- struct sockaddr_in6 *from);
+static boolean_t verify_opts(struct nd_opt_hdr *opt, int optlen,
+ struct sockaddr_in6 *from, boolean_t reject_dad_slla);
static void dad_failed(char *phyname, struct sockaddr_in6 *testaddr,
int code);
static void print_na(char *str, char *phyname,
@@ -314,8 +312,8 @@ run_dad(int s, char *phyname, struct sockaddr_in6 *testaddr,
while (1) {
(void) gettimeofday(&curtime, NULL);
time_left = RetransTimer -
- (curtime.tv_sec - starttime.tv_sec) * 1000 -
- (curtime.tv_usec - starttime.tv_usec) / 1000;
+ (curtime.tv_sec - starttime.tv_sec) * 1000 -
+ (curtime.tv_usec - starttime.tv_usec) / 1000;
if (debug) {
(void) printf("run_dad: time_left %d ms\n",
@@ -561,14 +559,22 @@ recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr, int ifindex)
}
if (len > sizeof (struct nd_neighbor_solicit)) {
- if (!verify_opt_len((struct nd_opt_hdr *)&ns[1],
- len - sizeof (struct nd_neighbor_solicit), &from))
+ /*
+ * For DAD type neighbor solicitation message,
+ * we need to further verify if SLLA option is present
+ * in received options,
+ * so we pass TRUE to reject_dad_slla argument.
+ */
+ if (!verify_opts((struct nd_opt_hdr *)&ns[1],
+ len - sizeof (struct nd_neighbor_solicit),
+ &from, _B_TRUE))
return (0);
}
if (debug)
print_ns("Received valid NS", phyname, ns, len, &from);
- if (!IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
+ if (!IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ||
+ !IN6_IS_ADDR_MC_SOLICITEDNODE(&dst)) {
/* Sender is doing address resolution */
return (0);
}
@@ -653,8 +659,14 @@ recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr, int ifindex)
}
if (len > sizeof (struct nd_neighbor_advert)) {
- if (!verify_opt_len((struct nd_opt_hdr *)&na[1],
- len - sizeof (struct nd_neighbor_advert), &from))
+ /*
+ * Since this is a Neighbor advertisement
+ * we unset the reject_dad_slla flag, thus
+ * there is no need to verify the SLLA options.
+ */
+ if (!verify_opts((struct nd_opt_hdr *)&na[1],
+ len - sizeof (struct nd_neighbor_advert),
+ &from, _B_FALSE))
return (0);
}
@@ -679,9 +691,12 @@ recv_dad(int s, char *phyname, struct sockaddr_in6 *testaddr, int ifindex)
/*
* Verify that all options have a non-zero length and that
* the options fit within the total length of the packet (optlen).
+ * If reject_dad_slla is set, then we also verify that no SLLA option is
+ * present as mandated by section 7.1.1 of RFC 2461.
*/
static boolean_t
-verify_opt_len(struct nd_opt_hdr *opt, int optlen, struct sockaddr_in6 *from)
+verify_opts(struct nd_opt_hdr *opt, int optlen, struct sockaddr_in6 *from,
+ boolean_t reject_dad_slla)
{
while (optlen > 0) {
if (opt->nd_opt_len == 0) {
@@ -715,6 +730,10 @@ verify_opt_len(struct nd_opt_hdr *opt, int optlen, struct sockaddr_in6 *from)
}
return (_B_FALSE);
}
+ if (reject_dad_slla &&
+ opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR) {
+ return (_B_FALSE);
+ }
opt = (struct nd_opt_hdr *)((char *)opt +
8 * opt->nd_opt_len);
}
diff --git a/usr/src/uts/common/inet/ip/ip_ndp.c b/usr/src/uts/common/inet/ip/ip_ndp.c
index c52881ca8d..626e8bea53 100644
--- a/usr/src/uts/common/inet/ip/ip_ndp.c
+++ b/usr/src/uts/common/inet/ip/ip_ndp.c
@@ -100,20 +100,6 @@ static int ndp_g_walker = 0; /* # of active thread */
/* ndp_g_walker_cleanup will be true, when deletion have to be defered */
static boolean_t ndp_g_walker_cleanup = B_FALSE;
-#ifdef _BIG_ENDIAN
-#define IN6_IS_ADDR_MC_SOLICITEDNODE(addr) \
- ((((addr)->s6_addr32[0] & 0xff020000) == 0xff020000) && \
- ((addr)->s6_addr32[1] == 0x0) && \
- ((addr)->s6_addr32[2] == 0x00000001) && \
- ((addr)->s6_addr32[3] & 0xff000000) == 0xff000000)
-#else /* _BIG_ENDIAN */
-#define IN6_IS_ADDR_MC_SOLICITEDNODE(addr) \
- ((((addr)->s6_addr32[0] & 0x000002ff) == 0x000002ff) && \
- ((addr)->s6_addr32[1] == 0x0) && \
- ((addr)->s6_addr32[2] == 0x01000000) && \
- ((addr)->s6_addr32[3] & 0x000000ff) == 0x000000ff)
-#endif
-
#define NCE_HASH_PTR(addr) \
(&(nce_hash_tbl[NCE_ADDR_HASH_V6(addr, NCE_TABLE_SIZE)]))
diff --git a/usr/src/uts/common/netinet/in.h b/usr/src/uts/common/netinet/in.h
index 7bed8be4b9..f6284c4882 100644
--- a/usr/src/uts/common/netinet/in.h
+++ b/usr/src/uts/common/netinet/in.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
@@ -603,6 +603,26 @@ struct sockaddr_in6 {
#endif /* _BIG_ENDIAN */
/*
+ * The IN6_IS_ADDR_MC_SOLICITEDNODE macro is not defined in any standard or
+ * RFC, and shouldn't be used by portable applications. It is used to see
+ * if an address is a solicited-node multicast address, which is prefixed
+ * with ff02:0:0:0:0:1:ff00::/104.
+ */
+#ifdef _BIG_ENDIAN
+#define IN6_IS_ADDR_MC_SOLICITEDNODE(addr) \
+ (((addr)->_S6_un._S6_u32[0] == 0xff020000) && \
+ ((addr)->_S6_un._S6_u32[1] == 0x00000000) && \
+ ((addr)->_S6_un._S6_u32[2] == 0x00000001) && \
+ (((addr)->_S6_un._S6_u32[3] & 0xff000000) == 0xff000000))
+#else
+#define IN6_IS_ADDR_MC_SOLICITEDNODE(addr) \
+ (((addr)->_S6_un._S6_u32[0] == 0x000002ff) && \
+ ((addr)->_S6_un._S6_u32[1] == 0x00000000) && \
+ ((addr)->_S6_un._S6_u32[2] == 0x01000000) && \
+ (((addr)->_S6_un._S6_u32[3] & 0x000000ff) == 0x000000ff))
+#endif
+
+/*
* Macros to a) test for 6to4 IPv6 address, and b) to test if two
* 6to4 addresses have the same /48 prefix, and, hence, are from the
* same 6to4 site.