Commit e68c5dcf authored by Jaehee Park's avatar Jaehee Park Committed by Jakub Kicinski
Browse files

net: ipv4: new arp_accept option to accept garp only if in-network



In many deployments, we want the option to not learn a neighbor from
garp if the src ip is not in the same subnet as an address configured
on the interface that received the garp message. net.ipv4.arp_accept
sysctl is currently used to control creation of a neigh from a
received garp packet. This patch adds a new option '2' to
net.ipv4.arp_accept which extends option '1' by including the subnet
check.

Signed-off-by: default avatarJaehee Park <jhpark1013@gmail.com>
Suggested-by: default avatarRoopa Prabhu <roopa@nvidia.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 459f326e
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -1633,12 +1633,15 @@ arp_notify - BOOLEAN
	     or hardware address changes.
	 ==  ==========================================================

arp_accept - BOOLEAN
	Define behavior for gratuitous ARP frames who's IP is not
	already present in the ARP table:
arp_accept - INTEGER
	Define behavior for accepting gratuitous ARP (garp) frames from devices
	that are not already present in the ARP table:

	- 0 - don't create new entries in the ARP table
	- 1 - create new entries in the ARP table
	- 2 - create new entries only if the source IP address is in the same
	  subnet as an address configured on the interface that received the
	  garp message.

	Both replies and requests type gratuitous arp will trigger the
	ARP table to be updated, if this setting is on.
+1 −1
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
	IN_DEV_ORCONF((in_dev), IGNORE_ROUTES_WITH_LINKDOWN)

#define IN_DEV_ARPFILTER(in_dev)	IN_DEV_ORCONF((in_dev), ARPFILTER)
#define IN_DEV_ARP_ACCEPT(in_dev)	IN_DEV_ORCONF((in_dev), ARP_ACCEPT)
#define IN_DEV_ARP_ACCEPT(in_dev)	IN_DEV_MAXCONF((in_dev), ARP_ACCEPT)
#define IN_DEV_ARP_ANNOUNCE(in_dev)	IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
#define IN_DEV_ARP_IGNORE(in_dev)	IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
#define IN_DEV_ARP_NOTIFY(in_dev)	IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
+22 −2
Original line number Diff line number Diff line
@@ -429,6 +429,26 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
	return !inet_confirm_addr(net, in_dev, sip, tip, scope);
}

static int arp_accept(struct in_device *in_dev, __be32 sip)
{
	struct net *net = dev_net(in_dev->dev);
	int scope = RT_SCOPE_LINK;

	switch (IN_DEV_ARP_ACCEPT(in_dev)) {
	case 0: /* Don't create new entries from garp */
		return 0;
	case 1: /* Create new entries from garp */
		return 1;
	case 2: /* Create a neighbor in the arp table only if sip
		 * is in the same subnet as an address configured
		 * on the interface that received the garp message
		 */
		return !!inet_confirm_addr(net, in_dev, sip, 0, scope);
	default:
		return 0;
	}
}

static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
{
	struct rtable *rt;
@@ -868,12 +888,12 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);

	addr_type = -1;
	if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
	if (n || arp_accept(in_dev, sip)) {
		is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
				      sip, tip, sha, tha);
	}

	if (IN_DEV_ARP_ACCEPT(in_dev)) {
	if (arp_accept(in_dev, sip)) {
		/* Unsolicited ARP is not accepted by default.
		   It is possible, that this option should be enabled for some
		   devices (strip is candidate)