From 56b42ead80a4cf0c990a24203718533c6af37ae3 Mon Sep 17 00:00:00 2001
From: Robert David Graham <robert_david_graham@yahoo.com>
Date: Thu, 10 May 2018 19:33:55 -0400
Subject: [PATCH] config changes

---
 src/main-conf.c | 1377 +++++++++++++++++++++++++++++------------------
 src/main.c      |    2 +-
 src/masscan.h   |   17 +-
 3 files changed, 877 insertions(+), 519 deletions(-)

diff --git a/src/main-conf.c b/src/main-conf.c
index bc464b4..af8fff3 100644
--- a/src/main-conf.c
+++ b/src/main-conf.c
@@ -30,6 +30,10 @@
 #define min(a,b) ((a)<(b)?(a):(b))
 #endif
 
+static void masscan_echo(struct Masscan *masscan, FILE *fp, unsigned is_echo_all);
+static void masscan_set_parameter(struct Masscan *masscan, const char *name, const char *value);
+
+
 /***************************************************************************
  ***************************************************************************/
 /*static struct Range top_ports_tcp[] = {
@@ -240,15 +244,17 @@ masscan_echo_nic(struct Masscan *masscan, FILE *fp, unsigned i)
     else
         sprintf_s(zzz, sizeof(zzz), "[%u]", i);
 
-    fprintf(fp, "adapter%s = %s\n", zzz, masscan->nic[i].ifname);
-    if (masscan->nic[i].src.ip.first == masscan->nic[i].src.ip.last)
+    if (masscan->nic[i].ifname && masscan->nic[i].ifname[0])
+        fprintf(fp, "adapter%s = %s\n", zzz, masscan->nic[i].ifname);
+    
+    if (masscan->nic[i].src.ip.first+1 == masscan->nic[i].src.ip.last)
         fprintf(fp, "adapter-ip%s = %u.%u.%u.%u\n", zzz,
             (masscan->nic[i].src.ip.first>>24)&0xFF,
             (masscan->nic[i].src.ip.first>>16)&0xFF,
             (masscan->nic[i].src.ip.first>> 8)&0xFF,
             (masscan->nic[i].src.ip.first>> 0)&0xFF
             );
-    else
+    else if (masscan->nic[i].src.ip.first+1 < masscan->nic[i].src.ip.last)
         fprintf(fp, "adapter-ip%s = %u.%u.%u.%u-%u.%u.%u.%u\n", zzz,
             (masscan->nic[i].src.ip.first>>24)&0xFF,
             (masscan->nic[i].src.ip.first>>16)&0xFF,
@@ -260,13 +266,14 @@ masscan_echo_nic(struct Masscan *masscan, FILE *fp, unsigned i)
             (masscan->nic[i].src.ip.last>> 0)&0xFF
             );
 
-    fprintf(fp, "adapter-mac%s = %02x:%02x:%02x:%02x:%02x:%02x\n", zzz,
-            masscan->nic[i].my_mac[0],
-            masscan->nic[i].my_mac[1],
-            masscan->nic[i].my_mac[2],
-            masscan->nic[i].my_mac[3],
-            masscan->nic[i].my_mac[4],
-            masscan->nic[i].my_mac[5]);
+    if (masscan->nic[i].my_mac_count)
+        fprintf(fp, "adapter-mac%s = %02x:%02x:%02x:%02x:%02x:%02x\n", zzz,
+                masscan->nic[i].my_mac[0],
+                masscan->nic[i].my_mac[1],
+                masscan->nic[i].my_mac[2],
+                masscan->nic[i].my_mac[3],
+                masscan->nic[i].my_mac[4],
+                masscan->nic[i].my_mac[5]);
     if (masscan->nic[i].router_ip) {
         fprintf(fp, "router-ip%s = %u.%u.%u.%u\n", zzz,
             (masscan->nic[i].router_ip>>24)&0xFF,
@@ -274,8 +281,8 @@ masscan_echo_nic(struct Masscan *masscan, FILE *fp, unsigned i)
             (masscan->nic[i].router_ip>> 8)&0xFF,
             (masscan->nic[i].router_ip>> 0)&0xFF
             );
-    } else
-    fprintf(fp, "router-mac%s = %02x:%02x:%02x:%02x:%02x:%02x\n", zzz,
+    } else if (memcmp(masscan->nic[i].router_mac, "\0\0\0\0\0\0", 6) != 0)
+        fprintf(fp, "router-mac%s = %02x:%02x:%02x:%02x:%02x:%02x\n", zzz,
             masscan->nic[i].router_mac[0],
             masscan->nic[i].router_mac[1],
             masscan->nic[i].router_mac[2],
@@ -285,194 +292,6 @@ masscan_echo_nic(struct Masscan *masscan, FILE *fp, unsigned i)
 
 }
 
-/***************************************************************************
- * Prints the current configuration to the command-line then exits.
- * Use#1: create a template file of all setable parameters.
- * Use#2: make sure your configuration was interpreted correctly.
- ***************************************************************************/
-static void
-masscan_echo(struct Masscan *masscan, FILE *fp)
-{
-    unsigned i;
-    unsigned l = 0;
-
-    fprintf(fp, "rate = %10.2f\n", masscan->max_rate);
-    fprintf(fp, "randomize-hosts = true\n");
-    fprintf(fp, "seed = %" PRIu64 "\n", masscan->seed);
-    
-    if (masscan->shard.one != 1 && masscan->shard.of != 1)
-        fprintf(fp, "shard = %u/%u\n", masscan->shard.one, masscan->shard.of);
-    if (masscan->is_banners)
-        fprintf(fp, "banners = true\n");
-    if (masscan->is_arp)
-        fprintf(fp, "arp = true\n");
-    if (masscan->is_noreset)
-        fprintf(fp, "noreset = true\n");
-
-    fprintf(fp, "# ADAPTER SETTINGS\n");
-    if (masscan->nic_count == 0)
-        masscan_echo_nic(masscan, fp, 0);
-    else {
-        for (i=0; i<masscan->nic_count; i++)
-            masscan_echo_nic(masscan, fp, i);
-    }
-
-
-    /*
-     * Output information
-     */
-    fprintf(fp, "# OUTPUT/REPORTING SETTINGS\n");
-    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_Unicornscan:fprintf(fp, "output-format = unicornscan\n"); break;
-    case Output_XML:        fprintf(fp, "output-format = xml\n"); break;
-    case Output_Binary:     fprintf(fp, "output-format = binary\n"); break;
-    case Output_Grepable:   fprintf(fp, "output-format = grepable\n"); break;
-    case Output_JSON:       fprintf(fp, "output-format = json\n"); break;
-    case Output_NDJSON:     fprintf(fp, "output-format = ndjson\n"); break;
-    case Output_Certs:      fprintf(fp, "output-format = certs\n"); break;
-    case Output_None:       fprintf(fp, "output-format = none\n"); break;
-    case Output_Redis:
-        fprintf(fp, "output-format = redis\n");
-        fprintf(fp, "redis = %u.%u.%u.%u:%u\n",
-            (unsigned char)(masscan->redis.ip>>24),
-            (unsigned char)(masscan->redis.ip>>16),
-            (unsigned char)(masscan->redis.ip>> 8),
-            (unsigned char)(masscan->redis.ip>> 0),
-            masscan->redis.port);
-        break;
-
-    default:
-        fprintf(fp, "output-format = unknown(%u)\n", masscan->output.format);
-        break;
-    }
-    fprintf(fp, "show = %s,%s,%s\n",
-            masscan->output.is_show_open?"open":"",
-            masscan->output.is_show_closed?"closed":"",
-            masscan->output.is_show_host?"host":""
-            );
-    if (!masscan->output.is_show_open)
-        fprintf(fp, "noshow = open\n");
-    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->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, "rotate-filesize = %" PRIu64 "\n", masscan->output.rotate.filesize);
-    fprintf(fp, "pcap = %s\n", masscan->pcap_filename);
-
-    /*
-     * Targets
-     */
-
-    fprintf(fp, "# TARGET SELECTION (IP, PORTS, EXCLUDES)\n");
-    fprintf(fp, "retries = %u\n", masscan->retries);
-    fprintf(fp, "ports = ");
-    /* Disable comma generation for the first element */
-    l = 0;
-    for (i=0; i<masscan->ports.count; i++) {
-        struct Range range = masscan->ports.list[i];
-        do {
-            struct Range rrange = range;
-            unsigned done = 0;
-            if (l)
-                fprintf(fp, ",");
-            l = 1;
-            if (rrange.begin >= Templ_ICMP_echo) {
-                rrange.begin -= Templ_ICMP_echo;
-                rrange.end -= Templ_ICMP_echo;
-                fprintf(fp,"I:");
-                done = 1;
-            } else if (rrange.begin >= Templ_SCTP) {
-                rrange.begin -= Templ_SCTP;
-                rrange.end -= Templ_SCTP;
-                fprintf(fp,"S:");
-                range.begin = Templ_ICMP_echo;
-            } else if (rrange.begin >= Templ_UDP) {
-                rrange.begin -= Templ_UDP;
-                rrange.end -= Templ_UDP;
-                fprintf(fp,"U:");
-                range.begin = Templ_SCTP;
-            } else
-                range.begin = Templ_UDP;
-            rrange.end = min(rrange.end, 65535);
-            if (rrange.begin == rrange.end)
-                fprintf(fp, "%u", rrange.begin);
-            else
-                fprintf(fp, "%u-%u", rrange.begin, rrange.end);
-            if (done)
-                break;
-        } while (range.begin <= range.end);
-    }
-    fprintf(fp, "\n");
-    for (i=0; i<masscan->targets.count; i++) {
-        struct Range range = masscan->targets.list[i];
-        fprintf(fp, "range = ");
-        fprintf(fp, "%u.%u.%u.%u",
-            (range.begin>>24)&0xFF,
-            (range.begin>>16)&0xFF,
-            (range.begin>> 8)&0xFF,
-            (range.begin>> 0)&0xFF
-            );
-        if (range.begin != range.end) {
-            unsigned cidr_bits = count_cidr_bits(range);
-
-            if (cidr_bits) {
-                fprintf(fp, "/%u", cidr_bits);
-            } else
-            fprintf(fp, "-%u.%u.%u.%u",
-                (range.end>>24)&0xFF,
-                (range.end>>16)&0xFF,
-                (range.end>> 8)&0xFF,
-                (range.end>> 0)&0xFF
-                );
-        }
-        fprintf(fp, "\n");
-    }
-
-    fprintf(fp, "\n");
-    if (masscan->http_user_agent)
-        fprintf(    fp,
-                "http-user-agent = %.*s\n",
-                masscan->http_user_agent_length,
-                masscan->http_user_agent);
-
-    for (i=0; i<sizeof(masscan->http_headers)/sizeof(masscan->http_headers[0]); i++) {
-        if (masscan->http_headers[i].header_name == 0)
-            continue;
-        fprintf(    fp,
-                    "http-header[%s] = %.*s\n",
-                    masscan->http_headers[i].header_name,
-                    masscan->http_headers[i].header_value_length,
-                masscan->http_headers[i].header_value);
-    }
-
-
-    fprintf(fp, "%scapture = cert\n", masscan->is_capture_cert?"":"no");
-    fprintf(fp, "%scapture = html\n", masscan->is_capture_html?"":"no");
-    fprintf(fp, "%scapture = heartbleed\n", masscan->is_capture_heartbleed?"":"no");
-    fprintf(fp, "%scapture = ticketbleed\n", masscan->is_capture_ticketbleed?"":"no");
-    
-    if (masscan->is_hello_ssl) {
-        fprintf(fp, "hello = ssl\n");
-    }
-
-    /*
-     *  TCP payloads
-     */
-    fprintf(fp, "\n");
-    fprintf(fp, "min-packet = %u\n", masscan->min_packet_size);
-
-    {
-        struct TcpCfgPayloads *pay;
-        for (pay = masscan->tcp_payloads; pay; pay = pay->next) {
-            fprintf(fp, "hello-string[%u] = %s\n",
-                pay->port, pay->payload_base64);
-        }
-    }
-}
 
 /***************************************************************************
  ***************************************************************************/
