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
This commit is contained in:
Konrad Sewiłło-Jopek 2022-05-27 11:02:57 +00:00 committed by Alexander V. Chernikov
parent 18054d0220
commit c9a5c48ae8
4 changed files with 29 additions and 6 deletions

View File

@ -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

View File

@ -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),

View File

@ -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 */

View File

@ -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 @@ in_arpinput(struct mbuf *m)
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;