summaryrefslogtreecommitdiff
path: root/rdns_scan/zmap4rdns/src/zmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdns_scan/zmap4rdns/src/zmap.c')
-rw-r--r--rdns_scan/zmap4rdns/src/zmap.c943
1 files changed, 943 insertions, 0 deletions
diff --git a/rdns_scan/zmap4rdns/src/zmap.c b/rdns_scan/zmap4rdns/src/zmap.c
new file mode 100644
index 0000000..9ac730d
--- /dev/null
+++ b/rdns_scan/zmap4rdns/src/zmap.c
@@ -0,0 +1,943 @@
+/*
+ * ZMap Copyright 2013 Regents of the University of Michigan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sched.h>
+#include <errno.h>
+#include <pwd.h>
+#include <time.h>
+
+#include <pcap/pcap.h>
+#include <json.h>
+
+#include <pthread.h>
+
+#include "../lib/includes.h"
+#include "../lib/blocklist.h"
+#include "../lib/logger.h"
+#include "../lib/random.h"
+#include "../lib/util.h"
+#include "../lib/xalloc.h"
+#include "../lib/pbm.h"
+
+#include "aesrand.h"
+#include "zopt.h"
+#include "send.h"
+#include "recv.h"
+#include "state.h"
+#include "monitor.h"
+#include "get_gateway.h"
+#include "filter.h"
+#include "summary.h"
+#include "utility.h"
+
+#include "output_modules/output_modules.h"
+#include "probe_modules/probe_modules.h"
+
+#ifdef PFRING
+#include <pfring_zc.h>
+static int32_t distrib_func(pfring_zc_pkt_buff *pkt, pfring_zc_queue *in_queue,
+ void *arg)
+{
+ (void)pkt;
+ (void)in_queue;
+ (void)arg;
+ return 0;
+}
+#endif
+
+pthread_mutex_t recv_ready_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct send_arg {
+ uint32_t cpu;
+ sock_t sock;
+ shard_t *shard;
+} send_arg_t;
+
+typedef struct recv_arg {
+ uint32_t cpu;
+} recv_arg_t;
+
+typedef struct mon_start_arg {
+ uint32_t cpu;
+ iterator_t *it;
+ pthread_mutex_t *recv_ready_mutex;
+} mon_start_arg_t;
+
+const char *default_help_text =
+ "By default, ZMap prints out unique, successful "
+ "IP addresses (e.g., SYN-ACK from a TCP SYN scan) "
+ "in ASCII form (e.g., 192.168.1.5) to stdout or the specified output "
+ "file. Internally this is handled by the \"csv\" output module and is "
+ "equivalent to running zmap --output-module=csv --output-fields=saddr "
+ "--output-filter=\"success = 1 && repeat = 0\" --no-header-row.";
+
+static void *start_send(void *arg)
+{
+ send_arg_t *s = (send_arg_t *)arg;
+ log_debug("zmap", "Pinning a send thread to core %u", s->cpu);
+ set_cpu(s->cpu);
+ send_run(s->sock, s->shard);
+ free(s);
+ return NULL;
+}
+
+static void *start_recv(void *arg)
+{
+ recv_arg_t *r = (recv_arg_t *)arg;
+ log_debug("zmap", "Pinning receive thread to core %u", r->cpu);
+ set_cpu(r->cpu);
+ recv_run(&recv_ready_mutex);
+ return NULL;
+}
+
+static void *start_mon(void *arg)
+{
+ mon_start_arg_t *mon_arg = (mon_start_arg_t *)arg;
+ log_debug("zmap", "Pinning monitor thread to core %u", mon_arg->cpu);
+ set_cpu(mon_arg->cpu);
+ monitor_run(mon_arg->it, mon_arg->recv_ready_mutex);
+ free(mon_arg);
+ return NULL;
+}
+
+static void start_zmap(void)
+{
+ if (zconf.iface == NULL) {
+ zconf.iface = get_default_iface();
+ assert(zconf.iface);
+ log_debug("zmap",
+ "no interface provided. will use default"
+ " interface (%s).",
+ zconf.iface);
+ }
+ if (zconf.number_source_ips == 0) {
+ struct in_addr default_ip;
+ if (get_iface_ip(zconf.iface, &default_ip) < 0) {
+ log_fatal("zmap",
+ "could not detect default IP address for %s."
+ " Try specifying a source address (-S).",
+ zconf.iface);
+ }
+ zconf.source_ip_addresses[0] = default_ip.s_addr;
+ zconf.number_source_ips++;
+ log_debug(
+ "zmap",
+ "no source IP address given. will use default address: %s.",
+ inet_ntoa(default_ip));
+ }
+ if (!zconf.gw_mac_set) {
+ struct in_addr gw_ip;
+ memset(&gw_ip, 0, sizeof(struct in_addr));
+ if (get_default_gw(&gw_ip, zconf.iface) < 0) {
+ log_fatal(
+ "zmap",
+ "could not detect default gateway address for %s."
+ " Try setting default gateway mac address (-G)."
+ " If this is a newly launched machine, try completing an outgoing network connection (e.g. curl https://zmap.io), and trying again.",
+ zconf.iface);
+ }
+ log_debug("zmap", "found gateway IP %s on %s", inet_ntoa(gw_ip),
+ zconf.iface);
+ zconf.gw_ip = gw_ip.s_addr;
+ memset(&zconf.gw_mac, 0, MAC_ADDR_LEN);
+ if (get_hw_addr(&gw_ip, zconf.iface, zconf.gw_mac)) {
+ log_fatal(
+ "zmap",
+ "could not detect GW MAC address for %s on %s."
+ " Try setting default gateway mac address (-G), or run"
+ " \"arp <gateway_ip>\" in terminal."
+ " If this is a newly launched machine, try completing an outgoing network connection (e.g. curl https://zmap.io), and trying again.",
+ inet_ntoa(gw_ip), zconf.iface);
+ }
+ zconf.gw_mac_set = 1;
+ }
+ log_debug("send", "gateway MAC address %02x:%02x:%02x:%02x:%02x:%02x",
+ zconf.gw_mac[0], zconf.gw_mac[1], zconf.gw_mac[2],
+ zconf.gw_mac[3], zconf.gw_mac[4], zconf.gw_mac[5]);
+ // Initialization
+ assert(zconf.output_module && "no output module set");
+ log_debug("zmap", "output module: %s", zconf.output_module->name);
+ if (zconf.output_module && zconf.output_module->init) {
+ if (zconf.output_module->init(&zconf, zconf.output_fields,
+ zconf.output_fields_len)) {
+ log_fatal(
+ "zmap",
+ "output module did not initialize successfully.");
+ }
+ }
+
+ iterator_t *it = send_init();
+ if (!it) {
+ log_fatal("zmap", "unable to initialize sending component");
+ }
+ if (zconf.output_module && zconf.output_module->start) {
+ zconf.output_module->start(&zconf, &zsend, &zrecv);
+ }
+
+ // start threads
+ uint32_t cpu = 0;
+ pthread_t *tsend, trecv, tmon;
+ int r;
+ if (!zconf.dryrun) {
+ recv_arg_t *recv_arg = xmalloc(sizeof(recv_arg_t));
+ recv_arg->cpu = zconf.pin_cores[cpu % zconf.pin_cores_len];
+ cpu += 1;
+ r = pthread_create(&trecv, NULL, start_recv, recv_arg);
+ if (r != 0) {
+ log_fatal("zmap", "unable to create recv thread");
+ }
+ for (;;) {
+ pthread_mutex_lock(&recv_ready_mutex);
+ if (zconf.recv_ready) {
+ pthread_mutex_unlock(&recv_ready_mutex);
+ break;
+ }
+ pthread_mutex_unlock(&recv_ready_mutex);
+ }
+ }
+#ifdef PFRING
+ pfring_zc_worker *zw = pfring_zc_run_balancer(
+ zconf.pf.queues, &zconf.pf.send, zconf.senders, 1,
+ zconf.pf.prefetches, round_robin_bursts_policy, NULL, distrib_func,
+ NULL, 0, zconf.pin_cores[cpu & zconf.pin_cores_len]);
+ cpu += 1;
+#endif
+ tsend = xmalloc(zconf.senders * sizeof(pthread_t));
+ for (uint8_t i = 0; i < zconf.senders; i++) {
+ sock_t sock;
+ if (zconf.dryrun) {
+ sock = get_dryrun_socket();
+ } else {
+ sock = get_socket(i);
+ }
+ send_arg_t *arg = xmalloc(sizeof(send_arg_t));
+
+ arg->sock = sock;
+ arg->shard = get_shard(it, i);
+ arg->cpu = zconf.pin_cores[cpu % zconf.pin_cores_len];
+ cpu += 1;
+ int r = pthread_create(&tsend[i], NULL, start_send, arg);
+ if (r != 0) {
+ log_fatal("zmap", "unable to create send thread");
+ exit(EXIT_FAILURE);
+ }
+ }
+ log_debug("zmap", "%d sender threads spawned", zconf.senders);
+
+ if (!zconf.dryrun) {
+ monitor_init();
+ mon_start_arg_t *mon_arg = xmalloc(sizeof(mon_start_arg_t));
+ mon_arg->it = it;
+ mon_arg->recv_ready_mutex = &recv_ready_mutex;
+ mon_arg->cpu = zconf.pin_cores[cpu % zconf.pin_cores_len];
+ int r = pthread_create(&tmon, NULL, start_mon, mon_arg);
+ if (r != 0) {
+ log_fatal("zmap", "unable to create monitor thread");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+#ifndef PFRING
+ drop_privs();
+#endif
+
+ // wait for completion
+ for (uint8_t i = 0; i < zconf.senders; i++) {
+ int r = pthread_join(tsend[i], NULL);
+ if (r != 0) {
+ log_fatal("zmap", "unable to join send thread");
+ exit(EXIT_FAILURE);
+ }
+ }
+ log_debug("zmap", "senders finished");
+#ifdef PFRING
+ pfring_zc_kill_worker(zw);
+ pfring_zc_sync_queue(zconf.pf.send, tx_only);
+ log_debug("zmap", "send queue flushed");
+#endif
+ // no receiving or monitoring thread is started in dry run mode
+ if (!zconf.dryrun) {
+ r = pthread_join(trecv, NULL);
+ if (r != 0) {
+ log_fatal("zmap", "unable to join recv thread");
+ exit(EXIT_FAILURE);
+ }
+ if (!zconf.quiet || zconf.status_updates_file) {
+ pthread_join(tmon, NULL);
+ if (r != 0) {
+ log_fatal("zmap",
+ "unable to join monitor thread");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ // finished
+ if (zconf.metadata_filename) {
+ json_metadata(zconf.metadata_file);
+ }
+ if (zconf.output_module && zconf.output_module->close) {
+ zconf.output_module->close(&zconf, &zsend, &zrecv);
+ }
+ if (zconf.probe_module && zconf.probe_module->close) {
+ zconf.probe_module->close(&zconf, &zsend, &zrecv);
+ }
+#ifdef PFRING
+ pfring_zc_destroy_cluster(zconf.pf.cluster);
+#endif
+ log_info("zmap", "completed");
+}
+
+#define SET_IF_GIVEN(DST, ARG) \
+ { \
+ if (args.ARG##_given) { \
+ (DST) = args.ARG##_arg; \
+ }; \
+ }
+#define SET_BOOL(DST, ARG) \
+ { \
+ if (args.ARG##_given) { \
+ (DST) = 1; \
+ }; \
+ }
+
+int main(int argc, char *argv[])
+{
+ struct gengetopt_args_info args;
+ struct cmdline_parser_params *params;
+ params = cmdline_parser_params_create();
+ params->initialize = 1;
+ params->override = 0;
+ params->check_required = 0;
+
+ int config_loaded = 0;
+
+ if (cmdline_parser_ext(argc, argv, &args, params) != 0) {
+ exit(EXIT_SUCCESS);
+ }
+ if (args.config_given || file_exists(args.config_arg)) {
+ params->initialize = 0;
+ params->override = 0;
+ if (cmdline_parser_config_file(args.config_arg, &args,
+ params) != 0) {
+ exit(EXIT_FAILURE);
+ }
+ config_loaded = 1;
+ }
+
+ // set defaults before loading in command line arguments
+ init_empty_global_configuration(&zconf);
+ // initialize logging. if no log file or log directory are specified
+ // default to using stderr.
+ zconf.log_level = args.verbosity_arg;
+ zconf.log_file = args.log_file_arg;
+ zconf.log_directory = args.log_directory_arg;
+ if (args.disable_syslog_given) {
+ zconf.syslog = 0;
+ } else {
+ zconf.syslog = 1;
+ }
+ if (zconf.log_file && zconf.log_directory) {
+ log_init(stderr, zconf.log_level, zconf.syslog, "zmap");
+ log_fatal("zmap", "log-file and log-directory cannot "
+ "specified simultaneously.");
+ }
+ FILE *log_location = NULL;
+ if (zconf.log_file) {
+ log_location = fopen(zconf.log_file, "w");
+ } else if (zconf.log_directory) {
+ time_t now;
+ time(&now);
+ struct tm *local = localtime(&now);
+ char path[100];
+ strftime(path, 100, "zmap-%Y-%m-%dT%H%M%S%z.log", local);
+ char *fullpath =
+ xmalloc(strlen(zconf.log_directory) + strlen(path) + 2);
+ sprintf(fullpath, "%s/%s", zconf.log_directory, path);
+ log_location = fopen(fullpath, "w");
+ free(fullpath);
+ } else {
+ log_location = stderr;
+ }
+ if (!log_location) {
+ log_init(stderr, zconf.log_level, zconf.syslog, "zmap");
+ log_fatal("zmap", "unable to open specified log file: %s",
+ strerror(errno));
+ }
+ log_init(log_location, zconf.log_level, zconf.syslog, "zmap");
+ log_debug("zmap", "zmap main thread started");
+ if (config_loaded) {
+ log_debug("zmap", "Loaded configuration file %s",
+ args.config_arg);
+ }
+ if (zconf.syslog) {
+ log_debug("zmap", "syslog support enabled");
+ } else {
+ log_info("zmap", "syslog support disabled");
+ }
+ // parse the provided probe and output module s.t. that we can support
+ // other command-line helpers (e.g. probe help)
+ log_debug("zmap", "requested ouput-module: %s", args.output_module_arg);
+
+ // ZMap's default behavior is to provide a simple file of the unique IP
+ // addresses that responded successfully. We only use this simple "default"
+ // mode if none of {output module, output filter, output fields} are set.
+ zconf.default_mode = (!(args.output_module_given || args.output_filter_given || args.output_fields_given));
+ if (zconf.default_mode) {
+ log_info("zmap", "By default, ZMap will output the unique IP addresses "
+ "of hosts that respond successfully (e.g., SYN-ACK packet). This "
+ "is equivalent to running ZMap with the following flags: "
+ "--output-module=csv --output-fields=saddr --output-filter='"
+ "success=1 && repeat=0' --no-header-row. "
+ "If you want all responses, explicitly set an output module or "
+ "set --output-filter=\"\".");
+ zconf.output_module = get_output_module_by_name("csv");
+ zconf.output_module_name = strdup("csv");
+ zconf.no_header_row = 1;
+ } else if (!args.output_module_given) {
+ log_debug("zmap", "No output module provided. Will use csv.");
+ zconf.output_module = get_output_module_by_name("csv");
+ zconf.output_module_name = strdup("csv");
+ } else {
+ zconf.output_module =
+ get_output_module_by_name(args.output_module_arg);
+ if (!zconf.output_module) {
+ log_fatal(
+ "zmap",
+ "specified output module (%s) does not exist\n",
+ args.output_module_arg);
+ }
+ zconf.output_module_name = strdup(args.output_module_arg);
+ }
+ zconf.probe_module = get_probe_module_by_name(args.probe_module_arg);
+ if (!zconf.probe_module) {
+ log_fatal("zmap",
+ "specified probe module (%s) does not exist\n",
+ args.probe_module_arg);
+ exit(EXIT_FAILURE);
+ }
+ // check whether the probe module is going to generate dynamic data
+ // and that the output module can support exporting that data out of
+ // zmap. If they can't, then quit.
+ if (zconf.probe_module->output_type == OUTPUT_TYPE_DYNAMIC &&
+ !zconf.output_module->supports_dynamic_output) {
+ log_fatal(
+ "zmap",
+ "specified probe module (%s) requires dynamic "
+ "output support, which output module (%s) does not support. "
+ "Most likely you want to use JSON output.",
+ args.probe_module_arg, args.output_module_arg);
+ }
+ if (args.help_given) {
+ cmdline_parser_print_help();
+ printf("\nProbe Module (%s) Help:\n", zconf.probe_module->name);
+ if (zconf.probe_module->helptext) {
+ fprintw(stdout, zconf.probe_module->helptext,
+ 80);
+ } else {
+ printf("no help text available\n");
+ }
+ assert(zconf.output_module && "no output module set");
+ const char *module_name = zconf.default_mode ? "Default" : zconf.output_module->name;
+ printf("\nOutput Module (%s) Help:\n", module_name);
+
+ if (zconf.default_mode) {
+ fprintw(stdout, default_help_text, 80);
+ } else if (zconf.output_module->helptext) {
+ fprintw(stdout, zconf.output_module->helptext,
+ 80);
+ } else {
+ printf("no help text available\n");
+ }
+ exit(EXIT_SUCCESS);
+ }
+ if (args.version_given) {
+ cmdline_parser_print_version();
+ exit(EXIT_SUCCESS);
+ }
+ if (args.list_output_modules_given) {
+ print_output_modules();
+ exit(EXIT_SUCCESS);
+ }
+ if (args.list_probe_modules_given) {
+ print_probe_modules();
+ exit(EXIT_SUCCESS);
+ }
+ if (args.iplayer_given) {
+ zconf.send_ip_pkts = 1;
+ zconf.gw_mac_set = 1;
+ memset(zconf.gw_mac, 0, MAC_ADDR_LEN);
+ }
+ if (cmdline_parser_required(&args, CMDLINE_PARSER_PACKAGE) != 0) {
+ exit(EXIT_FAILURE);
+ }
+ // now that we know the probe module, let's find what it supports
+ memset(&zconf.fsconf, 0, sizeof(struct fieldset_conf));
+ // the set of fields made available to a user is constructed
+ // of IP header fields + probe module fields + system fields
+ fielddefset_t *fds = &(zconf.fsconf.defs);
+ gen_fielddef_set(fds, (fielddef_t *)&(ip_fields), ip_fields_len);
+ gen_fielddef_set(fds, zconf.probe_module->fields,
+ zconf.probe_module->numfields);
+ gen_fielddef_set(fds, (fielddef_t *)&(sys_fields), sys_fields_len);
+ if (args.list_output_fields_given) {
+ for (int i = 0; i < fds->len; i++) {
+ printf("%-15s %6s: %s\n", fds->fielddefs[i].name,
+ fds->fielddefs[i].type, fds->fielddefs[i].desc);
+ }
+ exit(EXIT_SUCCESS);
+ }
+ // find the fields we need for the framework
+ zconf.fsconf.success_index =
+ fds_get_index_by_name(fds, "success");
+ if (zconf.fsconf.success_index < 0) {
+ log_fatal("fieldset", "probe module does not supply "
+ "required success field.");
+ }
+ zconf.fsconf.app_success_index = fds_get_index_by_name(fds, "app_success");
+
+ if (zconf.fsconf.app_success_index < 0) {
+ log_debug("fieldset", "probe module does not supply "
+ "application success field.");
+ } else {
+ log_debug( "fieldset",
+ "probe module supplies app_success"
+ " output field. It will be included in monitor output");
+ }
+ zconf.fsconf.classification_index = fds_get_index_by_name(fds, "classification");
+ if (zconf.fsconf.classification_index < 0) {
+ log_fatal("fieldset", "probe module does not supply "
+ "required packet classification field.");
+ }
+ // process the list of requested output fields.
+ if (args.output_fields_given) {
+ zconf.raw_output_fields = args.output_fields_arg;
+ } else {
+ zconf.raw_output_fields = "saddr";
+ }
+ // add all fields if wildcard received
+ if (!strcmp(zconf.raw_output_fields, "*")) {
+ zconf.output_fields_len = zconf.fsconf.defs.len;
+ zconf.output_fields =
+ xcalloc(zconf.fsconf.defs.len, sizeof(const char *));
+ for (int i = 0; i < zconf.fsconf.defs.len; i++) {
+ zconf.output_fields[i] =
+ zconf.fsconf.defs.fielddefs[i].name;
+ }
+ fs_generate_full_fieldset_translation(&zconf.fsconf.translation,
+ &zconf.fsconf.defs);
+ } else {
+ split_string(zconf.raw_output_fields,
+ &(zconf.output_fields_len),
+ &(zconf.output_fields));
+ for (int i = 0; i < zconf.output_fields_len; i++) {
+ log_debug("zmap", "requested output field (%i): %s", i,
+ zconf.output_fields[i]);
+ }
+ // generate a translation that can be used to convert output
+ // from a probe module to the input for an output module
+ fs_generate_fieldset_translation(
+ &zconf.fsconf.translation, &zconf.fsconf.defs,
+ zconf.output_fields, zconf.output_fields_len);
+ }
+ // default filtering behavior is to drop unsuccessful and duplicates
+ if (zconf.default_mode) {
+ log_debug(
+ "filter",
+ "No output filter specified. Will use default: exclude duplicates and unssuccessful");
+ } else if (args.output_filter_given && strcmp(args.output_filter_arg, "")) {
+ // Run it through yyparse to build the expression tree
+ if (!parse_filter_string(args.output_filter_arg)) {
+ log_fatal("zmap", "Unable to parse filter expression");
+ }
+ // Check the fields used against the fieldset in use
+ if (!validate_filter(zconf.filter.expression,
+ &zconf.fsconf.defs)) {
+ log_fatal("zmap", "Invalid filter");
+ }
+ zconf.output_filter_str = args.output_filter_arg;
+ log_debug("filter", "will use output filter %s",
+ args.output_filter_arg);
+ } else if (args.output_filter_given) { // (empty filter argument)
+ log_debug("filter", "Empty output filter provided. ZMap will output all "
+ "results, including duplicate and non-successful responses.");
+ } else {
+ log_info("filter", "No output filter provided. ZMap will output all "
+ "results, including duplicate and non-successful responses (e.g., "
+ "RST and ICMP packets). If you want a filter similar to ZMap's "
+ "default behavior, you can set an output filter similar to the "
+ "following: --output-filter=\"success=1 && repeat=0\".");
+ }
+ zconf.ignore_invalid_hosts = args.ignore_blocklist_errors_given;
+
+ SET_BOOL(zconf.dryrun, dryrun);
+ SET_BOOL(zconf.quiet, quiet);
+ SET_BOOL(zconf.no_header_row, no_header_row);
+ zconf.cooldown_secs = args.cooldown_time_arg;
+ SET_IF_GIVEN(zconf.output_filename, output_file);
+ SET_IF_GIVEN(zconf.blocklist_filename, blocklist_file);
+ SET_IF_GIVEN(zconf.list_of_ips_filename, list_of_ips_file);
+ SET_IF_GIVEN(zconf.probe_args, probe_args);
+ SET_IF_GIVEN(zconf.probe_ttl, probe_ttl);
+ SET_IF_GIVEN(zconf.output_args, output_args);
+ SET_IF_GIVEN(zconf.iface, interface);
+ SET_IF_GIVEN(zconf.max_runtime, max_runtime);
+ SET_IF_GIVEN(zconf.max_results, max_results);
+ SET_IF_GIVEN(zconf.rate, rate);
+ SET_IF_GIVEN(zconf.packet_streams, probes);
+ SET_IF_GIVEN(zconf.status_updates_file, status_updates_file);
+ SET_IF_GIVEN(zconf.num_retries, retries);
+ SET_IF_GIVEN(zconf.max_sendto_failures, max_sendto_failures);
+ SET_IF_GIVEN(zconf.min_hitrate, min_hitrate);
+
+ if (zconf.num_retries < 0) {
+ log_fatal("zmap", "Invalid retry count");
+ }
+
+ if (zconf.max_sendto_failures >= 0) {
+ log_debug("zmap",
+ "scan will abort if more than %i "
+ "sendto failures occur",
+ zconf.max_sendto_failures);
+ }
+ if (zconf.min_hitrate > 0.0) {
+ log_debug("zmap", "scan will abort if hitrate falls below %f",
+ zconf.min_hitrate);
+ }
+ if (args.metadata_file_arg) {
+ zconf.metadata_filename = args.metadata_file_arg;
+ if (!strcmp(zconf.metadata_filename, "-")) {
+ zconf.metadata_file = stdout;
+ } else {
+ zconf.metadata_file =
+ fopen(zconf.metadata_filename, "w");
+ }
+ if (!zconf.metadata_file) {
+ log_fatal("metadata",
+ "unable to open metadata file (%s): %s",
+ zconf.metadata_filename, strerror(errno));
+ }
+ log_debug("metadata", "metadata will be saved to %s",
+ zconf.metadata_filename);
+ }
+
+ if (args.user_metadata_given) {
+ zconf.custom_metadata_str = args.user_metadata_arg;
+ if (!json_tokener_parse(zconf.custom_metadata_str)) {
+ log_fatal("metadata",
+ "unable to parse custom user metadata");
+ } else {
+ log_debug("metadata",
+ "user metadata validated successfully");
+ }
+ }
+ if (args.notes_given) {
+ zconf.notes = args.notes_arg;
+ }
+
+ // find if zmap wants any specific cidrs scanned instead
+ // of the entire Internet
+ zconf.destination_cidrs = args.inputs;
+ zconf.destination_cidrs_len = args.inputs_num;
+ if (zconf.destination_cidrs && zconf.blocklist_filename &&
+ !strcmp(zconf.blocklist_filename, "/etc/zmap/blocklist.conf")) {
+ log_warn(
+ "blocklist",
+ "ZMap is currently using the default blocklist located "
+ "at /etc/zmap/blocklist.conf. By default, this blocklist excludes locally "
+ "scoped networks (e.g. 10.0.0.0/8, 127.0.0.1/8, and 192.168.0.0/16). If you are"
+ " trying to scan local networks, you can change the default blocklist by "
+ "editing the default ZMap configuration at /etc/zmap/zmap.conf.");
+ }
+ SET_IF_GIVEN(zconf.allowlist_filename, allowlist_file);
+
+ if (zconf.probe_module->port_args) {
+ if (args.source_port_given) {
+ char *dash = strchr(args.source_port_arg, '-');
+ if (dash) { // range
+ *dash = '\0';
+ zconf.source_port_first =
+ atoi(args.source_port_arg);
+ enforce_range("starting source-port",
+ zconf.source_port_first, 0,
+ 0xFFFF);
+ zconf.source_port_last = atoi(dash + 1);
+ enforce_range("ending source-port",
+ zconf.source_port_last, 0,
+ 0xFFFF);
+ if (zconf.source_port_first >
+ zconf.source_port_last) {
+ fprintf(
+ stderr,
+ "%s: invalid source port range: "
+ "last port is less than first port\n",
+ CMDLINE_PARSER_PACKAGE);
+ exit(EXIT_FAILURE);
+ }
+ } else { // single port
+ int port = atoi(args.source_port_arg);
+ enforce_range("source-port", port, 0, 0xFFFF);
+ zconf.source_port_first = port;
+ zconf.source_port_last = port;
+ }
+ }
+ if (!args.target_port_given) {
+ log_fatal(
+ "zmap",
+ "target port (-p) is required for this type of probe");
+ }
+ enforce_range("target-port", args.target_port_arg, 0, 0xFFFF);
+ zconf.target_port = args.target_port_arg;
+ }
+ if (args.source_ip_given) {
+ parse_source_ip_addresses(args.source_ip_arg);
+ }
+ if (args.gateway_mac_given) {
+ if (!parse_mac(zconf.gw_mac, args.gateway_mac_arg)) {
+ fprintf(stderr, "%s: invalid MAC address `%s'\n",
+ CMDLINE_PARSER_PACKAGE, args.gateway_mac_arg);
+ exit(EXIT_FAILURE);
+ }
+ zconf.gw_mac_set = 1;
+ }
+ if (args.source_mac_given) {
+ if (!parse_mac(zconf.hw_mac, args.source_mac_arg)) {
+ fprintf(stderr, "%s: invalid MAC address `%s'\n",
+ CMDLINE_PARSER_PACKAGE, args.gateway_mac_arg);
+ exit(EXIT_FAILURE);
+ }
+ log_debug("send",
+ "source MAC address specified on CLI: "
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ zconf.hw_mac[0], zconf.hw_mac[1], zconf.hw_mac[2],
+ zconf.hw_mac[3], zconf.hw_mac[4], zconf.hw_mac[5]);
+
+ zconf.hw_mac_set = 1;
+ }
+ // Check for a random seed
+ if (args.seed_given) {
+ zconf.seed = args.seed_arg;
+ zconf.seed_provided = 1;
+ } else {
+ // generate a seed randomly
+ if (!random_bytes(&zconf.seed, sizeof(uint64_t))) {
+ log_fatal("zmap", "unable to generate random bytes "
+ "needed for seed");
+ }
+ zconf.seed_provided = 0;
+ }
+ zconf.aes = aesrand_init_from_seed(zconf.seed);
+
+ // Set up sharding
+ zconf.shard_num = 0;
+ zconf.total_shards = 1;
+ if ((args.shard_given || args.shards_given) && !args.seed_given) {
+ log_fatal("zmap", "Need to specify seed if sharding a scan");
+ }
+ if (args.shard_given ^ args.shards_given) {
+ log_fatal(
+ "zmap",
+ "Need to specify both shard number and total number of shards");
+ }
+ if (args.shard_given) {
+ enforce_range("shard", args.shard_arg, 0, 65534);
+ }
+ if (args.shards_given) {
+ enforce_range("shards", args.shards_arg, 1, 65535);
+ }
+ SET_IF_GIVEN(zconf.shard_num, shard);
+ SET_IF_GIVEN(zconf.total_shards, shards);
+ if (zconf.shard_num >= zconf.total_shards) {
+ log_fatal("zmap",
+ "With %hhu total shards, shard number (%hhu)"
+ " must be in range [0, %hhu)",
+ zconf.total_shards, zconf.shard_num,
+ zconf.total_shards);
+ }
+
+ if (args.bandwidth_given) {
+ // Supported: G,g=*1000000000; M,m=*1000000 K,k=*1000 bits per
+ // second
+ zconf.bandwidth = atoi(args.bandwidth_arg);
+ char *suffix = args.bandwidth_arg;
+ while (*suffix >= '0' && *suffix <= '9') {
+ suffix++;
+ }
+ if (*suffix) {
+ switch (*suffix) {
+ case 'G':
+ case 'g':
+ zconf.bandwidth *= 1000000000;
+ break;
+ case 'M':
+ case 'm':
+ zconf.bandwidth *= 1000000;
+ break;
+ case 'K':
+ case 'k':
+ zconf.bandwidth *= 1000;
+ break;
+ default:
+ fprintf(stderr,
+ "%s: unknown bandwidth suffix '%s' "
+ "(supported suffixes are G, M and K)\n",
+ CMDLINE_PARSER_PACKAGE, suffix);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ if(args.batch_given){
+ zconf.batch = args.batch_arg;
+ }
+ if (args.max_targets_given) {
+ zconf.max_targets = parse_max_hosts(args.max_targets_arg);
+ }
+
+ // blocklist
+ if (blocklist_init(zconf.allowlist_filename, zconf.blocklist_filename,
+ zconf.destination_cidrs, zconf.destination_cidrs_len,
+ NULL, 0, zconf.ignore_invalid_hosts)) {
+ log_fatal("zmap", "unable to initialize blocklist / allowlist");
+ }
+ // if there's a list of ips to scan, then initialize PBM and populate
+ // it based on the provided file
+ if (zconf.list_of_ips_filename) {
+ zsend.list_of_ips_pbm = pbm_init();
+ zconf.list_of_ips_count = pbm_load_from_file(
+ zsend.list_of_ips_pbm, zconf.list_of_ips_filename);
+ }
+
+ // compute number of targets
+ uint64_t allowed = blocklist_count_allowed();
+ zconf.total_allowed = allowed;
+ zconf.total_disallowed = blocklist_count_not_allowed();
+ assert(allowed <= (1LL << 32));
+ if (!zconf.total_allowed) {
+ log_fatal("zmap", "zero eligible addresses to scan");
+ }
+ if (zconf.list_of_ips_count > 0 && 0xFFFFFFFFU / zconf.list_of_ips_count > 100000) {
+ log_warn("zmap", "list of IPs is small compared to address space. Performance will suffer, consider using an allowlist instead");
+ }
+ if (zconf.max_targets) {
+ zsend.max_targets = zconf.max_targets;
+ }
+#ifndef PFRING
+ // Set the correct number of threads, default to num_cores - 1
+ if (args.sender_threads_given) {
+ zconf.senders = args.sender_threads_arg;
+ } else {
+ zconf.senders = 1;
+ }
+ if (2 * zconf.senders >= zsend.max_targets) {
+ log_warn(
+ "zmap",
+ "too few targets relative to senders, dropping to one sender");
+ zconf.senders = 1;
+ }
+#else
+ zconf.senders = args.sender_threads_arg;
+#endif
+ // Figure out what cores to bind to
+ if (args.cores_given) {
+ const char **core_list = NULL;
+ int len = 0;
+ split_string(args.cores_arg, &len, &core_list);
+ zconf.pin_cores_len = (uint32_t)len;
+ zconf.pin_cores =
+ xcalloc(zconf.pin_cores_len, sizeof(uint32_t));
+ for (uint32_t i = 0; i < zconf.pin_cores_len; ++i) {
+ zconf.pin_cores[i] = atoi(core_list[i]);
+ }
+ } else {
+ int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
+ zconf.pin_cores_len = (uint32_t)num_cores;
+ zconf.pin_cores =
+ xcalloc(zconf.pin_cores_len, sizeof(uint32_t));
+ for (uint32_t i = 0; i < zconf.pin_cores_len; ++i) {
+ zconf.pin_cores[i] = i;
+ }
+ }
+
+// PFRING
+#ifdef PFRING
+#define MAX_CARD_SLOTS 32768
+#define QUEUE_LEN 8192
+#define ZMAP_PF_BUFFER_SIZE 1536
+#define ZMAP_PF_ZC_CLUSTER_ID 9627
+ uint32_t user_buffers = zconf.senders * 256;
+ uint32_t queue_buffers = zconf.senders * QUEUE_LEN;
+ uint32_t card_buffers = 2 * MAX_CARD_SLOTS;
+ uint32_t total_buffers =
+ user_buffers + queue_buffers + card_buffers + 2;
+ uint32_t metadata_len = 0;
+ uint32_t numa_node = 0; // TODO
+ zconf.pf.cluster = pfring_zc_create_cluster(
+ ZMAP_PF_ZC_CLUSTER_ID, ZMAP_PF_BUFFER_SIZE, metadata_len,
+ total_buffers, numa_node, NULL, NULL);
+ if (zconf.pf.cluster == NULL) {
+ log_fatal("zmap", "Could not create zc cluster: %s",
+ strerror(errno));
+ }
+
+ zconf.pf.buffers = xcalloc(user_buffers, sizeof(pfring_zc_pkt_buff *));
+ for (uint32_t i = 0; i < user_buffers; ++i) {
+ zconf.pf.buffers[i] =
+ pfring_zc_get_packet_handle(zconf.pf.cluster);
+ if (zconf.pf.buffers[i] == NULL) {
+ log_fatal("zmap", "Could not get ZC packet handle");
+ }
+ }
+
+ zconf.pf.send =
+ pfring_zc_open_device(zconf.pf.cluster, zconf.iface, tx_only, 0);
+ if (zconf.pf.send == NULL) {
+ log_fatal("zmap", "Could not open device %s for TX. [%s]",
+ zconf.iface, strerror(errno));
+ }
+
+ zconf.pf.recv =
+ pfring_zc_open_device(zconf.pf.cluster, zconf.iface, rx_only, 0);
+ if (zconf.pf.recv == NULL) {
+ log_fatal("zmap", "Could not open device %s for RX. [%s]",
+ zconf.iface, strerror(errno));
+ }
+
+ zconf.pf.queues = xcalloc(zconf.senders, sizeof(pfring_zc_queue *));
+ for (uint32_t i = 0; i < zconf.senders; ++i) {
+ zconf.pf.queues[i] =
+ pfring_zc_create_queue(zconf.pf.cluster, QUEUE_LEN);
+ if (zconf.pf.queues[i] == NULL) {
+ log_fatal("zmap", "Could not create queue: %s",
+ strerror(errno));
+ }
+ }
+
+ zconf.pf.prefetches = pfring_zc_create_buffer_pool(zconf.pf.cluster, 8);
+ if (zconf.pf.prefetches == NULL) {
+ log_fatal("zmap", "Could not open prefetch pool: %s",
+ strerror(errno));
+ }
+#endif
+
+ // resume scan if requested
+
+ start_zmap();
+
+ fclose(log_location);
+
+ cmdline_parser_free(&args);
+ free(params);
+ return EXIT_SUCCESS;
+}