1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-24 00:19:01 +00:00

Move the body of eth_get_pcap_devname back into intf_get_pcap_devname, leaving

eth_get_pcap_devname as a wrapper.

In addition to the hardware address check, add a check of the textual interface
descriptions in order better to distinguish interfaces. It appears to me that
the pcap description (pdev->description) is the same as what is returned by a
call to PacketRequest with an OID of OID_GEN_FRIENDLY_NAME, so that's what I'm
comparing. That differs from OID_GEN_VENDOR_NAME, which is what you get in
ifrow.bDescr from GetIfTable.

We've found that simply comparing hardware addresses is not enough when using
Windows "teamed" (link-aggregated) interfaces. In a simple example, two NICs
are teamed together, leading to three interfaces visible to libdnet: the two
physical NICs and the virtual teamed interface. All three of these have the
same MAC address. What was happening was the eth0 interface was being assigned
to one of the physical NICs, packets were sent over it, but the replies were
not necessarily coming back to the same physical NIC.
This commit is contained in:
david
2010-05-13 04:06:53 +00:00
parent 5de02049fc
commit 48c6e7b820
3 changed files with 106 additions and 100 deletions

View File

@@ -60,6 +60,7 @@ intf_t *intf_open(void);
int intf_get(intf_t *i, struct intf_entry *entry);
int intf_get_src(intf_t *i, struct intf_entry *entry, struct addr *src);
int intf_get_dst(intf_t *i, struct intf_entry *entry, struct addr *dst);
int intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen);
int intf_set(intf_t *i, const struct intf_entry *entry);
int intf_loop(intf_t *i, intf_handler callback, void *arg);
intf_t *intf_close(intf_t *i);

View File

