misc/122333: net/arping - patch to lookup for interface and src ip, second variant

Dmitry hanabana at mail.ru
Tue Apr 1 07:00:10 PDT 2008


>Number:         122333
>Category:       misc
>Synopsis:       net/arping - patch to lookup for interface and src ip, second variant
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 01 14:00:09 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Dmitry
>Release:        FreeBSD 6.3, FreeBSD 7.0
>Organization:
home
>Environment:
FreeBSD gatenew.aphn 6.3-STABLE FreeBSD 6.3-STABLE #0: Thu Feb 28 22:35:03 MSK 2008 root at gatenew.aphn:/var/tmp/obj/usr/src/sys/SRV i386
>Description:
This bugreport substitutes ports/122197. I've sent 3 followups to that port but freebsd.org definitly filters mail.ru.

This patch adds arping ability to find himself interface name and source
 IP for specified destination IP.

Also I've fixed choosing the incorrect interface when destination IP matches different netwoks with different prefix length.
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

--- arping-2/arping.c.orig	2007-09-13 20:43:37.000000000 +0400
+++ arping-2/arping.c	2008-03-29 10:27:14.000000000 +0300
@@ -48,6 +48,17 @@
 #include <libnet.h>
 #endif
 
+#ifdef __FreeBSD__
+#include <errno.h>
+#include <string.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
 #ifdef WIN32
 #include <win32/libnet.h>
 #endif
@@ -232,6 +243,154 @@
 }
 #endif
 