@@ -495,10 +314,8 @@ masscan_save_state(struct Masscan *masscan)
         return;
     }
 
-    fprintf(fp, "\n# resume information\n");
-    fprintf(fp, "resume-index = %" PRIu64 "\n", masscan->resume.index);
-
-    masscan_echo(masscan, fp);
+    
+    masscan_echo(masscan, fp, 0);
 
     fclose(fp);
 }
@@ -982,32 +799,679 @@ config_top_ports(struct Masscan *masscan, unsigned n)
         for (i=0; i<n && i<sizeof(top_tcp_ports)/sizeof(top_tcp_ports[0]); i++)
             rangelist_add_range(ports, top_tcp_ports[i], top_tcp_ports[i]);
     }
-    if (masscan->scan_type.udp) {
-        for (i=0; i<n && i<sizeof(top_tcp_ports)/sizeof(top_tcp_ports[0]); i++)
-            rangelist_add_range(ports, top_tcp_ports[i], top_tcp_ports[i]);
+    if (masscan->scan_type.udp) {
+        for (i=0; i<n && i<sizeof(top_tcp_ports)/sizeof(top_tcp_ports[0]); i++)
+            rangelist_add_range(ports, top_tcp_ports[i], top_tcp_ports[i]);
+    }
+}
+
+/***************************************************************************
+ ***************************************************************************/
+static int
+isInteger(const char *value)
+{
+    size_t i;
+    
+    if (value == NULL)
+        return 0;
+    
+    for (i=0; value[i]; i++)
+        if (!isdigit(value[i]&0xFF))
+            return 0;
+    return 1;
+}
+
+/***************************************************************************
+ ***************************************************************************/
+typedef int (*SET_PARAMETER)(struct Masscan *masscan, const char *name, const char *value);
+enum {CONF_OK, CONF_WARN, CONF_ERR};
+
+static int SET_arpscan(struct Masscan *masscan, const char *name, const char *value)
+{
+    struct Range range;
+    if (masscan->echo) {
+        if (masscan->scan_type.arp || masscan->echo_all)
+            fprintf(masscan->echo, "arpscan = %s\n", masscan->scan_type.arp?"true":"false");
+        return 0;
+    }
+    range.begin = Templ_ARP;
+    range.end = Templ_ARP;
+    rangelist_add_range(&masscan->ports, range.begin, range.end);
+    masscan_set_parameter(masscan, "router-mac", "ff-ff-ff-ff-ff-ff");
+    masscan->scan_type.arp = 1;
+    LOG(5, "--arpscan\n");
+    return CONF_OK;
+}
+
+static int SET_banners(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->is_banners || masscan->echo_all)
+            fprintf(masscan->echo, "banners = %s\n", masscan->is_banners?"true":"false");
+       return 0;
+    }
+    masscan->is_banners = parseBoolean(value);
+    return CONF_OK;
+}
+
+static int SET_capture(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (!masscan->is_capture_cert || masscan->echo_all)
+            fprintf(masscan->echo, "%scapture = cert\n", masscan->is_capture_cert?"":"no");
+        if (masscan->is_capture_html || masscan->echo_all)
+            fprintf(masscan->echo, "%scapture = html\n", masscan->is_capture_html?"":"no");
+        if (masscan->is_capture_heartbleed || masscan->echo_all)
+            fprintf(masscan->echo, "%scapture = heartbleed\n", masscan->is_capture_heartbleed?"":"no");
+        if (masscan->is_capture_ticketbleed || masscan->echo_all)
+            fprintf(masscan->echo, "%scapture = ticketbleed\n", masscan->is_capture_ticketbleed?"":"no");
+        return 0;
+    }
+    if (EQUALS("capture", name)) {
+        if (EQUALS("cert", value))
+            masscan->is_capture_cert = 1;
+        else if (EQUALS("html", value))
+            masscan->is_capture_html = 1;
+        else if (EQUALS("heartbleed", value))
+            masscan->is_capture_heartbleed = 1;
+        else if (EQUALS("ticketbleed", value))
+            masscan->is_capture_ticketbleed = 1;
+        else {
+            fprintf(stderr, "FAIL: %s: unknown capture type\n", value);
+            return CONF_ERR;
+        }
+    } else if (EQUALS("nocapture", name)) {
+        if (EQUALS("cert", value))
+            masscan->is_capture_cert = 0;
+        else if (EQUALS("html", value))
+            masscan->is_capture_html = 0;
+        else if (EQUALS("heartbleed", value))
+            masscan->is_capture_heartbleed = 0;
+        else if (EQUALS("ticketbleed", value))
+            masscan->is_capture_ticketbleed = 0;
+        else {
+            fprintf(stderr, "FAIL: %s: unknown nocapture type\n", value);
+            return CONF_ERR;
+        }
+    }
+    return CONF_OK;
+}
+
+static int SET_hello(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->is_hello_ssl) {
+            fprintf(masscan->echo, "hello = ssl\n");
+        }
+        return 0;
+    }
+    if (EQUALS("ssl", value))
+        masscan->is_hello_ssl = 1;
+    else {
+        fprintf(stderr, "FAIL: %s: unknown hello type\n", value);
+        return CONF_ERR;
+    }
+    return CONF_OK;
+}
+
+static int SET_hello_file(struct Masscan *masscan, const char *name, const char *value)
+{
+    unsigned index;
+    FILE *fp;
+    int x;
+    char buf[16384];
+    char buf2[16384];
+    size_t bytes_read;
+    size_t bytes_encoded;
+    char foo[64];
+
+    if (masscan->echo) {
+        //Echoed as a string "hello-string" that was originally read
+        //from a file, not the "hello-filename"
+        return 0;
+    }
+    
+    index = ARRAY(name);
+    if (index >= 65536) {
+        fprintf(stderr, "%s: bad index\n", name);
+        return CONF_ERR;
+    }
+
+    /* When connecting via TCP, send this file */
+    x = fopen_s(&fp, value, "rb");
+    if (x != 0) {
+        LOG(0, "[FAILED] could not read hello file\n");
+        perror(value);
+        return CONF_ERR;
+    }
+    
+    bytes_read = fread(buf, 1, sizeof(buf), fp);
+    if (bytes_read == 0) {
+        LOG(0, "[FAILED] could not read hello file\n");
+        perror(value);
+        fclose(fp);
+        return CONF_ERR;
+    }
+    fclose(fp);
+    
+    bytes_encoded = base64_encode(buf2, sizeof(buf2)-1, buf, bytes_read);
+    buf2[bytes_encoded] = '\0';
+    
+    sprintf_s(foo, sizeof(foo), "hello-string[%u]", (unsigned)index);
+    
+    masscan_set_parameter(masscan, foo, buf2);
+
+    return CONF_OK;
+}
+
+static int SET_hello_string(struct Masscan *masscan, const char *name, const char *value)
+{
+    unsigned index;
+    char *value2;
+    struct TcpCfgPayloads *pay;
+
+    if (masscan->echo) {
+        for (pay = masscan->tcp_payloads; pay; pay = pay->next) {
+            fprintf(masscan->echo, "hello-string[%u] = %s\n",
+                    pay->port, pay->payload_base64);
+        }
+        return 0;
+    }
+    
+    index = ARRAY(name);
+    if (index >= 65536) {
+        fprintf(stderr, "%s: bad index\n", name);
+        exit(1);
+    }
+
+    
+    value2 = (char*)malloc(strlen(value)+1);
+    memcpy(value2, value, strlen(value)+1);
+    
+    pay = (struct TcpCfgPayloads *)malloc(sizeof(*pay));
+    
+    pay->payload_base64 = value2;
+    pay->port = index;
+    pay->next = masscan->tcp_payloads;
+    masscan->tcp_payloads = pay;
+    return CONF_OK;
+}
+
+static int SET_hello_timeout(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->tcp_hello_timeout || masscan->echo_all)
+            fprintf(masscan->echo, "hello-timeout = %u\n", masscan->tcp_hello_timeout);
+        return 0;
+    }
+    masscan->tcp_hello_timeout = (unsigned)parseInt(value);
+    return CONF_OK;
+}
+
+static int SET_min_packet(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->min_packet_size != 60 || masscan->echo_all)
+            fprintf(masscan->echo, "min-packet = %u\n", masscan->min_packet_size);
+        return 0;
+    }
+    masscan->min_packet_size = (unsigned)parseInt(value);
+    return CONF_OK;
+}
+
+
+static int SET_nobanners(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        return 0;
+    }
+    masscan->is_banners = !parseBoolean(value);
+    return CONF_OK;
+}
+
+static int SET_noreset(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->is_noreset || masscan->echo_all)
+            fprintf(masscan->echo, "noreset = %s\n", masscan->is_noreset?"true":"false");
+        return 0;
+    }
+    masscan->is_noreset = parseBoolean(value);
+    return CONF_OK;
+}
+
+static int SET_output_append(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->output.is_append || masscan->echo_all)
+            fprintf(masscan->echo, "output-append = %s\n",
+                    masscan->output.is_append?"true":"false");
+        return 0;
+    }
+    if (EQUALS("overwrite", name) || !parseBoolean(value))
+        masscan->output.is_append = 0;
+    else
+        masscan->output.is_append = 1;
+    return CONF_OK;
+}
+
+static int SET_output_filename(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->output.filename[0] || masscan->echo_all)
+            fprintf(masscan->echo, "output-filename = %s\n", masscan->output.filename);
+        return 0;
+    }
+    if (masscan->output.format == 0)
+        masscan->output.format = Output_XML; /*TODO: Why is the default XML?*/
+    strcpy_s(masscan->output.filename,
+             sizeof(masscan->output.filename),
+             value);
+    return CONF_OK;
+}
+
+static int SET_output_format(struct Masscan *masscan, const char *name, const char *value)
+{
+    enum OutputFormat x = 0;
+    if (masscan->echo) {
+        FILE *fp = masscan->echo;
+        switch (masscan->output.format) {
+            case Output_Default:    if (masscan->echo_all) fprintf(fp, "output-format = interactive\n"); break;
+            case Output_Interactive:fprintf(fp, "output-format = interactive\n"); break;
+            case Output_List:       fprintf(fp, "output-format = list\n"); break;
+            case Output_Unicornscan:fprintf(fp, "output-format = unicornscan\n"); break;
+            case Output_XML:        fprintf(fp, "output-format = xml\n"); break;
+            case Output_Binary:     fprintf(fp, "output-format = binary\n"); break;
+            case Output_Grepable:   fprintf(fp, "output-format = grepable\n"); break;
+            case Output_JSON:       fprintf(fp, "output-format = json\n"); break;
+            case Output_NDJSON:     fprintf(fp, "output-format = ndjson\n"); break;
+            case Output_Certs:      fprintf(fp, "output-format = certs\n"); break;
+            case Output_None:       fprintf(fp, "output-format = none\n"); break;
+            case Output_Redis:
+                fprintf(fp, "output-format = redis\n");
+                fprintf(fp, "redis = %u.%u.%u.%u:%u\n",
+                        (unsigned char)(masscan->redis.ip>>24),
+                        (unsigned char)(masscan->redis.ip>>16),
+                        (unsigned char)(masscan->redis.ip>> 8),
+                        (unsigned char)(masscan->redis.ip>> 0),
+                        masscan->redis.port);
+                break;
+                
+            default:
+                fprintf(fp, "output-format = unknown(%u)\n", masscan->output.format);
+                break;
+        }
+        return 0;
+    }
+    if (EQUALS("unknown(0)", value))        x = Output_Interactive;
+    else if (EQUALS("interactive", value))  x = Output_Interactive;
+    else if (EQUALS("list", value))         x = Output_List;
+    else if (EQUALS("unicornscan", value))  x = Output_Unicornscan;
+    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("ndjson", value))       x = Output_NDJSON;
+    else if (EQUALS("certs", value))        x = Output_Certs;
+    else if (EQUALS("none", value))         x = Output_None;
+    else if (EQUALS("redis", value))        x = Output_Redis;
+    else {
+        LOG(0, "FAIL: unknown output-format: %s\n", value);
+        LOG(0, "  hint: 'binary', 'xml', 'grepable', ...\n");
+        return CONF_ERR;
+    }
+    masscan->output.format = x;
+
+    return CONF_OK;
+}
+
+static int SET_output_noshow(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->echo_all) {
+            fprintf(masscan->echo, "output-noshow = %s%s%s\n",
+                    (!masscan->output.is_show_open)?"open,":"",
+                    (!masscan->output.is_show_closed)?"closed,":"",
+                    (!masscan->output.is_show_host)?"host,":""
+                    );
+        }
+        return 0;
+    }
+    for (;;) {
+        const char *val2 = value;
+        unsigned val2_len = INDEX_OF(val2, ',');
+        if (val2_len == 0)
+            break;
+        if (EQUALSx("open", val2, val2_len))
+            masscan->output.is_show_open = 0;
+        else if (EQUALSx("closed", val2, val2_len) || EQUALSx("close", val2, val2_len))
+            masscan->output.is_show_closed = 0;
+        else if (EQUALSx("open", val2, val2_len))
+            masscan->output.is_show_host = 0;
+        else if (EQUALSx("all",val2,val2_len)) {
+            masscan->output.is_show_open = 0;
+            masscan->output.is_show_host = 0;
+            masscan->output.is_show_closed = 0;
+        }
+        else {
+            LOG(0, "FAIL: unknown 'noshow' spec: %.*s\n", val2_len, val2);
+            exit(1);
+        }
+        value += val2_len;
+        while (*value == ',')
+            value++;
+    }
+    return CONF_OK;
+}
+
+static int SET_output_show(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->echo_all) {
+            fprintf(masscan->echo, "output-show = %s%s%s\n",
+                    masscan->output.is_show_open?"open,":"",
+                    masscan->output.is_show_closed?"closed,":"",
+                    masscan->output.is_show_host?"host,":""
+                    );
+        }
+        return 0;
+    }
+    for (;;) {
+        const char *val2 = value;
+        unsigned val2_len = INDEX_OF(val2, ',');
+        if (val2_len == 0)
+            break;
+        if (EQUALSx("open", val2, val2_len))
+            masscan->output.is_show_open = 1;
+        else if (EQUALSx("closed", val2, val2_len) || EQUALSx("close", val2, val2_len))
+            masscan->output.is_show_closed = 1;
+        else if (EQUALSx("open", val2, val2_len))
+            masscan->output.is_show_host = 1;
+        else if (EQUALSx("all",val2,val2_len)) {
+            masscan->output.is_show_open = 1;
+            masscan->output.is_show_host = 1;
+            masscan->output.is_show_closed = 1;
+        }
+        else {
+            LOG(0, "FAIL: unknown 'show' spec: %.*s\n", val2_len, val2);
+            exit(1);
+        }
+        value += val2_len;
+        while (*value == ',')
+            value++;
+    }
+    return CONF_OK;
+}
+static int SET_output_show_open(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        return 0;
+    }
+    /* "open" "open-only" */
+    masscan->output.is_show_open = 1;
+    masscan->output.is_show_closed = 0;
+    masscan->output.is_show_host = 0;
+    return CONF_OK;
+}
+static int SET_pcap_filename(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->pcap_filename && masscan->pcap_filename[0])
+            fprintf(masscan->echo, "pcap-filename = %s\n", masscan->pcap_filename);
+        return 0;
+    }
+    if (value)
+        strcpy_s(masscan->pcap_filename, sizeof(masscan->pcap_filename), value);
+    return CONF_OK;
+}
+
+static int SET_randomize_hosts(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        //fprintf(masscan->echo, "randomize-hosts = true\n");
+        return 0;
+    }
+    return CONF_OK;
+}
+
+
+static int SET_rate(struct Masscan *masscan, const char *name, const char *value)
+{
+    double rate = 0.0;
+    double point = 10.0;
+    unsigned i;
+    
+    if (masscan->echo) {
+        fprintf(masscan->echo, "rate = %-10.2f\n", masscan->max_rate);
+        return 0;
+    }
+    
+    for (i=0; value[i] && value[i] != '.'; i++) {
+        char c = value[i];
+        if (c < '0' || '9' < c) {
+            fprintf(stderr, "CONF: non-digit in rate spec: %s=%s\n", name, value);
+            return CONF_ERR;
+        }
+        rate = rate * 10.0 + (c - '0');
+    }
+    
+    if (value[i] == '.') {
+        i++;
+        while (value[i]) {
+            char c = value[i];
+            if (c < '0' || '9' < c) {
+                fprintf(stderr, "CONF: non-digit in rate spec: %s=%s\n",
+                        name, value);
+                return CONF_ERR;
+            }
+            rate += (c - '0')/point;
+            point /= 10.0;
+            value++;
+        }
+    }
+    
+    masscan->max_rate = rate;
+    return CONF_OK;
+}
+
+static int SET_resume_count(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->resume.count || masscan->echo_all) {
+            fprintf(masscan->echo, "resume-count = %" PRIu64 "\n", masscan->resume.count);
+        }
+        return 0;
+    }
+    masscan->resume.count = parseInt(value);
+    return CONF_OK;
+}
+
+static int SET_resume_index(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->resume.index  || masscan->echo_all) {
+            fprintf(masscan->echo, "\n# resume information\n");
+            fprintf(masscan->echo, "resume-index = %" PRIu64 "\n", masscan->resume.index);
+        }
+        return 0;
+    }
+    masscan->resume.index = parseInt(value);
+    return CONF_OK;
+}
+
+static int SET_retries(struct Masscan *masscan, const char *name, const char *value)
+{
+    uint64_t x;
+    
+    if (masscan->echo) {
+        if (masscan->retries || masscan->echo_all)
+            fprintf(masscan->echo, "retries = %u\n", masscan->retries);
+        return 0;
+    }
+    x = strtoul(value, 0, 0);
+    if (x >= 1000) {
+        fprintf(stderr, "FAIL: retries=<n>: expected number less than 1000\n");
+        return CONF_ERR;
+    }
+    masscan->retries = (unsigned)x;
+    return CONF_OK;
+    
+}
+
+static int SET_rotate_time(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->output.rotate.timeout || masscan->echo_all)
+            fprintf(masscan->echo, "rotate = %u\n", masscan->output.rotate.timeout);
+        return 0;
+    }
+    masscan->output.rotate.timeout = (unsigned)parseTime(value);
+    return CONF_OK;
+}
+static int SET_rotate_directory(struct Masscan *masscan, const char *name, const char *value)
+{
+    char *p;
+    if (masscan->echo) {
+        if (memcmp(masscan->output.rotate.directory, ".",2) != 0 || masscan->echo_all) {
+            fprintf(masscan->echo, "rotate-dir = %s\n", masscan->output.rotate.directory);
+        }
+        return 0;
+    }
+    strcpy_s(   masscan->output.rotate.directory,
+             sizeof(masscan->output.rotate.directory),
+             value);
+    /* strip trailing slashes */
+    p = masscan->output.rotate.directory;
+    while (*p && (p[strlen(p)-1] == '/' || p[strlen(p)-1] == '/'))
+        p[strlen(p)-1] = '\0';
+    return CONF_OK;
+}
+static int SET_rotate_offset(struct Masscan *masscan, const char *name, const char *value)
+{
+    /* Time offset, otherwise output files are aligned to nearest time
+     * interval, e.g. at the start of the hour for "hourly" */
+    if (masscan->echo) {
+        if (masscan->output.rotate.offset || masscan->echo_all)
+            fprintf(masscan->echo, "rotate-offset = %u\n", masscan->output.rotate.offset);
+        return 0;
+    }
+    masscan->output.rotate.offset = (unsigned)parseTime(value);
+    return CONF_OK;
+}
+static int SET_rotate_filesize(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        if (masscan->output.rotate.filesize || masscan->echo_all)
+            fprintf(masscan->echo, "rotate-size = %" PRIu64 "\n", masscan->output.rotate.filesize);
+        return 0;
+    }
+    masscan->output.rotate.filesize = parseSize(value);
+    return CONF_OK;
+    
+}
+
+
+
+static int SET_seed(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        fprintf(masscan->echo, "seed = %" PRIu64 "\n", masscan->seed);
+        return 0;
+    }
+    if (EQUALS("time", value))
+        masscan->seed = time(0);
+    else
+        masscan->seed = parseInt(value);
+    return CONF_OK;
+}
+
+static int SET_space(struct Masscan *masscan, const char *name, const char *value)
+{
+    if (masscan->echo) {
+        fprintf(masscan->echo, "\n");
+        return 0;
     }
+    return CONF_OK;
 }
 
