masscan-mark-ii/src/main.c

1869 lines
65 KiB
C

/*
main
This includes:
* main()
* transmit_thread() - transmits probe packets
* receive_thread() - receives response packets
You'll be wanting to study the transmit/receive threads, because that's
where all the action is.
This is the lynch-pin of the entire program, so it includes a heckuva lot
of headers, and the functions have a lot of local variables. I'm trying
to make this file relative "flat" this way so that everything is visible.
*/
#include "masscan.h"
#include "masscan-version.h"
#include "masscan-status.h" /* open or closed */
#include "massip-parse.h"
#include "massip-port.h"
#include "main-status.h" /* printf() regular status updates */
#include "main-throttle.h" /* rate limit */
#include "main-dedup.h" /* ignore duplicate responses */
#include "main-ptrace.h" /* for nmap --packet-trace feature */
#include "main-globals.h" /* all the global variables in the program */
#include "main-readrange.h"
#include "crypto-siphash24.h" /* hash function, for hash tables */
#include "crypto-blackrock.h" /* the BlackRock shuffling func */
#include "crypto-lcg.h" /* the LCG randomization func */
#include "crypto-base64.h" /* base64 encode/decode */
#include "templ-pkt.h" /* packet template, that we use to send */
#include "util-logger.h" /* adjust with -v command-line opt */
#include "stack-ndpv6.h" /* IPv6 Neighbor Discovery Protocol */
#include "stack-arpv4.h" /* Handle ARP resolution and requests */
#include "rawsock.h" /* API on top of Linux, Windows, Mac OS X*/
#include "rawsock-adapter.h" /* Get Ethernet adapter configuration */
#include "rawsock-pcapfile.h" /* for saving pcap files w/ raw packets */
#include "syn-cookie.h" /* for SYN-cookies on send */
#include "output.h" /* for outputting results */
#include "rte-ring.h" /* producer/consumer ring buffer */
#include "stub-pcap.h" /* dynamically load libpcap library */
#include "smack.h" /* Aho-corasick state-machine pattern-matcher */
#include "pixie-timer.h" /* portable time functions */
#include "pixie-threads.h" /* portable threads */
#include "pixie-backtrace.h" /* maybe print backtrace on crash */
#include "templ-payloads.h" /* UDP packet payloads */
#include "in-binary.h" /* convert binary output to XML/JSON */
#include "vulncheck.h" /* checking vulns like monlist, poodle, heartblee */
#include "scripting.h"
#include "read-service-probes.h"
#include "misc-rstfilter.h"
#include "proto-x509.h"
#include "proto-arp.h" /* for responding to ARP requests */
#include "proto-banner1.h" /* for snatching banners from systems */
#include "stack-tcp-core.h" /* for TCP/IP connection table */
#include "proto-preprocess.h" /* quick parse of packets */
#include "proto-icmp.h" /* handle ICMP responses */
#include "proto-udp.h" /* handle UDP responses */
#include "proto-snmp.h" /* parse SNMP responses */
#include "proto-ntp.h" /* parse NTP responses */
#include "proto-coap.h" /* CoAP selftest */
#include "proto-zeroaccess.h"
#include "proto-sctp.h"
#include "proto-oproto.h" /* Other protocols on top of IP */
#include "util-malloc.h"
#include "util-checksum.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>
#include <stdint.h>
#if defined(WIN32)
#include <WinSock.h>
#if defined(_MSC_VER)
#pragma comment(lib, "Ws2_32.lib")
#endif
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
/*
* yea I know globals suck
*/
unsigned volatile is_tx_done = 0;
unsigned volatile is_rx_done = 0;
time_t global_now;
uint64_t usec_start;
/***************************************************************************
* We create a pair of transmit/receive threads for each network adapter.
* This structure contains the parameters we send to each pair.
***************************************************************************/
struct ThreadPair {
/** This points to the central configuration. Note that it's 'const',
* meaning that the thread cannot change the contents. That'd be
* unsafe */
const struct Masscan *masscan;
/** The adapter used by the thread-pair. Normally, thread-pairs have
* their own network adapter, especially when doing PF_RING
* clustering. */
struct Adapter *adapter;
struct stack_t *stack;
/**
* The index of the network adapter that we are using for this
* thread-pair. This is an index into the "masscan->nic[]"
* array.
*
* NOTE: this is also the "thread-id", because we create one
* transmit/receive thread pair per NIC.
*/
unsigned nic_index;
/**
* A copy of the master 'index' variable. This is just advisory for
* other threads, to tell them how far we've gotten.
*/
volatile uint64_t my_index;
/* This is used both by the transmit and receive thread for
* formatting packets */
struct TemplateSet tmplset[1];
/**
* The current IP address we are using for transmit/receive.
*/
struct stack_src_t _src_;
macaddress_t source_mac;
macaddress_t router_mac_ipv4;
macaddress_t router_mac_ipv6;
unsigned done_transmitting;
unsigned done_receiving;
double pt_start;
struct Throttler throttler[1];
uint64_t *total_synacks;
uint64_t *total_tcbs;
uint64_t *total_syns;
size_t thread_handle_xmit;
size_t thread_handle_recv;
};
struct source_t {
unsigned ipv4;
unsigned ipv4_mask;
unsigned port;
unsigned port_mask;
ipv6address ipv6;
ipv6address ipv6_mask;
};
/***************************************************************************
* We support a range of source IP/port. This function converts that
* range into useful variables we can use to pick things form that range.
***************************************************************************/
static void
adapter_get_source_addresses(const struct Masscan *masscan,
unsigned nic_index,
struct source_t *src)
{
const struct stack_src_t *ifsrc = &masscan->nic[nic_index].src;
static ipv6address mask = {~0ULL, ~0ULL};
src->ipv4 = ifsrc->ipv4.first;
src->ipv4_mask = ifsrc->ipv4.last - ifsrc->ipv4.first;
src->port = ifsrc->port.first;
src->port_mask = ifsrc->port.last - ifsrc->port.first;
src->ipv6 = ifsrc->ipv6.first;
/* TODO: currently supports only a single address. This needs to
* be fixed to support a list of addresses */
src->ipv6_mask = mask;
}
/***************************************************************************
* This thread spews packets as fast as it can
*
* THIS IS WHERE ALL THE EXCITEMENT HAPPENS!!!!
* 90% of CPU cycles are in the function.
*
***************************************************************************/
static void
transmit_thread(void *v) /*aka. scanning_thread() */
{
struct ThreadPair *parms = (struct ThreadPair *)v;
uint64_t i;
uint64_t start;
uint64_t end;
const struct Masscan *masscan = parms->masscan;
uint64_t retries = masscan->retries;
uint64_t rate = (uint64_t)masscan->max_rate;
unsigned r = (unsigned)retries + 1;
uint64_t range;
uint64_t range_ipv6;
struct BlackRock blackrock;
uint64_t count_ipv4 = rangelist_count(&masscan->targets.ipv4);
uint64_t count_ipv6 = range6list_count(&masscan->targets.ipv6).lo;
struct Throttler *throttler = parms->throttler;
struct TemplateSet pkt_template = templ_copy(parms->tmplset);
struct Adapter *adapter = parms->adapter;
uint64_t packets_sent = 0;
unsigned increment = masscan->shard.of * masscan->nic_count;
struct source_t src;
uint64_t seed = masscan->seed;
uint64_t repeats = 0; /* --infinite repeats */
uint64_t *status_syn_count;
uint64_t entropy = masscan->seed;
/* Wait to make sure receive_thread is ready */
pixie_usleep(1000000);
LOG(1, "[+] starting transmit thread #%u\n", parms->nic_index);
/* export a pointer to this variable outside this threads so
* that the 'status' system can print the rate of syns we are
* sending */
status_syn_count = MALLOC(sizeof(uint64_t));
*status_syn_count = 0;
parms->total_syns = status_syn_count;
/* Normally, we have just one source address. In special cases, though
* we can have multiple. */
adapter_get_source_addresses(masscan, parms->nic_index, &src);
/* "THROTTLER" rate-limits how fast we transmit, set with the
* --max-rate parameter */
throttler_start(throttler, masscan->max_rate/masscan->nic_count);
infinite:
/* Create the shuffler/randomizer. This creates the 'range' variable,
* which is simply the number of IP addresses times the number of
* ports.
* IPv6: low index will pick addresses from the IPv6 ranges, and high
* indexes will pick addresses from the IPv4 ranges. */
range = count_ipv4 * rangelist_count(&masscan->targets.ports)
+ count_ipv6 * rangelist_count(&masscan->targets.ports);
range_ipv6 = count_ipv6 * rangelist_count(&masscan->targets.ports);
blackrock_init(&blackrock, range, seed, masscan->blackrock_rounds);
/* Calculate the 'start' and 'end' of a scan. One reason to do this is
* to support --shard, so that multiple machines can co-operate on
* the same scan. Another reason to do this is so that we can bleed
* a little bit past the end when we have --retries. Yet another
* thing to do here is deal with multiple network adapters, which
* is essentially the same logic as shards. */
start = masscan->resume.index + (masscan->shard.one-1) * masscan->nic_count + parms->nic_index;
end = range;
if (masscan->resume.count && end > start + masscan->resume.count)
end = start + masscan->resume.count;
end += retries * range;
/* -----------------
* the main loop
* -----------------*/
LOG(3, "THREAD: xmit: starting main loop: [%llu..%llu]\n", start, end);
for (i=start; i<end; ) {
uint64_t batch_size;
/*
* Do a batch of many packets at a time. That because per-packet
* throttling is expensive at 10-million pps, so we reduce the
* per-packet cost by doing batches. At slower rates, the batch
* size will always be one. (--max-rate)
*/
batch_size = throttler_next_batch(throttler, packets_sent);
/*
* Transmit packets from other thread, when doing --banners. This
* takes priority over sending SYN packets. If there is so much
* activity grabbing banners that we cannot transmit more SYN packets,
* then "batch_size" will get decremented to zero, and we won't be
* able to transmit SYN packets.
*/
stack_flush_packets(parms->stack, adapter,
&packets_sent, &batch_size);
/*
* Transmit a bunch of packets. At any rate slower than 100,000
* packets/second, the 'batch_size' is likely to be 1. At higher
* rates, we can't afford to throttle on a per-packet basis and
* instead throttle on a per-batch basis. In other words, throttle
* based on 2-at-a-time, 3-at-time, and so on, with the batch
* size increasing as the packet rate increases. This gives us
* very precise packet-timing for low rates below 100,000 pps,
* while not incurring the overhead for high packet rates.
*/
while (batch_size && i < end) {
uint64_t xXx;
uint64_t cookie;
/*
* RANDOMIZE THE TARGET:
* This is kinda a tricky bit that picks a random IP and port
* number in order to scan. We monotonically increment the
* index 'i' from [0..range]. We then shuffle (randomly transmog)
* that index into some other, but unique/1-to-1, number in the
* same range. That way we visit all targets, but in a random
* order. Then, once we've shuffled the index, we "pick" the
* IP address and port that the index refers to.
*/
xXx = (i + (r--) * rate);
if (rate > range)
xXx %= range;
else
while (xXx >= range)
xXx -= range;
xXx = blackrock_shuffle(&blackrock, xXx);
if (xXx < range_ipv6) {
ipv6address ip_them;
unsigned port_them;
ipv6address ip_me;
unsigned port_me;
ip_them = range6list_pick(&masscan->targets.ipv6, xXx % count_ipv6);
port_them = rangelist_pick(&masscan->targets.ports, xXx / count_ipv6);
ip_me = src.ipv6;
port_me = src.port;
cookie = syn_cookie_ipv6(ip_them, port_them, ip_me, port_me, entropy);
rawsock_send_probe_ipv6(
adapter,
ip_them, port_them,
ip_me, port_me,
(unsigned)cookie,
!batch_size, /* flush queue on last packet in batch */
&pkt_template
);
/* Our index selects an IPv6 target */
} else {
/* Our index selects an IPv4 target. In other words, low numbers
* index into the IPv6 ranges, and high numbers index into the
* IPv4 ranges. */
ipv4address ip_them;
ipv4address port_them;
unsigned ip_me;
unsigned port_me;
xXx -= range_ipv6;
ip_them = rangelist_pick(&masscan->targets.ipv4, xXx % count_ipv4);
port_them = rangelist_pick(&masscan->targets.ports, xXx / count_ipv4);
/*
* SYN-COOKIE LOGIC
* Figure out the source IP/port, and the SYN cookie
*/
if (src.ipv4_mask > 1 || src.port_mask > 1) {
uint64_t ck = syn_cookie_ipv4((unsigned)(i+repeats),
(unsigned)((i+repeats)>>32),
(unsigned)xXx, (unsigned)(xXx>>32),
entropy);
port_me = src.port + (ck & src.port_mask);
ip_me = src.ipv4 + ((ck>>16) & src.ipv4_mask);
} else {
ip_me = src.ipv4;
port_me = src.port;
}
cookie = syn_cookie_ipv4(ip_them, port_them, ip_me, port_me, entropy);
/*
* SEND THE PROBE
* This is sorta the entire point of the program, but little
* exciting happens here. The thing to note that this may
* be a "raw" transmit that bypasses the kernel, meaning
* we can call this function millions of times a second.
*/
rawsock_send_probe_ipv4(
adapter,
ip_them, port_them,
ip_me, port_me,
(unsigned)cookie,
!batch_size, /* flush queue on last packet in batch */
&pkt_template
);
}
batch_size--;
packets_sent++;
(*status_syn_count)++;
/*
* SEQUENTIALLY INCREMENT THROUGH THE RANGE
* Yea, I know this is a puny 'i++' here, but it's a core feature
* of the system that is linearly increments through the range,
* but produces from that a shuffled sequence of targets (as
* described above). Because we are linearly incrementing this
* number, we can do lots of creative stuff, like doing clever
* retransmits and sharding.
*/
if (r == 0) {
i += increment; /* <------ increment by 1 normally, more with shards/nics */
r = (unsigned)retries + 1;
}
} /* end of batch */
/* save our current location for resuming, if the user pressed
* <ctrl-c> to exit early */
parms->my_index = i;
/* If the user pressed <ctrl-c>, then we need to exit. In case
* the user wants to --resume the scan later, we save the current
* state in a file */
if (is_tx_done) {
break;
}
}
/*
* --infinite
* For load testing, go around and do this again
*/
if (masscan->is_infinite && !is_tx_done) {
seed++;
repeats++;
goto infinite;
}
/*
* Flush any untransmitted packets. High-speed mechanisms like Windows
* "sendq" and Linux's "PF_RING" queue packets and transmit many together,
* so there may be some packets that we've queued but not yet transmitted.
* This call makes sure they are transmitted.
*/
rawsock_flush(adapter);
/*
* Wait until the receive thread realizes the scan is over
*/
LOG(1, "[+] transmit thread #%u complete\n", parms->nic_index);
/*
* We are done transmitting. However, response packets will take several
* seconds to arrive. Therefore, sit in short loop waiting for those
* packets to arrive. Pressing <ctrl-c> a second time will exit this
* prematurely.
*/
while (!is_rx_done) {
unsigned k;
uint64_t batch_size;
for (k=0; k<1000; k++) {
/*
* Only send a few packets at a time, throttled according to the max
* --max-rate set by the user
*/
batch_size = throttler_next_batch(throttler, packets_sent);
/* Transmit packets from the receive thread */
stack_flush_packets( parms->stack, adapter,
&packets_sent,
&batch_size);
/* Make sure they've actually been transmitted, not just queued up for
* transmit */
rawsock_flush(adapter);
pixie_usleep(100);
}
}
/* Thread is about to exit */
parms->done_transmitting = 1;
LOG(1, "[+] exiting transmit thread #%u \n", parms->nic_index);
}
/***************************************************************************
***************************************************************************/
static unsigned
is_nic_port(const struct Masscan *masscan, unsigned ip)
{
unsigned i;
for (i=0; i<masscan->nic_count; i++)
if (is_my_port(&masscan->nic[i].src, ip))
return 1;
return 0;
}
static unsigned
is_ipv6_multicast(ipaddress ip_me)
{
/* If this is an IPv6 multicast packet, one sent to the IPv6
* address with a prefix of FF02::/16 */
return ip_me.version == 6 && (ip_me.ipv6.hi>>48ULL) == 0xFF02;
}
/***************************************************************************
*
* Asynchronous receive thread
*
* The transmit and receive threads run independently of each other. There
* is no record what was transmitted. Instead, the transmit thread sets a
* "SYN-cookie" in transmitted packets, which the receive thread will then
* use to match up requests with responses.
***************************************************************************/
static void
receive_thread(void *v)
{
struct ThreadPair *parms = (struct ThreadPair *)v;
const struct Masscan *masscan = parms->masscan;
struct Adapter *adapter = parms->adapter;
int data_link = stack_if_datalink(adapter);
struct Output *out;
struct DedupTable *dedup;
struct PcapFile *pcapfile = NULL;
struct TCP_ConnectionTable *tcpcon = 0;
uint64_t *status_synack_count;
uint64_t *status_tcb_count;
uint64_t entropy = masscan->seed;
struct ResetFilter *rf;
struct stack_t *stack = parms->stack;
struct source_t src = {0};
/* For reducing RST responses, see rstfilter_is_filter() below */
rf = rstfilter_create(entropy, 16384);
/* some status variables */
status_synack_count = MALLOC(sizeof(uint64_t));
*status_synack_count = 0;
parms->total_synacks = status_synack_count;
status_tcb_count = MALLOC(sizeof(uint64_t));
*status_tcb_count = 0;
parms->total_tcbs = status_tcb_count;
LOG(1, "[+] starting receive thread #%u\n", parms->nic_index);
/* Lock this thread to a CPU. Transmit threads are on even CPUs,
* receive threads on odd CPUs */
if (pixie_cpu_get_count() > 1) {
unsigned cpu_count = pixie_cpu_get_count();
unsigned cpu = parms->nic_index * 2 + 1;
while (cpu >= cpu_count) {
cpu -= cpu_count;
cpu++;
}
//TODO:
//pixie_cpu_set_affinity(cpu);
}
/*
* If configured, open a --pcap file for saving raw packets. This is
* so that we can debug scans, but also so that we can look at the
* strange things people send us. Note that we don't record transmitted
* packets, just the packets we've received.
*/
if (masscan->pcap_filename[0]) {
pcapfile = pcapfile_openwrite(masscan->pcap_filename, 1);
}
/*
* Open output. This is where results are reported when saving
* the --output-format to the --output-filename
*/
out = output_create(masscan, parms->nic_index);
/*
* Create deduplication table. This is so when somebody sends us
* multiple responses, we only record the first one.
*/
dedup = dedup_create();
/*
* Create a TCP connection table (per thread pair) for interacting with live
* connections when doing --banners
*/
if (masscan->is_banners) {
struct TcpCfgPayloads *pay;
size_t i;
/*
* Create TCP connection table
*/
tcpcon = tcpcon_create_table(
(size_t)((masscan->max_rate/5) / masscan->nic_count),
parms->stack,
&parms->tmplset->pkts[Proto_TCP],
output_report_banner,
out,
masscan->tcb.timeout,
masscan->seed
);
/*
* Initialize TCP scripting
*/
scripting_init_tcp(tcpcon, masscan->scripting.L);
/*
* Get the possible source IP addresses and ports that masscan
* might be using to transmit from.
*/
adapter_get_source_addresses(masscan, parms->nic_index, &src);
/*
* Set some flags [kludge]
*/
tcpcon_set_banner_flags(tcpcon,
masscan->is_capture_cert,
masscan->is_capture_servername,
masscan->is_capture_html,
masscan->is_capture_heartbleed,
masscan->is_capture_ticketbleed);
if (masscan->is_hello_smbv1)
tcpcon_set_parameter(tcpcon, "hello", 1, "smbv1");
if (masscan->is_hello_http)
tcpcon_set_parameter(tcpcon, "hello", 1, "http");
if (masscan->is_hello_ssl)
tcpcon_set_parameter(tcpcon, "hello", 1, "ssl");
if (masscan->is_heartbleed)
tcpcon_set_parameter(tcpcon, "heartbleed", 1, "1");
if (masscan->is_ticketbleed)
tcpcon_set_parameter(tcpcon, "ticketbleed", 1, "1");
if (masscan->is_poodle_sslv3)
tcpcon_set_parameter(tcpcon, "sslv3", 1, "1");
if (masscan->http.payload)
tcpcon_set_parameter( tcpcon,
"http-payload",
masscan->http.payload_length,
masscan->http.payload);
if (masscan->http.user_agent)
tcpcon_set_parameter( tcpcon,
"http-user-agent",
masscan->http.user_agent_length,
masscan->http.user_agent);
if (masscan->http.host)
tcpcon_set_parameter( tcpcon,
"http-host",
masscan->http.host_length,
masscan->http.host);
if (masscan->http.method)
tcpcon_set_parameter( tcpcon,
"http-method",
masscan->http.method_length,
masscan->http.method);
if (masscan->http.url)
tcpcon_set_parameter( tcpcon,
"http-url",
masscan->http.url_length,
masscan->http.url);
if (masscan->http.version)
tcpcon_set_parameter( tcpcon,
"http-version",
masscan->http.version_length,
masscan->http.version);
if (masscan->tcp_connection_timeout) {
char foo[64];
snprintf(foo, sizeof(foo), "%u", masscan->tcp_connection_timeout);
tcpcon_set_parameter( tcpcon,
"timeout",
strlen(foo),
foo);
}
if (masscan->tcp_hello_timeout) {
char foo[64];
snprintf(foo, sizeof(foo), "%u", masscan->tcp_hello_timeout);
tcpcon_set_parameter( tcpcon,
"hello-timeout",
strlen(foo),
foo);
}
for (i=0; i<masscan->http.headers_count; i++) {
tcpcon_set_http_header(tcpcon,
masscan->http.headers[i].name,
masscan->http.headers[i].value_length,
masscan->http.headers[i].value,
http_field_replace);
}
for (i=0; i<masscan->http.cookies_count; i++) {
tcpcon_set_http_header(tcpcon,
"Cookie",
masscan->http.cookies[i].value_length,
masscan->http.cookies[i].value,
http_field_add);
}
for (i=0; i<masscan->http.remove_count; i++) {
tcpcon_set_http_header(tcpcon,
masscan->http.headers[i].name,
0,
0,
http_field_remove);
}
for (pay = masscan->payloads.tcp; pay; pay = pay->next) {
char name[64];
snprintf(name, sizeof(name), "hello-string[%u]", pay->port);
tcpcon_set_parameter( tcpcon,
name,
strlen(pay->payload_base64),
pay->payload_base64);
}
}
/*
* In "offline" mode, we don't have any receive threads, so simply
* wait until transmitter thread is done then go to the end
*/
if (masscan->is_offline) {
while (!is_rx_done)
pixie_usleep(10000);
parms->done_receiving = 1;
goto end;
}
/*
* Receive packets. This is where we catch any responses and print
* them to the terminal.
*/
LOG(2, "[+] THREAD: recv: starting main loop\n");
while (!is_rx_done) {
int status;
unsigned length;
unsigned secs;
unsigned usecs;
const unsigned char *px;
int err;
unsigned x;
struct PreprocessedInfo parsed;
ipaddress ip_me;
unsigned port_me;
ipaddress ip_them;
unsigned port_them;
unsigned seqno_me;
unsigned seqno_them;
unsigned cookie;
unsigned Q = 0;
/*
* RECEIVE
*
* This is the boring part of actually receiving a packet
*/
err = rawsock_recv_packet(
adapter,
&length,
&secs,
&usecs,
&px);
if (err != 0) {
if (tcpcon)
tcpcon_timeouts(tcpcon, (unsigned)time(0), 0);
continue;
}
/*
* Do any TCP event timeouts based on the current timestamp from
* the packet. For example, if the connection has been open for
* around 10 seconds, we'll close the connection. (--banners)
*/
if (tcpcon) {
tcpcon_timeouts(tcpcon, secs, usecs);
}
if (length > 1514)
continue;
/*
* "Preprocess" the response packet. This means to go through and
* figure out where the TCP/IP headers are and the locations of
* some fields, like IP address and port numbers.
*/
x = preprocess_frame(px, length, data_link, &parsed);
if (!x)
continue; /* corrupt packet */
ip_me = parsed.dst_ip;
ip_them = parsed.src_ip;
port_me = parsed.port_dst;
port_them = parsed.port_src;
seqno_them = TCP_SEQNO(px, parsed.transport_offset);
seqno_me = TCP_ACKNO(px, parsed.transport_offset);
assert(ip_me.version != 0);
assert(ip_them.version != 0);
switch (parsed.ip_protocol) {
case 132: /* SCTP */
cookie = syn_cookie(ip_them, port_them | (Proto_SCTP<<16), ip_me, port_me, entropy) & 0xFFFFFFFF;
break;
default:
cookie = syn_cookie(ip_them, port_them, ip_me, port_me, entropy) & 0xFFFFFFFF;
}
/* verify: my IP address */
if (!is_my_ip(stack->src, ip_me)) {
/* NDP Neighbor Solicitations don't come to our IP address, but to
* a multicast address */
if (is_ipv6_multicast(ip_me)) {
if (parsed.found == FOUND_NDPv6 && parsed.opcode == 135) {
stack_ndpv6_incoming_request(stack, &parsed, px, length);
}
}
continue;
}
/*
* Handle non-TCP protocols
*/
switch (parsed.found) {
case FOUND_NDPv6:
switch (parsed.opcode) {
case 133: /* Router Solicitation */
/* Ignore router solicitations, since we aren't a router */
continue;
case 134: /* Router advertisement */
/* TODO: We need to process router advertisements while scanning
* so that we can print warning messages if router information
* changes while scanning. */
continue;
case 135: /* Neighbor Solicitation */
/* When responses come back from our scans, the router will send us
* these packets. We need to respond to them, so that the router
* can then forward the packets to us. If we don't respond, we'll
* get no responses. */
stack_ndpv6_incoming_request(stack, &parsed, px, length);
continue;
case 136: /* Neighbor Advertisement */
/* TODO: If doing an --ndpscan, the scanner subsystem needs to deal
* with these */
continue;
case 137: /* Redirect */
/* We ignore these, since we really don't have the capability to send
* packets to one router for some destinations and to another router
* for other destinations */
continue;
default:
break;
}
continue;
case FOUND_ARP:
LOGip(2, ip_them, 0, "-> ARP [%u] \n", px[parsed.found_offset]);
switch (parsed.opcode) {
case 1: /* request */
/* This function will transmit a "reply" to somebody's ARP request
* for our IP address (as part of our user-mode TCP/IP).
* Since we completely bypass the TCP/IP stack, we have to handle ARPs
* ourself, or the router will lose track of us.*/
stack_arp_incoming_request(stack,
ip_me.ipv4,
parms->source_mac,
px, length);
break;
case 2: /* response */
/* This is for "arp scan" mode, where we are ARPing targets rather
* than port scanning them */
/* If we aren't doing an ARP scan, then ignore ARP responses */
if (!masscan->scan_type.arp)
break;
/* If this response isn't in our range, then ignore it */
if (!rangelist_is_contains(&masscan->targets.ipv4, ip_them.ipv4))
break;
/* Ignore duplicates */
if (dedup_is_duplicate(dedup, ip_them, 0, ip_me, 0))
continue;
/* ...everything good, so now report this response */
arp_recv_response(out, secs, px, length, &parsed);
break;
}
continue;
case FOUND_UDP:
case FOUND_DNS:
if (!is_nic_port(masscan, port_me))
continue;
if (parms->masscan->nmap.packet_trace)
packet_trace(stdout, parms->pt_start, px, length, 0);
handle_udp(out, secs, px, length, &parsed, entropy);
continue;
case FOUND_ICMP:
handle_icmp(out, secs, px, length, &parsed, entropy);
continue;
case FOUND_SCTP:
handle_sctp(out, secs, px, length, cookie, &parsed, entropy);
break;
case FOUND_OPROTO: /* other IP proto */
handle_oproto(out, secs, px, length, &parsed, entropy);
break;
case FOUND_TCP:
/* fall down to below */
break;
default:
continue;
}
/* verify: my port number */
if (!is_my_port(stack->src, port_me))
continue;
if (parms->masscan->nmap.packet_trace)
packet_trace(stdout, parms->pt_start, px, length, 0);
Q = 0;
/* Save raw packet in --pcap file */
if (pcapfile) {
pcapfile_writeframe(
pcapfile,
px,
length,
length,
secs,
usecs);
}
{
char buf[64];
LOGip(5, ip_them, port_them, "-> TCP ackno=0x%08x flags=0x%02x(%s)\n",
seqno_me,
TCP_FLAGS(px, parsed.transport_offset),
reason_string(TCP_FLAGS(px, parsed.transport_offset), buf, sizeof(buf)));
}
/* If recording --banners, create a new "TCP Control Block (TCB)" */
if (tcpcon) {
struct TCP_Control_Block *tcb;
/* does a TCB already exist for this connection? */
tcb = tcpcon_lookup_tcb(tcpcon,
ip_me, ip_them,
port_me, port_them);
if (TCP_IS_SYNACK(px, parsed.transport_offset)) {
if (cookie != seqno_me - 1) {
ipaddress_formatted_t fmt = ipaddress_fmt(ip_them);
LOG(0, "%s - bad cookie: ackno=0x%08x expected=0x%08x\n",
fmt.string, seqno_me-1, cookie);
continue;
}
if (tcb == NULL) {
tcb = tcpcon_create_tcb(tcpcon,
ip_me, ip_them,
port_me, port_them,
seqno_me, seqno_them+1,
parsed.ip_ttl, NULL,
secs, usecs);
(*status_tcb_count)++;
}
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_SYNACK,
0, 0, secs, usecs, seqno_them+1, seqno_me);
} else if (tcb) {
/* If this is an ACK, then handle that first */
if (TCP_IS_ACK(px, parsed.transport_offset)) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_ACK,
0, 0, secs, usecs, seqno_them, seqno_me);
}
/* If this contains payload, handle that second */
if (parsed.app_length) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_DATA,
px + parsed.app_offset, parsed.app_length,
secs, usecs, seqno_them, seqno_me);
}
/* If this is a FIN, handle that. Note that ACK +
* payload + FIN can come together */
if (TCP_IS_FIN(px, parsed.transport_offset)
&& !TCP_IS_RST(px, parsed.transport_offset)) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_FIN,
0, 0,
secs, usecs,
seqno_them + parsed.app_length, /* the FIN comes after any data in the packet */
seqno_me);
}
/* If this is a RST, then we'll be closing the connection */
if (TCP_IS_RST(px, parsed.transport_offset)) {
Q += stack_incoming_tcp(tcpcon, tcb, TCP_WHAT_RST,
0, 0, secs, usecs, seqno_them, seqno_me);
}
} else if (TCP_IS_FIN(px, parsed.transport_offset)) {
ipaddress_formatted_t fmt;
/*
* NO TCB!
* This happens when we've sent a FIN, deleted our connection,
* but the other side didn't get the packet.
*/
fmt = ipaddress_fmt(ip_them);
LOG(4, "%s: received FIN but no TCB\n", fmt.string);
if (TCP_IS_RST(px, parsed.transport_offset))
; /* ignore if it's own TCP flag is set */
else {
int is_suppress;
is_suppress = rstfilter_is_filter(rf, ip_me, port_me, ip_them, port_them);
if (!is_suppress)
tcpcon_send_RST(
tcpcon,
ip_me, ip_them,
port_me, port_them,
seqno_them, seqno_me);
}
}
}
if (Q == 0)
; //printf("\nerr\n");
if (TCP_IS_SYNACK(px, parsed.transport_offset)
|| TCP_IS_RST(px, parsed.transport_offset)) {
/* figure out the status */
status = PortStatus_Unknown;
if (TCP_IS_SYNACK(px, parsed.transport_offset))
status = PortStatus_Open;
if (TCP_IS_RST(px, parsed.transport_offset)) {
status = PortStatus_Closed;
}
/* verify: syn-cookies */
if (cookie != seqno_me - 1) {
ipaddress_formatted_t fmt = ipaddress_fmt(ip_them);
LOG(2, "%s - bad cookie: ackno=0x%08x expected=0x%08x\n",
fmt.string, seqno_me-1, cookie);
continue;
}
/* verify: ignore duplicates */
if (dedup_is_duplicate(dedup, ip_them, port_them, ip_me, port_me))
continue;
/* keep statistics on number received */
if (TCP_IS_SYNACK(px, parsed.transport_offset))
(*status_synack_count)++;
/*
* This is where we do the output
*/
output_report_status(
out,
global_now,
status,
ip_them,
6, /* ip proto = tcp */
port_them,
px[parsed.transport_offset + 13], /* tcp flags */
parsed.ip_ttl,
parsed.mac_src
);
/*
* Send RST so other side isn't left hanging (only doing this in
* complete stateless mode where we aren't tracking banners)
*/
if (tcpcon == NULL && !masscan->is_noreset)
tcp_send_RST(
&parms->tmplset->pkts[Proto_TCP],
parms->stack,
ip_them, ip_me,
port_them, port_me,
0, seqno_me);
}
}
LOG(1, "[+] exiting receive thread #%u \n", parms->nic_index);
/*
* cleanup
*/
end:
if (tcpcon)
tcpcon_destroy_table(tcpcon);
dedup_destroy(dedup);
output_destroy(out);
if (pcapfile)
pcapfile_close(pcapfile);
/*TODO: free stack packet buffers */
/* Thread is about to exit */
parms->done_receiving = 1;
}
/***************************************************************************
* We trap the <ctrl-c> so that instead of exiting immediately, we sit in
* a loop for a few seconds waiting for any late response. But, the user
* can press <ctrl-c> a second time to exit that waiting.
***************************************************************************/
static void control_c_handler(int x)
{
static unsigned control_c_pressed = 0;
static unsigned control_c_pressed_again = 0;
if (control_c_pressed == 0) {
fprintf(stderr,
"waiting several seconds to exit..."
" \n"
);
fflush(stderr);
control_c_pressed = 1+x;
is_tx_done = control_c_pressed;
} else {
if (is_rx_done) {
fprintf(stderr, "\nERROR: threads not exiting %d\n", is_rx_done);
if (is_rx_done++ > 1)
exit(1);
} else {
control_c_pressed_again = 1;
is_rx_done = control_c_pressed_again;
}
}
}
/***************************************************************************
* Called from main() to initiate the scan.
* Launches the 'transmit_thread()' and 'receive_thread()' and waits for
* them to exit.
***************************************************************************/
static int
main_scan(struct Masscan *masscan)
{
struct ThreadPair parms_array[8];
uint64_t count_ips;
uint64_t count_ports;
uint64_t range;
unsigned index;
time_t now = time(0);
struct Status status;
uint64_t min_index = UINT64_MAX;
struct MassVulnCheck *vulncheck = NULL;
struct stack_t *stack;
memset(parms_array, 0, sizeof(parms_array));
/*
* Vuln check initialization
*/
if (masscan->vuln_name) {
unsigned i;
unsigned is_error;
vulncheck = vulncheck_lookup(masscan->vuln_name);
/* If no ports specified on command-line, grab default ports */
is_error = 0;
if (rangelist_count(&masscan->targets.ports) == 0)
rangelist_parse_ports(&masscan->targets.ports, vulncheck->ports, &is_error, 0);
/* Kludge: change normal port range to vulncheck range */
for (i=0; i<masscan->targets.ports.count; i++) {
struct Range *r = &masscan->targets.ports.list[i];
r->begin = (r->begin&0xFFFF) | Templ_VulnCheck;
r->end = (r->end & 0xFFFF) | Templ_VulnCheck;
}
}
/*
* Initialize the task size
*/
count_ips = rangelist_count(&masscan->targets.ipv4) + range6list_count(&masscan->targets.ipv6).lo;
if (count_ips == 0) {
LOG(0, "FAIL: target IP address list empty\n");
LOG(0, " [hint] try something like \"--range 10.0.0.0/8\"\n");
LOG(0, " [hint] try something like \"--range 192.168.0.100-192.168.0.200\"\n");
return 1;
}
count_ports = rangelist_count(&masscan->targets.ports);
if (count_ports == 0) {
LOG(0, "FAIL: no ports were specified\n");
LOG(0, " [hint] try something like \"-p80,8000-9000\"\n");
LOG(0, " [hint] try something like \"--ports 0-65535\"\n");
return 1;
}
range = count_ips * count_ports;
range += (uint64_t)(masscan->retries * range);
/*
* If doing an ARP scan, then don't allow port scanning
*/
if (rangelist_is_contains(&masscan->targets.ports, Templ_ARP)) {
if (masscan->targets.ports.count != 1) {
LOG(0, "FAIL: cannot arpscan and portscan at the same time\n");
return 1;
}
}
/*
* If the IP address range is very big, then require that that the
* user apply an exclude range
*/
if (count_ips > 1000000000ULL && rangelist_count(&masscan->exclude.ipv4) == 0) {
LOG(0, "FAIL: range too big, need confirmation\n");
LOG(0, " [hint] to prevent accidents, at least one --exclude must be specified\n");
LOG(0, " [hint] use \"--exclude 255.255.255.255\" as a simple confirmation\n");
exit(1);
}
/*
* trim the nmap UDP payloads down to only those ports we are using. This
* makes lookups faster at high packet rates.
*/
payloads_udp_trim(masscan->payloads.udp, &masscan->targets);
payloads_oproto_trim(masscan->payloads.oproto, &masscan->targets);
#ifdef __AFL_HAVE_MANUAL_CONTROL
__AFL_INIT();
#endif
/*
* Start scanning threats for each adapter
*/
for (index=0; index<masscan->nic_count; index++) {
struct ThreadPair *parms = &parms_array[index];
int err;
parms->masscan = masscan;
parms->nic_index = index;
parms->my_index = masscan->resume.index;
parms->done_transmitting = 0;
parms->done_receiving = 0;
/* needed for --packet-trace option so that we know when we started
* the scan */
parms->pt_start = 1.0 * pixie_gettime() / 1000000.0;
/*
* Turn the adapter on, and get the running configuration
*/
err = masscan_initialize_adapter(
masscan,
index,
&parms->source_mac,
&parms->router_mac_ipv4,
&parms->router_mac_ipv6
);
if (err != 0)
exit(1);
parms->adapter = masscan->nic[index].adapter;
if (!masscan->nic[index].is_usable) {
LOG(0, "FAIL: failed to detect IP of interface\n");
LOG(0, " [hint] did you spell the name correctly?\n");
LOG(0, " [hint] if it has no IP address, "
"manually set with \"--adapter-ip 192.168.100.5\"\n");
exit(1);
}
/*
* Initialize the TCP packet template. The way this works is that
* we parse an existing TCP packet, and use that as the template for
* scanning. Then, we adjust the template with additional features,
* such as the IP address and so on.
*/
parms->tmplset->vulncheck = vulncheck;
template_packet_init(
parms->tmplset,
parms->source_mac,
parms->router_mac_ipv4,
parms->router_mac_ipv6,
masscan->payloads.udp,
masscan->payloads.oproto,
stack_if_datalink(masscan->nic[index].adapter),
masscan->seed,
masscan->templ_opts);
/*
* Set the "source port" of everything we transmit.
*/
if (masscan->nic[index].src.port.range == 0) {
unsigned port = 40000 + now % 20000;
masscan->nic[index].src.port.first = port;
masscan->nic[index].src.port.last = port + 16;
masscan->nic[index].src.port.range = 16;
}
stack = stack_create(parms->source_mac, &masscan->nic[index].src);
parms->stack = stack;
/*
* Set the "TTL" (IP time-to-live) of everything we send.
*/
if (masscan->nmap.ttl)
template_set_ttl(parms->tmplset, masscan->nmap.ttl);
if (masscan->nic[0].is_vlan)
template_set_vlan(parms->tmplset, masscan->nic[0].vlan_id);
/*
* trap <ctrl-c> to pause
*/
signal(SIGINT, control_c_handler);
}
/*
* Print helpful text
*/
{
char buffer[80];
struct tm x;
now = time(0);
safe_gmtime(&x, &now);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S GMT", &x);
LOG(0, "Starting masscan " MASSCAN_VERSION " (http://bit.ly/14GZzcT) at %s\n",
buffer);
if (count_ports == 1 && \
masscan->targets.ports.list->begin == Templ_ICMP_echo && \
masscan->targets.ports.list->end == Templ_ICMP_echo)
{ /* ICMP only */
//LOG(0, " -- forced options: -sn -n --randomize-hosts -v --send-eth\n");
LOG(0, "Initiating ICMP Echo Scan\n");
LOG(0, "Scanning %u hosts\n",(unsigned)count_ips);
}
else /* This could actually also be a UDP only or mixed UDP/TCP/ICMP scan */
{
//LOG(0, " -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth\n");
LOG(0, "Initiating SYN Stealth Scan\n");
LOG(0, "Scanning %u hosts [%u port%s/host]\n",
(unsigned)count_ips, (unsigned)count_ports, (count_ports==1)?"":"s");
}
}
/*
* Start all the threads
*/
for (index=0; index<masscan->nic_count; index++) {
struct ThreadPair *parms = &parms_array[index];
/*
* Start the scanning thread.
* THIS IS WHERE THE PROGRAM STARTS SPEWING OUT PACKETS AT A HIGH
* RATE OF SPEED.
*/
parms->thread_handle_xmit = pixie_begin_thread(transmit_thread, 0, parms);
/*
* Start the MATCHING receive thread. Transmit and receive threads
* come in matching pairs.
*/
parms->thread_handle_recv = pixie_begin_thread(receive_thread, 0, parms);
}
/*
* Now wait for <ctrl-c> to be pressed OR for threads to exit
*/
pixie_usleep(1000 * 100);
LOG(1, "[+] waiting for threads to finish\n");
status_start(&status);
status.is_infinite = masscan->is_infinite;
while (!is_tx_done && masscan->output.is_status_updates) {
unsigned i;
double rate = 0;
uint64_t total_tcbs = 0;
uint64_t total_synacks = 0;
uint64_t total_syns = 0;
/* Find the minimum index of all the threads */
min_index = UINT64_MAX;
for (i=0; i<masscan->nic_count; i++) {
struct ThreadPair *parms = &parms_array[i];
if (min_index > parms->my_index)
min_index = parms->my_index;
rate += parms->throttler->current_rate;
if (parms->total_tcbs)
total_tcbs += *parms->total_tcbs;
if (parms->total_synacks)
total_synacks += *parms->total_synacks;
if (parms->total_syns)
total_syns += *parms->total_syns;
}
if (min_index >= range && !masscan->is_infinite) {
/* Note: This is how we can tell the scan has ended */
is_tx_done = 1;
}
/*
* update screen about once per second with statistics,
* namely packets/second.
*/
if (masscan->output.is_status_updates)
status_print(&status, min_index, range, rate,
total_tcbs, total_synacks, total_syns,
0, masscan->output.is_status_ndjson);
/* Sleep for almost a second */
pixie_mssleep(750);
}
/*
* If we haven't completed the scan, then save the resume
* information.
*/
if (min_index < count_ips * count_ports) {
masscan->resume.index = min_index;
/* Write current settings to "paused.conf" so that the scan can be restarted */
masscan_save_state(masscan);
}
/*
* Now wait for all threads to exit
*/
now = time(0);
for (;;) {
unsigned transmit_count = 0;
unsigned receive_count = 0;
unsigned i;
double rate = 0;
uint64_t total_tcbs = 0;
uint64_t total_synacks = 0;
uint64_t total_syns = 0;
/* Find the minimum index of all the threads */
min_index = UINT64_MAX;
for (i=0; i<masscan->nic_count; i++) {
struct ThreadPair *parms = &parms_array[i];
if (min_index > parms->my_index)
min_index = parms->my_index;
rate += parms->throttler->current_rate;
if (parms->total_tcbs)
total_tcbs += *parms->total_tcbs;
if (parms->total_synacks)
total_synacks += *parms->total_synacks;
if (parms->total_syns)
total_syns += *parms->total_syns;
}
if (time(0) - now >= masscan->wait) {
is_rx_done = 1;
}
if (time(0) - now - 10 > masscan->wait) {
LOG(0, "[-] Passed the wait window but still running, forcing exit...\n");
exit(0);
}
if (masscan->output.is_status_updates) {
status_print(&status, min_index, range, rate,
total_tcbs, total_synacks, total_syns,
masscan->wait - (time(0) - now),
masscan->output.is_status_ndjson);
for (i=0; i<masscan->nic_count; i++) {
struct ThreadPair *parms = &parms_array[i];
transmit_count += parms->done_transmitting;
receive_count += parms->done_receiving;
}
pixie_mssleep(250);
if (transmit_count < masscan->nic_count)
continue;
is_tx_done = 1;
is_rx_done = 1;
if (receive_count < masscan->nic_count)
continue;
} else {
/* [AFL-fuzz]
* Join the threads, which doesn't allow us to print out
* status messages, but allows us to exit cleanly without
* any waiting */
for (i=0; i<masscan->nic_count; i++) {
struct ThreadPair *parms = &parms_array[i];
pixie_thread_join(parms->thread_handle_xmit);
parms->thread_handle_xmit = 0;
pixie_thread_join(parms->thread_handle_recv);
parms->thread_handle_recv = 0;
}
is_tx_done = 1;
is_rx_done = 1;
}
break;
}
/*
* Now cleanup everything
*/
status_finish(&status);
if (!masscan->output.is_status_updates) {
uint64_t usec_now = pixie_gettime();
printf("%u milliseconds elapsed\n", (unsigned)((usec_now - usec_start)/1000));
}
LOG(1, "[+] all threads have exited \n");
return 0;
}
/***************************************************************************
***************************************************************************/
int main(int argc, char *argv[])
{
struct Masscan masscan[1];
unsigned i;
int has_target_addresses = 0;
int has_target_ports = 0;
usec_start = pixie_gettime();
#if defined(WIN32)
{WSADATA x; WSAStartup(0x101, &x);}
#endif
global_now = time(0);
/* Set system to report debug information on crash */
{
int is_backtrace = 1;
for (i=1; i<(unsigned)argc; i++) {
if (strcmp(argv[i], "--nobacktrace") == 0)
is_backtrace = 0;
}
if (is_backtrace)
pixie_backtrace_init(argv[0]);
}
/*
* Initialize those defaults that aren't zero
*/
memset(masscan, 0, sizeof(*masscan));
/* 14 rounds seem to give way better statistical distribution than 4 with a
very low impact on scan rate */
masscan->blackrock_rounds = 14;
masscan->output.is_show_open = 1; /* default: show syn-ack, not rst */
masscan->output.is_status_updates = 1; /* default: show status updates */
masscan->wait = 10; /* how long to wait for responses when done */
masscan->max_rate = 100.0; /* max rate = hundred packets-per-second */
masscan->nic_count = 1;
masscan->shard.one = 1;
masscan->shard.of = 1;
masscan->min_packet_size = 60;
masscan->redis.password = NULL;
masscan->payloads.udp = payloads_udp_create();
masscan->payloads.oproto = payloads_oproto_create();
safe_strcpy( masscan->output.rotate.directory,
sizeof(masscan->output.rotate.directory),
".");
masscan->is_capture_cert = 1;
/*
* Pre-parse the command-line
*/
if (masscan_conf_contains("--readscan", argc, argv)) {
masscan->is_readscan = 1;
}
/*
* On non-Windows systems, read the defaults from the file in
* the /etc directory. These defaults will contain things
* like the output directory, max packet rates, and so on. Most
* importantly, the master "--excludefile" might be placed here,
* so that blacklisted ranges won't be scanned, even if the user
* makes a mistake
*/
#if !defined(WIN32)
if (!masscan->is_readscan) {
if (access("/etc/masscan/masscan.conf", 0) == 0) {
masscan_read_config_file(masscan, "/etc/masscan/masscan.conf");
}
}
#endif
/*
* Read in the configuration from the command-line. We are looking for
* either options or a list of IPv4 address ranges.
*/
masscan_command_line(masscan, argc, argv);
if (masscan->seed == 0)
masscan->seed = get_entropy(); /* entropy for randomness */
/*
* Load database files like "nmap-payloads" and "nmap-service-probes"
*/
masscan_load_database_files(masscan);
/*
* Load the scripting engine if needed and run those that were
* specified.
*/
if (masscan->is_scripting)
scripting_init(masscan);
/* We need to do a separate "raw socket" initialization step. This is
* for Windows and PF_RING. */
if (pcap_init() != 0)
LOG(2, "libpcap: failed to load\n");
rawsock_init();
/* Init some protocol parser data structures */
snmp_init();
x509_init();
/*
* Apply excludes. People ask us not to scan them, so we maintain a list
* of their ranges, and when doing wide scans, add the exclude list to
* prevent them from being scanned.
*/
has_target_addresses = massip_has_ipv4_targets(&masscan->targets) || massip_has_ipv6_targets(&masscan->targets);
has_target_ports = massip_has_target_ports(&masscan->targets);
massip_apply_excludes(&masscan->targets, &masscan->exclude);
if (!has_target_ports && masscan->op == Operation_ListScan)
massip_add_port_string(&masscan->targets, "80", 0);
/* Optimize target selection so it's a quick binary search instead
* of walking large memory tables. When we scan the entire Internet
* our --excludefile will chop up our pristine 0.0.0.0/0 range into
* hundreds of subranges. This allows us to grab addresses faster. */
massip_optimize(&masscan->targets);
/* FIXME: we only support 63-bit scans at the current time.
* This is big enough for the IPv4 Internet, where scanning
* for all TCP ports on all IPv4 addresses results in a 48-bit
* scan, but this isn't big enough even for a single port on
* an IPv6 subnet (which are 64-bits in size, usually). However,
* even at millions of packets per second scanning rate, you still
* can't complete a 64-bit scan in a reasonable amount of time.
* Nor would you want to attempt the feat, as it would overload
* the target IPv6 subnet. Since implementing this would be
* difficult for 32-bit processors, for now, I'm going to stick
* to a simple 63-bit scan.
*/
if (massint128_bitcount(massip_range(&masscan->targets)) > 63) {
fprintf(stderr, "[-] FAIL: scan range too large, max is 63-bits, requested is %u bits\n",
massint128_bitcount(massip_range(&masscan->targets)));
fprintf(stderr, " Hint: scan range is number of IP addresses times number of ports\n");
fprintf(stderr, " Hint: IPv6 subnet must be at least /66 \n");
exit(1);
}
/*
* Once we've read in the configuration, do the operation that was
* specified
*/
switch (masscan->op) {
case Operation_Default:
/* Print usage info and exit */
masscan_usage();
break;
case Operation_Scan:
/*
* THIS IS THE NORMAL THING
*/
if (rangelist_count(&masscan->targets.ipv4) == 0 && massint128_is_zero(range6list_count(&masscan->targets.ipv6))) {
/* We check for an empty target list here first, before the excludes,
* so that we can differentiate error messages after excludes, in case
* the user specified addresses, but they were removed by excludes. */
LOG(0, "FAIL: target IP address list empty\n");
if (has_target_addresses) {
LOG(0, " [hint] all addresses were removed by exclusion ranges\n");
} else {
LOG(0, " [hint] try something like \"--range 10.0.0.0/8\"\n");
LOG(0, " [hint] try something like \"--range 192.168.0.100-192.168.0.200\"\n");
}
exit(1);
}
if (rangelist_count(&masscan->targets.ports) == 0) {
if (has_target_ports) {
LOG(0, " [hint] all ports were removed by exclusion ranges\n");
} else {
LOG(0, "FAIL: no ports were specified\n");
LOG(0, " [hint] try something like \"-p80,8000-9000\"\n");
LOG(0, " [hint] try something like \"--ports 0-65535\"\n");
}
return 1;
}
return main_scan(masscan);
case Operation_ListScan:
/* Create a randomized list of IP addresses */
main_listscan(masscan);
return 0;
case Operation_List_Adapters:
/* List the network adapters we might want to use for scanning */
rawsock_list_adapters();
break;
case Operation_DebugIF:
for (i=0; i<masscan->nic_count; i++)
rawsock_selftest_if(masscan->nic[i].ifname);
return 0;
case Operation_ReadRange:
main_readrange(masscan);
return 0;
case Operation_ReadScan:
{
unsigned start;
unsigned stop;
/* find first file */
for (start=1; start<(unsigned)argc; start++) {
if (memcmp(argv[start], "--readscan", 10) == 0) {
start++;
break;
}
}
/* find last file */
for (stop=start+1; stop<(unsigned)argc && argv[stop][0] != '-'; stop++)
;
/*
* read the binary files, and output them again depending upon
* the output parameters
*/
readscan_binary_scanfile(masscan, start, stop, argv);
}
break;
case Operation_Benchmark:
printf("=== benchmarking (%u-bits) ===\n\n", (unsigned)sizeof(void*)*8);
blackrock_benchmark(masscan->blackrock_rounds);
blackrock2_benchmark(masscan->blackrock_rounds);
smack_benchmark();
exit(1);
break;
case Operation_Echo:
masscan_echo(masscan, stdout, 0);
exit(0);
break;
case Operation_EchoAll:
masscan_echo(masscan, stdout, 0);
exit(0);
break;
case Operation_EchoCidr:
masscan_echo_cidr(masscan, stdout, 0);
exit(0);
break;
case Operation_Selftest:
/*
* Do a regression test of all the significant units
*/
{
int x = 0;
extern int proto_isakmp_selftest(void);
x += massip_selftest();
x += ranges6_selftest();
x += dedup_selftest();
x += checksum_selftest();
x += ipv6address_selftest();
x += proto_coap_selftest();
x += smack_selftest();
x += sctp_selftest();
x += base64_selftest();
x += banner1_selftest();
x += output_selftest();
x += siphash24_selftest();
x += ntp_selftest();
x += snmp_selftest();
x += proto_isakmp_selftest();
x += templ_payloads_selftest();
x += blackrock_selftest();
x += rawsock_selftest();
x += lcg_selftest();
x += template_selftest();
x += ranges_selftest();
x += massip_parse_selftest();
x += pixie_time_selftest();
x += rte_ring_selftest();
x += mainconf_selftest();
x += zeroaccess_selftest();
x += nmapserviceprobes_selftest();
x += rstfilter_selftest();
x += masscan_app_selftest();
if (x != 0) {
/* one of the selftests failed, so return error */
fprintf(stderr, "regression test: failed :( \n");
return 1;
} else {
fprintf(stderr, "regression test: success!\n");
return 0;
}
}
break;
}
return 0;
}