diff options
author | dd193516 <none@none> | 2006-05-17 16:43:08 -0700 |
---|---|---|
committer | dd193516 <none@none> | 2006-05-17 16:43:08 -0700 |
commit | b94bb0f0e78c11b6013e1a33c11fd73901947bfc (patch) | |
tree | af2f1566808ba423371b1f4a361c6f041e284562 | |
parent | 43fb4b48d7d5ba4ce77cb215445844e34af5848b (diff) | |
download | illumos-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.c | 49 | ||||
-rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/ifconfig/dupl_addr.c | 51 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip_ndp.c | 14 | ||||
-rw-r--r-- | usr/src/uts/common/netinet/in.h | 22 |
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. |