Skip to content

Commit

Permalink
net: ipv4: new arp_accept option to accept garp only if in-network
Browse files Browse the repository at this point in the history
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: Jaehee Park <jhpark1013@gmail.com>
Suggested-by: Roopa Prabhu <roopa@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Jaehee Park authored and Jakub Kicinski committed Jul 16, 2022
1 parent 459f326 commit e68c5dc
Showing 3 changed files with 29 additions and 6 deletions.
9 changes: 6 additions & 3 deletions Documentation/networking/ip-sysctl.rst
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion include/linux/inetdevice.h
Original file line number Diff line number Diff line change
@@ -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)
24 changes: 22 additions & 2 deletions net/ipv4/arp.c
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit e68c5dc

Please sign in to comment.