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:
@@ -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);
|
||||
|
||||
@@ -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(ð, &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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user