When using IPv4, if the remote server is not yet in the ARP cache, the MAC resolution will fail and data appear to not be shared via alfred. Add a routine (modified from batctl sources) to request MAC resolution by simply sending a datagram to the discard port (UDP/9). This adds the remote MAC to the ARP cache, resulting in successful MAC resolution.
Fixes: c7da798113a2 ("alfred: IPv4 multicast distribution support.") Signed-off-by: Jonathan Haws jhaws@sdl.usu.edu --- util.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/util.c b/util.c index dd3f00f..3a0c279 100644 --- a/util.c +++ b/util.c @@ -30,6 +30,7 @@ #include <sys/ioctl.h> #include <sys/time.h> #include <time.h> +#include <unistd.h> #include "alfred.h"
int time_diff(struct timespec *tv1, struct timespec *tv2, @@ -80,11 +81,35 @@ bool is_valid_ether_addr(uint8_t addr[ETH_ALEN]) return true; }
+static void ipv4_request_mac_resolve(const alfred_addr *addr) +{ + const struct sockaddr *sockaddr; + struct sockaddr_in inet4; + size_t sockaddr_len; + int sock; + char t = 0; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + return; + + memset(&inet4, 0, sizeof(inet4)); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(9); + inet4.sin_addr.s_addr = addr->ipv4.s_addr; + sockaddr = (const struct sockaddr *)&inet4; + sockaddr_len = sizeof(inet4); + + sendto(sock, &t, sizeof(t), 0, sockaddr, sockaddr_len); + close(sock); +} + int ipv4_arp_request(struct interface *interface, const alfred_addr *addr, struct ether_addr *mac) { struct arpreq arpreq; struct sockaddr_in *sin; + int retries = 1;
memset(&arpreq, 0, sizeof(arpreq)); memset(mac, 0, ETH_ALEN); @@ -99,6 +124,14 @@ int ipv4_arp_request(struct interface *interface, const alfred_addr *addr, if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0) return -1;
+ while (retries-- && !(arpreq.arp_flags & ATF_COM)) { + ipv4_request_mac_resolve(addr); + usleep(200000); + + if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0) + return -1; + } + if (arpreq.arp_flags & ATF_COM) { memcpy(mac, arpreq.arp_ha.sa_data, sizeof(*mac)); } else {
On Mittwoch, 24. Oktober 2018 13:21:28 CEST Jonathan Haws wrote: [...]
while (retries-- && !(arpreq.arp_flags & ATF_COM)) {
ipv4_request_mac_resolve(addr);
usleep(200000);
if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0)
return -1;
}
if (arpreq.arp_flags & ATF_COM) { memcpy(mac, arpreq.arp_ha.sa_data, sizeof(*mac)); } else {
According to gary [1], this doesn't work because the ioctl fails for him and then the function returns immediately (before the while loop).
Please adjust your patch - but please don't use his code - it looks rather ugly and also doesn't work for multiple retries. You most likely want to drop the if-ioctl completely and then put everything in your while loop:
while (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0 || !(arpreq.arp_flags & ATF_COM)) { if (retries-- <= 0) break;
ipv4_request_mac_resolve(addr); usleep(200000); }
But feel to propose a different (cleaner) approach.
Kind regards, Sven
[1] https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2018-October/018195.html
Ah, yes - I see the issue now. I'll update that when I get back. And I apologize for the top posting! My phone's email client doesn't do inline too well...
Sent from my Verizon, Samsung Galaxy smartphone
-------- Original message -------- From: Sven Eckelmann sven@narfation.org Date: 10/25/18 3:42 AM (GMT-07:00) To: b.a.t.m.a.n@lists.open-mesh.org Cc: Jonathan Haws jhaws@sdl.usu.edu, guohuizou2000@sina.com Subject: Re: [B.A.T.M.A.N.] [PATCH v2] alfred: Request MAC resolution for IPv4 address not in ARP cache
On Mittwoch, 24. Oktober 2018 13:21:28 CEST Jonathan Haws wrote: [...]
while (retries-- && !(arpreq.arp_flags & ATF_COM)) {
ipv4_request_mac_resolve(addr);
usleep(200000);
if (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0)
return -1;
}
if (arpreq.arp_flags & ATF_COM) { memcpy(mac, arpreq.arp_ha.sa_data, sizeof(*mac)); } else {
According to gary [1], this doesn't work because the ioctl fails for him and then the function returns immediately (before the while loop).
Please adjust your patch - but please don't use his code - it looks rather ugly and also doesn't work for multiple retries. You most likely want to drop the if-ioctl completely and then put everything in your while loop:
while (ioctl(interface->netsock, SIOCGARP, &arpreq) < 0 || !(arpreq.arp_flags & ATF_COM)) { if (retries-- <= 0) break;
ipv4_request_mac_resolve(addr); usleep(200000); }
But feel to propose a different (cleaner) approach.
Kind regards, Sven
[1] https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2018-October/018195.html
b.a.t.m.a.n@lists.open-mesh.org