-/***************************************************************************
- ***************************************************************************/
-int
-isInteger(const char *value)
+static int SET_shard(struct Masscan *masscan, const char *name, const char *value)
 {
-    size_t i;
-    
-    if (value == NULL)
+    unsigned one = 0;
+    unsigned of = 0;
+
+    if (masscan->echo) {
+        if ((masscan->shard.one != 1 && masscan->shard.of != 1)  || masscan->echo_all)
+            fprintf(masscan->echo, "shard = %u/%u\n", masscan->shard.one, masscan->shard.of);
         return 0;
+    }
+    while (isdigit(*value))
+        one = one*10 + (*(value++)) - '0';
+    while (ispunct(*value))
+        value++;
+    while (isdigit(*value))
+        of = of*10 + (*(value++)) - '0';
     
-    for (i=0; value[i]; i++)
-        if (!isdigit(value[i]&0xFF))
-            return 0;
-    return 1;
+    if (one < 1) {
+        LOG(0, "FAIL: shard index can't be zero\n");
+        LOG(0, "hint   it goes like 1/4 2/4 3/4 4/4\n");
+        return CONF_ERR;
+    }
+    if (one > of) {
+        LOG(0, "FAIL: shard spec is wrong\n");
+        LOG(0, "hint   it goes like 1/4 2/4 3/4 4/4\n");
+        return CONF_ERR;
+    }
+    masscan->shard.one = one;
+    masscan->shard.of = of;
+    return CONF_OK;
 }
 
