Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys nd6: add a nonce to DaD probes in-case they are looped b...
details: https://anonhg.NetBSD.org/src/rev/f5403f29b242
branches: trunk
changeset: 321206:f5403f29b242
user: roy <roy%NetBSD.org@localhost>
date: Tue Mar 06 10:57:00 2018 +0000
description:
nd6: add a nonce to DaD probes in-case they are looped back to us
This implements RFC 7527, based a similar change in FreeBSD.
diffstat:
sys/netinet/icmp6.h | 14 +++++-
sys/netinet6/nd6.c | 9 ++-
sys/netinet6/nd6.h | 17 +++++-
sys/netinet6/nd6_nbr.c | 120 +++++++++++++++++++++++++++++++++++-------------
4 files changed, 118 insertions(+), 42 deletions(-)
diffs (truncated from 415 to 300 lines):
diff -r 2497a32bfba2 -r f5403f29b242 sys/netinet/icmp6.h
--- a/sys/netinet/icmp6.h Tue Mar 06 10:07:06 2018 +0000
+++ b/sys/netinet/icmp6.h Tue Mar 06 10:57:00 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: icmp6.h,v 1.49 2018/01/23 10:55:38 maxv Exp $ */
+/* $NetBSD: icmp6.h,v 1.50 2018/03/06 10:57:00 roy Exp $ */
/* $KAME: icmp6.h,v 1.84 2003/04/23 10:26:51 itojun Exp $ */
@@ -305,10 +305,12 @@
#define ND_OPT_HOMEAGENT_INFO 8
#define ND_OPT_SOURCE_ADDRLIST 9
#define ND_OPT_TARGET_ADDRLIST 10
+#define ND_OPT_NONCE 14 /* RFC 3971 */
#define ND_OPT_MAP 23 /* RFC 5380 */
#define ND_OPT_ROUTE_INFO 24 /* RFC 4191 */
#define ND_OPT_RDNSS 25 /* RFC 6016 */
#define ND_OPT_DNSSL 31 /* RFC 6016 */
+#define ND_OPT_MAX 31
struct nd_opt_route_info { /* route info */
u_int8_t nd_opt_rti_type;
@@ -348,6 +350,16 @@
u_int32_t nd_opt_mtu_mtu;
} __packed;
+#define ND_OPT_NONCE_LEN ((1 * 8) - 2)
+#if ((ND_OPT_NONCE_LEN + 2) % 8) != 0
+#error "(ND_OPT_NONCE_LEN + 2) must be a multiple of 8."
+#endif
+struct nd_opt_nonce {
+ u_int8_t nd_opt_nonce_type;
+ u_int8_t nd_opt_nonce_len;
+ u_int8_t nd_opt_nonce[ND_OPT_NONCE_LEN];
+} __packed;
+
struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
u_int8_t nd_opt_rdnss_type;
u_int8_t nd_opt_rdnss_len;
diff -r 2497a32bfba2 -r f5403f29b242 sys/netinet6/nd6.c
--- a/sys/netinet6/nd6.c Tue Mar 06 10:07:06 2018 +0000
+++ b/sys/netinet6/nd6.c Tue Mar 06 10:57:00 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nd6.c,v 1.246 2018/03/06 07:24:01 ozaki-r Exp $ */
+/* $NetBSD: nd6.c,v 1.247 2018/03/06 10:57:00 roy Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.246 2018/03/06 07:24:01 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.247 2018/03/06 10:57:00 roy Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -347,6 +347,7 @@
case ND_OPT_TARGET_LINKADDR:
case ND_OPT_MTU:
case ND_OPT_REDIRECTED_HEADER:
+ case ND_OPT_NONCE:
if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
nd6log(LOG_INFO,
"duplicated ND6 option found (type=%d)\n",
@@ -554,7 +555,7 @@
psrc = nd6_llinfo_get_holdsrc(ln, &src);
LLE_FREE_LOCKED(ln);
ln = NULL;
- nd6_ns_output(ifp, daddr6, taddr6, psrc, 0);
+ nd6_ns_output(ifp, daddr6, taddr6, psrc, NULL);
}
out:
@@ -2420,7 +2421,7 @@
psrc = nd6_llinfo_get_holdsrc(ln, &src);
LLE_WUNLOCK(ln);
ln = NULL;
- nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, 0);
+ nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL);
} else {
/* We did the lookup so we need to do the unlock here. */
LLE_WUNLOCK(ln);
diff -r 2497a32bfba2 -r f5403f29b242 sys/netinet6/nd6.h
--- a/sys/netinet6/nd6.h Tue Mar 06 10:07:06 2018 +0000
+++ b/sys/netinet6/nd6.h Tue Mar 06 10:57:00 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nd6.h,v 1.85 2017/06/22 09:24:02 ozaki-r Exp $ */
+/* $NetBSD: nd6.h,v 1.86 2018/03/06 10:57:00 roy Exp $ */
/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */
/*
@@ -397,7 +397,7 @@
extern int nd6_numroutes;
union nd_opts {
- struct nd_opt_hdr *nd_opt_array[8];
+ struct nd_opt_hdr *nd_opt_array[16]; /* max = ND_OPT_NONCE */
struct {
struct nd_opt_hdr *zero;
struct nd_opt_hdr *src_lladdr;
@@ -405,6 +405,16 @@
struct nd_opt_prefix_info *pi_beg; /* multiple opts, start */
struct nd_opt_rd_hdr *rh;
struct nd_opt_mtu *mtu;
+ struct nd_opt_hdr *__res6;
+ struct nd_opt_hdr *__res7;
+ struct nd_opt_hdr *__res8;
+ struct nd_opt_hdr *__res9;
+ struct nd_opt_hdr *__res10;
+ struct nd_opt_hdr *__res11;
+ struct nd_opt_hdr *__res12;
+ struct nd_opt_hdr *__res13;
+ struct nd_opt_nonce *nonce;
+ struct nd_opt_hdr *__res15;
struct nd_opt_hdr *search; /* multiple opts */
struct nd_opt_hdr *last; /* multiple opts */
int done;
@@ -417,6 +427,7 @@
#define nd_opts_pi_end nd_opt_each.pi_end
#define nd_opts_rh nd_opt_each.rh
#define nd_opts_mtu nd_opt_each.mtu
+#define nd_opts_nonce nd_opt_each.nonce
#define nd_opts_search nd_opt_each.search
#define nd_opts_last nd_opt_each.last
#define nd_opts_done nd_opt_each.done
@@ -454,7 +465,7 @@
const struct in6_addr *, u_long, int, const struct sockaddr *);
void nd6_ns_input(struct mbuf *, int, int);
void nd6_ns_output(struct ifnet *, const struct in6_addr *,
- const struct in6_addr *, struct in6_addr *, int);
+ const struct in6_addr *, struct in6_addr *, uint8_t *);
const void *nd6_ifptomac(const struct ifnet *);
void nd6_dad_start(struct ifaddr *, int);
void nd6_dad_stop(struct ifaddr *);
diff -r 2497a32bfba2 -r f5403f29b242 sys/netinet6/nd6_nbr.c
--- a/sys/netinet6/nd6_nbr.c Tue Mar 06 10:07:06 2018 +0000
+++ b/sys/netinet6/nd6_nbr.c Tue Mar 06 10:57:00 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nd6_nbr.c,v 1.148 2018/02/24 07:53:15 ozaki-r Exp $ */
+/* $NetBSD: nd6_nbr.c,v 1.149 2018/03/06 10:57:00 roy Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.148 2018/02/24 07:53:15 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.149 2018/03/06 10:57:00 roy Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -52,6 +52,7 @@
#include <sys/syslog.h>
#include <sys/queue.h>
#include <sys/callout.h>
+#include <sys/cprng.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -77,16 +78,15 @@
#include <net/net_osdep.h>
struct dadq;
-static struct dadq *nd6_dad_find(struct ifaddr *);
+static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *);
static void nd6_dad_starttimer(struct dadq *, int);
static void nd6_dad_destroytimer(struct dadq *);
static void nd6_dad_timer(struct dadq *);
static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
-static void nd6_dad_ns_input(struct ifaddr *);
+static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *);
static void nd6_dad_na_input(struct ifaddr *);
static void nd6_dad_duplicated(struct dadq *);
-static int dad_ignore_ns = 0; /* ignore NS in DAD - specwise incorrect*/
static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */
/*
@@ -309,7 +309,7 @@
* silently ignore it.
*/
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
- nd6_dad_ns_input(ifa);
+ nd6_dad_ns_input(ifa, ndopts.nd_opts_nonce);
ifa_release(ifa, &psref_ia);
ifa = NULL;
@@ -374,7 +374,7 @@
nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
const struct in6_addr *taddr6,
struct in6_addr *hsrc,
- int dad /* duplicate address detection */)
+ uint8_t *nonce /* duplicate address detection */)
{
struct mbuf *m;
struct ip6_hdr *ip6;
@@ -441,7 +441,7 @@
if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
goto bad;
}
- if (!dad) {
+ if (nonce == NULL) {
int s;
/*
* RFC2461 7.2.2:
@@ -512,7 +512,7 @@
* Multicast NS MUST add one add the option
* Unicast NS SHOULD add one add the option
*/
- if (!dad && (mac = nd6_ifptomac(ifp))) {
+ if (nonce == NULL && (mac = nd6_ifptomac(ifp))) {
int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
/* 8 byte alignments... */
@@ -527,12 +527,30 @@
memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen);
}
+ /* Add a nonce option (RFC 3971) to detect looped back NS messages.
+ * This behavior is documented in RFC 7527. */
+ if (nonce != NULL) {
+ int optlen = sizeof(struct nd_opt_hdr) + ND_OPT_NONCE_LEN;
+ struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
+
+ /* 8-byte alignment is required. */
+ optlen = (optlen + 7) & ~7;
+ m->m_pkthdr.len += optlen;
+ m->m_len += optlen;
+ icmp6len += optlen;
+ memset(nd_opt, 0, optlen);
+ nd_opt->nd_opt_type = ND_OPT_NONCE;
+ nd_opt->nd_opt_len = optlen >> 3;
+ memcpy(nd_opt + 1, nonce, ND_OPT_NONCE_LEN);
+ }
+
ip6->ip6_plen = htons((u_int16_t)icmp6len);
nd_ns->nd_ns_cksum = 0;
nd_ns->nd_ns_cksum =
in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
- ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL);
+ ip6_output(m, NULL, &ro, nonce != NULL ? IPV6_UNSPECSRC : 0,
+ &im6o, NULL, NULL);
icmp6_ifstat_inc(ifp, ifs6_out_msg);
icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_SOLICIT);
@@ -1055,12 +1073,24 @@
struct dadq {
TAILQ_ENTRY(dadq) dad_list;
struct ifaddr *dad_ifa;
- int dad_count; /* max NS to send */
- int dad_ns_tcount; /* # of trials to send NS */
- int dad_ns_ocount; /* NS sent so far */
+ int dad_count; /* max NS to send */
+ int dad_ns_tcount; /* # of trials to send NS */
+ int dad_ns_ocount; /* NS sent so far */
int dad_ns_icount;
int dad_na_icount;
+ int dad_ns_lcount; /* looped back NS */
struct callout dad_timer_ch;
+#define ND_OPT_NONCE_STORE 3 /* dad_count should not exceed this */
+ /*
+ * The default ip6_dad_count is 1 as specified by RFC 4862 and
+ * practically must users won't exceed this.
+ * A storage of 3 is defaulted to here, in-case the administrator wants
+ * to match the equivalent behaviour in our ARP implementation.
+ * This constraint could be removed by sending the on wire nonce as
+ * hmac(key, dad_ns_ocount), but that would increase the nonce size
+ * sent on the wire.
+ */
+ uint8_t dad_nonce[ND_OPT_NONCE_STORE][ND_OPT_NONCE_LEN];
};
static struct dadq_head dadq;
@@ -1068,17 +1098,42 @@
static kmutex_t nd6_dad_lock;
static struct dadq *
-nd6_dad_find(struct ifaddr *ifa)
+nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *nonce)
{
struct dadq *dp;
+ int i, nonce_max;
KASSERT(mutex_owned(&nd6_dad_lock));
TAILQ_FOREACH(dp, &dadq, dad_list) {
- if (dp->dad_ifa == ifa)
- return dp;
+ if (dp->dad_ifa != ifa)
+ continue;
+
+ if (nonce == NULL ||
+ nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8)
+ break;
+
+ nonce_max = MIN(dp->dad_ns_ocount, ND_OPT_NONCE_STORE);
+ for (i = 0; i < nonce_max; i++) {
Home |
Main Index |
Thread Index |
Old Index