$Id$

This is Dug Song's excellent Libdnet networking library version 1.12.
It has been stripped down for inclusion within Nmap and modified as follows:

o Removed the following directories:
  python, test, man, trunk

o Removed the fw-* files except for fw-none because Nmap doesn't use
  the firewall API.  Changed configure.in to always use fw-non.

o Removed files in now-removed dirs that were referenced in the AC_OUTPUT
  at the end of configure.in

o Ran "aclocal -I . -I config" to regenerate aclocal.m4 with my newer
  aclocal.

o Added this NMAP_MODIFICATIONS file.

o Added include/winconfig.h, which is a modified config.h to better support
  Windows compilation via Visual Studio.  Added conditional includes
  for it to a bunch of the dnet source files.

o A number of portability changes to remove errors/warnings during
  Win32 Visual Studio.Net compilation.  This was mostly a matter of
  adding casts and a few extra include files.

o Added libdnet-stripped.vcproj -- A Visual Studio.Net project file
  for dnet.

o Regenerated build files with Autoconf 2.63, Automake 1.10.1, and
  libtool 2.2.6.

o Added a check for socklen_t in configure.in and used socklen_t when
  calling getsockname and getsockopt to avoid a "pointer targets differ
  in signedness" warning on platforms where socklen_t is unsigned.