@@ -34,56 +34,25 @@ eth_t *
eth_open(const char *device)
{
eth_t *eth;
intf_t *intf;
struct intf_entry ifent;
eth_addr_t ea;
char *p, *buf;
ULONG len;
char pcapdev[128];
/* Get interface entry. */
memset(&ifent, 0, sizeof(ifent));
if ((intf = intf_open()) != NULL) {
strlcpy(ifent.intf_name, device, sizeof(ifent.intf_name));
intf_get(intf, &ifent);
intf_close(intf);
}
if (ifent.intf_link_addr.addr_type != ADDR_TYPE_ETH)
if (eth_get_pcap_devname(device, pcapdev, sizeof(pcapdev)) != 0)
return (NULL);
/* Get Packet driver adapter name/desc lists. */
buf = NULL;
PacketGetAdapterNames(buf, &len);
if (len > 0 && (buf = malloc(len)) != NULL) {
if (!PacketGetAdapterNames(buf, &len)) {
free(buf);
buf = NULL;
}
}
if (buf == NULL)
if ((eth = calloc(1, sizeof(*eth))) == NULL)
return (NULL);
/* XXX - find adapter with matching interface MAC address. */
if ((eth = calloc(1, sizeof(*eth))) == NULL) {
free(buf);
eth->lpa = PacketOpenAdapter(pcapdev);
if (eth->lpa == NULL) {
eth_close(eth);
return (NULL);
}
for (p = buf; *p != '\0'; p += strlen(p) + 1) {
if ((eth->lpa = PacketOpenAdapter(p)) != NULL) {
if (eth->lpa->hFile != INVALID_HANDLE_VALUE &&
eth_get(eth, &ea) == 0 &&
memcmp(&ea, &ifent.intf_link_addr.addr_eth,
ETH_ADDR_LEN) == 0) {
PacketSetBuff(eth->lpa, 512000);
eth->pkt = PacketAllocatePacket();
break;
}
PacketCloseAdapter(eth->lpa);
}
PacketSetBuff(eth->lpa, 512000);
eth->pkt = PacketAllocatePacket();
if (eth->pkt == NULL) {
eth_close(eth);
return NULL;
}
free(buf);
if (eth->pkt == NULL)
eth = eth_close(eth);
return (eth);
}
@@ -142,61 +111,8 @@ eth_set(eth_t *eth, const eth_addr_t *ea)
return (-1);
}
/* Converts a dnet interface name (ifname) to its pcap equivalent, which is stored in
pcapdev (up to a length of pcapdevlen). Returns 0 and fills in pcapdev if successful. */
int eth_get_pcap_devname(const char *ifname, char *pcapdev, int pcapdevlen) {
intf_t *intf;
struct intf_entry ie;
pcap_if_t *pcapdevs;
pcap_if_t *pdev;
char pname[128];
if ((intf = intf_open()) == NULL)
return -1;
pname[0] = '\0';
memset(&ie, 0, sizeof(ie));
strlcpy(ie.intf_name, ifname, sizeof(ie.intf_name));
if (intf_get(intf, &ie) != 0) {
intf_close(intf);
return -1;
}
intf_close(intf);
/* Next we must find the pcap device name corresponding to the device.
The device description used to be compared with those from PacketGetAdapterNames(), but
that was unrelaible because dnet and pcap sometimes give different descriptions. For example,
dnet gave me "AMD PCNET Family PCI Ethernet Adapter - Packet Scheduler Miniport" for one of my
adapters (in vmware), while pcap described it as "VMware Accelerated AMD PCNet Adapter (Microsoft's
Packet Scheduler)". Then IP addresses used to be compared, but that proved to be unreliable
as well. Now we compare hardware addresses much like eth_open() does */
if (pcap_findalldevs(&pcapdevs, NULL) == -1)
return -1;
if (pname[0] == '\0' && ie.intf_link_addr.addr_type == ADDR_TYPE_ETH) {
for(pdev=pcapdevs; pdev && !pname[0]; pdev = pdev->next) {
eth_t eth;
eth_addr_t ea;
eth.lpa = PacketOpenAdapter(pdev->name);
if (eth.lpa == NULL)
continue;
if (eth.lpa->hFile != INVALID_HANDLE_VALUE &&
eth_get(&eth, &ea) == 0 &&
memcmp(&ea, &ie.intf_link_addr.addr_eth,
ETH_ADDR_LEN) == 0) {
/* Found it -- Yay! */
strlcpy(pname, pdev->name, sizeof(pname));
}
PacketCloseAdapter(eth.lpa);
}
}
pcap_freealldevs(pcapdevs);
if (pname[0]) {
strlcpy(pcapdev, pname, pcapdevlen);
return 0;
}
return -1;
int
eth_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
{
return intf_get_pcap_devname(intf_name, pcapdev, pcapdevlen);
}

View File

@@ -21,6 +21,9 @@
#include <string.h>
#include "dnet.h"
#include "pcap.h"
#include <Packet32.h>
#include <Ntddndis.h>
struct ifcombo {
DWORD *idx;
@@ -384,3 +387,89 @@ intf_close(intf_t *intf)
}
return (NULL);
}
/* Converts a libdnet interface name to its pcap equivalent. The pcap name is
stored in pcapdev up to a length of pcapdevlen, including the terminating
'\0'. Returns -1 on error. */
int
intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
{
wchar_t descr_wc[512];
pcap_if_t *pcapdevs;
pcap_if_t *pdev;
intf_t *intf;
MIB_IFROW ifrow;
if ((intf = intf_open()) == NULL)
return (-1);
if (_refresh_tables(intf) < 0) {
intf_close(intf);
return (-1);
}
ifrow.dwIndex = _find_ifindex(intf, intf_name);
intf_close(intf);
if (GetIfEntry(&ifrow) != NO_ERROR)
return (-1);
/* OID_GEN_FRIENDLY_NAME returns a wide-character string, so convert
the description to wide characters for string comparison. */
mbstowcs(descr_wc, ifrow.bDescr, sizeof(descr_wc) / sizeof(descr_wc[0]) - 1);
descr_wc[sizeof(descr_wc) / sizeof(descr_wc[0]) - 1] = L'\0';
if (pcap_findalldevs(&pcapdevs, NULL) == -1)
return (-1);
/* Loop through all the pcap devices until we find a match. pcap gets
its interface list from the registry; dnet gets it from GetIfList.
We must match them up using values common to both data sets. We do
it by comparing hardware addresses and interface descriptions. */
for (pdev = pcapdevs; pdev != NULL; pdev = pdev->next) {
PACKET_OID_DATA *data;
u_char buf[512];
LPADAPTER lpa;
lpa = PacketOpenAdapter(pdev->name);
if (lpa == NULL)
continue;
if (lpa->hFile == INVALID_HANDLE_VALUE)
goto close_adapter;
data = (PACKET_OID_DATA *) buf;
/* Check the MAC address if available. */
data->Oid = OID_802_3_CURRENT_ADDRESS;
data->Length = sizeof(buf) - sizeof(*data);
if (PacketRequest(lpa, FALSE, data) == TRUE) {
if (data->Length != ifrow.dwPhysAddrLen)
goto close_adapter;
if (memcmp(ifrow.bPhysAddr, data->Data, data->Length) != 0)
goto close_adapter;
}
/* Distinct interfaces can have the same MAC address in the
case of "teamed" interfaces. Additionally check the
description string. */
data->Oid = OID_GEN_FRIENDLY_NAME;
data->Length = sizeof(buf) - sizeof(*data);
if (PacketRequest(lpa, FALSE, data) != TRUE)
goto close_adapter;
if (wcscmp(descr_wc, (wchar_t *) data->Data) != 0)
goto close_adapter;
/* Found it. */
PacketCloseAdapter(lpa);
break;
close_adapter:
PacketCloseAdapter(lpa);
}
if (pdev != NULL)
strlcpy(pcapdev, pdev->name, pcapdevlen);
pcap_freealldevs(pcapdevs);
if (pdev == NULL)
return -1;
else
return 0;
}