Tue Oct 11 13:59:31 2016 UTC ()
Implement RFC 5227 2.4 Ongoing Conflict Detection and Address Defence.

If ip_dad_count is 0, then the conflict is just logged and the address
is not marked as duplicated.


(roy)
diff -r1.229 -r1.230 src/sys/netinet/if_arp.c
diff -r1.87 -r1.88 src/sys/netinet/in_var.h

cvs diff -r1.229 -r1.230 src/sys/netinet/if_arp.c (expand / switch to unified diff)

--- src/sys/netinet/if_arp.c 2016/10/11 12:32:30 1.229
+++ src/sys/netinet/if_arp.c 2016/10/11 13:59:30 1.230
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if_arp.c,v 1.229 2016/10/11 12:32:30 roy Exp $ */ 1/* $NetBSD: if_arp.c,v 1.230 2016/10/11 13:59:30 roy Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Public Access Networks Corporation ("Panix"). It was developed under 8 * by Public Access Networks Corporation ("Panix"). It was developed under
9 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon. 9 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -58,27 +58,27 @@ @@ -58,27 +58,27 @@
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE. 59 * SUCH DAMAGE.
60 * 60 *
61 * @(#)if_ether.c 8.2 (Berkeley) 9/26/94 61 * @(#)if_ether.c 8.2 (Berkeley) 9/26/94
62 */ 62 */
63 63
64/* 64/*
65 * Ethernet address resolution protocol. 65 * Ethernet address resolution protocol.
66 * TODO: 66 * TODO:
67 * add "inuse/lock" bit (or ref. count) along with valid bit 67 * add "inuse/lock" bit (or ref. count) along with valid bit
68 */ 68 */
69 69
70#include <sys/cdefs.h> 70#include <sys/cdefs.h>
71__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.229 2016/10/11 12:32:30 roy Exp $"); 71__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.230 2016/10/11 13:59:30 roy Exp $");
72 72
73#ifdef _KERNEL_OPT 73#ifdef _KERNEL_OPT
74#include "opt_ddb.h" 74#include "opt_ddb.h"
75#include "opt_inet.h" 75#include "opt_inet.h"
76#endif 76#endif
77 77
78#ifdef INET 78#ifdef INET
79 79
80#include "arp.h" 80#include "arp.h"
81#include "bridge.h" 81#include "bridge.h"
82 82
83#include <sys/param.h> 83#include <sys/param.h>
84#include <sys/systm.h> 84#include <sys/systm.h>
@@ -168,27 +168,27 @@ static void arp_settimer(struct llentry  @@ -168,27 +168,27 @@ static void arp_settimer(struct llentry
168static struct llentry *arplookup(struct ifnet *, struct mbuf *, 168static struct llentry *arplookup(struct ifnet *, struct mbuf *,
169 const struct in_addr *, const struct sockaddr *, int); 169 const struct in_addr *, const struct sockaddr *, int);
170static struct llentry *arpcreate(struct ifnet *, struct mbuf *, 170static struct llentry *arpcreate(struct ifnet *, struct mbuf *,
171 const struct in_addr *, const struct sockaddr *, int); 171 const struct in_addr *, const struct sockaddr *, int);
172static void in_arpinput(struct mbuf *); 172static void in_arpinput(struct mbuf *);
173static void in_revarpinput(struct mbuf *); 173static void in_revarpinput(struct mbuf *);
174static void revarprequest(struct ifnet *); 174static void revarprequest(struct ifnet *);
175 175
176static void arp_drainstub(void); 176static void arp_drainstub(void);
177 177
178static void arp_dad_timer(struct ifaddr *); 178static void arp_dad_timer(struct ifaddr *);
179static void arp_dad_start(struct ifaddr *); 179static void arp_dad_start(struct ifaddr *);
180static void arp_dad_stop(struct ifaddr *); 180static void arp_dad_stop(struct ifaddr *);
181static void arp_dad_duplicated(struct ifaddr *); 181static void arp_dad_duplicated(struct ifaddr *, const char *);
182 182
183static void arp_init_llentry(struct ifnet *, struct llentry *); 183static void arp_init_llentry(struct ifnet *, struct llentry *);
184#if NTOKEN > 0 184#if NTOKEN > 0
185static void arp_free_llentry_tokenring(struct llentry *); 185static void arp_free_llentry_tokenring(struct llentry *);
186#endif 186#endif
187 187
188struct ifqueue arpintrq = { 188struct ifqueue arpintrq = {
189 .ifq_head = NULL, 189 .ifq_head = NULL,
190 .ifq_tail = NULL, 190 .ifq_tail = NULL,
191 .ifq_len = 0, 191 .ifq_len = 0,
192 .ifq_maxlen = 50, 192 .ifq_maxlen = 50,
193 .ifq_drops = 0, 193 .ifq_drops = 0,
194}; 194};
@@ -1123,57 +1123,46 @@ in_arpinput(struct mbuf *m) @@ -1123,57 +1123,46 @@ in_arpinput(struct mbuf *m)
1123 } 1123 }
1124 1124
1125 /* 1125 /*
1126 * If the source IP address is zero, this is an RFC 5227 ARP probe 1126 * If the source IP address is zero, this is an RFC 5227 ARP probe
1127 */ 1127 */
1128 if (in_nullhost(isaddr)) 1128 if (in_nullhost(isaddr))
1129 ARP_STATINC(ARP_STAT_RCVZEROSPA); 1129 ARP_STATINC(ARP_STAT_RCVZEROSPA);
1130 else if (in_hosteq(isaddr, myaddr)) 1130 else if (in_hosteq(isaddr, myaddr))
1131 ARP_STATINC(ARP_STAT_RCVLOCALSPA); 1131 ARP_STATINC(ARP_STAT_RCVLOCALSPA);
1132 1132
1133 if (in_nullhost(itaddr)) 1133 if (in_nullhost(itaddr))
1134 ARP_STATINC(ARP_STAT_RCVZEROTPA); 1134 ARP_STATINC(ARP_STAT_RCVZEROTPA);
1135 1135
1136 /* DAD check, RFC 5227 2.1.1, Probe Details */ 1136 /* DAD check, RFC 5227 */
1137 if (in_hosteq(isaddr, myaddr) || 1137 if (in_hosteq(isaddr, myaddr) ||
1138 (in_nullhost(isaddr) && in_hosteq(itaddr, myaddr))) 1138 (in_nullhost(isaddr) && in_hosteq(itaddr, myaddr)))
1139 { 1139 {
1140 /* If our address is tentative, mark it as duplicated */ 1140 arp_dad_duplicated((struct ifaddr *)ia,
1141 if (ia->ia4_flags & IN_IFF_TENTATIVE) 1141 lla_snprintf(ar_sha(ah), ah->ar_hln));
1142 arp_dad_duplicated((struct ifaddr *)ia); 1142 goto out;
1143 /* If our address is unuseable, don't reply */ 
1144 if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) 
1145 goto out; 
1146 } 1143 }
1147 1144
1148 /* 1145 /*
1149 * If the target IP address is zero, ignore the packet. 1146 * If the target IP address is zero, ignore the packet.
1150 * This prevents the code below from tring to answer 1147 * This prevents the code below from tring to answer
1151 * when we are using IP address zero (booting). 1148 * when we are using IP address zero (booting).
1152 */ 1149 */
1153 if (in_nullhost(itaddr)) 1150 if (in_nullhost(itaddr))
1154 goto out; 1151 goto out;
1155 1152
1156 if (in_nullhost(isaddr)) 1153 if (in_nullhost(isaddr))
1157 goto reply; 1154 goto reply;
1158 1155
1159 if (in_hosteq(isaddr, myaddr)) { 
1160 log(LOG_ERR, 
1161 "duplicate IP address %s sent from link address %s\n", 
1162 in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln)); 
1163 itaddr = myaddr; 
1164 goto reply; 
1165 } 
1166 
1167 if (in_hosteq(itaddr, myaddr)) 1156 if (in_hosteq(itaddr, myaddr))
1168 la = arpcreate(ifp, m, &isaddr, NULL, 1); 1157 la = arpcreate(ifp, m, &isaddr, NULL, 1);
1169 else 1158 else
1170 la = arplookup(ifp, m, &isaddr, NULL, 1); 1159 la = arplookup(ifp, m, &isaddr, NULL, 1);
1171 if (la == NULL) 1160 if (la == NULL)
1172 goto reply; 1161 goto reply;
1173 1162
1174 if ((la->la_flags & LLE_VALID) && 1163 if ((la->la_flags & LLE_VALID) &&
1175 memcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { 1164 memcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) {
1176 if (la->la_flags & LLE_STATIC) { 1165 if (la->la_flags & LLE_STATIC) {
1177 ARP_STATINC(ARP_STAT_RCVOVERPERM); 1166 ARP_STATINC(ARP_STAT_RCVOVERPERM);
1178 if (!log_permanent_modify) 1167 if (!log_permanent_modify)
1179 goto out; 1168 goto out;
@@ -1764,61 +1753,65 @@ announce: @@ -1764,61 +1753,65 @@ announce:
1764 1753
1765 TAILQ_REMOVE(&dadq, dp, dad_list); 1754 TAILQ_REMOVE(&dadq, dp, dad_list);
1766 free(dp, M_IPARP); 1755 free(dp, M_IPARP);
1767 dp = NULL; 1756 dp = NULL;
1768 ifafree(ifa); 1757 ifafree(ifa);
1769 1758
1770done: 1759done:
1771 mutex_exit(&arp_dad_lock); 1760 mutex_exit(&arp_dad_lock);
1772 KERNEL_UNLOCK_ONE(NULL); 1761 KERNEL_UNLOCK_ONE(NULL);
1773 mutex_exit(softnet_lock); 1762 mutex_exit(softnet_lock);
1774} 1763}
1775 1764
1776static void 1765static void
1777arp_dad_duplicated(struct ifaddr *ifa) 1766arp_dad_duplicated(struct ifaddr *ifa, const char *sha)
1778{ 1767{
1779 struct in_ifaddr *ia = (struct in_ifaddr *)ifa; 1768 struct in_ifaddr *ia = (struct in_ifaddr *)ifa;
1780 struct ifnet *ifp; 1769 struct ifnet *ifp = ifa->ifa_ifp;
1781 struct dadq *dp; 1770 const char *iastr = in_fmtaddr(ia->ia_addr.sin_addr);
1782 1771
1783 mutex_enter(&arp_dad_lock); 1772 if (ia->ia4_flags & (IN_IFF_TENTATIVE|IN_IFF_DUPLICATED)) {
1784 dp = arp_dad_find(ifa); 1773 log(LOG_ERR,
1785 if (dp == NULL) { 1774 "%s: DAD duplicate address %s from %s\n",
1786 mutex_exit(&arp_dad_lock); 1775 if_name(ifp), iastr, sha);
1787 /* DAD seems to be stopping, so do nothing. */ 1776 } else if (ia->ia_dad_defended == 0 ||
 1777 ia->ia_dad_defended < time_uptime - DEFEND_INTERVAL) {
 1778 ia->ia_dad_defended = time_uptime;
 1779 arpannounce1(ifa);
 1780 log(LOG_ERR,
 1781 "%s: DAD defended address %s from %s\n",
 1782 if_name(ifp), iastr, sha);
1788 return; 1783 return;
 1784 } else {
 1785 /* If DAD is disabled, just report the duplicate. */
 1786 if (ip_dad_count == 0) {
 1787 log(LOG_ERR,
 1788 "%s: DAD ignoring duplicate address %s from %s\n",
 1789 if_name(ifp), iastr, sha);
 1790 return;
 1791 }
 1792 log(LOG_ERR,
 1793 "%s: DAD defence failed for %s from %s\n",
 1794 if_name(ifp), iastr, sha);
1789 } 1795 }
1790 1796
1791 ifp = ifa->ifa_ifp; 1797 arp_dad_stop(ifa);
1792 log(LOG_ERR, 
1793 "%s: DAD detected duplicate IPv4 address %s: ARP out=%d\n", 
1794 if_name(ifp), in_fmtaddr(ia->ia_addr.sin_addr), 
1795 dp->dad_arp_ocount); 
1796 1798
1797 ia->ia4_flags &= ~IN_IFF_TENTATIVE; 1799 ia->ia4_flags &= ~IN_IFF_TENTATIVE;
1798 ia->ia4_flags |= IN_IFF_DUPLICATED; 1800 if ((ia->ia4_flags & IN_IFF_DUPLICATED) == 0) {
1799 1801 ia->ia4_flags |= IN_IFF_DUPLICATED;
1800 /* We are done with DAD, with duplicated address found. (failure) */ 1802 /* Inform the routing socket of the duplicate address */
1801 arp_dad_stoptimer(dp); 1803 rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
1802 1804 }
1803 /* Inform the routing socket that DAD has completed */ 
1804 rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); 
1805 
1806 TAILQ_REMOVE(&dadq, dp, dad_list); 
1807 mutex_exit(&arp_dad_lock); 
1808 
1809 free(dp, M_IPARP); 
1810 dp = NULL; 
1811 ifafree(ifa); 
1812} 1805}
1813 1806
1814/* 1807/*
1815 * Called from 10 Mb/s Ethernet interrupt handlers 1808 * Called from 10 Mb/s Ethernet interrupt handlers
1816 * when ether packet type ETHERTYPE_REVARP 1809 * when ether packet type ETHERTYPE_REVARP
1817 * is received. Common length and type checks are done here, 1810 * is received. Common length and type checks are done here,
1818 * then the protocol-specific routine is called. 1811 * then the protocol-specific routine is called.
1819 */ 1812 */
1820void 1813void
1821revarpinput(struct mbuf *m) 1814revarpinput(struct mbuf *m)
1822{ 1815{
1823 struct arphdr *ar; 1816 struct arphdr *ar;
1824 1817

cvs diff -r1.87 -r1.88 src/sys/netinet/in_var.h (expand / switch to unified diff)

--- src/sys/netinet/in_var.h 2016/09/29 15:18:18 1.87
+++ src/sys/netinet/in_var.h 2016/10/11 13:59:30 1.88
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: in_var.h,v 1.87 2016/09/29 15:18:18 roy Exp $ */ 1/* $NetBSD: in_var.h,v 1.88 2016/10/11 13:59:30 roy Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Public Access Networks Corporation ("Panix"). It was developed under 8 * by Public Access Networks Corporation ("Panix"). It was developed under
9 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon. 9 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -97,26 +97,27 @@ struct in_ifaddr { @@ -97,26 +97,27 @@ struct in_ifaddr {
97 LIST_ENTRY(in_ifaddr) ia_hash; /* entry in bucket of inet addresses */ 97 LIST_ENTRY(in_ifaddr) ia_hash; /* entry in bucket of inet addresses */
98 TAILQ_ENTRY(in_ifaddr) ia_list; /* list of internet addresses */ 98 TAILQ_ENTRY(in_ifaddr) ia_list; /* list of internet addresses */
99 struct sockaddr_in ia_addr; /* reserve space for interface name */ 99 struct sockaddr_in ia_addr; /* reserve space for interface name */
100 struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */ 100 struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
101#define ia_broadaddr ia_dstaddr 101#define ia_broadaddr ia_dstaddr
102 struct sockaddr_in ia_sockmask; /* reserve space for general netmask */ 102 struct sockaddr_in ia_sockmask; /* reserve space for general netmask */
103 LIST_HEAD(, in_multi) ia_multiaddrs; /* list of multicast addresses */ 103 LIST_HEAD(, in_multi) ia_multiaddrs; /* list of multicast addresses */
104 struct in_multi *ia_allhosts; /* multicast address record for 104 struct in_multi *ia_allhosts; /* multicast address record for
105 the allhosts multicast group */ 105 the allhosts multicast group */
106 uint16_t ia_idsalt; /* ip_id salt for this ia */ 106 uint16_t ia_idsalt; /* ip_id salt for this ia */
107 int ia4_flags; /* address flags */ 107 int ia4_flags; /* address flags */
108 void (*ia_dad_start) (struct ifaddr *); /* DAD start function */ 108 void (*ia_dad_start) (struct ifaddr *); /* DAD start function */
109 void (*ia_dad_stop) (struct ifaddr *); /* DAD stop function */ 109 void (*ia_dad_stop) (struct ifaddr *); /* DAD stop function */
 110 time_t ia_dad_defended; /* last time of DAD defence */
110 111
111#ifdef _KERNEL 112#ifdef _KERNEL
112 struct pslist_entry ia_hash_pslist_entry; 113 struct pslist_entry ia_hash_pslist_entry;
113 struct pslist_entry ia_pslist_entry; 114 struct pslist_entry ia_pslist_entry;
114#endif 115#endif
115}; 116};
116 117
117#ifdef _KERNEL 118#ifdef _KERNEL
118static inline void 119static inline void
119ia4_acquire(struct in_ifaddr *ia, struct psref *psref) 120ia4_acquire(struct in_ifaddr *ia, struct psref *psref)
120{ 121{
121 122
122 KASSERT(ia != NULL); 123 KASSERT(ia != NULL);