[alfred] Request MAC resolution for IPv4 address not in ARP cache

Message ID 20181024183511.19902-1-jhaws@sdl.usu.edu (mailing list archive)
State Superseded, archived
Delegated to: Simon Wunderlich
Headers
Series [alfred] Request MAC resolution for IPv4 address not in ARP cache |

Commit Message

Jonathan Haws Oct. 24, 2018, 6:35 p.m. UTC
  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.

Signed-off-by: Jonathan Haws <jhaws@sdl.usu.edu>
---
 alfred.h |  1 +
 util.c   | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)
  

Comments

Sven Eckelmann Oct. 24, 2018, 6:57 p.m. UTC | #1
Please start the subject with "alfred: " when it is a patch for alfred.

On Mittwoch, 24. Oktober 2018 20:35:11 CEST Jonathan Haws wrote:
> 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.
> 
> Signed-off-by: Jonathan Haws <jhaws@sdl.usu.edu>

Please add the info which commit was fixed by this change right before 
the Signed-off-by:

Fixes: c7da798113a2 ("alfred: IPv4 multicast distribution support.")

[...]
> index eecfdfd..5771483 100644
> --- a/alfred.h
> +++ b/alfred.h
> @@ -213,3 +213,4 @@ uint16_t get_random_id(void);
>  bool is_valid_ether_addr(uint8_t *addr);
>  int ipv4_arp_request(struct interface *interface, const alfred_addr *addr,
>  		     struct ether_addr *mac);
> +void ipv4_request_mac_resolve(const alfred_addr *addr);

This doesn't make sense. The function is in util.c and only called in util.c. 
So it should be static and not in this header at all.

Kind regards,
	Sven
  
Jonathan Haws Oct. 24, 2018, 7:20 p.m. UTC | #2
On Wed, 2018-10-24 at 20:57 +0200, Sven Eckelmann wrote:
> Please start the subject with "alfred: " when it is a patch for
> alfred.

Right - my mistake. It's been a long time since I last submitted....

> 
> On Mittwoch, 24. Oktober 2018 20:35:11 CEST Jonathan Haws wrote:
> > 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.
> > 
> > Signed-off-by: Jonathan Haws <jhaws@sdl.usu.edu>
> 
> Please add the info which commit was fixed by this change right
> before 
> the Signed-off-by:
> 
> Fixes: c7da798113a2 ("alfred: IPv4 multicast distribution support.")
> 

Done.

> [...]
> > index eecfdfd..5771483 100644
> > --- a/alfred.h
> > +++ b/alfred.h
> > @@ -213,3 +213,4 @@ uint16_t get_random_id(void);
> >  bool is_valid_ether_addr(uint8_t *addr);
> >  int ipv4_arp_request(struct interface *interface, const
> > alfred_addr *addr,
> >  		     struct ether_addr *mac);
> > +void ipv4_request_mac_resolve(const alfred_addr *addr);
> 
> This doesn't make sense. The function is in util.c and only called in
> util.c. 
> So it should be static and not in this header at all.

You're right - I blindly mimicked the previous ipv4_arp_request routine
without thinking about it.

Fixed in v2.

v2 forthcoming...
  

Patch

diff --git a/alfred.h b/alfred.h
index eecfdfd..5771483 100644
--- a/alfred.h
+++ b/alfred.h
@@ -213,3 +213,4 @@  uint16_t get_random_id(void);
 bool is_valid_ether_addr(uint8_t *addr);
 int ipv4_arp_request(struct interface *interface, const alfred_addr *addr,
 		     struct ether_addr *mac);
+void ipv4_request_mac_resolve(const alfred_addr *addr);
diff --git a/util.c b/util.c
index dd3f00f..a6a98b9 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,
@@ -85,6 +86,7 @@  int ipv4_arp_request(struct interface *interface, const alfred_addr *addr,
 {
 	struct arpreq arpreq;
 	struct sockaddr_in *sin;
+	int retries = 1;
 
 	memset(&arpreq, 0, sizeof(arpreq));
 	memset(mac, 0, ETH_ALEN);
@@ -99,6 +101,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 {
@@ -108,3 +118,26 @@  int ipv4_arp_request(struct interface *interface, const alfred_addr *addr,
 
 	return 0;
 }
+
+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);
+}