o Made some code changes to intf.c (the patch below).  This does the following:

  o Preserve the alias qualifier from interface name in more cases
    (e.g. don't blow away :2 from eth0:2 when it may still be needed.

  o Set the SO_BROADCAST flag on the interface list descriptor so that
    broadcast/network IPs can be investigated.

  o Update _match_intf_src so that it checks interface aliases for the
    given source address rather than only the main interface address.

diff -Nruw old/src/intf.c nmap-3.83.new/src/intf.c
--- src/intf.c  2005-05-03 09:41:35.000000000 -0700
+++ src/intf.c  2005-07-16 20:55:05.000000000 -0700
@@ -119,12 +119,16 @@
 intf_open(void)
 {
        intf_t *intf;
+       int one = 1;
 
        if ((intf = calloc(1, sizeof(*intf))) != NULL) {
                intf->fd = intf->fd6 = -1;
 
                if ((intf->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
                        return (intf_close(intf));
+
+               setsockopt(intf->fd, SOL_SOCKET, SO_BROADCAST, 
+                          (const char *) &one, sizeof(one));
 #ifdef SIOCGIFNETMASK_IN6
                if ((intf->fd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
 #  ifdef EPROTONOSUPPORT
@@ -472,6 +476,7 @@
 _intf_get_aliases(intf_t *intf, struct intf_entry *entry)
 {
        struct ifreq *ifr, *lifr;
+       struct ifreq tmpifr;
        struct addr *ap, *lap;
        char *p;
 
@@ -492,9 +497,12 @@
                if ((p = strchr(ifr->ifr_name, ':')) != NULL)
                        *p = '\0';
 
-               if (strcmp(ifr->ifr_name, entry->intf_name) != 0)
+               if (strcmp(ifr->ifr_name, entry->intf_name) != 0) {
+                 if (p) *p = ':';
                        continue;
+               }
 
+               if (p) *p = ':'; /* Fix the name back up */
                if (addr_ston(&ifr->ifr_addr, ap) < 0)
                        continue;
 
@@ -506,6 +514,11 @@
                        if (ap->addr_ip == entry->intf_addr.addr_ip ||
                            ap->addr_ip == entry->intf_dst_addr.addr_ip)
                                continue;
+                       strlcpy(tmpifr.ifr_name, ifr->ifr_name, 
+                              sizeof(tmpifr.ifr_name));
+                       if (ioctl(intf->fd, SIOCGIFNETMASK, &tmpifr) == 0)
+                         addr_stob(&tmpifr.ifr_addr, &ap->addr_bits);
+
                }
 #ifdef SIOCGIFNETMASK_IN6
                else if (ap->addr_type == ADDR_TYPE_IP6 && intf->fd6 != -1) {
@@ -547,10 +560,22 @@
 static int
 _match_intf_src(const struct intf_entry *entry, void *arg)
 {
+       int matched = 0;
+       int cnt;
        struct intf_entry *save = (struct intf_entry *)arg;
 
        if (entry->intf_addr.addr_type == ADDR_TYPE_IP &&
-           entry->intf_addr.addr_ip == save->intf_addr.addr_ip) {
+           entry->intf_addr.addr_ip == save->intf_addr.addr_ip)
+         matched = 1;
+  
+       for (cnt = 0; !matched && cnt < (int) entry->intf_alias_num; cnt++) {
+         if (entry->intf_alias_addrs[cnt].addr_type != ADDR_TYPE_IP)
+           continue;
+         if (entry->intf_alias_addrs[cnt].addr_ip == save->intf_addr.addr_ip)
+           matched = 1;
+       }
+
+       if (matched) {
                /* XXX - truncated result if entry is too small. */
                if (save->intf_len < entry->intf_len)
                        memcpy(save, entry, save->intf_len);
@@ -678,14 +703,18 @@
                if ((p = strchr(ifr->ifr_name, ':')) != NULL)
                        *p = '\0';
 
-               if (pifr != NULL && strcmp(ifr->ifr_name, pifr->ifr_name) == 0)
+               if (pifr != NULL && strcmp(ifr->ifr_name, pifr->ifr_name) == 0) {
+                 if (p) *p = ':';
                        continue;
+               }
 
                memset(ebuf, 0, sizeof(ebuf));
                strlcpy(entry->intf_name, ifr->ifr_name,
                    sizeof(entry->intf_name));
                entry->intf_len = sizeof(ebuf);
 
+               /* Repair the alias name back up. */
+               if (p) *p = ':';
                if (_intf_get_noalias(intf, entry) < 0)
                        return (-1);
                if (_intf_get_aliases(intf, entry) < 0)



o Made some AIX/HP-UX portability changes sent in by Peter O'Gorman
(nmap-dev@mlists.thewrittenword.com), part 2:
Index: src/arp-ioctl.c
===================================================================
--- src/arp-ioctl.c     (revision 3309)
+++ src/arp-ioctl.c     (working copy)
@@ -383,7 +383,7 @@
        }
        return (ret);
 }
-#elif defined(HAVE_NET_RADIX_H)
+#elif defined(HAVE_NET_RADIX_H) && !defined(_AIX)
 /* XXX - Tru64, others? */
 #include <netinet/if_ether.h>
 #include <nlist.h>
Index: src/intf.c
===================================================================
--- src/intf.c  (revision 3309)
+++ src/intf.c  (working copy)
@@ -284,7 +284,9 @@
        /* Set interface MTU. */
        if (entry->intf_mtu != 0) {
                ifr.ifr_mtu = entry->intf_mtu;
+#ifdef SIOCSIFMTU
                if (ioctl(intf->fd, SIOCSIFMTU, &ifr) < 0)
+#endif
                        return (-1);
        }
        /* Set interface address. */
@@ -396,7 +398,9 @@
        _intf_set_type(entry);

        /* Get interface MTU. */
+#ifdef SIOCGIFMTU
        if (ioctl(intf->fd, SIOCGIFMTU, &ifr) < 0)
+#endif
                return (-1);
        entry->intf_mtu = ifr.ifr_mtu;

o Made the following change for Windows Vista support (thanks to Dan
Griffin):
--- old/intf-win32.c        2005-12-28 16:30:38.000000000 -0800
+++ intf-win32.c        2006-11-26 20:46:13.000000000 -0800
@@ -31,7 +31,7 @@
        int              max;
 };

-#define MIB_IF_TYPE_MAX         32     /* XXX - ipifcons.h */
+#define MIB_IF_TYPE_MAX                MAX_IF_TYPE     /* XXX - ipifcons.h */

 struct intf_handle {
        struct ifcombo   ifcombo[MIB_IF_TYPE_MAX];

o Fix a compiler "may be used unitialized" warning:
Index: addr-util.c
===================================================================
--- addr-util.c (revision 3855)
+++ addr-util.c (working copy)
@@ -177,6 +177,8 @@
        struct { int base, len; } best, cur;
        char *p = dst;
        int i;
+
+       cur.len = best.len = 0;

        if (len < 46)
                return (NULL);

o Removed config.sub, config.guess, install-sh, ltmain.sh, and missing from the
  config directory. These files are found in the parent (i.e., Nmap's)
  directory. Also removed config/mkinstalldirs because it is replaced with
  $(install_sh) -d. Change Makefile.am not to use ac_aux_dir, which is an
  internal Autoconf variable.
Index: configure.in
===================================================================
--- configure.in	(revision 6317)
+++ configure.in	(working copy)
@@ -6,8 +6,6 @@
 dnl $Id$
 
 AC_INIT(include/dnet.h)
-AC_CONFIG_AUX_DIR(config)
-AC_SUBST(ac_aux_dir)
 
 AM_INIT_AUTOMAKE(libdnet, 1.10)
 AM_CONFIG_HEADER(include/config.h)
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 6317)
+++ Makefile.am	(working copy)
@@ -10,16 +10,12 @@
 
 CLEANFILES =	dnet-config
 
-AUX_DIST =	$(ac_aux_dir)/acinclude.m4	\
-		$(ac_aux_dir)/config.guess	\
-		$(ac_aux_dir)/config.sub	\
-		$(ac_aux_dir)/install-sh	\
-		$(ac_aux_dir)/ltmain.sh		\
-		$(ac_aux_dir)/missing		\
-		$(ac_aux_dir)/mkinstalldirs
+aux_dir = config
 
+AUX_DIST =	$(aux_dir)/acinclude.m4
+
 dist-hook:
-	(cd $(distdir) && mkdir $(ac_aux_dir))
+	(cd $(distdir) && mkdir $(aux_dir))
 	for file in $(AUX_DIST); do \
 		cp $$file $(distdir)/$$file; \
 	done

o Remember the entry->intf_len before zeroing entry in _ifrow_to_entry.
intf_loop relies on passing the length inside the structure to make sure
interface aliases are accounted for.
Index: src/intf-win32.c
===================================================================
--- src/intf-win32.c	(revision 6288)
+++ src/intf-win32.c	(working copy)
@@ -103,7 +103,12 @@
 	struct addr *ap, *lap;
 	int i;
 	
+	/* The total length of the entry may be passed in inside entry.
+	   Remember it and clear the entry. */
+	u_int intf_len = entry->intf_len;
 	memset(entry, 0, sizeof(*entry));
+	/* Restore the length. */
+	entry->intf_len = intf_len;
 
 	for (i = 0; i < intf->ifcombo[ifrow->dwType].cnt; i++) {
 		if (intf->ifcombo[ifrow->dwType].idx[i] == ifrow->dwIndex)

o Forced interface type numbers to be canonicalized to internal numbers to
avoid accessing uninitialized memory when an unknown device name is
given.
Index: libdnet-stripped/src/intf-win32.c
===================================================================
--- libdnet-stripped/src/intf-win32.c	(revision 6413)
+++ libdnet-stripped/src/intf-win32.c	(working copy)
@@ -42,9 +42,12 @@
 static char *
 _ifcombo_name(int type)
 {
-	char *name = "net";	/* XXX */
+	/* Unknown interface types get the prefix "net". */
+	char *name = "net";
 	
-	if (type == MIB_IF_TYPE_ETHERNET) {
+	if (type == MIB_IF_TYPE_ETHERNET || type == IF_TYPE_IEEE80211) {
+		/* INTF_TYPE_IEEE80211 is used for wireless devices on
+		   Windows Vista. */
 		name = "eth";
 	} else if (type == MIB_IF_TYPE_TOKENRING) {
 		name = "tr";
@@ -60,9 +63,12 @@
 	return (name);
 }
 
+/* Return a canonical internal interface type number for the given
+ * device string. */
 static int
 _ifcombo_type(const char *device)
 {
+	/* Unknown device names (like "net") get mapped to INTF_TYPE_OTHER. */
 	int type = INTF_TYPE_OTHER;
 	
 	if (strncmp(device, "eth", 3) == 0) {
@@ -81,6 +87,20 @@
 	return (type);
 }
 
+/* Map an MIB_IFROW.dwType interface type into an internal interface
+   type. The internal types are never exposed to users of this library;
+   they exist only for the sake of ordering interface types within an
+   intf_handle, which has an array of ifcombo structures ordered by
+   type. Entries in an intf_handle must not be stored or accessed by a
+   raw MIB_IFROW.dwType number because they will not be able to be found
+   by a device name such as "net0" if the device name does not map
+   exactly to the dwType. */
+static int
+_if_type_canonicalize(int type)
+{
+	return _ifcombo_type(_ifcombo_name(type));
+}
+
 static void
 _ifcombo_add(struct ifcombo *ifc, DWORD idx)
 {
@@ -102,6 +122,7 @@
 {
 	struct addr *ap, *lap;
 	int i;
+	int type;
 	
 	/* The total length of the entry may be passed in inside entry.
 	   Remember it and clear the entry. */
@@ -110,14 +131,15 @@
 	/* Restore the length. */
 	entry->intf_len = intf_len;
 
-	for (i = 0; i < intf->ifcombo[ifrow->dwType].cnt; i++) {
-		if (intf->ifcombo[ifrow->dwType].idx[i] == ifrow->dwIndex)
+	type = _if_type_canonicalize(ifrow->dwType);
+	for (i = 0; i < intf->ifcombo[type].cnt; i++) {
+		if (intf->ifcombo[type].idx[i] == ifrow->dwIndex)
 			break;
 	}
-	/* XXX - dwType matches MIB-II ifType. */
+	/* XXX - type matches MIB-II ifType. */
 	snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
-	    _ifcombo_name(ifrow->dwType), i);
-	entry->intf_type = (uint16_t)ifrow->dwType;
+	    _ifcombo_name(type), i);
+	entry->intf_type = (uint16_t)type;
 	
 	/* Get interface flags. */
 	entry->intf_flags = 0;
@@ -201,9 +223,11 @@
 	 * XXX - like IP_ADAPTER_INFO ComboIndex
 	 */
 	for (i = 0; i < intf->iftable->dwNumEntries; i++) {
+		int type;
 		ifrow = &intf->iftable->table[i];
-		if (ifrow->dwType < MIB_IF_TYPE_MAX) {
-			_ifcombo_add(&intf->ifcombo[ifrow->dwType],
+		type = _if_type_canonicalize(ifrow->dwType);
+		if (type < MIB_IF_TYPE_MAX) {
+			_ifcombo_add(&intf->ifcombo[type],
 			    ifrow->dwIndex);
 		} else
 			return (-1);

o Added eth_get_pcap_devname() that matches up a dnet name to its pcap
  equivalent by matching hardwar addresses.  It's similar to the code
  used in eth_open()

o Handle the case of sa_len == 0 (meaning 0.0.0.0) in addr_stob.
Index: src/addr.c
===================================================================
--- src/addr.c	(revision 12591)
+++ src/addr.c	(working copy)
@@ -385,11 +385,17 @@
 	} else
 #endif
 	{
+		p = (u_char *)&so->sin.sin_addr.s_addr;
 #ifdef HAVE_SOCKADDR_SA_LEN
-		if ((len = sa->sa_len - IP_ADDR_LEN) > IP_ADDR_LEN)
+		len = sa->sa_len - ((void *) p - (void *) sa);
+		/* Handles the special case of sa->sa_len == 0. */
+		if (len < 0)
+			len = 0;
+		else if (len > IP_ADDR_LEN)
+			len = IP_ADDR_LEN;
+#else
+		len = IP_ADDR_LEN;
 #endif
-		len = IP_ADDR_LEN;
-		p = (u_char *)&so->sin.sin_addr.s_addr;
 	}
 	for (n = i = 0; i < len; i++, n += 8) {
 		if (p[i] != 0xff)

o Fixed a case where an open file may not be closed in intf_loop() [Josh]
Index: src/intf.c
===================================================================
--- src/intf.c	(revision 14004)
+++ src/intf.c	(working copy)
@@ -677,8 +677,10 @@
 	intf->ifc.ifc_buf = (caddr_t)intf->ifcbuf;
 	intf->ifc.ifc_len = sizeof(intf->ifcbuf);
 	
-	if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0)
+	if (ioctl(intf->fd, SIOCGIFCONF, &intf->ifc) < 0) {
+		fclose(fp);
 		return (-1);
+	}
 
 	ret = 0;
 	while (fgets(buf, sizeof(buf), fp) != NULL) {

o Added casts to calls of ctype functions so that their arguments are explicitly
cast to (int) [Josh Marlow]
Index: src/blob.c
===================================================================
--- src/blob.c	(revision 14763)
+++ src/blob.c	(working copy)
@@ -162,7 +162,7 @@
 	for (p = (char *)fmt; *p != '\0'; p++) {
 		if (*p == '%') {
 			p++;
-			if (isdigit((int)*p)) {
+			if (isdigit((int) (unsigned char) *p)) {
 				len = strtol(p, &p, 10);
 			} else if (*p == '*') {
 				len = va_arg(*ap, int);
Index: src/intf-win32.c
===================================================================
--- src/intf-win32.c	(revision 14763)
+++ src/intf-win32.c	(working copy)
@@ -234,7 +234,7 @@
 	char *p = (char *)device;
 	int n, type = _ifcombo_type(device);
 	
-	while (isalpha(*p)) p++;
+	while (isalpha((int) (unsigned char) *p)) p++;
 	n = atoi(p);
 
 	return (intf->ifcombo[type].idx[n]);


===CHANGES ALREADY MERGED TO UPSTREAM LIBDNET GO BELOW THIS LINE===

o Made some AIX/HP-UX portability changes sent in by Peter O'Gorman
  (nmap-dev@mlists.thewrittenword.com), part 1.
  Merged to libdnet r653.

o Added SCTP support. [Daniel Roethlisberger]
  Merged to libdnet r651 and r652.

o Applied a fix for building on GNU/kFreeBSD from Peter Salinger:
--- configure	(revision 15144)
+++ configure	(working copy)
@@ -14712,12 +14712,22 @@
 
 elif test "$ac_cv_header_net_if_tun_h" = yes ; then
 	if test "$ac_cv_header_stropts_h" = yes ; then
-		case " $LIBOBJS " in
+               case "$host_os" in
+               *kfreebsd*)
+                       case " $LIBOBJS " in
+  *" tun-bsd.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS tun-bsd.$ac_objext"
+ ;;
+esac
+;;
+               *)
+                       case " $LIBOBJS " in
   *" tun-solaris.$ac_objext "* ) ;;
   *) LIBOBJS="$LIBOBJS tun-solaris.$ac_objext"
  ;;
 esac
-
+;;
+               esac
 	else
 		case " $LIBOBJS " in
   *" tun-bsd.$ac_objext "* ) ;;