Commit 239850cc authored by Robert David Graham's avatar Robert David Graham
Browse files

cleanup

parent e40218cf
Loading
Loading
Loading
Loading
+57 −47
Original line number Diff line number Diff line
@@ -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;
@@ -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);

    /*
@@ -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)) {
@@ -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);
@@ -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);
@@ -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)) {
@@ -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;
@@ -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)) {
@@ -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)) {
@@ -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);
@@ -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");
+2 −3
Original line number Diff line number Diff line
@@ -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 */
@@ -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;

+176 −59
Original line number Diff line number Diff line
@@ -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];
@@ -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;
@@ -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;


    /**
+15 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
        }

@@ -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 {
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ struct Output
        time_t last;
        unsigned period;
        unsigned offset;
        size_t filesize;
        char *directory;
    } rotate;