-/***************************************************************************
- ***************************************************************************/
 
 
+
+struct ConfigParameter {
+    const char *name;
+    SET_PARAMETER set;
+    unsigned flags;
+    const char *alts[6];
+};
+enum {F_NONE, F_BOOL};
+struct ConfigParameter config_parameters[] = {
+    {"resume-index",    SET_resume_index},
+    {"resume-count",    SET_resume_count},
+    {"seed",            SET_seed},
+    {"arpscan",         SET_arpscan,            F_BOOL, {"arp",0}},
+    {"randomize-hosts", SET_randomize_hosts,    F_BOOL},
+    {"rate",            SET_rate,               0, {"max-rate",0}},
+    {"shard",           SET_shard,              0, {"shards",0}},
+    {"banners",         SET_banners,            F_BOOL, {"banner",0}},
+    {"nobanners",       SET_nobanners,          F_BOOL, {"nobanner",0}},
+    {"retries",         SET_retries,            0, {"retry", "max-retries", "max-retry", 0}},
+    {"noreset",         SET_noreset,            F_BOOL},
+    {"pcap-filename",   SET_pcap_filename,      0, {"pcap",0}},
+    {"hello",           SET_hello},
+    {"hello-file",      SET_hello_file,         0, {"hello-filename",0}},
+    {"hello-string",    SET_hello_string},
+    {"hello-timeout",   SET_hello_timeout},
+    {"min-packet",      SET_min_packet,         0, {"min-pkt",0}},
+    {"capture",         SET_capture},
+    {"SPACE",           SET_space},
+    {"output-filename", SET_output_filename,    0, {"output-file",0}},
+    {"output-format",   SET_output_format},
+    {"output-show",     SET_output_show,        0, {"output-status", "show",0}},
+    {"output-noshow",   SET_output_noshow,      0, {"noshow",0}},
+    {"output-show-open",SET_output_show_open,   F_BOOL, {"open", "open-only", 0}},
+    {"output-append",   SET_output_append,      0, {"append-output",0}},
+    {"rotate",          SET_rotate_time,        0, {"output-rotate", "rotate-output", "rotate-time", 0}},
+    {"rotate-dir",      SET_rotate_directory,   0, {"output-rotate-dir", "rotate-directory", 0}},
+    {"rotate-offset",   SET_rotate_offset,      0, {"output-rotate-offset", 0}},
+    {"rotate-size",     SET_rotate_filesize,    0, {"output-rotate-filesize", "rotate-filesize", 0}},
+    
+    {"SPACE",           SET_space},
+    {0}
+};
+
 /***************************************************************************
  * Called either from the "command-line" parser when it sees a --parm,
  * or from the "config-file" parser for normal options.
@@ -1021,7 +1485,36 @@ masscan_set_parameter(struct Masscan *masscan,
         fprintf(stderr, "%s: bad index\n", name);
         exit(1);
     }
+    
+    /*
+     * NEW:
+     * Go through configured list of parameters
+     */
+    {
+        size_t i;
+        
+        for (i=0; config_parameters[i].name; i++) {
+            if (EQUALS(config_parameters[i].name, name)) {
+                config_parameters[i].set(masscan, name, value);
+                return;
+            } else {
+                size_t j;
+                for (j=0; config_parameters[i].alts[j]; j++) {
+                    if (EQUALS(config_parameters[i].alts[j], name)) {
+                        config_parameters[i].set(masscan, name, value);
+                        return;
+                    }
+                }
+            }
+        }
+    }
 
