Loading src/main-conf.c +57 −47 Original line number Diff line number Diff line Loading @@ -227,7 +227,7 @@ masscan_echo(struct Masscan *masscan, FILE *fp) * Output information */ fprintf(fp, "# OUTPUT/REPORTING SETTINGS\n"); switch (masscan->nmap.format) { switch (masscan->output.format) { case Output_Interactive:fprintf(fp, "output-format = interactive\n"); break; case Output_List: fprintf(fp, "output-format = list\n"); break; case Output_XML: fprintf(fp, "output-format = xml\n"); break; Loading @@ -246,17 +246,17 @@ masscan_echo(struct Masscan *masscan, FILE *fp) break; default: fprintf(fp, "output-format = unknown(%u)\n", masscan->nmap.format); fprintf(fp, "output-format = unknown(%u)\n", masscan->output.format); break; } fprintf(fp, "output-status = %s\n", masscan->nmap.open_only?"open":"all"); fprintf(fp, "output-filename = %s\n", masscan->nmap.filename); if (masscan->nmap.append) masscan->output.is_open_only?"open":"all"); fprintf(fp, "output-filename = %s\n", masscan->output.filename); if (masscan->output.is_append) fprintf(fp, "output-append = true\n"); fprintf(fp, "rotate = %u\n", masscan->rotate_output); fprintf(fp, "rotate-dir = %s\n", masscan->rotate_directory); fprintf(fp, "rotate-offset = %u\n", masscan->rotate_offset); fprintf(fp, "rotate = %u\n", masscan->output.rotate.timeout); fprintf(fp, "rotate-dir = %s\n", masscan->output.rotate.directory); fprintf(fp, "rotate-offset = %u\n", masscan->output.rotate.offset); fprintf(fp, "pcap = %s\n", masscan->pcap_filename); /* Loading Loading @@ -926,9 +926,9 @@ masscan_set_parameter(struct Masscan *masscan, masscan->op = Operation_Scan; } else if (EQUALS("append-output", name) || EQUALS("output-append", name)) { if (EQUALS("overwrite", name)) masscan->nmap.append = 0; masscan->output.is_append = 0; else masscan->nmap.append = 1; masscan->output.is_append = 1; } else if (EQUALS("badsum", name)) { masscan->nmap.badsum = 1; } else if (EQUALS("banner1", name)) { Loading Loading @@ -1066,7 +1066,9 @@ masscan_set_parameter(struct Masscan *masscan, } else if (EQUALS("infinite", name)) { masscan->is_infinite = 1; } else if (EQUALS("interactive", name)) { masscan->is_interactive = 1; masscan->output.is_interactive = 1; } else if (EQUALS("nointeractive", name)) { masscan->output.is_interactive = 0; } else if (EQUALS("ip-options", name)) { fprintf(stderr, "nmap(%s): unsupported: maybe soon\n", name); exit(1); Loading Loading @@ -1118,10 +1120,10 @@ masscan_set_parameter(struct Masscan *masscan, * it's not */ masscan->is_offline = 1; } else if (EQUALS("open", name) || EQUALS("open-only", name)) { masscan->nmap.open_only = 1; masscan->output.is_open_only = 1; } else if (EQUALS("output-status", name)) { if (EQUALS("open", value)) masscan->nmap.open_only = 1; masscan->output.is_open_only = 1; } else if (EQUALS("osscan-limit", name)) { fprintf(stderr, "nmap(%s): OS scanning unsupported\n", name); Loading @@ -1130,24 +1132,29 @@ masscan_set_parameter(struct Masscan *masscan, fprintf(stderr, "nmap(%s): OS scanning unsupported\n", name); exit(1); } else if (EQUALS("output-format", name)) { masscan->is_interactive = 0; if (EQUALS("list", value)) masscan->nmap.format = Output_List; else if (EQUALS("interactive", value)) masscan->nmap.format = Output_Interactive; else if (EQUALS("xml", value)) masscan->nmap.format = Output_XML; else if (EQUALS("binary", value)) masscan->nmap.format = Output_Binary; else if (EQUALS("greppable", value)) masscan->nmap.format = Output_Grepable; else if (EQUALS("grepable", value)) masscan->nmap.format = Output_Grepable; else if (EQUALS("json", value)) masscan->nmap.format = Output_JSON; else if (EQUALS("none", value)) masscan->nmap.format = Output_None; else if (EQUALS("redis", value)) masscan->nmap.format = Output_Redis; enum OutputFormat x = 0; if (EQUALS("interactive", value)) masscan->output.format = Output_Interactive; else if (EQUALS("list", value)) x = Output_List; else if (EQUALS("xml", value)) x = Output_XML; else if (EQUALS("binary", value)) x = Output_Binary; else if (EQUALS("greppable", value)) x = Output_Grepable; else if (EQUALS("grepable", value)) x = Output_Grepable; else if (EQUALS("json", value)) x = Output_JSON; else if (EQUALS("none", value)) x = Output_None; else if (EQUALS("redis", value)) x = Output_Redis; else { fprintf(stderr, "error: %s=%s\n", name, value); LOG(0, "FAIL: unknown output-format: %s\n", value); LOG(0, " hint: 'binary', 'xml', 'grepable', ...\n"); exit(1); } masscan->output.format = x; } else if (EQUALS("output-filename", name) || EQUALS("output-file", name)) { if (masscan->nmap.format == 0) masscan->nmap.format = Output_XML; masscan->is_interactive = 0; strcpy_s(masscan->nmap.filename, sizeof(masscan->nmap.filename), value); if (masscan->output.format == 0) masscan->output.format = Output_XML; strcpy_s(masscan->output.filename, sizeof(masscan->output.filename), value); } else if (EQUALS("pcap", name)) { strcpy_s(masscan->pcap_filename, sizeof(masscan->pcap_filename), value); } else if (EQUALS("packet-trace", name) || EQUALS("trace-packet", name)) { Loading @@ -1164,7 +1171,7 @@ masscan_set_parameter(struct Masscan *masscan, /* already do that */ ; } else if (EQUALS("reason", name)) { masscan->nmap.reason = 1; masscan->output.is_reason = 1; } else if (EQUALS("redis", name)) { struct Range range; unsigned offset = 0; Loading @@ -1190,8 +1197,10 @@ masscan_set_parameter(struct Masscan *masscan, masscan->redis.ip = range.begin; masscan->redis.port = port; masscan->nmap.format = Output_Redis; strcpy_s(masscan->nmap.filename, sizeof(masscan->nmap.filename), "<redis>"); masscan->output.format = Output_Redis; strcpy_s(masscan->output.filename, sizeof(masscan->output.filename), "<redis>"); } else if (EQUALS("release-memory", name)) { fprintf(stderr, "nmap(%s): this is our default option\n", name); } else if (EQUALS("resume", name)) { Loading @@ -1209,17 +1218,17 @@ masscan_set_parameter(struct Masscan *masscan, masscan->retries = x; } } else if (EQUALS("rotate-output", name) || EQUALS("rotate", name) || EQUALS("ouput-rotate", name)) { masscan->rotate_output = (unsigned)parseTime(value); masscan->output.rotate.timeout = (unsigned)parseTime(value); } else if (EQUALS("rotate-offset", name) || EQUALS("ouput-rotate-offset", name)) { masscan->rotate_offset = (unsigned)parseTime(value); masscan->output.rotate.offset = (unsigned)parseTime(value); } else if (EQUALS("rotate-dir", name) || EQUALS("rotate-directory", name) || EQUALS("ouput-rotate-dir", name)) { char *p; strcpy_s( masscan->rotate_directory, sizeof(masscan->rotate_directory), strcpy_s( masscan->output.rotate.directory, sizeof(masscan->output.rotate.directory), value); /* strip trailing slashes */ p = masscan->rotate_directory; p = masscan->output.rotate.directory; while (*p && (p[strlen(p)-1] == '/' || p[strlen(p)-1] == '/')) p[strlen(p)-1] = '\0'; } else if (EQUALS("script", name)) { Loading Loading @@ -1290,9 +1299,11 @@ masscan_set_parameter(struct Masscan *masscan, masscan->shard.of = of; } else if (EQUALS("no-stylesheet", name)) { masscan->nmap.stylesheet[0] = '\0'; masscan->output.stylesheet[0] = '\0'; } else if (EQUALS("stylesheet", name)) { strcpy_s(masscan->nmap.stylesheet, sizeof(masscan->nmap.stylesheet), value); strcpy_s(masscan->output.stylesheet, sizeof(masscan->output.stylesheet), value); } else if (EQUALS("system-dns", name)) { fprintf(stderr, "nmap(%s): DNS lookups will never be supported by this code\n", name); exit(1); Loading Loading @@ -1559,39 +1570,38 @@ masscan_command_line(struct Masscan *masscan, int argc, char *argv[]) /* Do nothing: this code never does DNS lookups anyway */ break; case 'o': /* nmap output format */ masscan->is_interactive = 0; switch (argv[i][2]) { case 'A': masscan->nmap.format = Output_All; masscan->output.format = Output_All; fprintf(stderr, "nmap(%s): unsupported output format\n", argv[i]); exit(1); break; case 'B': masscan->nmap.format = Output_Binary; masscan->output.format = Output_Binary; break; case 'J': masscan->nmap.format = Output_JSON; masscan->output.format = Output_JSON; break; case 'N': masscan->nmap.format = Output_Nmap; masscan->output.format = Output_Nmap; fprintf(stderr, "nmap(%s): unsupported output format\n", argv[i]); exit(1); break; case 'X': masscan->nmap.format = Output_XML; masscan->output.format = Output_XML; break; case 'R': masscan->nmap.format = Output_Redis; masscan->output.format = Output_Redis; if (i+1 < argc && argv[i+1][0] != '-') masscan_set_parameter(masscan, "redis", argv[i+1]); break; case 'S': masscan->nmap.format = Output_ScriptKiddie; masscan->output.format = Output_ScriptKiddie; fprintf(stderr, "nmap(%s): unsupported output format\n", argv[i]); exit(1); break; case 'G': masscan->nmap.format = Output_Grepable; masscan->output.format = Output_Grepable; break; case 'L': masscan_set_parameter(masscan, "output-format", "list"); Loading src/main.c +2 −3 Original line number Diff line number Diff line Loading @@ -1372,7 +1372,6 @@ int main(int argc, char *argv[]) * Initialize those defaults that aren't zero */ memset(masscan, 0, sizeof(*masscan)); masscan->is_interactive = 1; masscan->seed = time(0); /* a predictable, but 'random' seed */ masscan->wait = 10; /* how long to wait for responses when done */ masscan->max_rate = 100.0; /* max rate = hundred packets-per-second */ Loading @@ -1381,8 +1380,8 @@ int main(int argc, char *argv[]) masscan->shard.of = 1; masscan->min_packet_size = 60; masscan->payloads = payloads_create(); strcpy_s( masscan->rotate_directory, sizeof(masscan->rotate_directory), strcpy_s( masscan->output.rotate.directory, sizeof(masscan->output.rotate.directory), "."); masscan->is_capture_cert = 1; Loading src/masscan.h +176 −59 Original line number Diff line number Diff line Loading @@ -14,44 +14,88 @@ struct Adapter; struct TemplateSet; struct Banner1; enum { /** * This is the "operationg" to be performed by masscan, which is almost always * to "scan" the network. However, there are some lesser operations to do * instead, like run a "regression self test", or "debug", or something else * instead of scanning. We parse the command-line in order to figure out the * proper operation */ enum Operation { Operation_Default = 0, /* nothing specified, so print usage */ Operation_List_Adapters = 1, Operation_Selftest = 2, Operation_List_Adapters = 1, /* --listif */ Operation_Selftest = 2, /* --selftest or --regress */ Operation_Scan = 3, /* this is what you expect */ Operation_DebugIF = 4, Operation_ListScan = 5, Operation_ReadScan = 6, /* re-interpret output files in different format */ Operation_DebugIF = 4, /* --debug if */ Operation_ListScan = 5, /* -sL */ Operation_ReadScan = 6, /* --readscan <binary-output> */ }; enum OutpuFormat { Output_Interactive = 0x0001, /** * The format of the output. If nothing is specified, then the default will * be "--interactive", meaning that we'll print to the command-line live as * results come in. Only one output format can be specified, except that * "--interactive" can be specified alongside any of the other ones. * FIXME: eventually we'll support multiple file formats and "all" * outputing simultaneously. */ enum OutputFormat { Output_Interactive = 0x0001, /* --interactive, print to cmdline */ Output_List = 0x0002, Output_Binary = 0x0004, Output_XML = 0x0008, Output_JSON = 0x0010, Output_Binary = 0x0004, /* -oB, "binary", the primary format */ Output_XML = 0x0008, /* -oX, "xml" */ Output_JSON = 0x0010, /* -oJ, "json" */ Output_Nmap = 0x0020, Output_ScriptKiddie = 0x0040, Output_Grepable = 0x0080, Output_Grepable = 0x0080, /* -oG, "grepable" */ Output_Redis = 0x0100, Output_None = 0x0200, Output_All = 0xFFBF, Output_All = 0xFFBF, /* not supported */ }; /** * Holds the list of TCP "hello" payloads, specified with the "--hello-file" * or "--hello-string" options */ struct TcpCfgPayloads { /** The "hello" data in base64 format. This is either the base64 string * specified in the cmdline/cfgfile with "--hello-string", or the * contents of a file specified with "--hello-file" that we've converted * into base64 */ char *payload_base64; /** The TCP port that this hello belongs to */ unsigned port; /** These configuration options are stored as a linked-list */ struct TcpCfgPayloads *next; }; /** * This is the master MASSCAN configuration structure. It is created on startup * by reading the command-line and parsing configuration files. * * Once read in at the start, this structure doesn't change. The transmit * and receive threads have only a "const" pointer to this structure. */ struct Masscan { int op; /** * What this progrma is doing, which is normally "Operation_Scan", but * which can be other things, like "Operation_SelfTest" */ enum Operation op; /** * One or more network adapters that we'll use for scanning. * One or more network adapters that we'll use for scanning. Each adapter * should have a separate set of IP source addresses, except in the case * of PF_RING dnaX:Y adapters. * FIXME: add support for link aggregation across adapters */ struct { char ifname[256]; Loading @@ -67,110 +111,194 @@ struct Masscan /** * The target ranges of IPv4 addresses that are included in the scan. * The user can specify anything here, and we'll resolve all overlaps * and such, and sort the target ranges. */ struct RangeList targets; /** * The ports we are scanning for * The ports we are scanning for. The user can specify repeated ports * and overlapping ranges, but we'll deduplicate them, scanning ports * only once. * NOTE: TCP ports are stored 0-64k, but UDP ports are stored in the * range 64k-128k, thus, allowing us to scan both at the same time. */ struct RangeList ports; /** * IPv4 addresses/ranges that are to be exluded from the scan. This takes * precedence over any 'include' statement * precedence over any 'include' statement. What happens is this: after * all the configuration has been read, we then apply the exclude/blacklist * on top of the target/whitelist, leaving only a target/whitelist left. * Thus, during the scan, we only choose from the target/whitelist and * don't consult the exclude/blacklist. */ struct RangeList exclude_ip; struct RangeList exclude_port; /** * Maximum rate, in packets-per-second (--rate parameter) * Maximum rate, in packets-per-second (--rate parameter). This can be * a fraction of a packet-per-second, or be as high as 30000000.0 (or * more actually, but I've only tested to 30megapps). */ double max_rate; /** * Number of retries (--retries or --max-retries parameter) * Number of retries (--retries or --max-retries parameter). Retries * happen a few seconds apart. */ unsigned retries; unsigned is_pfring:1; /* --pfring */ unsigned is_sendq:1; /* --sendq */ unsigned is_banners:1; /* --banners */ unsigned is_offline:1; /* --offline */ unsigned is_interactive:1; /* --interactive */ unsigned is_arp:1; /* --arp */ unsigned is_gmt:1; /* --gmt, all times in GMT */ unsigned is_capture_cert:1; /* --capture cert */ unsigned is_capture_html:1; /* --capture html */ unsigned is_test_csv:1; /* (temporary testing feature) */ unsigned is_infinite:1; /* -infinite */ unsigned is_readscan:1; /* --readscan, Operation_Readscan */ /** * Wait forever for responses, instead of the default 10 seconds */ unsigned wait; /** * --resume * This structure contains options for pausing the scan (by exiting the * program) and restarting it later. */ struct { /** --resume-index */ uint64_t index; /** --resume-count */ uint64_t count; /** Derives the --resume-index from the target ip:port */ struct { unsigned ip; unsigned port; } target; } resume; /** * --shard n/m * This is used for distributin a scan acros multiple "shards". Every * shard in the scan must know the total number of shards, and must also * know which of those shards is it's identity. Thus, shard 1/5 scans * a different range than 2/5. These numbers start at 1, so it's * 1/3 (#1 out of three), 2/3, and 3/3 (but not 0/3). */ struct { unsigned one; unsigned of; } shard; /** * The packet template we are current using * The packet template set we are current using. We store a binary template * for TCP, UDP, SCTP, ICMP, and so on. All the scans using that protocol * are then scanned using that basic template. IP and TCP options can be * added to the basic template without affecting any other component * of the system. */ struct TemplateSet *pkt_template; /** * A random seed for randomization if zero, otherwise we'll use * the configured seed for repeatable tests. */ uint64_t seed; /** * This block configures what we do for the output files */ struct OutputStuff { /** * --output-format * Examples are "xml", "binary", "json", "grepable", and so on. */ enum OutputFormat format; /** * --output-filename * The name of the file where we are storing scan results. * Note: the filename "-" means that we should send the file to * <stdout> rather than to a file. */ char filename[256]; /** * A feature of the XML output where we can insert an optional * stylesheet into the file for better rendering on web browsers */ char stylesheet[256]; /** * --append * We should append to the output file rather than overwriting it. */ unsigned is_append:1; /** * --open * Whether to show only open ports (not closed ports) */ unsigned is_open_only:1; /** * print reason port is open, which is redundant for us */ unsigned is_reason:1; /** * --interactive * Print to command-line while also writing to output file */ unsigned is_interactive:1; struct { /** * When we should rotate output into the target directory */ unsigned rotate_output; unsigned timeout; /** * A random seed for randomization if zero, otherwise we'll use * the configured seed for repeatable tests. * When doing "--rotate daily", the rotation is done at GMT. In * orderto fix this, add an offset. */ uint64_t seed; unsigned offset; /** * Instead of rotating by timeout, we can rotate by filesize */ size_t filesize; /** * When doing "--rotate daily", the rotation is done at GMT. In order * to fix this, add an offset. * The directory to which we store rotated files */ unsigned rotate_offset; char directory[256]; } rotate; } output; struct { unsigned data_length; /* number of bytes to randomly append */ unsigned ttl; /* starting IP TTL field */ unsigned badsum; /* bad TCP/UDP/SCTP checksum */ /* output options */ unsigned packet_trace:1; /* print transmit messages */ unsigned open_only:1; /* show only open ports */ unsigned reason; /* print reason port is open, which is redundant for us */ unsigned format; /* see enum OutputFormat */ unsigned append; /* append instead of clobber file */ char datadir[256]; char filename[256]; char stylesheet[256]; } nmap; char rotate_directory[256]; char pcap_filename[256]; //PACKET_QUEUE *packet_buffers; //PACKET_QUEUE *transmit_queue; struct { unsigned timeout; } tcb; Loading @@ -195,17 +323,6 @@ struct Masscan unsigned port; } redis; /** * --infinite * Restarts the scan from the beginning, for load testing, but * by incrementing the seed */ unsigned is_infinite:1; /** * --readscan */ unsigned is_readscan:1; /** Loading src/output.c +15 −14 Original line number Diff line number Diff line Loading @@ -372,21 +372,22 @@ output_create(const struct Masscan *masscan, unsigned thread_index) /* * Copy the configuration information from the 'masscan' structure. */ out->rotate.period = masscan->rotate_output; out->rotate.offset = masscan->rotate_offset; out->rotate.period = masscan->output.rotate.timeout; out->rotate.offset = masscan->output.rotate.offset; out->rotate.filesize = masscan->output.rotate.filesize; out->redis.port = masscan->redis.port; out->redis.ip = masscan->redis.ip; out->is_banner = masscan->is_banners; out->is_gmt = masscan->is_gmt; out->is_interactive = masscan->is_interactive; out->is_open_only = masscan->nmap.open_only; out->is_append = masscan->nmap.append; out->xml.stylesheet = duplicate_string(masscan->nmap.stylesheet); out->rotate.directory = duplicate_string(masscan->rotate_directory); out->is_interactive = masscan->output.is_interactive; out->is_open_only = masscan->output.is_open_only; out->is_append = masscan->output.is_append; out->xml.stylesheet = duplicate_string(masscan->output.stylesheet); out->rotate.directory = duplicate_string(masscan->output.rotate.directory); if (masscan->nic_count <= 1) out->filename = duplicate_string(masscan->nmap.filename); out->filename = duplicate_string(masscan->output.filename); else out->filename = indexed_filename(masscan->nmap.filename, thread_index); out->filename = indexed_filename(masscan->output.filename, thread_index); for (i=0; i<8; i++) { out->src[i] = masscan->nic[i].src; Loading @@ -396,7 +397,7 @@ output_create(const struct Masscan *masscan, unsigned thread_index) * Link the appropriate output module. * TODO: support multiple output modules */ out->format = masscan->nmap.format; out->format = masscan->output.format; switch (out->format) { case Output_List: out->funcs = &text_output; Loading Loading @@ -426,12 +427,12 @@ output_create(const struct Masscan *masscan, unsigned thread_index) * so that we can immediately notify the user of an error, rather than * waiting midway through a long scan and have it fail. */ if (masscan->nmap.filename[0] && out->funcs != &null_output) { if (masscan->output.filename[0] && out->funcs != &null_output) { FILE *fp; fp = open_rotate(out, masscan->nmap.filename); fp = open_rotate(out, masscan->output.filename); if (fp == NULL) { perror(masscan->nmap.filename); perror(masscan->output.filename); exit(1); } Loading @@ -444,7 +445,7 @@ output_create(const struct Masscan *masscan, unsigned thread_index) * this time will be set at "infinity" in the future. * TODO: this code isn't Y2036 compliant. */ if (masscan->rotate_output == 0) { if (masscan->output.rotate.timeout == 0) { /* TODO: how does one find the max time_t value??*/ out->rotate.next = (time_t)LONG_MAX; } else { Loading src/output.h +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ struct Output time_t last; unsigned period; unsigned offset; size_t filesize; char *directory; } rotate; Loading Loading
src/main-conf.c +57 −47 Original line number Diff line number Diff line Loading @@ -227,7 +227,7 @@ masscan_echo(struct Masscan *masscan, FILE *fp) * Output information */ fprintf(fp, "# OUTPUT/REPORTING SETTINGS\n"); switch (masscan->nmap.format) { switch (masscan->output.format) { case Output_Interactive:fprintf(fp, "output-format = interactive\n"); break; case Output_List: fprintf(fp, "output-format = list\n"); break; case Output_XML: fprintf(fp, "output-format = xml\n"); break; Loading @@ -246,17 +246,17 @@ masscan_echo(struct Masscan *masscan, FILE *fp) break; default: fprintf(fp, "output-format = unknown(%u)\n", masscan->nmap.format); fprintf(fp, "output-format = unknown(%u)\n", masscan->output.format); break; } fprintf(fp, "output-status = %s\n", masscan->nmap.open_only?"open":"all"); fprintf(fp, "output-filename = %s\n", masscan->nmap.filename); if (masscan->nmap.append) masscan->output.is_open_only?"open":"all"); fprintf(fp, "output-filename = %s\n", masscan->output.filename); if (masscan->output.is_append) fprintf(fp, "output-append = true\n"); fprintf(fp, "rotate = %u\n", masscan->rotate_output); fprintf(fp, "rotate-dir = %s\n", masscan->rotate_directory); fprintf(fp, "rotate-offset = %u\n", masscan->rotate_offset); fprintf(fp, "rotate = %u\n", masscan->output.rotate.timeout); fprintf(fp, "rotate-dir = %s\n", masscan->output.rotate.directory); fprintf(fp, "rotate-offset = %u\n", masscan->output.rotate.offset); fprintf(fp, "pcap = %s\n", masscan->pcap_filename); /* Loading Loading @@ -926,9 +926,9 @@ masscan_set_parameter(struct Masscan *masscan, masscan->op = Operation_Scan; } else if (EQUALS("append-output", name) || EQUALS("output-append", name)) { if (EQUALS("overwrite", name)) masscan->nmap.append = 0; masscan->output.is_append = 0; else masscan->nmap.append = 1; masscan->output.is_append = 1; } else if (EQUALS("badsum", name)) { masscan->nmap.badsum = 1; } else if (EQUALS("banner1", name)) { Loading Loading @@ -1066,7 +1066,9 @@ masscan_set_parameter(struct Masscan *masscan, } else if (EQUALS("infinite", name)) { masscan->is_infinite = 1; } else if (EQUALS("interactive", name)) { masscan->is_interactive = 1; masscan->output.is_interactive = 1; } else if (EQUALS("nointeractive", name)) { masscan->output.is_interactive = 0; } else if (EQUALS("ip-options", name)) { fprintf(stderr, "nmap(%s): unsupported: maybe soon\n", name); exit(1); Loading Loading @@ -1118,10 +1120,10 @@ masscan_set_parameter(struct Masscan *masscan, * it's not */ masscan->is_offline = 1; } else if (EQUALS("open", name) || EQUALS("open-only", name)) { masscan->nmap.open_only = 1; masscan->output.is_open_only = 1; } else if (EQUALS("output-status", name)) { if (EQUALS("open", value)) masscan->nmap.open_only = 1; masscan->output.is_open_only = 1; } else if (EQUALS("osscan-limit", name)) { fprintf(stderr, "nmap(%s): OS scanning unsupported\n", name); Loading @@ -1130,24 +1132,29 @@ masscan_set_parameter(struct Masscan *masscan, fprintf(stderr, "nmap(%s): OS scanning unsupported\n", name); exit(1); } else if (EQUALS("output-format", name)) { masscan->is_interactive = 0; if (EQUALS("list", value)) masscan->nmap.format = Output_List; else if (EQUALS("interactive", value)) masscan->nmap.format = Output_Interactive; else if (EQUALS("xml", value)) masscan->nmap.format = Output_XML; else if (EQUALS("binary", value)) masscan->nmap.format = Output_Binary; else if (EQUALS("greppable", value)) masscan->nmap.format = Output_Grepable; else if (EQUALS("grepable", value)) masscan->nmap.format = Output_Grepable; else if (EQUALS("json", value)) masscan->nmap.format = Output_JSON; else if (EQUALS("none", value)) masscan->nmap.format = Output_None; else if (EQUALS("redis", value)) masscan->nmap.format = Output_Redis; enum OutputFormat x = 0; if (EQUALS("interactive", value)) masscan->output.format = Output_Interactive; else if (EQUALS("list", value)) x = Output_List; else if (EQUALS("xml", value)) x = Output_XML; else if (EQUALS("binary", value)) x = Output_Binary; else if (EQUALS("greppable", value)) x = Output_Grepable; else if (EQUALS("grepable", value)) x = Output_Grepable; else if (EQUALS("json", value)) x = Output_JSON; else if (EQUALS("none", value)) x = Output_None; else if (EQUALS("redis", value)) x = Output_Redis; else { fprintf(stderr, "error: %s=%s\n", name, value); LOG(0, "FAIL: unknown output-format: %s\n", value); LOG(0, " hint: 'binary', 'xml', 'grepable', ...\n"); exit(1); } masscan->output.format = x; } else if (EQUALS("output-filename", name) || EQUALS("output-file", name)) { if (masscan->nmap.format == 0) masscan->nmap.format = Output_XML; masscan->is_interactive = 0; strcpy_s(masscan->nmap.filename, sizeof(masscan->nmap.filename), value); if (masscan->output.format == 0) masscan->output.format = Output_XML; strcpy_s(masscan->output.filename, sizeof(masscan->output.filename), value); } else if (EQUALS("pcap", name)) { strcpy_s(masscan->pcap_filename, sizeof(masscan->pcap_filename), value); } else if (EQUALS("packet-trace", name) || EQUALS("trace-packet", name)) { Loading @@ -1164,7 +1171,7 @@ masscan_set_parameter(struct Masscan *masscan, /* already do that */ ; } else if (EQUALS("reason", name)) { masscan->nmap.reason = 1; masscan->output.is_reason = 1; } else if (EQUALS("redis", name)) { struct Range range; unsigned offset = 0; Loading @@ -1190,8 +1197,10 @@ masscan_set_parameter(struct Masscan *masscan, masscan->redis.ip = range.begin; masscan->redis.port = port; masscan->nmap.format = Output_Redis; strcpy_s(masscan->nmap.filename, sizeof(masscan->nmap.filename), "<redis>"); masscan->output.format = Output_Redis; strcpy_s(masscan->output.filename, sizeof(masscan->output.filename), "<redis>"); } else if (EQUALS("release-memory", name)) { fprintf(stderr, "nmap(%s): this is our default option\n", name); } else if (EQUALS("resume", name)) { Loading @@ -1209,17 +1218,17 @@ masscan_set_parameter(struct Masscan *masscan, masscan->retries = x; } } else if (EQUALS("rotate-output", name) || EQUALS("rotate", name) || EQUALS("ouput-rotate", name)) { masscan->rotate_output = (unsigned)parseTime(value); masscan->output.rotate.timeout = (unsigned)parseTime(value); } else if (EQUALS("rotate-offset", name) || EQUALS("ouput-rotate-offset", name)) { masscan->rotate_offset = (unsigned)parseTime(value); masscan->output.rotate.offset = (unsigned)parseTime(value); } else if (EQUALS("rotate-dir", name) || EQUALS("rotate-directory", name) || EQUALS("ouput-rotate-dir", name)) { char *p; strcpy_s( masscan->rotate_directory, sizeof(masscan->rotate_directory), strcpy_s( masscan->output.rotate.directory, sizeof(masscan->output.rotate.directory), value); /* strip trailing slashes */ p = masscan->rotate_directory; p = masscan->output.rotate.directory; while (*p && (p[strlen(p)-1] == '/' || p[strlen(p)-1] == '/')) p[strlen(p)-1] = '\0'; } else if (EQUALS("script", name)) { Loading Loading @@ -1290,9 +1299,11 @@ masscan_set_parameter(struct Masscan *masscan, masscan->shard.of = of; } else if (EQUALS("no-stylesheet", name)) { masscan->nmap.stylesheet[0] = '\0'; masscan->output.stylesheet[0] = '\0'; } else if (EQUALS("stylesheet", name)) { strcpy_s(masscan->nmap.stylesheet, sizeof(masscan->nmap.stylesheet), value); strcpy_s(masscan->output.stylesheet, sizeof(masscan->output.stylesheet), value); } else if (EQUALS("system-dns", name)) { fprintf(stderr, "nmap(%s): DNS lookups will never be supported by this code\n", name); exit(1); Loading Loading @@ -1559,39 +1570,38 @@ masscan_command_line(struct Masscan *masscan, int argc, char *argv[]) /* Do nothing: this code never does DNS lookups anyway */ break; case 'o': /* nmap output format */ masscan->is_interactive = 0; switch (argv[i][2]) { case 'A': masscan->nmap.format = Output_All; masscan->output.format = Output_All; fprintf(stderr, "nmap(%s): unsupported output format\n", argv[i]); exit(1); break; case 'B': masscan->nmap.format = Output_Binary; masscan->output.format = Output_Binary; break; case 'J': masscan->nmap.format = Output_JSON; masscan->output.format = Output_JSON; break; case 'N': masscan->nmap.format = Output_Nmap; masscan->output.format = Output_Nmap; fprintf(stderr, "nmap(%s): unsupported output format\n", argv[i]); exit(1); break; case 'X': masscan->nmap.format = Output_XML; masscan->output.format = Output_XML; break; case 'R': masscan->nmap.format = Output_Redis; masscan->output.format = Output_Redis; if (i+1 < argc && argv[i+1][0] != '-') masscan_set_parameter(masscan, "redis", argv[i+1]); break; case 'S': masscan->nmap.format = Output_ScriptKiddie; masscan->output.format = Output_ScriptKiddie; fprintf(stderr, "nmap(%s): unsupported output format\n", argv[i]); exit(1); break; case 'G': masscan->nmap.format = Output_Grepable; masscan->output.format = Output_Grepable; break; case 'L': masscan_set_parameter(masscan, "output-format", "list"); Loading
src/main.c +2 −3 Original line number Diff line number Diff line Loading @@ -1372,7 +1372,6 @@ int main(int argc, char *argv[]) * Initialize those defaults that aren't zero */ memset(masscan, 0, sizeof(*masscan)); masscan->is_interactive = 1; masscan->seed = time(0); /* a predictable, but 'random' seed */ masscan->wait = 10; /* how long to wait for responses when done */ masscan->max_rate = 100.0; /* max rate = hundred packets-per-second */ Loading @@ -1381,8 +1380,8 @@ int main(int argc, char *argv[]) masscan->shard.of = 1; masscan->min_packet_size = 60; masscan->payloads = payloads_create(); strcpy_s( masscan->rotate_directory, sizeof(masscan->rotate_directory), strcpy_s( masscan->output.rotate.directory, sizeof(masscan->output.rotate.directory), "."); masscan->is_capture_cert = 1; Loading
src/masscan.h +176 −59 Original line number Diff line number Diff line Loading @@ -14,44 +14,88 @@ struct Adapter; struct TemplateSet; struct Banner1; enum { /** * This is the "operationg" to be performed by masscan, which is almost always * to "scan" the network. However, there are some lesser operations to do * instead, like run a "regression self test", or "debug", or something else * instead of scanning. We parse the command-line in order to figure out the * proper operation */ enum Operation { Operation_Default = 0, /* nothing specified, so print usage */ Operation_List_Adapters = 1, Operation_Selftest = 2, Operation_List_Adapters = 1, /* --listif */ Operation_Selftest = 2, /* --selftest or --regress */ Operation_Scan = 3, /* this is what you expect */ Operation_DebugIF = 4, Operation_ListScan = 5, Operation_ReadScan = 6, /* re-interpret output files in different format */ Operation_DebugIF = 4, /* --debug if */ Operation_ListScan = 5, /* -sL */ Operation_ReadScan = 6, /* --readscan <binary-output> */ }; enum OutpuFormat { Output_Interactive = 0x0001, /** * The format of the output. If nothing is specified, then the default will * be "--interactive", meaning that we'll print to the command-line live as * results come in. Only one output format can be specified, except that * "--interactive" can be specified alongside any of the other ones. * FIXME: eventually we'll support multiple file formats and "all" * outputing simultaneously. */ enum OutputFormat { Output_Interactive = 0x0001, /* --interactive, print to cmdline */ Output_List = 0x0002, Output_Binary = 0x0004, Output_XML = 0x0008, Output_JSON = 0x0010, Output_Binary = 0x0004, /* -oB, "binary", the primary format */ Output_XML = 0x0008, /* -oX, "xml" */ Output_JSON = 0x0010, /* -oJ, "json" */ Output_Nmap = 0x0020, Output_ScriptKiddie = 0x0040, Output_Grepable = 0x0080, Output_Grepable = 0x0080, /* -oG, "grepable" */ Output_Redis = 0x0100, Output_None = 0x0200, Output_All = 0xFFBF, Output_All = 0xFFBF, /* not supported */ }; /** * Holds the list of TCP "hello" payloads, specified with the "--hello-file" * or "--hello-string" options */ struct TcpCfgPayloads { /** The "hello" data in base64 format. This is either the base64 string * specified in the cmdline/cfgfile with "--hello-string", or the * contents of a file specified with "--hello-file" that we've converted * into base64 */ char *payload_base64; /** The TCP port that this hello belongs to */ unsigned port; /** These configuration options are stored as a linked-list */ struct TcpCfgPayloads *next; }; /** * This is the master MASSCAN configuration structure. It is created on startup * by reading the command-line and parsing configuration files. * * Once read in at the start, this structure doesn't change. The transmit * and receive threads have only a "const" pointer to this structure. */ struct Masscan { int op; /** * What this progrma is doing, which is normally "Operation_Scan", but * which can be other things, like "Operation_SelfTest" */ enum Operation op; /** * One or more network adapters that we'll use for scanning. * One or more network adapters that we'll use for scanning. Each adapter * should have a separate set of IP source addresses, except in the case * of PF_RING dnaX:Y adapters. * FIXME: add support for link aggregation across adapters */ struct { char ifname[256]; Loading @@ -67,110 +111,194 @@ struct Masscan /** * The target ranges of IPv4 addresses that are included in the scan. * The user can specify anything here, and we'll resolve all overlaps * and such, and sort the target ranges. */ struct RangeList targets; /** * The ports we are scanning for * The ports we are scanning for. The user can specify repeated ports * and overlapping ranges, but we'll deduplicate them, scanning ports * only once. * NOTE: TCP ports are stored 0-64k, but UDP ports are stored in the * range 64k-128k, thus, allowing us to scan both at the same time. */ struct RangeList ports; /** * IPv4 addresses/ranges that are to be exluded from the scan. This takes * precedence over any 'include' statement * precedence over any 'include' statement. What happens is this: after * all the configuration has been read, we then apply the exclude/blacklist * on top of the target/whitelist, leaving only a target/whitelist left. * Thus, during the scan, we only choose from the target/whitelist and * don't consult the exclude/blacklist. */ struct RangeList exclude_ip; struct RangeList exclude_port; /** * Maximum rate, in packets-per-second (--rate parameter) * Maximum rate, in packets-per-second (--rate parameter). This can be * a fraction of a packet-per-second, or be as high as 30000000.0 (or * more actually, but I've only tested to 30megapps). */ double max_rate; /** * Number of retries (--retries or --max-retries parameter) * Number of retries (--retries or --max-retries parameter). Retries * happen a few seconds apart. */ unsigned retries; unsigned is_pfring:1; /* --pfring */ unsigned is_sendq:1; /* --sendq */ unsigned is_banners:1; /* --banners */ unsigned is_offline:1; /* --offline */ unsigned is_interactive:1; /* --interactive */ unsigned is_arp:1; /* --arp */ unsigned is_gmt:1; /* --gmt, all times in GMT */ unsigned is_capture_cert:1; /* --capture cert */ unsigned is_capture_html:1; /* --capture html */ unsigned is_test_csv:1; /* (temporary testing feature) */ unsigned is_infinite:1; /* -infinite */ unsigned is_readscan:1; /* --readscan, Operation_Readscan */ /** * Wait forever for responses, instead of the default 10 seconds */ unsigned wait; /** * --resume * This structure contains options for pausing the scan (by exiting the * program) and restarting it later. */ struct { /** --resume-index */ uint64_t index; /** --resume-count */ uint64_t count; /** Derives the --resume-index from the target ip:port */ struct { unsigned ip; unsigned port; } target; } resume; /** * --shard n/m * This is used for distributin a scan acros multiple "shards". Every * shard in the scan must know the total number of shards, and must also * know which of those shards is it's identity. Thus, shard 1/5 scans * a different range than 2/5. These numbers start at 1, so it's * 1/3 (#1 out of three), 2/3, and 3/3 (but not 0/3). */ struct { unsigned one; unsigned of; } shard; /** * The packet template we are current using * The packet template set we are current using. We store a binary template * for TCP, UDP, SCTP, ICMP, and so on. All the scans using that protocol * are then scanned using that basic template. IP and TCP options can be * added to the basic template without affecting any other component * of the system. */ struct TemplateSet *pkt_template; /** * A random seed for randomization if zero, otherwise we'll use * the configured seed for repeatable tests. */ uint64_t seed; /** * This block configures what we do for the output files */ struct OutputStuff { /** * --output-format * Examples are "xml", "binary", "json", "grepable", and so on. */ enum OutputFormat format; /** * --output-filename * The name of the file where we are storing scan results. * Note: the filename "-" means that we should send the file to * <stdout> rather than to a file. */ char filename[256]; /** * A feature of the XML output where we can insert an optional * stylesheet into the file for better rendering on web browsers */ char stylesheet[256]; /** * --append * We should append to the output file rather than overwriting it. */ unsigned is_append:1; /** * --open * Whether to show only open ports (not closed ports) */ unsigned is_open_only:1; /** * print reason port is open, which is redundant for us */ unsigned is_reason:1; /** * --interactive * Print to command-line while also writing to output file */ unsigned is_interactive:1; struct { /** * When we should rotate output into the target directory */ unsigned rotate_output; unsigned timeout; /** * A random seed for randomization if zero, otherwise we'll use * the configured seed for repeatable tests. * When doing "--rotate daily", the rotation is done at GMT. In * orderto fix this, add an offset. */ uint64_t seed; unsigned offset; /** * Instead of rotating by timeout, we can rotate by filesize */ size_t filesize; /** * When doing "--rotate daily", the rotation is done at GMT. In order * to fix this, add an offset. * The directory to which we store rotated files */ unsigned rotate_offset; char directory[256]; } rotate; } output; struct { unsigned data_length; /* number of bytes to randomly append */ unsigned ttl; /* starting IP TTL field */ unsigned badsum; /* bad TCP/UDP/SCTP checksum */ /* output options */ unsigned packet_trace:1; /* print transmit messages */ unsigned open_only:1; /* show only open ports */ unsigned reason; /* print reason port is open, which is redundant for us */ unsigned format; /* see enum OutputFormat */ unsigned append; /* append instead of clobber file */ char datadir[256]; char filename[256]; char stylesheet[256]; } nmap; char rotate_directory[256]; char pcap_filename[256]; //PACKET_QUEUE *packet_buffers; //PACKET_QUEUE *transmit_queue; struct { unsigned timeout; } tcb; Loading @@ -195,17 +323,6 @@ struct Masscan unsigned port; } redis; /** * --infinite * Restarts the scan from the beginning, for load testing, but * by incrementing the seed */ unsigned is_infinite:1; /** * --readscan */ unsigned is_readscan:1; /** Loading
src/output.c +15 −14 Original line number Diff line number Diff line Loading @@ -372,21 +372,22 @@ output_create(const struct Masscan *masscan, unsigned thread_index) /* * Copy the configuration information from the 'masscan' structure. */ out->rotate.period = masscan->rotate_output; out->rotate.offset = masscan->rotate_offset; out->rotate.period = masscan->output.rotate.timeout; out->rotate.offset = masscan->output.rotate.offset; out->rotate.filesize = masscan->output.rotate.filesize; out->redis.port = masscan->redis.port; out->redis.ip = masscan->redis.ip; out->is_banner = masscan->is_banners; out->is_gmt = masscan->is_gmt; out->is_interactive = masscan->is_interactive; out->is_open_only = masscan->nmap.open_only; out->is_append = masscan->nmap.append; out->xml.stylesheet = duplicate_string(masscan->nmap.stylesheet); out->rotate.directory = duplicate_string(masscan->rotate_directory); out->is_interactive = masscan->output.is_interactive; out->is_open_only = masscan->output.is_open_only; out->is_append = masscan->output.is_append; out->xml.stylesheet = duplicate_string(masscan->output.stylesheet); out->rotate.directory = duplicate_string(masscan->output.rotate.directory); if (masscan->nic_count <= 1) out->filename = duplicate_string(masscan->nmap.filename); out->filename = duplicate_string(masscan->output.filename); else out->filename = indexed_filename(masscan->nmap.filename, thread_index); out->filename = indexed_filename(masscan->output.filename, thread_index); for (i=0; i<8; i++) { out->src[i] = masscan->nic[i].src; Loading @@ -396,7 +397,7 @@ output_create(const struct Masscan *masscan, unsigned thread_index) * Link the appropriate output module. * TODO: support multiple output modules */ out->format = masscan->nmap.format; out->format = masscan->output.format; switch (out->format) { case Output_List: out->funcs = &text_output; Loading Loading @@ -426,12 +427,12 @@ output_create(const struct Masscan *masscan, unsigned thread_index) * so that we can immediately notify the user of an error, rather than * waiting midway through a long scan and have it fail. */ if (masscan->nmap.filename[0] && out->funcs != &null_output) { if (masscan->output.filename[0] && out->funcs != &null_output) { FILE *fp; fp = open_rotate(out, masscan->nmap.filename); fp = open_rotate(out, masscan->output.filename); if (fp == NULL) { perror(masscan->nmap.filename); perror(masscan->output.filename); exit(1); } Loading @@ -444,7 +445,7 @@ output_create(const struct Masscan *masscan, unsigned thread_index) * this time will be set at "infinity" in the future. * TODO: this code isn't Y2036 compliant. */ if (masscan->rotate_output == 0) { if (masscan->output.rotate.timeout == 0) { /* TODO: how does one find the max time_t value??*/ out->rotate.next = (time_t)LONG_MAX; } else { Loading
src/output.h +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ struct Output time_t last; unsigned period; unsigned offset; size_t filesize; char *directory; } rotate; Loading