$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 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): Index: include/dnet/ip6.h =================================================================== --- include/dnet/ip6.h (revision 3309) +++ include/dnet/ip6.h (working copy) @@ -25,7 +25,9 @@ } ip6_addr_t; #ifndef __GNUC__ +#ifndef __attribute__ # define __attribute__(x) +#endif # pragma pack(1) #endif Index: include/dnet/ip.h =================================================================== --- include/dnet/ip.h (revision 3309) +++ include/dnet/ip.h (working copy) @@ -25,7 +25,9 @@ typedef uint32_t ip_addr_t; #ifndef __GNUC__ +#ifndef __attribute__ # define __attribute__(x) +#endif # pragma pack(1) #endif Index: include/dnet/arp.h =================================================================== --- include/dnet/arp.h (revision 3309) +++ include/dnet/arp.h (working copy) @@ -16,7 +16,9 @@ #define ARP_ETHIP_LEN 20 /* base ARP message length */ #ifndef __GNUC__ +#ifndef __attribute__ # define __attribute__(x) +#endif # pragma pack(1) #endif Index: include/dnet/tcp.h =================================================================== --- include/dnet/tcp.h (revision 3309) +++ include/dnet/tcp.h (working copy) @@ -17,7 +17,9 @@ #define TCP_HDR_LEN_MAX (TCP_HDR_LEN + TCP_OPT_LEN_MAX) #ifndef __GNUC__ +#ifndef __attribute__ # define __attribute__(x) +#endif # pragma pack(1) #endif Index: include/dnet/icmp.h =================================================================== --- include/dnet/icmp.h (revision 3309) +++ include/dnet/icmp.h (working copy) @@ -16,7 +16,9 @@ #define ICMP_LEN_MIN 8 /* minimum ICMP message size, with header */ #ifndef __GNUC__ +#ifndef __attribute__ # define __attribute__(x) +#endif # pragma pack(1) #endif 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 #include 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 Added SCTP support. Not including patches since the SCTP changes will be included in the next libdnet release. [Daniel Roethlisberger] 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)