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

Consolidate raw socket acquisition.

This commit is contained in:
dmiller
2025-06-30 19:24:32 +00:00
parent fc71b7544d
commit 67a796844f
16 changed files with 162 additions and 207 deletions

View File

@@ -118,7 +118,7 @@ FPNetworkControl::~FPNetworkControl() {
/* (Re)-Initialize object's state (default parameter setup and nsock
* initialization). */
void FPNetworkControl::init(const char *ifname, devtype iftype) {
void FPNetworkControl::init(const char *ifname) {
/* Init congestion control parameters */
this->cc_init();
@@ -155,27 +155,14 @@ void FPNetworkControl::init(const char *ifname, devtype iftype) {
/* Flag it as already initialized so we free this nsp next time */
this->nsock_init = true;
/* We don't need to store the eth handle because FPProbes come with a
* suitable one (FPProbes::getEthernet()), we just attempt to obtain one
* to see if it fails. */
netutil_eth_t *ethsd = NULL;
/* Obtain raw socket or check that we can obtain an eth descriptor. */
if ((o.sendpref & PACKET_SEND_ETH) && (iftype == devt_ethernet
#ifdef WIN32
|| (o.have_pcap && iftype == devt_loopback)
#endif
) && ifname != NULL) {
/* We don't need to store the eth handler because FPProbes come with a
* suitable one (FPProbes::getEthernet()), we just attempt to obtain one
* to see if it fails. */
if (eth_open_cached(ifname) == NULL)
fatal("dnet: failed to open device %s", ifname);
this->rawsd = -1;
} else {
#ifdef WIN32
win32_fatal_raw_sockets(ifname);
#endif
if (this->rawsd >= 0)
close(this->rawsd);
rawsd = nmap_raw_socket();
if (rawsd < 0)
pfatal("Couldn't obtain raw socket in %s", __func__);
if (!raw_socket_or_eth(o.sendpref, ifname, &this->rawsd, &ethsd)) {
fatal("Couldn't obtain raw socket or eth handle in %s", __func__);
}
/* De-register existing callers */
@@ -1135,7 +1122,7 @@ int FPEngine6::os_scan(std::vector<Target *> &Targets) {
/* Initialize variables, timers, etc. */
gettimeofday(&begin_time, NULL);
global_netctl.init(Targets[0]->deviceName(), Targets[0]->ifType());
global_netctl.init(Targets[0]->deviceName());
for (size_t i = 0; i < Targets.size(); i++) {
if (o.debugging > 3) {
log_write(LOG_PLAIN, "[FPEngine] Allocating FPHost6 for %s %s\n",

View File

@@ -157,7 +157,7 @@ class FPNetworkControl {
public:
FPNetworkControl();
~FPNetworkControl();
void init(const char *ifname, devtype iftype);
void init(const char *ifname);
int register_caller(FPHost *newcaller);
int unregister_caller(FPHost *oldcaller);
int setup_sniffer(const char *iface, const char *bfp_filter);

View File

@@ -68,6 +68,7 @@
#include "NmapOps.h"
#include "osscan.h"
#include "nmap_error.h"
#include "libnetutil/netutil.h"
NmapOps o;

View File

@@ -123,24 +123,6 @@ class NmapOps {
u8 debugging;
bool resuming;
#define PACKET_SEND_NOPREF 1
#define PACKET_SEND_ETH_WEAK 2
#define PACKET_SEND_ETH_STRONG 4
#define PACKET_SEND_ETH 6
#define PACKET_SEND_IP_WEAK 8
#define PACKET_SEND_IP_STRONG 16
#define PACKET_SEND_IP 24
/* How should we send raw IP packets? Nmap can generally use either
ethernet or raw ip sockets. Which is better depends on platform
and goals. A _STRONG preference means that Nmap should use the
preferred method whenever it is possible (obviously it isn't
always possible -- sending ethernet frames won't work over a PPP
connection). This is useful when the other type doesn't work at
all. A _WEAK preference means that Nmap may use the other type
where it is substantially more efficient to do so. For example,
Nmap will still do an ARP ping scan of a local network even when
the pref is SEND_IP_WEAK */
int sendpref;
bool packetTrace() { return (debugging >= 3)? true : pTrace; }
bool versionTrace() { return packetTrace()? true : vTrace; }

View File

@@ -599,30 +599,19 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
/* Now lets send some probes to check IP ID algorithm ... */
/* First we need a raw socket ... */
if ((o.sendpref & PACKET_SEND_ETH) && (proxy->host.ifType() == devt_ethernet
#ifdef WIN32
|| (o.have_pcap && proxy->host.ifType() == devt_loopback)
#endif
)) {
if (!raw_socket_or_eth(o.sendpref, proxy->host.deviceName(),
&proxy->rawsd, &proxy->eth.ethsd)) {
fatal("%s: Failed to open raw socket or ethernet handle", __func__);
}
if (proxy->eth.ethsd != NULL) {
if (!setTargetNextHopMAC(&proxy->host))
fatal("%s: Failed to determine dst MAC address for Idle proxy", __func__);
memcpy(proxy->eth.srcmac, proxy->host.SrcMACAddress(), 6);
memcpy(proxy->eth.dstmac, proxy->host.NextHopMACAddress(), 6);
proxy->eth.ethsd = eth_open_cached(proxy->host.deviceName());
if (proxy->eth.ethsd == NULL)
fatal("%s: Failed to open ethernet device (%s)", __func__, proxy->host.deviceName());
proxy->rawsd = -1;
proxy->ethptr = &proxy->eth;
} else {
#ifdef WIN32
win32_fatal_raw_sockets(proxy->host.deviceName());
#endif
proxy->rawsd = nmap_raw_socket();
if (proxy->rawsd < 0)
pfatal("socket troubles in %s", __func__);
}
else {
unblock_socket(proxy->rawsd);
proxy->eth.ethsd = NULL;
proxy->ethptr = NULL;
}
if (proxy->host.af() == AF_INET6)

View File

@@ -1088,6 +1088,98 @@ void eth_close_cached() {
return;
}
static void netutil_perror(const char *msg) {
int err = socket_errno();
netutil_error("%s: (%d) %s", msg, err, socket_strerror(err));
}
/* Create a raw socket and do things that always apply to raw sockets:
* Set SO_BROADCAST.
* Set IP_HDRINCL.
* Bind to an interface with SO_BINDTODEVICE (if device is not NULL).
The socket is created with address family AF_INET, but may be usable for
AF_INET6, depending on the operating system. */
int netutil_raw_socket(const char *device) {
#ifdef WIN32
netutil_error("Windows does not have adequate raw socket support.");
return -1;
#else
int rawsd;
int one = 1;
rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (rawsd < 0) {
netutil_perror("Couldn't open a raw socket. "
#if defined(sun) && defined(__SVR4)
"In Solaris shared-IP non-global zones, this requires the PRIV_NET_RAWACCESS privilege. "
#endif
"Error");
return -1;
}
if (setsockopt (rawsd, SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof(int)) != 0) {
netutil_perror("setsockopt(SO_BROADCAST) failed");
}
sethdrinclude(rawsd);
socket_bindtodevice(rawsd, device);
return rawsd;
#endif
}
int raw_socket_or_eth(int sendpref, const char *ifname,
int *rawsd, netutil_eth_t **ethsd) {
assert(rawsd != NULL);
*rawsd = -1;
assert(ethsd != NULL);
*ethsd = NULL;
bool may_try_eth = ifname && !(sendpref & PACKET_SEND_IP_STRONG);
bool may_try_ip = !(sendpref & PACKET_SEND_ETH_STRONG);
bool try_eth = may_try_eth && (sendpref & PACKET_SEND_ETH);
bool try_ip = may_try_ip && (sendpref & PACKET_SEND_IP);
for (int i = 0; i < 2; i++) {
if (try_eth) {
try_eth = false;
may_try_eth = false;
try_ip = may_try_ip;
netutil_eth_t *e = eth_open_cached(ifname);
*ethsd = e;
if (e == NULL) {
netutil_error("dnet: failed to open device %s", ifname);
}
else if (!netutil_eth_can_send(e)) {
netutil_error("%s is not a supported device for sending.", ifname);
e = NULL;
}
else {
break;
}
}
if (try_ip) {
try_ip = false;
may_try_ip = false;
try_eth = may_try_eth;
#ifdef WIN32
/* For Windows, don't even bother trying unless the caller insists, to
* avoid excessive error messages. */
if (!(sendpref & PACKET_SEND_IP_STRONG)) {
continue;
}
#endif
int sd = netutil_raw_socket(ifname);
*rawsd = sd;
if (sd >= 0) {
break;
}
}
}
return (*ethsd != NULL || *rawsd >= 0) ? 1 : 0;
}
/* Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IP,
* etc, and returns an ASCII representation (or the string "unknown" if
* it doesn't recognize the number). If uppercase is non zero, the

View File

@@ -305,6 +305,34 @@ int netutil_eth_can_send(const netutil_eth_t *e);
/* See the description for eth_open_cached */
void eth_close_cached();
/* Create a raw socket and do things that always apply to raw sockets:
* Set SO_BROADCAST.
* Set IP_HDRINCL.
* Bind to an interface with SO_BINDTODEVICE (if device is not NULL).
The socket is created with address family AF_INET, but may be usable for
AF_INET6, depending on the operating system. */
int netutil_raw_socket(const char *device);
/* How should we send raw IP packets? Nmap can generally use either
ethernet or raw ip sockets. Which is better depends on platform
and goals. A _STRONG preference means that Nmap should use the
preferred method whenever it is possible (obviously it isn't
always possible -- sending ethernet frames won't work over a PPP
connection). This is useful when the other type doesn't work at
all. A _WEAK preference means that Nmap may use the other type
where it is substantially more efficient to do so. For example,
Nmap will still do an ARP ping scan of a local network even when
the pref is SEND_IP_WEAK */
#define PACKET_SEND_NOPREF 0x01
#define PACKET_SEND_ETH_WEAK 0x02
#define PACKET_SEND_ETH_STRONG 0x04
#define PACKET_SEND_ETH (PACKET_SEND_ETH_WEAK | PACKET_SEND_ETH_STRONG)
#define PACKET_SEND_IP_WEAK 0x08
#define PACKET_SEND_IP_STRONG 0x10
#define PACKET_SEND_IP (PACKET_SEND_IP_WEAK | PACKET_SEND_IP_STRONG)
int raw_socket_or_eth(int sendpref, const char *ifname,
int *rawsd, netutil_eth_t **ethsd);
/* Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, or
* IPPROTO_IP and returns a ascii representation (or "unknown" if it
* doesn't recognize the number). Returned string is in lowercase. */

View File

@@ -105,7 +105,6 @@ NpingOps::NpingOps() {
sendpref_set=false;
send_eth=false;
send_eth_set=false;
delay=0;
delay_set=false;
@@ -620,10 +619,10 @@ bool NpingOps::issetPacketCount(){
* PACKET_SEND_ETH, PACKET_SEND_IP_WEAK, PACKET_SEND_IP_STRONG, PACKET_SEND_IP
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
int NpingOps::setSendPreference(int v){
if( v!=PACKET_SEND_NOPREF && v!=PACKET_SEND_ETH_WEAK &&
v!=PACKET_SEND_ETH_STRONG && v!=PACKET_SEND_ETH &&
v!=PACKET_SEND_IP_WEAK && v!=PACKET_SEND_IP_STRONG &&
v!=PACKET_SEND_IP ){
// Validate: no extra bits set
if( (v & ~(PACKET_SEND_ETH | PACKET_SEND_IP))
// Validate: both ETH and IP cannot be STRONG
|| ((v & PACKET_SEND_ETH_STRONG) && (v & PACKET_SEND_IP_STRONG))) {
nping_fatal(QT_3,"setSendPreference(): Invalid value supplied\n");
return OP_FAILURE;
}else{
@@ -648,51 +647,31 @@ bool NpingOps::issetSendPreference(){
/* Returns true if send preference is Ethernet */
bool NpingOps::sendPreferenceEthernet(){
if ( this->getSendPreference()==PACKET_SEND_ETH_WEAK )
return true;
else if (this->getSendPreference()==PACKET_SEND_ETH_STRONG)
return true;
else if (this->getSendPreference()==PACKET_SEND_ETH )
return true;
else
return false;
return (this->sendpref & PACKET_SEND_ETH);
} /* End of sendPreferenceEthernet() */
/* Returns true if send preference is Ethernet */
bool NpingOps::sendPreferenceIP(){
if ( this->getSendPreference()==PACKET_SEND_IP_WEAK )
return true;
else if (this->getSendPreference()==PACKET_SEND_IP_STRONG)
return true;
else if (this->getSendPreference()==PACKET_SEND_IP )
return true;
else
return false;
return (this->sendpref & PACKET_SEND_IP);
} /* End of sendPreferenceIP() */
/** Sets SendEth.
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
int NpingOps::setSendEth(bool val){
this->send_eth=val;
this->send_eth_set=true;
this->sendpref = PACKET_SEND_ETH;
this->sendpref_set = true;
return OP_SUCCESS;
} /* End of setSendEth() */
/** Returns value of attribute send_eth */
bool NpingOps::sendEth(){
return this->send_eth;
return (this->sendpref & PACKET_SEND_ETH_STRONG);
} /* End of getSendEth() */
/* Returns true if option has been set */
bool NpingOps::issetSendEth(){
return this->send_eth_set;
} /* End of issetSendEth() */
/** Sets inter-probe delay. Supplied parameter is assumed to be in milliseconds
* and must be a long integer greater than zero.
* @warning timeout is assumed to be in milliseconds. Use tval2msecs() from

View File

@@ -97,14 +97,6 @@
#define FLAG_SYN 6
#define FLAG_FIN 7
#define PACKET_SEND_NOPREF 1 /* These have been taken from NmapOps.h */
#define PACKET_SEND_ETH_WEAK 2
#define PACKET_SEND_ETH_STRONG 4
#define PACKET_SEND_ETH 6
#define PACKET_SEND_IP_WEAK 8
#define PACKET_SEND_IP_STRONG 16
#define PACKET_SEND_IP 24
#define IP_VERSION_4 0x04
#define IP_VERSION_6 0x06

View File

@@ -223,7 +223,7 @@ static int ethernet_send (lua_State *L)
static int ip_open (lua_State *L)
{
nse_dnet_udata *udata = (nse_dnet_udata *) nseU_checkudata(L, 1, DNET_METATABLE, "dnet");
udata->sock = nmap_raw_socket();
udata->sock = netutil_raw_socket(NULL);
if (udata->sock == -1) {
if (o.scriptTrace())
{

View File

@@ -1336,24 +1336,11 @@ HostOsScan::HostOsScan(Target *t) {
rawsd = -1;
ethsd = NULL;
if ((o.sendpref & PACKET_SEND_ETH) && (t->ifType() == devt_ethernet
#ifdef WIN32
|| (o.have_pcap && t->ifType() == devt_loopback)
#endif
)) {
if ((ethsd = eth_open_cached(t->deviceName())) == NULL)
fatal("%s: Failed to open ethernet device (%s)", __func__, t->deviceName());
rawsd = -1;
} else {
#ifdef WIN32
win32_fatal_raw_sockets(t->deviceName());
#endif
rawsd = nmap_raw_socket();
if (rawsd < 0)
pfatal("socket troubles in %s", __func__);
unblock_socket(rawsd);
ethsd = NULL;
if (!raw_socket_or_eth(o.sendpref, t->deviceName(), &rawsd, &ethsd)) {
fatal("%s: Failed to open raw socket or ethernet device", __func__);
}
if (rawsd >= 0)
unblock_socket(rawsd);
if (o.magic_port_set) {
tcpPortBase = o.magic_port;

View File

@@ -218,22 +218,6 @@ static void print_xml_service(const struct serviceDeductions *sd) {
}
#ifdef WIN32
/* Show a fatal error explaining that an interface is not Ethernet and won't
work on Windows. Do nothing if --send-ip (PACKET_SEND_IP_STRONG) was used. */
void win32_fatal_raw_sockets(const char *devname) {
if ((o.sendpref & PACKET_SEND_IP_STRONG) != 0)
return;
if (devname != NULL) {
fatal("Only ethernet devices can be used for raw scans on Windows, and\n"
"\"%s\" is not an ethernet device. Use the --unprivileged option\n"
"for this scan.", devname);
} else {
fatal("Only ethernet devices can be used for raw scans on Windows. Use\n"
"the --unprivileged option for this scan.");
}
}
/* Display the mapping from libdnet interface names (like "eth0") to Npcap
interface names (like "\Device\NPF_{...}"). This is the same mapping used by
eth_open and so can help diagnose connection problems. Additionally display

View File

@@ -123,12 +123,6 @@ class Target;
# endif
#endif
#ifdef WIN32
/* Show a fatal error explaining that an interface is not Ethernet and won't
work on Windows. Do nothing if --send-ip (PACKET_SEND_IP_STRONG) was used. */
void win32_fatal_raw_sockets(const char *devname);
#endif
/* Prints the familiar Nmap tabular output showing the "interesting"
ports found on the machine. It also handles the Machine/Grepable
output and the XML output. It is pretty ugly -- in particular I

View File

@@ -949,39 +949,15 @@ void UltraScanInfo::Init(std::vector<Target *> &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()) {
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(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 eth failed, we can fall back to raw socket. The only exception is
* ARP ping, which needs Ethernet link. */
int sendpref = o.sendpref;
if (ping_scan_arp) {
assert(!(sendpref & PACKET_SEND_IP_STRONG));
sendpref = PACKET_SEND_ETH;
}
if (ethsd == NULL) {
#ifdef WIN32
win32_fatal_raw_sockets(Targets[0]->deviceName());
#endif
rawsd = nmap_raw_socket();
if (rawsd < 0)
pfatal("Couldn't open a raw socket. "
#if defined(sun) && defined(__SVR4)
"In Solaris shared-IP non-global zones, this requires the PRIV_NET_RAWACCESS privilege. "
#endif
"Error"
);
/* We do not want to unblock the socket since we want to wait
if kernel send buffers fill up rather than get ENOBUF, and
we won't be receiving on the socket anyway
unblock_socket(rawsd);*/
ethsd = NULL;
if (!raw_socket_or_eth(sendpref, Targets[0]->deviceName(), &rawsd, &ethsd)) {
fatal("Couldn't open a raw socket or eth handle.");
}
/* Raw scan types also need to know the source IP. */
Targets[0]->SourceSockAddr(&sourceSockAddr, NULL);

View File

@@ -87,31 +87,6 @@ extern NmapOps o;
static PacketCounter PktCt;
/* Create a raw socket and do things that always apply to raw sockets:
* Set SO_BROADCAST.
* Set IP_HDRINCL.
* Bind to an interface with SO_BINDTODEVICE (if o.device is set).
The socket is created with address family AF_INET, but may be usable for
AF_INET6, depending on the operating system. */
int nmap_raw_socket() {
int rawsd;
int one = 1;
rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (rawsd < 0)
return rawsd;
if (setsockopt (rawsd, SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof(int)) != 0) {
error("Failed to secure socket broadcasting permission");
perror("setsockopt");
}
#ifndef WIN32
sethdrinclude(rawsd);
#endif
socket_bindtodevice(rawsd, o.device);
return rawsd;
}
/* Fill buf (up to buflen -- truncate if necessary but always
terminate) with a short representation of the packet stats.
Returns buf. Aborts if there is a problem. */

View File

@@ -837,19 +837,8 @@ TracerouteState::TracerouteState(std::vector<Target *> &targets) {
assert(targets.size() > 0);
if ((o.sendpref & PACKET_SEND_ETH) && targets[0]->ifType() == devt_ethernet) {
ethsd = eth_open_cached(targets[0]->deviceName());
if (ethsd == NULL)
fatal("dnet: failed to open device %s", targets[0]->deviceName());
rawsd = -1;
} else {
#ifdef WIN32
win32_fatal_raw_sockets(targets[0]->deviceName());
#endif
rawsd = nmap_raw_socket();
if (rawsd < 0)
pfatal("traceroute: socket troubles");
ethsd = NULL;
if (!raw_socket_or_eth(o.sendpref, targets[0]->deviceName(), &rawsd, &ethsd)) {
fatal("traceroute: socket troubles");
}
/* Assume that all the targets share the same device. */