mirror of
https://github.com/nmap/nmap.git
synced 2025-12-10 06:31:30 +00:00
Consolidate raw socket acquisition.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user