+    /*
+     * OLD:
+     * Configure the old parameters, the ones we don't have in the new config
+     * system yet (see the NEW part above).
+     * TODO: transition all these old params to the new system
+     */
     if (EQUALS("conf", name) || EQUALS("config", name)) {
         masscan_read_config_file(masscan, value);
     } else if (EQUALS("adapter", name) || EQUALS("if", name) || EQUALS("interface", name)) {
@@ -1062,7 +1555,7 @@ masscan_set_parameter(struct Masscan *masscan,
 
         masscan->nic[index].src.ip.first = range.begin;
         masscan->nic[index].src.ip.last = range.end;
-        masscan->nic[index].src.ip.range = (uint64_t)range.end - range.begin + 1;
+        masscan->nic[index].src.ip.range = range.end - range.begin + 1;
     } else if (EQUALS("adapter-port", name) || EQUALS("source-port", name)
                || EQUALS("src-port", name)) {
         /* Send packets FROM this port number */
@@ -1146,38 +1639,6 @@ masscan_set_parameter(struct Masscan *masscan,
 
         masscan->nic[index].router_ip = range.begin;
     }
-    else if (EQUALS("rate", name) || EQUALS("max-rate", name) ) {
-        double rate = 0.0;
-        double point = 10.0;
-        unsigned i;
-
-        for (i=0; value[i] && value[i] != '.'; i++) {
-            char c = value[i];
-            if (c < '0' || '9' < c) {
-                fprintf(stderr, "CONF: non-digit in rate spec: %s=%s\n", name, value);
-                return;
-            }
-            rate = rate * 10.0 + (c - '0');
-        }
-
-        if (value[i] == '.') {
-            i++;
-            while (value[i]) {
-                char c = value[i];
-                if (c < '0' || '9' < c) {
-                    fprintf(stderr, "CONF: non-digit in rate spec: %s=%s\n",
-                            name, value);
-                    return;
-                }
-                rate += (c - '0')/point;
-                point /= 10.0;
-                value++;
-            }
-        }
-
-        masscan->max_rate = rate;
-
-    }
     else if (EQUALS("udp-ports", name) || EQUALS("udp-port", name)) {
         unsigned is_error = 0;
         masscan->scan_type.udp = 1;
@@ -1218,73 +1679,26 @@ masscan_set_parameter(struct Masscan *masscan,
             fprintf(stderr, "err\n");
             exit(1);
         }
-    }
-    else if (EQUALS("exclude-ports", name) || EQUALS("exclude-port", name)) {
+    } else if (EQUALS("exclude-ports", name) || EQUALS("exclude-port", name)) {
         unsigned is_error = 0;
         rangelist_parse_ports(&masscan->exclude_port, value, &is_error, 0);
         if (is_error) {
             LOG(0, "FAIL: bad exclude port: %s\n", value);
             exit(1);
         }
-    } else if (EQUALS("arp", name) || EQUALS("arpscan", name)) {
-        /* Add ICMP ping request */
-        struct Range range;
-        range.begin = Templ_ARP;
-        range.end = Templ_ARP;
-        rangelist_add_range(&masscan->ports, range.begin, range.end);
-        masscan_set_parameter(masscan, "router-mac", "ff-ff-ff-ff-ff-ff");
-        masscan->is_arp = 1; /* needs additional flag */
-        LOG(5, "--arpscan\n");
-    } else if (EQUALS("noreset", name)) {
-        if (value && value[0])
-            masscan->is_noreset = parseBoolean(value);
-        else
-            masscan->is_noreset = 1;
     } else if (EQUALS("bpf", name)) {
         size_t len = strlen(value) + 1;
         if (masscan->bpf_filter)
             free(masscan->bpf_filter);
         masscan->bpf_filter = (char*)malloc(len);
         memcpy(masscan->bpf_filter, value, len);
-    } else if (EQUALS("hello", name)) {
-        if (EQUALS("ssl", value))
-            masscan->is_hello_ssl = 1;
-        else {
-            fprintf(stderr, "FAIL: %s: unknown hello type\n", value);
-            exit(1);
-        }
-    } else if (EQUALS("capture", name)) {
-        if (EQUALS("cert", value))
-            masscan->is_capture_cert = 1;
-        else if (EQUALS("html", value))
-            masscan->is_capture_html = 1;
-        else if (EQUALS("heartbleed", value))
-            masscan->is_capture_heartbleed = 1;
-        else if (EQUALS("ticketbleed", value))
-            masscan->is_capture_ticketbleed = 1;
-        else {
-            fprintf(stderr, "FAIL: %s: unknown capture type\n", value);
-            exit(1);
-        }
-    } else if (EQUALS("nocapture", name)) {
-        if (EQUALS("cert", value))
-            masscan->is_capture_cert = 0;
-        else if (EQUALS("html", value))
-            masscan->is_capture_html = 0;
-        else if (EQUALS("heartbleed", value))
-            masscan->is_capture_heartbleed = 0;
-        else if (EQUALS("ticketbleed", value))
-            masscan->is_capture_ticketbleed = 0;
-        else {
-            fprintf(stderr, "FAIL: %s: unknown capture type\n", value);
-            exit(1);
-        }
     } else if (EQUALS("ping", name) || EQUALS("ping-sweep", name)) {
         /* Add ICMP ping request */
         struct Range range;
         range.begin = Templ_ICMP_echo;
         range.end = Templ_ICMP_echo;
         rangelist_add_range(&masscan->ports, range.begin, range.end);
+        masscan->scan_type.ping = 1;
         LOG(5, "--ping\n");
     } else if (EQUALS("range", name) || EQUALS("ranges", name)
                || EQUALS("ip", name) || EQUALS("ipv4", name)
@@ -1343,27 +1757,16 @@ masscan_set_parameter(struct Masscan *masscan,
         }
         if (masscan->op == 0)
             masscan->op = Operation_Scan;
-    } else if (EQUALS("append-output", name) || EQUALS("output-append", name)) {
-        if (EQUALS("overwrite", name))
-            masscan->output.is_append = 0;
-        else
-            masscan->output.is_append = 1;
     } else if (EQUALS("badsum", name)) {
         masscan->nmap.badsum = 1;
     } else if (EQUALS("banner1", name)) {
         banner1_test(value);
         exit(1);
-    } else if (EQUALS("banners", name) || EQUALS("banner", name)) {
-        masscan->is_banners = 1;
-    } else if (EQUALS("nobanners", name) || EQUALS("nobanner", name)) {
-        masscan->is_banners = 0;
     } else if (EQUALS("blackrock-rounds", name)) {
         masscan->blackrock_rounds = (unsigned)parseInt(value);
     } else if (EQUALS("connection-timeout", name) || EQUALS("tcp-timeout", name)) {
-        /* The timeout for "banners" TCP connections */
+        /* The timeout for banners TCP connections */
         masscan->tcp_connection_timeout = (unsigned)parseInt(value);
-    } else if (EQUALS("hello-timeout", name)) {
-        masscan->tcp_hello_timeout = (unsigned)parseInt(value);
     } else if (EQUALS("datadir", name)) {
         strcpy_s(masscan->nmap.datadir, sizeof(masscan->nmap.datadir), value);
     } else if (EQUALS("data-length", name)) {
@@ -1381,8 +1784,8 @@ masscan_set_parameter(struct Masscan *masscan,
         fprintf(stderr, "nmap(%s): unsupported: DNS lookups too synchronous\n",
                 name);
         exit(1);
-    } else if (EQUALS("echo", name)) {
-        masscan_echo(masscan, stdout);
+    } else if (EQUALS("echo", name) || EQUALS("echo-all", name)) {
+        masscan_echo(masscan, stdout, EQUALS("echo-all", name));
         exit(0);
     } else if (EQUALS("excludefile", name)) {
         unsigned count1 = masscan->exclude_ip.count;
@@ -1403,51 +1806,6 @@ masscan_set_parameter(struct Masscan *masscan,
         masscan_set_parameter(masscan, "no-capture", "cert");
         masscan_set_parameter(masscan, "no-capture", "ticketbleed");
         masscan_set_parameter(masscan, "banners", "true");
-    } else if (EQUALS("hello-file", name)) {
-        /* When connecting via TCP, send this file */
-        FILE *fp;
-        int x;
-        char buf[16384];
-        char buf2[16384];
-        size_t bytes_read;
-        size_t bytes_encoded;
-        char foo[64];
-
-        x = fopen_s(&fp, value, "rb");
-        if (x != 0) {
-            LOG(0, "[FAILED] could not read hello file\n");
-            perror(value);
-            exit(1);
-        }
-
-        bytes_read = fread(buf, 1, sizeof(buf), fp);
-        if (bytes_read == 0) {
-            LOG(0, "[FAILED] could not read hello file\n");
-            perror(value);
-            fclose(fp);
-            exit(1);
-        }
-        fclose(fp);
-
-        bytes_encoded = base64_encode(buf2, sizeof(buf2)-1, buf, bytes_read);
-        buf2[bytes_encoded] = '\0';
-
-        sprintf_s(foo, sizeof(foo), "hello-string[%u]", (unsigned)index);
-
-        masscan_set_parameter(masscan, foo, buf2);
-    } else if (EQUALS("hello-string", name)) {
-        char *value2;
-        struct TcpCfgPayloads *pay;
-
-        value2 = (char*)malloc(strlen(value)+1);
-        memcpy(value2, value, strlen(value)+1);
-
-        pay = (struct TcpCfgPayloads *)malloc(sizeof(*pay));
-        
-        pay->payload_base64 = value2;
-        pay->port = index;
-        pay->next = masscan->tcp_payloads;
-        masscan->tcp_payloads = pay;
     } else if (EQUALS("host-timeout", name)) {
         fprintf(stderr, "nmap(%s): unsupported: this is an asynchronous tool, so no timeouts\n", name);
         exit(1);
@@ -1515,12 +1873,6 @@ masscan_set_parameter(struct Masscan *masscan,
     } else if (EQUALS("log-errors", name)) {
         fprintf(stderr, "nmap(%s): unsupported: maybe soon\n", name);
         exit(1);
-    } else if (EQUALS("min-packet", name) || EQUALS("min-pkt", name)) {
-        masscan->min_packet_size = (unsigned)parseInt(value);
-    } else if (EQUALS("max-retries", name)) {
-        masscan_set_parameter(masscan, "retries", value);
-    } else if (EQUALS("max-rate", name)) {
-        masscan_set_parameter(masscan, "rate", value);
     } else if (EQUALS("min-hostgroup", name) || EQUALS("max-hostgroup", name)) {
         fprintf(stderr, "nmap(%s): unsupported: we randomize all the groups!\n", name);
         exit(1);
@@ -1559,92 +1911,12 @@ masscan_set_parameter(struct Masscan *masscan,
         /* Run in "offline" mode where it thinks it's sending packets, but
          * it's not */
         masscan->is_offline = 1;
-    } else if (EQUALS("open", name) || EQUALS("open-only", name)) {
-        masscan->output.is_show_open = 1;
-        masscan->output.is_show_closed = 0;
-        masscan->output.is_show_host = 0;
-    } else if (EQUALS("output-status", name) || EQUALS("show", name)) {
-        for (;;) {
-            const char *val2 = value;
-            unsigned val2_len = INDEX_OF(val2, ',');
-            if (val2_len == 0)
-                break;
-            if (EQUALSx("open", val2, val2_len))
-                masscan->output.is_show_open = 1;
-            else if (EQUALSx("closed", val2, val2_len) || EQUALSx("close", val2, val2_len))
-                masscan->output.is_show_closed = 1;
-            else if (EQUALSx("open", val2, val2_len))
-                masscan->output.is_show_host = 1;
-            else if (EQUALSx("all",val2,val2_len)) {
-                masscan->output.is_show_open = 1;
-                masscan->output.is_show_host = 1;
-                masscan->output.is_show_closed = 1;
-            }
-            else {
-                LOG(0, "FAIL: unknown 'show' spec: %.*s\n", val2_len, val2);
-                exit(1);
-            }
-            value += val2_len;
-            while (*value == ',')
-                value++;
-        }
-    } else if (EQUALS("noshow", name)) {
-        for (;;) {
-            const char *val2 = value;
-            unsigned val2_len = INDEX_OF(val2, ',');
-            if (val2_len == 0)
-                break;
-            if (EQUALSx("open", val2, val2_len))
-                masscan->output.is_show_open = 0;
-            else if (EQUALSx("closed", val2, val2_len) || EQUALSx("close", val2, val2_len))
-                masscan->output.is_show_closed = 0;
-            else if (EQUALSx("open", val2, val2_len))
-                masscan->output.is_show_host = 0;
-            else {
-                LOG(0, "FAIL: unknown 'show' spec: %.*s\n", val2_len, val2);
-                exit(1);
-            }
-            value += val2_len;
-            while (*value == ',')
-                value++;
-        }
     } else if (EQUALS("osscan-limit", name)) {
         fprintf(stderr, "nmap(%s): OS scanning unsupported\n", name);
         exit(1);
     } else if (EQUALS("osscan-guess", name)) {
         fprintf(stderr, "nmap(%s): OS scanning unsupported\n", name);
         exit(1);
-    } else if (EQUALS("output-format", name)) {
-        enum OutputFormat x = 0;
-        if (EQUALS("unknown(0)", value)) {
-            x = Output_Interactive;
-        }
-        else if (EQUALS("interactive", value))  x = Output_Interactive;
-        else if (EQUALS("list", value))         x = Output_List;
-        else if (EQUALS("unicornscan", value))  x = Output_Unicornscan;
-        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("ndjson", value))       x = Output_NDJSON;
-        else if (EQUALS("certs", value))        x = Output_Certs;
-        else if (EQUALS("none", value))         x = Output_None;
-        else if (EQUALS("redis", value))        x = Output_Redis;
-        else {
-            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->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)) {
         masscan->nmap.packet_trace = 1;
     } else if (EQUALS("privileged", name) || EQUALS("unprivileged", name)) {
@@ -1655,9 +1927,6 @@ masscan_set_parameter(struct Masscan *masscan,
     } else if (EQUALS("port-ratio", name)) {
         fprintf(stderr, "nmap(%s): unsupported\n", name);
         exit(1);
-    } else if (EQUALS("randomize-hosts", name)) {
-        /* already do that */
-        ;
     } else if (EQUALS("readrange", name) || EQUALS("readranges", name)) {
         masscan->op = Operation_ReadRange;
     } else if (EQUALS("reason", name)) {
@@ -1696,34 +1965,6 @@ masscan_set_parameter(struct Masscan *masscan,
     } else if (EQUALS("resume", name)) {
         masscan_read_config_file(masscan, value);
         masscan_set_parameter(masscan, "output-append", "true");
-    } else if (EQUALS("resume-index", name)) {
-        masscan->resume.index = parseInt(value);
-    } else if (EQUALS("resume-count", name)) {
-        masscan->resume.count = parseInt(value);
-    } else if (EQUALS("retries", name) || EQUALS("retry", name)) {
-        unsigned x = (unsigned)strtoul(value, 0, 0);
-        if (x >= 1000) {
-            fprintf(stderr, "error: retries=<n>: expected number less than 1000\n");
-        } else {
-            masscan->retries = x;
-        }
-    } else if (EQUALS("rotate-output", name) || EQUALS("rotate", name) 
-        || EQUALS("ouput-rotate", name) || EQUALS("rotate-time", name) ) {
-        masscan->output.rotate.timeout = (unsigned)parseTime(value);
-    } else if (EQUALS("rotate-offset", name) || EQUALS("ouput-rotate-offset", name)) {
-        masscan->output.rotate.offset = (unsigned)parseTime(value);
-    } else if (EQUALS("rotate-size", name) || EQUALS("rotate-filesize", name)) {
-        masscan->output.rotate.filesize = parseSize(value);
-    } else if (EQUALS("rotate-dir", name) || EQUALS("rotate-directory", name) || EQUALS("ouput-rotate-dir", name)) {
-        char *p;
-        strcpy_s(   masscan->output.rotate.directory,
-                    sizeof(masscan->output.rotate.directory),
-                    value);
-
-        /* strip trailing slashes */
-        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)) {
         if (EQUALS("heartbleed", value)) {
             masscan_set_parameter(masscan, "heartbleed", "true");
@@ -1762,11 +2003,6 @@ masscan_set_parameter(struct Masscan *masscan,
     } else if (EQUALS("scanflags", name)) {
         fprintf(stderr, "nmap(%s): TCP scan flags not yet supported\n", name);
         exit(1);
-    } else if (EQUALS("seed", name)) {
-        if (EQUALS("time", value))
-            masscan->seed = time(0);
-        else
-            masscan->seed = parseInt(value);
     } else if (EQUALS("sendq", name) || EQUALS("sendqueue", name)) {
         masscan->is_sendq = 1;
     } else if (EQUALS("send-eth", name)) {
@@ -1782,31 +2018,6 @@ masscan_set_parameter(struct Masscan *masscan,
         return;
     } else if (EQUALS("source-port", name) || EQUALS("sourceport", name)) {
         masscan_set_parameter(masscan, "adapter-port", value);
-    } else if (EQUALS("shard", name) || EQUALS("shards", name)) {
-        unsigned one = 0;
-        unsigned of = 0;
-
-        while (isdigit(*value))
-            one = one*10 + (*(value++)) - '0';
-        while (ispunct(*value))
-            value++;
-        while (isdigit(*value))
-            of = of*10 + (*(value++)) - '0';
-
-        if (one < 1) {
-            LOG(0, "FAIL: shard index can't be zero\n");
-            LOG(0, "hint   it goes like 1/4 2/4 3/4 4/4\n");
-            exit(1);
-        }
-        if (one > of) {
-            LOG(0, "FAIL: shard spec is wrong\n");
-            LOG(0, "hint   it goes like 1/4 2/4 3/4 4/4\n");
-            exit(1);
-        }
-
-        masscan->shard.one = one;
-        masscan->shard.of = of;
-
     } else if (EQUALS("nobacktrace", name) || EQUALS("backtrace", name)) {
         ;
     } else if (EQUALS("no-stylesheet", name)) {
@@ -1867,6 +2078,7 @@ masscan_set_parameter(struct Masscan *masscan,
         masscan_set_parameter(masscan, "stylesheet", "http://nmap.org/svn/docs/nmap.xsl");
     } else {
         fprintf(stderr, "CONF: unknown config option: %s=%s\n", name, value);
+        exit(1);
     }
 }
 
@@ -1878,7 +2090,7 @@ static int
 is_singleton(const char *name)
 {
     static const char *singletons[] = {
-        "echo", "selftest", "self-test", "regress",
+        "echo", "echo-all", "selftest", "self-test", "regress",
         "benchmark",
         "system-dns", "traceroute", "version",
         "version-light",
@@ -1888,12 +2100,10 @@ is_singleton(const char *name)
         "packet-trace", "release-memory",
         "log-errors", "append-output", "webxml", "no-stylesheet",
         "no-stylesheet", "heartbleed", "ticketbleed",
-        "send-eth", "send-ip", "iflist", "randomize-hosts",
+        "send-eth", "send-ip", "iflist",
         "nmap", "trace-packet", "pfring", "sendq",
-        "banners", "banner", "nobanners", "nobanner",
         "offline", "ping", "ping-sweep", "nobacktrace", "backtrace",
-        "arp",  "infinite", "nointeractive", "interactive", "status", "nostatus",
-        "arpscan", "noreset", 
+        "infinite", "nointeractive", "interactive", "status", "nostatus",
         "read-range", "read-ranges", "readrange", "read-ranges",
         0};
     size_t i;
@@ -1902,6 +2112,20 @@ is_singleton(const char *name)
         if (EQUALS(singletons[i], name))
             return 1;
     }
+    
+    for (i=0; config_parameters[i].name; i++) {
+        if (EQUALS(config_parameters[i].name, name)) {
+            return (config_parameters[i].flags & F_BOOL) == F_BOOL;
+        } else {
+            size_t j;
+            for (j=0; config_parameters[i].alts[j]; j++) {
+                if (EQUALS(config_parameters[i].alts[j], name)) {
+                    return (config_parameters[i].flags & F_BOOL) == F_BOOL;
+                }
+            }
+        }
+    }
+    
     return 0;
 }
 
@@ -2326,6 +2550,133 @@ masscan_command_line(struct Masscan *masscan, int argc, char *argv[])
     }
 }
 
+/***************************************************************************
+ * Prints the current configuration to the command-line then exits.
+ * Use#1: create a template file of all setable parameters.
+ * Use#2: make sure your configuration was interpreted correctly.
+ ***************************************************************************/
+static void
+masscan_echo(struct Masscan *masscan, FILE *fp, unsigned is_echo_all)
+{
+    unsigned i;
+    unsigned l = 0;
+    
+    /*
+     * NEW:
+     * Print all configuration parameters
+     */
+    masscan->echo = fp;
+    masscan->echo_all = is_echo_all;
+    for (i=0; config_parameters[i].name; i++) {
+        config_parameters[i].set(masscan, 0, 0);
+    }
+    masscan->echo = 0;
+    masscan->echo_all = 0;
+    
+    /*
+     * OLD:
+     * Things here below are the old way of echoing parameters.
+     * TODO: cleanup this code, replacing with the new way.
+     */
+    if (masscan->nic_count == 0)
+        masscan_echo_nic(masscan, fp, 0);
+    else {
+        for (i=0; i<masscan->nic_count; i++)
+            masscan_echo_nic(masscan, fp, i);
+    }
+    
+    
+    /*
+     * Targets
+     */
+    fprintf(fp, "# TARGET SELECTION (IP, PORTS, EXCLUDES)\n");
+    fprintf(fp, "ports = ");
+    /* Disable comma generation for the first element */
+    l = 0;
+    for (i=0; i<masscan->ports.count; i++) {
+        struct Range range = masscan->ports.list[i];
+        do {
+            struct Range rrange = range;
+            unsigned done = 0;
+            if (l)
+                fprintf(fp, ",");
+            l = 1;
+            if (rrange.begin >= Templ_ICMP_echo) {
+                rrange.begin -= Templ_ICMP_echo;
+                rrange.end -= Templ_ICMP_echo;
+                fprintf(fp,"I:");
+                done = 1;
+            } else if (rrange.begin >= Templ_SCTP) {
+                rrange.begin -= Templ_SCTP;
+                rrange.end -= Templ_SCTP;
+                fprintf(fp,"S:");
+                range.begin = Templ_ICMP_echo;
+            } else if (rrange.begin >= Templ_UDP) {
+                rrange.begin -= Templ_UDP;
+                rrange.end -= Templ_UDP;
+                fprintf(fp,"U:");
+                range.begin = Templ_SCTP;
+            } else
+                range.begin = Templ_UDP;
+            rrange.end = min(rrange.end, 65535);
+            if (rrange.begin == rrange.end)
+                fprintf(fp, "%u", rrange.begin);
+            else
+                fprintf(fp, "%u-%u", rrange.begin, rrange.end);
+            if (done)
+                break;
+        } while (range.begin <= range.end);
+    }
+    fprintf(fp, "\n");
+    for (i=0; i<masscan->targets.count; i++) {
+        struct Range range = masscan->targets.list[i];
+        fprintf(fp, "range = ");
+        fprintf(fp, "%u.%u.%u.%u",
+                (range.begin>>24)&0xFF,
+                (range.begin>>16)&0xFF,
+                (range.begin>> 8)&0xFF,
+                (range.begin>> 0)&0xFF
+                );
+        if (range.begin != range.end) {
+            unsigned cidr_bits = count_cidr_bits(range);
+            
+            if (cidr_bits) {
+                fprintf(fp, "/%u", cidr_bits);
+            } else
+                fprintf(fp, "-%u.%u.%u.%u",
+                        (range.end>>24)&0xFF,
+                        (range.end>>16)&0xFF,
+                        (range.end>> 8)&0xFF,
+                        (range.end>> 0)&0xFF
+                        );
+        }
+        fprintf(fp, "\n");
+    }
+    
+    fprintf(fp, "\n");
+    if (masscan->http_user_agent)
+        fprintf(    fp,
+                "http-user-agent = %.*s\n",
+                masscan->http_user_agent_length,
+                masscan->http_user_agent);
+    
+    for (i=0; i<sizeof(masscan->http_headers)/sizeof(masscan->http_headers[0]); i++) {
+        if (masscan->http_headers[i].header_name == 0)
+            continue;
+        fprintf(    fp,
+                "http-header[%s] = %.*s\n",
+                masscan->http_headers[i].header_name,
+                masscan->http_headers[i].header_value_length,
+                masscan->http_headers[i].header_value);
+    }
+    
+    
+    
+    
+    
+}
+
+
 /***************************************************************************
  * remove leading/trailing whitespace
  ***************************************************************************/
diff --git a/src/main.c b/src/main.c
index 750a497..0df770a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -786,7 +786,7 @@ receive_thread(void *v)
                      * than port scanning them */
 
                     /* If we aren't doing an ARP scan, then ignore ARP responses */
-                    if (!masscan->is_arp)
+                    if (!masscan->scan_type.arp)
                         break;
 
                     /* If this response isn't in our range, then ignore it */
diff --git a/src/masscan.h b/src/masscan.h
index e9554ee..b6d19da 100644
--- a/src/masscan.h
+++ b/src/masscan.h
@@ -42,6 +42,7 @@ enum Operation {
  * outputing simultaneously.
  */
 enum OutputFormat {
+    Output_Default      = 0x0000,
     Output_Interactive  = 0x0001,   /* --interactive, print to cmdline */
     Output_List         = 0x0002,
     Output_Binary       = 0x0004,   /* -oB, "binary", the primary format */
@@ -100,14 +101,21 @@ struct Masscan
         unsigned tcp:1;
         unsigned udp:1;
         unsigned sctp:1;
-        unsigned ping:1;
-        unsigned arp:1; /*TODO*/
+        unsigned ping:1; /* --ping, ICMP echo */
+        unsigned arp:1; /* --arp, local ARP scan */
     } scan_type;
     
     /**
      * After scan type has been configured, add these ports
      */
     unsigned top_ports;
+    
+    /**
+     * Temporary file to echo parameters to, used for saving configuration
+     * to a file
+     */
+    FILE *echo;
+    unsigned echo_all;
 
     /**
      * One or more network adapters that we'll use for scanning. Each adapter
@@ -123,7 +131,7 @@ struct Masscan
         unsigned char router_mac[6];
         unsigned router_ip;
         int link_type; /* libpcap definitions */
-        unsigned char my_mac_count;
+        unsigned char my_mac_count; /*is there a MAC address? */
         unsigned vlan_id;
         unsigned is_vlan:1;
     } nic[8];
@@ -180,8 +188,7 @@ struct Masscan
     unsigned is_sendq:1;        /* --sendq */
     unsigned is_banners:1;      /* --banners */
     unsigned is_offline:1;      /* --offline */
-    unsigned is_arp:1;          /* --arp */
-    unsigned is_noreset:1;      /* --noreset */
+    unsigned is_noreset:1;      /* --noreset, don't transmit RST */
     unsigned is_gmt:1;          /* --gmt, all times in GMT */
     unsigned is_capture_cert:1; /* --capture cert */
     unsigned is_capture_html:1; /* --capture html */
-- 
GitLab