From fc71b7544d933f24cde0886b712e1977b4b9dc2f Mon Sep 17 00:00:00 2001 From: dmiller Date: Thu, 26 Jun 2025 19:03:01 +0000 Subject: [PATCH] Allow layer-2 sending for non-Ethernet links; MAC addr optional --- FPEngine.cc | 69 +++++++++++++++++++++++++++++++--------------- FPEngine.h | 5 ++-- scan_engine.cc | 27 ++++++++++-------- scan_engine_raw.cc | 20 ++++++++------ traceroute.cc | 6 ++-- 5 files changed, 82 insertions(+), 45 deletions(-) diff --git a/FPEngine.cc b/FPEngine.cc index fc949a421..ffa58d086 100644 --- a/FPEngine.cc +++ b/FPEngine.cc @@ -1725,7 +1725,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID(TCP_DESCS[i].id); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } /* Mark as a timed probe. */ this->fp_probes[this->total_probes].setTimed(); this->timed_probes++; @@ -1766,7 +1768,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID("IE1"); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } this->total_probes++; /* ICMP Probe #2: Echo Request with badly ordered extension headers */ @@ -1803,7 +1807,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID("IE2"); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } this->total_probes++; /* ICMP Probe #3: Neighbor Solicitation. (only sent to on-link targets) */ @@ -1833,7 +1839,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID("NS"); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } this->total_probes++; } @@ -1862,7 +1870,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID("U1"); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } this->total_probes++; /* Set TECN probe */ @@ -1879,7 +1889,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID(TCP_DESCS[i].id); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } this->total_probes++; } i++; @@ -1904,7 +1916,9 @@ int FPHost6::build_probe_list() { this->fp_probes[this->total_probes].host = this; this->fp_probes[this->total_probes].setPacket(ip6); this->fp_probes[this->total_probes].setProbeID(TCP_DESCS[i].id); - this->fp_probes[this->total_probes].setEthernet(this->target_host->SrcMACAddress(), this->target_host->NextHopMACAddress(), this->target_host->deviceName()); + if (this->netctl->l2_frames()) { + this->fp_probes[this->total_probes].setEthernet(this->target_host); + } this->total_probes++; } @@ -2491,22 +2505,33 @@ size_t FPPacket::getLength() const { * values, like this: instance.setEthernet(NULL, NULL, NULL); * Otherwise, pass the source address, the next hop address and the name of * the network interface the packet should be injected through. */ -int FPPacket::setEthernet(const u8 *src_mac, const u8 *dst_mac, const char *devname) { - if (src_mac == NULL || dst_mac == NULL) { - memset(&(this->eth_hdr), 0, sizeof(struct eth_nfo)); - this->link_eth = false; - return OP_FAILURE; - } - memcpy(this->eth_hdr.srcmac, src_mac, 6); - memcpy(this->eth_hdr.dstmac, dst_mac, 6); - this->link_eth = true; +int FPPacket::setEthernet(const Target *target) { + const char *devname = target->deviceName(); + this->link_eth = false; if (devname != NULL) { - strncpy(this->eth_hdr.devname, devname, sizeof(this->eth_hdr.devname)-1); - if ((this->eth_hdr.ethsd = eth_open_cached(devname)) == NULL) - fatal("%s: Failed to open ethernet device (%s)", __func__, devname); - } else { - this->eth_hdr.devname[0] = '\0'; - this->eth_hdr.ethsd = NULL; + netutil_eth_t *ethsd = eth_open_cached(devname); + if (ethsd == NULL) { + error("%s: Failed to open ethernet device (%s)", __func__, devname); + } + else if (netutil_eth_can_send(ethsd)) { + this->link_eth = true; + if (netutil_eth_datalink(ethsd) == DLT_EN10MB){ + const u8 *src_mac = target->SrcMACAddress(); + const u8 *dst_mac = target->NextHopMACAddress(); + if (src_mac == NULL || dst_mac == NULL) { + this->link_eth = false; + } + else { + memcpy(this->eth_hdr.srcmac, src_mac, 6); + memcpy(this->eth_hdr.dstmac, dst_mac, 6); + } + } + } + } + + if (!this->link_eth) { + memset(&(this->eth_hdr), 0, sizeof(struct eth_nfo)); + return OP_FAILURE; } return OP_SUCCESS; } diff --git a/FPEngine.h b/FPEngine.h index 09d65d867..e489534d9 100644 --- a/FPEngine.h +++ b/FPEngine.h @@ -167,7 +167,8 @@ class FPNetworkControl { void response_reception_handler(nsock_pool nsp, nsock_event nse, void *arg); bool request_slots(size_t num_packets); int cc_report_final_timeout(); - + // Do we need to send l2 (ethernet) frames? + bool l2_frames() { return (rawsd < 0); } }; /* +-----------+ @@ -249,7 +250,7 @@ class FPPacket { int setTime(const struct timeval *tv = NULL); struct timeval getTime() const; int setPacket(PacketElement *pkt); - int setEthernet(const u8 *src_mac, const u8 *dst_mac, const char *devname); + int setEthernet(const Target *target); const struct eth_nfo *getEthernet() const; const PacketElement *getPacket() const; size_t getLength() const; diff --git a/scan_engine.cc b/scan_engine.cc index a9bd4388d..a3eaf0b05 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -949,18 +949,23 @@ void UltraScanInfo::Init(std::vector &Targets, const struct scan_lists aren't doing a TCP connect scan, or if we're doing a ping scan that requires it. */ if (isRawScan()) { - if (ping_scan_arp || (ping_scan_nd && o.sendpref != PACKET_SEND_IP_STRONG) || ((o.sendpref & PACKET_SEND_ETH) && - (Targets[0]->ifType() == devt_ethernet -#ifdef WIN32 - || (Targets[0]->ifType() == devt_loopback) -#endif - ))) { + const char *device = Targets[0]->deviceName(); + if (ping_scan_arp || (ping_scan_nd && o.sendpref != PACKET_SEND_IP_STRONG) || (o.sendpref & PACKET_SEND_ETH)) { /* We'll send ethernet packets with dnet */ - ethsd = eth_open_cached(Targets[0]->deviceName()); - if (ethsd == NULL) - fatal("dnet: Failed to open device %s", Targets[0]->deviceName()); - rawsd = -1; - } else { + ethsd = eth_open_cached(device); + if (ethsd == NULL) { + error("dnet: Failed to open device %s", device); + } + else if (!netutil_eth_can_send(ethsd)) { + ethsd = NULL; + } + /* If eth failed, we can fall back to raw socket. The only exception is + * ARP ping, which needs Ethernet link. */ + if (ping_scan_arp && (ethsd == NULL || netutil_eth_datalink(ethsd) != DLT_EN10MB)) { + fatal("ARP ping not supported on %s", device); + } + } + if (ethsd == NULL) { #ifdef WIN32 win32_fatal_raw_sockets(Targets[0]->deviceName()); #endif diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc index 5497e5892..97ebe13e4 100644 --- a/scan_engine_raw.cc +++ b/scan_engine_raw.cc @@ -969,13 +969,15 @@ UltraProbe *sendNDScanProbe(UltraScanInfo *USI, HostScanStats *hss, ns_dst_ip6 = *hss->target->v6hostip(); if (USI->ethsd) { - unsigned char ns_dst_mac[6] = {0x33, 0x33, 0xff}; - ns_dst_mac[3] = ns_dst_ip6.s6_addr[13]; - ns_dst_mac[4] = ns_dst_ip6.s6_addr[14]; - ns_dst_mac[5] = ns_dst_ip6.s6_addr[15]; + if (netutil_eth_datalink(USI->ethsd) == DLT_EN10MB) { + unsigned char ns_dst_mac[6] = {0x33, 0x33, 0xff}; + ns_dst_mac[3] = ns_dst_ip6.s6_addr[13]; + ns_dst_mac[4] = ns_dst_ip6.s6_addr[14]; + ns_dst_mac[5] = ns_dst_ip6.s6_addr[15]; - memcpy(eth.srcmac, hss->target->SrcMACAddress(), 6); - memcpy(eth.dstmac, ns_dst_mac, 6); + memcpy(eth.srcmac, hss->target->SrcMACAddress(), 6); + memcpy(eth.dstmac, ns_dst_mac, 6); + } eth.ethsd = USI->ethsd; eth.devname[0] = '\0'; ethptr = ð @@ -1159,8 +1161,10 @@ UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, u16 icmp_ident = (get_random_u16() % 0xffff) + 1; if (USI->ethsd) { - memcpy(eth.srcmac, hss->target->SrcMACAddress(), 6); - memcpy(eth.dstmac, hss->target->NextHopMACAddress(), 6); + if (netutil_eth_datalink(USI->ethsd) == DLT_EN10MB) { + memcpy(eth.srcmac, hss->target->SrcMACAddress(), 6); + memcpy(eth.dstmac, hss->target->NextHopMACAddress(), 6); + } eth.ethsd = USI->ethsd; eth.devname[0] = '\0'; ethptr = ð diff --git a/traceroute.cc b/traceroute.cc index b4c7766e8..dc9f40483 100644 --- a/traceroute.cc +++ b/traceroute.cc @@ -596,8 +596,10 @@ void Probe::send(int rawsd, netutil_eth_t *ethsd, struct timeval *now) { /* Set up the Ethernet handle if we're using that. */ if (ethsd != NULL) { - memcpy(eth.srcmac, host->target->SrcMACAddress(), 6); - memcpy(eth.dstmac, host->target->NextHopMACAddress(), 6); + if (netutil_eth_datalink(ethsd) == DLT_EN10MB) { + memcpy(eth.srcmac, host->target->SrcMACAddress(), 6); + memcpy(eth.dstmac, host->target->NextHopMACAddress(), 6); + } eth.ethsd = ethsd; eth.devname[0] = '\0'; ethp = ð