| From foo@baz Mon Apr 9 17:09:24 CEST 2018 |
| From: Ihar Hrachyshka <ihrachys@redhat.com> |
| Date: Tue, 16 May 2017 07:53:43 -0700 |
| Subject: arp: honour gratuitous ARP _replies_ |
| |
| From: Ihar Hrachyshka <ihrachys@redhat.com> |
| |
| |
| [ Upstream commit 23d268eb240954e6e78f7cfab04f2b1e79f84489 ] |
| |
| When arp_accept is 1, gratuitous ARPs are supposed to override matching |
| entries irrespective of whether they arrive during locktime. This was |
| implemented in commit 56022a8fdd87 ("ipv4: arp: update neighbour address |
| when a gratuitous arp is received and arp_accept is set") |
| |
| There is a glitch in the patch though. RFC 2002, section 4.6, "ARP, |
| Proxy ARP, and Gratuitous ARP", defines gratuitous ARPs so that they can |
| be either of Request or Reply type. Those Reply gratuitous ARPs can be |
| triggered with standard tooling, for example, arping -A option does just |
| that. |
| |
| This patch fixes the glitch, making both Request and Reply flavours of |
| gratuitous ARPs to behave identically. |
| |
| As per RFC, if gratuitous ARPs are of Reply type, their Target Hardware |
| Address field should also be set to the link-layer address to which this |
| cache entry should be updated. The field is present in ARP over Ethernet |
| but not in IEEE 1394. In this patch, I don't consider any broadcasted |
| ARP replies as gratuitous if the field is not present, to conform the |
| standard. It's not clear whether there is such a thing for IEEE 1394 as |
| a gratuitous ARP reply; until it's cleared up, we will ignore such |
| broadcasts. Note that they will still update existing ARP cache entries, |
| assuming they arrive out of locktime time interval. |
| |
| Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/arp.c | 16 ++++++++++++++-- |
| 1 file changed, 14 insertions(+), 2 deletions(-) |
| |
| --- a/net/ipv4/arp.c |
| +++ b/net/ipv4/arp.c |
| @@ -658,6 +658,7 @@ static int arp_process(struct net *net, |
| unsigned char *arp_ptr; |
| struct rtable *rt; |
| unsigned char *sha; |
| + unsigned char *tha = NULL; |
| __be32 sip, tip; |
| u16 dev_type = dev->type; |
| int addr_type; |
| @@ -729,6 +730,7 @@ static int arp_process(struct net *net, |
| break; |
| #endif |
| default: |
| + tha = arp_ptr; |
| arp_ptr += dev->addr_len; |
| } |
| memcpy(&tip, arp_ptr, 4); |
| @@ -847,8 +849,18 @@ static int arp_process(struct net *net, |
| It is possible, that this option should be enabled for some |
| devices (strip is candidate) |
| */ |
| - is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && |
| - addr_type == RTN_UNICAST; |
| + is_garp = tip == sip && addr_type == RTN_UNICAST; |
| + |
| + /* Unsolicited ARP _replies_ also require target hwaddr to be |
| + * the same as source. |
| + */ |
| + if (is_garp && arp->ar_op == htons(ARPOP_REPLY)) |
| + is_garp = |
| + /* IPv4 over IEEE 1394 doesn't provide target |
| + * hardware address field in its ARP payload. |
| + */ |
| + tha && |
| + !memcmp(tha, sha, dev->addr_len); |
| |
| if (!n && |
| ((arp->ar_op == htons(ARPOP_REPLY) && |