+#ifdef __FreeBSD__
+static const char*
+FBSD_lookupIface(in_addr_t dstip, char* ebuf, in_addr_t *ifce_ip) {
+    int mib[6] = {
+	CTL_NET,
+	PF_ROUTE,
+	0, /* Protocol */
+	0, /* Address family */
+	NET_RT_IFLIST,
+	0
+    };
+    char  *buf, *lim;
+    int   bufSize;
+    int   c;
+    int			ifCnt = 0;
+    in_addr_t		ifMaskH = 0;
+    struct in_addr	ifAddr;
+    static char		ifName[IFNAMSIZ];
+
+
+    for(c=0;;) {
+	if( sysctl(mib,6,NULL,&bufSize,NULL,0) < 0 ) {
+	    strcpy(ebuf,"sysctl: get buffer size error");
+	    return NULL;
+	}
+	if( (buf = malloc(bufSize)) == NULL ) {
+	    strcpy(ebuf, "malloc: error");
+	    return NULL;
+	}
+	if( sysctl(mib,6,buf,&bufSize,NULL,0) == 0 )
+	    break;
+	if( errno != ENOMEM || ++c >= 10 ) {
+	    strcpy(ebuf,"sysctl: get ifaces error");
+	    return NULL;
+	}
+	fprintf(stderr,"sysctl: buffer size changed");
+	free(buf);
+	sleep(1);
+    }
+
+    lim = buf + bufSize;
+
+    while( buf < lim ) {
+	struct sockaddr_dl *sdl;
+	char  tmpIfName[IFNAMSIZ];
+	int   i;
+
+	struct if_msghdr * ifh = (struct if_msghdr *)buf;
+	if( ifh->ifm_type != RTM_IFINFO ) {
+	    strcpy(ebuf,"Wrong data in NET_RT_IFLIST");
+	    return NULL;
+	}
+	if( ifh->ifm_data.ifi_datalen == 0 )
+	    ifh->ifm_data.ifi_datalen = sizeof(struct if_data);
+	sdl =
+	    (struct sockaddr_dl *)(
+		buf +
+		sizeof(struct if_msghdr) -
+		sizeof(struct if_data) +
+		ifh->ifm_data.ifi_datalen
+	    );
+
+	i = sdl->sdl_nlen < sizeof(ifName)?sdl->sdl_nlen:(sizeof(tmpIfName)-1);
+	memcpy(tmpIfName,sdl->sdl_data,i);
+	tmpIfName[i] = 0;
+
+	buf += ifh->ifm_msglen;
+	i = 0;
+	while( buf < lim ) {
+	    struct ifa_msghdr *ifht = (struct ifa_msghdr *)buf;
+	    char*  addrPtr;
+	    int	   c;
+	    struct sockaddr_in *if_addr = NULL;
+	    struct sockaddr_in *if_nmsk = NULL;
+	    struct sockaddr_in *if_bcst = NULL;
+
+	    if( ifht->ifam_type != RTM_NEWADDR )
+		break;
+
+	    addrPtr = buf + sizeof(struct ifa_msghdr);
+	    buf += ifht->ifam_msglen;
+
+	    if( ifh->ifm_flags & (IFF_LOOPBACK|IFF_POINTOPOINT) )
+		continue;
+
+	    for(c=1;c<(1<<RTAX_MAX);c<<=1) {
+		switch(c & ifht->ifam_addrs) {
+		case 0:
+		    continue;
+		case RTA_NETMASK:
+		    if_nmsk = (struct sockaddr_in *)addrPtr;
+		    break;
+		case RTA_IFA:
+		    if_addr = (struct sockaddr_in *)addrPtr;
+		    break;
+		case RTA_BRD:
+		    if_bcst = (struct sockaddr_in *)addrPtr;
+		    break;
+		}
+		addrPtr += SA_SIZE((struct sockaddr *)addrPtr);
+	    }
+
+
+	    if( if_addr && if_addr->sin_family == AF_INET ) {
+		if(
+		    ( dstip & if_nmsk->sin_addr.s_addr )
+			==
+		    ( if_addr->sin_addr.s_addr & if_nmsk->sin_addr.s_addr )
+		) {
+		    in_addr_t mask = ntohl(if_nmsk->sin_addr.s_addr);
+		    if( verbose )
+			printf(
+			    "Specified addr matches interface '%s' ("
+			    "IP addr %s, mask %s, bcast %s).\n",
+			    tmpIfName,
+			    inet_ntoa(if_addr->sin_addr),
+			    inet_ntoa(if_nmsk->sin_addr),
+			    inet_ntoa(if_bcst->sin_addr)
+			);
+		    ifCnt ++;
+		    if( mask > ifMaskH ) {
+			memcpy(ifName,tmpIfName,sizeof(ifName));
+			ifMaskH = mask;
+			ifAddr  = if_addr->sin_addr;
+		    }
+		}
+	    }
+	}
+    }
+
+    if( ifCnt == 0 ) {
+	strcpy(ebuf,"No interface found that matches specified IP");
+	return NULL;
+    }
+
+    if( verbose && ifCnt > 1 )
+	printf(
+	    "Using interface '%s' with src IP %s due to longer mask.\n",
+	    ifName,
+	    inet_ntoa(ifAddr)
+	);
+
+    if( ifce_ip != 0 )
+	*ifce_ip = ifAddr.s_addr;
+    return ifName;
+}
+#endif
+
 
 #ifdef WIN32
 static BOOL WINAPI arping_console_ctrl_handler(DWORD dwCtrlType)
@@ -1143,7 +1302,18 @@
 		if (dont_use_arping_lookupdev) {
 			ifname = arping_lookupdev_default(srcip,dstip,ebuf);
 		} else {
+#ifndef __FreeBSD__
 			ifname = arping_lookupdev(srcip,dstip,ebuf);
+#else
+			{
+			    in_addr_t ifce_ip = 0;
+			    ifname = FBSD_lookupIface(dstip,ebuf,&ifce_ip);
+			    if( !srcip_given ) {
+				srcip = ifce_ip;
+				srcip_given = 1;
+			    }
+			}
+#endif
 		}
 		if (!ifname) {
 			fprintf(stderr, "arping: arping_lookupdev(): %s\n",


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list