git: c9a5c48ae88d - main - arp: Implement sticky ARP mode for interfaces.

From: Alexander V. Chernikov <melifaro_at_FreeBSD.org>
Date: Fri, 27 May 2022 12:44:06 UTC
The branch main has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=c9a5c48ae88dcd10c1a1273e028f98761887f190

commit c9a5c48ae88dcd10c1a1273e028f98761887f190
Author:     Konrad Sewiłło-Jopek <kjopek@gmail.com>
AuthorDate: 2022-05-27 11:02:57 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2022-05-27 12:41:30 +0000

    arp: Implement sticky ARP mode for interfaces.
    
    Provide sticky ARP flag for network interface which marks it as the
    "sticky" one similarly to what we have for bridges. Once interface is
    marked sticky, any address resolved using the ARP will be saved as a
    static one in the ARP table. Such functionality may be used to prevent
    ARP spoofing or to decrease latencies in Ethernet networks.
    
    The drawbacks include potential limitations in usage of ARP-based
    load-balancers and high-availability solutions such as carp(4).
    
    The implemented option is disabled by default, therefore should not
    impact the default behaviour of the networking stack.
    
    Sponsored by:           Conclusive Engineering sp. z o.o.
    Reviewed By:            melifaro, pauamma_gundo.com
    Differential Revision: https://reviews.freebsd.org/D35314
    MFC after:              2 weeks
---
 sbin/ifconfig/ifconfig.8 | 19 ++++++++++++++++++-
 sbin/ifconfig/ifconfig.c |  4 +++-
 sys/net/if.h             |  1 +
 sys/netinet/if_ether.c   | 11 +++++++----
 4 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index bd1a79bee897..91d6764e35fc 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
 .\" $FreeBSD$
 .\"
-.Dd April 11, 2022
+.Dd May 26, 2022
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -419,6 +419,23 @@ and will never send any requests.
 If the Address Resolution Protocol is enabled,
 the host will perform normally,
 sending out requests and listening for replies.
+.It Cm stickyarp
+Enable so-called sticky ARP mode for the interface.
+If this option is enabled on the given interface, any resolved address is
+marked as a static one and never expires. This may be used to increase
+security of the network by preventing ARP spoofing or to reduce latency for
+high-performance Ethernet networks where the time needed for ARP resolution is
+too high. Please note that a similar feature is also provided for bridges. See
+the sticky option in the
+.Sx Bridge Interface Parameters
+section. Enabling this
+option may impact techniques which rely on ARP expiration/overwriting feature
+such as load-balancers or high-availabity solutions such as
+.Xr carp 4 .
+.It Fl stickyarp
+Disable so-called sticky ARP mode for the interface (default).
+Resolved addresses will expire normally respecting the kernel ARP
+configuration.
 .It Cm broadcast
 (Inet only.)
 Specify the address to use to represent broadcasts to the
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 4a0c3522c8e5..ec8a3fd52803 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1407,7 +1407,7 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
 #define	IFFBITS \
 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \
 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
-"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
+"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP\25STICKYARP"
 
 #define	IFCAPBITS \
 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
@@ -1771,6 +1771,8 @@ static struct cmd basic_cmds[] = {
 	DEF_CMD("-mextpg",	-IFCAP_MEXTPG,	setifcap),
 	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
 	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
+	DEF_CMD("stickyarp",	IFF_STICKYARP,	setifflags),
+	DEF_CMD("-stickyarp",	-IFF_STICKYARP,	setifflags),
 	DEF_CMD("rxcsum6",	IFCAP_RXCSUM_IPV6,	setifcap),
 	DEF_CMD("-rxcsum6",	-IFCAP_RXCSUM_IPV6,	setifcap),
 	DEF_CMD("txcsum6",	IFCAP_TXCSUM_IPV6,	setifcap),
diff --git a/sys/net/if.h b/sys/net/if.h
index 301a34c9f54f..a559219d700b 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -160,6 +160,7 @@ struct if_data {
 #define	IFF_PPROMISC	0x20000		/* (n) user-requested promisc mode */
 #define	IFF_MONITOR	0x40000		/* (n) user-requested monitor mode */
 #define	IFF_STATICARP	0x80000		/* (n) static ARP */
+#define	IFF_STICKYARP	0x100000	/* (n) sticky ARP */
 #define	IFF_DYING	0x200000	/* (n) interface is winding down */
 #define	IFF_RENAMING	0x400000	/* (n) interface is being renamed */
 #define	IFF_NOGROUP	0x800000	/* (n) interface is not part of any groups */
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index fd0423858bb8..380f8fde35c5 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -186,7 +186,7 @@ static void	in_arpinput(struct mbuf *);
 
 static void arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr,
     struct ifnet *ifp, int bridged, struct llentry *la);
-static void arp_mark_lle_reachable(struct llentry *la);
+static void arp_mark_lle_reachable(struct llentry *la, struct ifnet *ifp);
 static void arp_iflladdr(void *arg __unused, struct ifnet *ifp);
 
 static eventhandler_tag iflladdr_tag;
@@ -999,7 +999,7 @@ match:
 		IF_AFDATA_WUNLOCK(ifp);
 
 		if (la_tmp == NULL) {
-			arp_mark_lle_reachable(la);
+			arp_mark_lle_reachable(la, ifp);
 			LLE_WUNLOCK(la);
 		} else {
 			/* Free newly-create entry and handle packet */
@@ -1247,7 +1247,7 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp
 		llentry_mark_used(la);
 	}
 
-	arp_mark_lle_reachable(la);
+	arp_mark_lle_reachable(la, ifp);
 
 	/*
 	 * The packets are all freed within the call to the output
@@ -1267,7 +1267,7 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp
 }
 
 static void
-arp_mark_lle_reachable(struct llentry *la)
+arp_mark_lle_reachable(struct llentry *la, struct ifnet *ifp)
 {
 	int canceled, wtime;
 
@@ -1276,6 +1276,9 @@ arp_mark_lle_reachable(struct llentry *la)
 	la->ln_state = ARP_LLINFO_REACHABLE;
 	EVENTHANDLER_INVOKE(lle_event, la, LLENTRY_RESOLVED);
 
+	if ((ifp->if_flags & IFF_STICKYARP) != 0)
+		la->la_flags |= LLE_STATIC;
+
 	if (!(la->la_flags & LLE_STATIC)) {
 		LLE_ADDREF(la);
 		la->la_expire = time_uptime + V_arpt_keep;