1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Wrap dnet eth functions for non-Ethernet links

This commit is contained in:
dmiller
2025-06-23 20:54:32 +00:00
parent 7637ce3674
commit 3499025302
9 changed files with 177 additions and 49 deletions

View File

@@ -959,10 +959,91 @@ int pcap_select(pcap_t *p, long usecs) {
return ret;
}
struct netutil_eth_t {
union {
pcap_t *pt;
eth_t *ethsd;
};
int datalink;
};
int netutil_eth_datalink(const netutil_eth_t *e) {
if (e) return e->datalink;
return -1;
}
#ifdef WIN32
#define eth_handle(_eth) (_eth->pt)
#define eth_handle_send pcap_inject
#define eth_handle_close eth_close
#else
#define eth_handle(_eth) (_eth->ethsd)
#define eth_handle_send eth_send
#define eth_handle_close eth_close
#endif
netutil_eth_t *netutil_eth_open(const char *device) {
assert(device != NULL);
assert(device[0] != '\0');
netutil_eth_t *e = (netutil_eth_t *)safe_zalloc(sizeof(netutil_eth_t));
e->datalink = -1;
#ifdef WIN32
char err0r[PCAP_ERRBUF_SIZE] = {0};
char pcapdev[128] = {0};
int failed = 0;
pcap_t *pt = NULL;
do {
if (!DnetName2PcapName(device, pcapdev, sizeof(pcapdev))) {
break;
}
pt = pcap_create(pcapdev, err0r);
if (!pt) {
netutil_error("pcap_create(%s) FAILED: %s.", pcapdev, err0r);
break;
}
failed = pcap_activate(pt);
if (failed < 0) {
// PCAP error
netutil_error("pcap_activate(%s) FAILED: %s.", pcapdev, pcap_geterr(pt));
pcap_close(pt);
return NULL;
}
else if (failed > 0) {
// PCAP warning, report but assume it'll still work
netutil_error("pcap_activate(%s) WARNING: %s.", pcapdev, pcap_geterr(pt));
}
eth_handle(e) = pt;
e->datalink = pcap_datalink(pt);
} while (0);
#else
eth_handle(e) = eth_open(device);
e->datalink = DLT_EN10MB;
#endif
if (eth_handle(e) == NULL) {
free(e);
return NULL;
}
return e;
}
void netutil_eth_close(netutil_eth_t *e) {
assert(e != NULL);
eth_handle_close(eth_handle(e));
free(e);
}
ssize_t netutil_eth_send(netutil_eth_t *e, const void *buf, size_t len) {
assert(e != NULL);
assert(eth_handle(e) != NULL);
return eth_handle_send(eth_handle(e), buf, len);
}
/* These two are for eth_open_cached() and eth_close_cached() */
static char etht_cache_device_name[64];
static eth_t *etht_cache_device = NULL;
static netutil_eth_t *etht_cache_device = NULL;
/* A simple function that caches the eth_t from dnet for one device,
to avoid opening, closing, and re-opening it thousands of tims. If
@@ -972,7 +1053,7 @@ static eth_t *etht_cache_device = NULL;
eth_close() A DEVICE OBTAINED FROM THIS FUNCTION. Instead, you can
call eth_close_cached() to close whichever device (if any) is
cached. Returns NULL if it fails to open the device. */
eth_t *eth_open_cached(const char *device) {
netutil_eth_t *eth_open_cached(const char *device) {
if (!device)
netutil_fatal("%s() called with NULL device name!", __func__);
if (!*device)
@@ -984,12 +1065,12 @@ eth_t *eth_open_cached(const char *device) {
}
if (*etht_cache_device_name) {
eth_close(etht_cache_device);
netutil_eth_close(etht_cache_device);
etht_cache_device_name[0] = '\0';
etht_cache_device = NULL;
}
etht_cache_device = eth_open(device);
etht_cache_device = netutil_eth_open(device);
if (etht_cache_device)
Strncpy(etht_cache_device_name, device,
sizeof(etht_cache_device_name));
@@ -1000,7 +1081,7 @@ eth_t *eth_open_cached(const char *device) {
/* See the description for eth_open_cached */
void eth_close_cached() {
if (etht_cache_device) {
eth_close(etht_cache_device);
netutil_eth_close(etht_cache_device);
etht_cache_device = NULL;
etht_cache_device_name[0] = '\0';
}
@@ -3448,19 +3529,27 @@ int Sendto(const char *functionname, int sd,
}
int netutil_eth_can_send(const netutil_eth_t *e) {
switch (netutil_eth_datalink(e)) {
case DLT_NULL:
case DLT_EN10MB:
case DLT_RAW:
return 1;
break;
default:
return 0;
break;
}
}
/* Send an IP packet over an ethernet handle. */
static int send_ip_packet_eth(const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen, int af) {
eth_t *ethsd;
u8 *eth_frame;
netutil_eth_t *ethsd;
u8 *eth_frame = NULL;
int res;
size_t framelen;
uint16_t ethertype = (af == AF_INET6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP);
framelen = 14 + packetlen;
eth_frame = (u8 *) safe_malloc(framelen);
memcpy(eth_frame + 14, packet, packetlen);
eth_pack_hdr(eth_frame, eth->dstmac, eth->srcmac, ethertype);
if (!eth->ethsd) {
ethsd = eth_open_cached(eth->devname);
if (!ethsd)
@@ -3468,9 +3557,42 @@ static int send_ip_packet_eth(const struct eth_nfo *eth, const u8 *packet, unsig
} else {
ethsd = eth->ethsd;
}
res = eth_send(ethsd, eth_frame, framelen);
switch (ethsd->datalink) {
case DLT_EN10MB:
framelen = 14 + packetlen;
eth_frame = (u8 *) safe_malloc(framelen);
memcpy(eth_frame + 14, packet, packetlen);
eth_pack_hdr(eth_frame, eth->dstmac, eth->srcmac, ethertype);
break;
case DLT_NULL:
framelen = 4 + packetlen;
eth_frame = (u8 *) safe_malloc(framelen);
memcpy(eth_frame + 4, packet, packetlen);
if (af == AF_INET6) {
/* These values are per libpcap/gencode.c */
#if defined(__APPLE__)
*(uint32_t *)eth_frame = 30; // macOS, iOS, other Darwin-based OSes
#elif defined(__FreeBSD__)
*(uint32_t *)eth_frame = 28; // FreeBSD
#else
*(uint32_t *)eth_frame = 24; // NetBSD, OpenBSD, BSD/OS, Npcap
#endif
}
else {
*(uint32_t *)eth_frame = AF_INET;
}
break;
case DLT_RAW:
framelen = packetlen;
break;
default:
netutil_fatal("%s: unsupported DLT for %s: %d", __func__, eth->devname, ethsd->datalink);
break;
}
res = netutil_eth_send(ethsd, eth_frame ? eth_frame : packet, framelen);
/* No need to close ethsd due to caching */
free(eth_frame);
if (eth_frame != packet)
free(eth_frame);
return res;
}
@@ -4364,7 +4486,7 @@ bool doND(const char *dev, const u8 *srcmac,
int timeouts[] = { 100000, 400000, 800000 };
int max_sends = 3;
int num_sends = 0; // How many we have sent so far
eth_t *ethsd;
netutil_eth_t *ethsd;
u8 frame[ETH_HDR_LEN + IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8];
struct timeval start, now, rcvdtime;
int timeleft;
@@ -4423,7 +4545,7 @@ bool doND(const char *dev, const u8 *srcmac,
while (!foundit && num_sends < max_sends) {
/* Send the sucker */
rc = eth_send(ethsd, frame, sizeof(frame));
rc = netutil_eth_send(ethsd, frame, sizeof(frame));
if (rc != sizeof(frame)) {
netutil_error("WARNING: %s: eth_send of Neighbor Solicitation packet returned %u rather than expected %d bytes", __func__, rc, (int) sizeof(frame));
}
@@ -4484,7 +4606,7 @@ bool doArp(const char *dev, const u8 *srcmac,
int timeouts[] = { 100000, 400000, 800000 };
int max_sends = 3;
int num_sends = 0; // How many we have sent so far
eth_t *ethsd;
netutil_eth_t *ethsd;
u8 frame[ETH_HDR_LEN + ARP_HDR_LEN + ARP_ETHIP_LEN];
const struct sockaddr_in *targetsin = (struct sockaddr_in *) targetip;
const struct sockaddr_in *srcsin = (struct sockaddr_in *) srcip;
@@ -4520,7 +4642,7 @@ bool doArp(const char *dev, const u8 *srcmac,
while (!foundit && num_sends < max_sends) {
/* Send the sucker */
rc = eth_send(ethsd, frame, sizeof(frame));
rc = netutil_eth_send(ethsd, frame, sizeof(frame));
if (rc != sizeof(frame)) {
netutil_error("WARNING: %s: eth_send of ARP packet returned %u rather than expected %d bytes", __func__, rc, (int) sizeof(frame));
}

View File

@@ -74,8 +74,8 @@ extern "C" {
}
#endif
#include "dnet.h"
#include <nbase.h>
#include <dnet.h>
/* It is VERY important to never change the value of these two constants.
* Specially, OP_FAILURE should never be positive, as some pieces of code take
@@ -278,10 +278,12 @@ struct sys_route {
int metric;
};
struct netutil_eth_t;
struct eth_nfo {
char srcmac[6];
char dstmac[6];
eth_t *ethsd; // Optional, but improves performance. Set to NULL if unavail
netutil_eth_t *ethsd; // Optional, but improves performance. Set to NULL if unavail
char devname[16]; // Only needed if ethsd is NULL.
};
@@ -293,7 +295,12 @@ struct eth_nfo {
eth_close() A DEVICE OBTAINED FROM THIS FUNCTION. Instead, you can
call eth_close_cached() to close whichever device (if any) is
cached. Returns NULL if it fails to open the device. */
eth_t *eth_open_cached(const char *device);
netutil_eth_t *eth_open_cached(const char *device);
netutil_eth_t *netutil_eth_open(const char *device);
void netutil_eth_close(netutil_eth_t *e);
ssize_t netutil_eth_send(netutil_eth_t *e, const void *buf, size_t len);
int netutil_eth_datalink(const netutil_eth_t *e);
int netutil_eth_can_send(const netutil_eth_t *e);
/* See the description for eth_open_cached */
void eth_close_cached();

View File

@@ -66,7 +66,6 @@
#include "output.h"
#include "nbase.h"
#include "pcap.h"
#include "dnet.h"
#include <vector>
extern NpingOps o;
@@ -1111,8 +1110,8 @@ int send_packet(NpingTarget *target, int rawfd, u8 *pkt, size_t pktLen){
assert(pktLen > 0);
if ( o.sendEth() ){
eth_t *ethsd = eth_open_cached(o.getDevice());
eth_send(ethsd, pkt, pktLen);
netutil_eth_t *ethsd = eth_open_cached(o.getDevice());
netutil_eth_send(ethsd, pkt, pktLen);
}else{
if( o.ipv6() ){ /* IPv6 */
memset(&s6, 0, sizeof(struct sockaddr_in6));

View File

@@ -24,7 +24,7 @@ enum {
typedef struct nse_dnet_udata
{
eth_t *eth;
netutil_eth_t *eth;
int sock; /* raw ip socket */
char devname[32]; /* libnetutil uses this len; dnet generally uses 16 */
} nse_dnet_udata;
@@ -123,23 +123,23 @@ static int l_dnet_get_interface_info (lua_State *L)
static int close_eth (lua_State *L)
{
eth_t **eth = (eth_t **) nseU_checkudata(L, 1, DNET_ETHERNET_METATABLE, "ethernet");
netutil_eth_t **eth = (netutil_eth_t **) nseU_checkudata(L, 1, DNET_ETHERNET_METATABLE, "ethernet");
assert(*eth != NULL);
eth_close(*eth);
netutil_eth_close(*eth);
*eth = NULL;
return nseU_success(L);
}
static eth_t *open_eth_cached (lua_State *L, int dnet_index, const char *device)
static netutil_eth_t *open_eth_cached (lua_State *L, int dnet_index, const char *device)
{
eth_t **eth;
netutil_eth_t **eth;
lua_getfield(L, CACHE_DEVICE_ETHERNET, device);
if (!lua_isuserdata(L, -1))
{
lua_pop(L, 1);
eth = (eth_t **) lua_newuserdatauv(L, sizeof(eth_t *), 0);
*eth = eth_open(device);
eth = (netutil_eth_t **) lua_newuserdatauv(L, sizeof(netutil_eth_t *), 0);
*eth = netutil_eth_open(device);
if (*eth == NULL)
luaL_error(L, "unable to open dnet on ethernet interface %s", device);
lua_pushvalue(L, DNET_ETHERNET_METATABLE);
@@ -147,13 +147,13 @@ static eth_t *open_eth_cached (lua_State *L, int dnet_index, const char *device)
lua_pushvalue(L, -1);
lua_setfield(L, CACHE_DEVICE_ETHERNET, device);
}
eth = (eth_t **) lua_touserdata(L, -1);
eth = (netutil_eth_t **) lua_touserdata(L, -1);
lua_pushvalue(L, dnet_index);
lua_pushvalue(L, -2); /* eth_t userdata */
lua_pushvalue(L, -2); /* netutil_eth_t userdata */
lua_rawset(L, CACHE_DNET_ETHERNET);
lua_pop(L, 1); /* eth_t userdata */
lua_pop(L, 1); /* netutil_eth_t userdata */
return *eth;
}
@@ -213,11 +213,11 @@ static int ethernet_send (lua_State *L)
log_write(LOG_STDOUT, "%s: Ethernet frame (%lu bytes) > %s\n",
SCRIPT_ENGINE, len, udata->devname);
}
size_t sent = eth_send(udata->eth, frame, len);
size_t sent = netutil_eth_send(udata->eth, frame, len);
if (sent == len)
return nseU_success(L);
else
return nseU_safeerror(L, "eth_send error: %lu", sent);
return nseU_safeerror(L, "netutil_eth_send error: %lu", sent);
}
static int ip_open (lua_State *L)

View File

@@ -1172,7 +1172,7 @@ void HostOsScanStats::initScanStats() {
/* Fill in an eth_nfo struct with the appropriate source and destination MAC
addresses and a given Ethernet handle. The return value is suitable to pass
to send_ip_packet: if ethsd is NULL, returns NULL; otherwise returns eth. */
struct eth_nfo *HostOsScanStats::fill_eth_nfo(struct eth_nfo *eth, eth_t *ethsd) const {
struct eth_nfo *HostOsScanStats::fill_eth_nfo(struct eth_nfo *eth, netutil_eth_t *ethsd) const {
if (ethsd == NULL)
return NULL;

View File

@@ -64,7 +64,7 @@
#define OSSCAN2_H
#include "nbase.h"
#include <dnet.h>
#include "libnetutil/netutil.h"
#include <pcap.h>
#include <vector>
@@ -232,7 +232,7 @@ class HostOsScanStats {
HostOsScanStats(Target *t);
~HostOsScanStats();
void initScanStats();
struct eth_nfo *fill_eth_nfo(struct eth_nfo *eth, eth_t *ethsd) const;
struct eth_nfo *fill_eth_nfo(struct eth_nfo *eth, netutil_eth_t *ethsd) const;
void addNewProbe(OFProbeType type, int subid);
void removeActiveProbe(std::list<OFProbe *>::iterator probeI);
/* Get an active probe from active probe list identified by probe type
@@ -431,7 +431,7 @@ private:
int get_tcpopt_string(const struct tcp_hdr *tcp, int mss, char *result, int maxlen) const;
int rawsd; /* Raw socket descriptor */
eth_t *ethsd; /* Ethernet handle */
netutil_eth_t *ethsd; /* Ethernet handle */
unsigned int tcpSeqBase; /* Seq value used in TCP probes */
unsigned int tcpAck; /* Ack value used in TCP probes */

View File

@@ -68,7 +68,7 @@
#include "scan_lists.h"
#include "probespec.h"
#include <dnet.h>
#include "libnetutil/netutil.h"
#include "timing.h"
@@ -626,7 +626,7 @@ public:
const struct scan_lists *ports;
int rawsd; /* raw socket descriptor */
pcap_t *pd;
eth_t *ethsd;
netutil_eth_t *ethsd;
u32 seqmask; /* This mask value is used to encode values in sequence
numbers. It is set randomly in UltraScanInfo::Init() */
u16 base_port;

View File

@@ -940,7 +940,7 @@ UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
gettimeofday(&USI->now, NULL);
probe->sent = USI->now;
hss->probeSent(sizeof(frame));
if ((rc = eth_send(USI->ethsd, frame, sizeof(frame))) != sizeof(frame)) {
if ((rc = netutil_eth_send(USI->ethsd, frame, sizeof(frame))) != sizeof(frame)) {
int err = socket_errno();
error("WARNING: eth_send of ARP packet returned %i rather than expected %d (errno=%i: %s)", rc, (int) sizeof(frame), err, strerror(err));
}

View File

@@ -229,7 +229,7 @@ public:
~HostState();
bool has_more_probes() const;
bool is_finished() const;
bool send_next_probe(int rawsd, eth_t *ethsd);
bool send_next_probe(int rawsd, netutil_eth_t *ethsd);
void next_ttl();
void count_up();
int cancel_probe(std::list<Probe *>::iterator it);
@@ -262,8 +262,8 @@ public:
Probe(HostState *host, struct probespec pspec, u8 ttl);
virtual ~Probe();
void send(int rawsd, eth_t *ethsd, struct timeval *now = NULL);
void resend(int rawsd, eth_t *ethsd, struct timeval *now = NULL);
void send(int rawsd, netutil_eth_t *ethsd, struct timeval *now = NULL);
void resend(int rawsd, netutil_eth_t *ethsd, struct timeval *now = NULL);
bool is_timedout(struct timeval *now = NULL) const;
bool may_resend() const;
virtual unsigned char *build_packet(const struct sockaddr_storage *source,
@@ -292,7 +292,7 @@ public:
double completion_fraction() const;
private:
eth_t *ethsd;
netutil_eth_t *ethsd;
int rawsd;
pcap_t *pd;
int num_active_probes;
@@ -348,7 +348,7 @@ bool HostState::is_finished() const {
&& active_probes.empty() && pending_resends.empty();
}
bool HostState::send_next_probe(int rawsd, eth_t *ethsd) {
bool HostState::send_next_probe(int rawsd, netutil_eth_t *ethsd) {
Probe *probe;
/* Do a resend if possible. */
@@ -589,7 +589,7 @@ Probe::Probe(HostState *host, struct probespec pspec, u8 ttl) {
Probe::~Probe() {
}
void Probe::send(int rawsd, eth_t *ethsd, struct timeval *now) {
void Probe::send(int rawsd, netutil_eth_t *ethsd, struct timeval *now) {
struct eth_nfo eth;
struct eth_nfo *ethp;
int decoy;
@@ -623,7 +623,7 @@ void Probe::send(int rawsd, eth_t *ethsd, struct timeval *now) {
}
}
void Probe::resend(int rawsd, eth_t *ethsd, struct timeval *now) {
void Probe::resend(int rawsd, netutil_eth_t *ethsd, struct timeval *now) {
num_resends++;
this->send(rawsd, ethsd, now);
}