Пример #1
0
void
throttler_start(struct Throttler *throttler, double max_rate)
{
    unsigned i;

    memset(throttler, 0, sizeof(*throttler));

    throttler->max_rate = max_rate;

    for (i=0; i<sizeof(throttler->buckets)/sizeof(throttler->buckets[0]); i++) {
        throttler->buckets[i].timestamp = pixie_gettime();
        throttler->buckets[i].packet_count = 0;
    }

    throttler->batch_size = 1;

    LOG(1, "maxrate = %0.2f\n", throttler->max_rate);
}
Пример #2
0
/***************************************************************************
 * Print a status message about once-per-second to the command-line. This
 * algorithm is a little funky because checking the timestamp on EVERY
 * packet is slow.
 ***************************************************************************/
void
status_print(
    struct Status *status, 
    uint64_t count, 
    uint64_t max_count, 
    double x)
{
    double elapsed_time;
    double rate;
    double now;
    double percent_done;
    double time_remaining;

    /*
     * ####  FUGGLY TIME HACK  ####
     *
     * PF_RING doesn't timestamp packets well, so we can't base time from
     * incoming packets. Checking the time ourself is too ugly on per-packet
     * basis. Therefore, we are going to create a global variable that keeps
     * the time, and update that variable whenever it's convienient. This
     * is one of those convenient places.
     */
    global_now = time(0);


    /* Get the time. NOTE: this is CLOCK_MONOTONIC_RAW on Linux, not
     * wall-clock time. */
    now = (double)pixie_gettime();

    /* Figure how many SECONDS have elapsed, in a floating point value.
     * Since the above timestamp is in microseconds, we need to 
     * shift it by 1-million
     */
    elapsed_time = (now - status->last.clock)/1000000.0;
    if (elapsed_time == 0)
        return;

    /* Figure out the "packets-per-second" number, which is just:
     *
     *  rate = packets_sent / elapsed_time;
     */
    rate = (count - status->last.count)*1.0/elapsed_time;

    /*
     * Smooth the number by averaging over the last 8 seconds 
     */
     status->last_rates[status->last_count++ & 0x7] = rate;
     rate =     status->last_rates[0]
                + status->last_rates[1]
                + status->last_rates[2]
                + status->last_rates[3]
                + status->last_rates[4]
                + status->last_rates[5]
                + status->last_rates[6]
                + status->last_rates[7]
                ;
    rate /= 8;
    if (rate == 0)
        return;

    /*
     * Calculate "percent-done", which is just the total number of
     * packets sent divided by the number we need to send.
     */
    percent_done = (double)(count*100.0/max_count);


    /*
     * Calulate the time remaining in the scan
     */
    time_remaining  = (1.0 - percent_done/100.0) * (max_count / rate);


    /*
     * Print the message to <stderr> so that <stdout> can be redirected
     * to a file (<stdout> reports what systems were found).
     */
    fprintf(stderr, "rate:%6.2f-kpps, %5.2f%% done,%4u:%02u:%02u remaining, %llu-tcbs,     \r",
                    x/1000.0,
                    percent_done,
                    (unsigned)(time_remaining/60/60),
                    (unsigned)(time_remaining/60)%60,
                    (unsigned)(time_remaining)%60,
                    global_tcb_count
                    //(unsigned)rate
                    );
    fflush(stderr);

    /*
     * Remember the values to be diffed against the next time around
     */
    status->last.clock = now;
    status->last.count = count;
}
Пример #3
0
struct Adapter *
rawsock_init_adapter(const char *adapter_name,
                     unsigned is_pfring,
                     unsigned is_sendq,
                     unsigned is_packet_trace,
                     unsigned is_offline,
                     const char *bpf_filter,
                     unsigned is_vlan,
                     unsigned vlan_id)
{
    struct Adapter *adapter;
    char errbuf[PCAP_ERRBUF_SIZE];

    adapter = (struct Adapter *)malloc(sizeof(*adapter));
    if (adapter == NULL)
        exit(1);
    memset(adapter, 0, sizeof(*adapter));
    adapter->is_packet_trace = is_packet_trace;
    adapter->pt_start = 1.0 * pixie_gettime() / 1000000.0;

    adapter->is_vlan = is_vlan;
    adapter->vlan_id = vlan_id;
    
    if (is_offline)
        return adapter;

    /*----------------------------------------------------------------
     * PORTABILITY: WINDOWS
     * If is all digits index, then look in indexed list
     *----------------------------------------------------------------*/
    if (is_numeric_index(adapter_name)) {
        const char *new_adapter_name;

        new_adapter_name = adapter_from_index(atoi(adapter_name));
        if (new_adapter_name == 0) {
            fprintf(stderr, "pcap_open_live(%s) error: bad index\n",
                    adapter_name);
            return 0;
        } else
            adapter_name = new_adapter_name;
    }

    /*----------------------------------------------------------------
     * PORTABILITY: PF_RING
     *  If we've been told to use --pfring, then attempt to open the
     *  network adapter usign the PF_RING API rather than libpcap.
     *  Since a lot of things can go wrong, we do a lot of extra
     *  logging here.
     *----------------------------------------------------------------*/
    if (is_pfring || is_pfring_dna(adapter_name)) {
        int err;
        unsigned version;

        /*
         * Open
         *
         * TODO: Do we need the PF_RING_REENTRANT flag? We only have one
         * transmit and one receive thread, so I don't think we need it.
         * Also, this reduces performance in half, from 12-mpps to
         * 6-mpps.
         * NOTE: I don't think it needs the "re-entrant" flag, because it
         * transmit and receive are separate functions?
         */
        LOG(2, "pfring:'%s': opening...\n", adapter_name);
        adapter->ring = PFRING.open(adapter_name, 1500, 0);//PF_RING_REENTRANT);
        adapter->pcap = (pcap_t*)adapter->ring;
        adapter->link_type = 1;
        if (adapter->ring == NULL) {
            LOG(0, "pfring:'%s': OPEN ERROR: %s\n",
                adapter_name, strerror_x(errno));
            return 0;
        } else
            LOG(1, "pfring:'%s': successfully opened\n", adapter_name);

        /*
         * Housekeeping
         */
        PFRING.set_application_name(adapter->ring, "masscan");
        PFRING.version(adapter->ring, &version);
        LOG(1, "pfring: version %d.%d.%d\n",
                (version >> 16) & 0xFFFF,
                (version >> 8) & 0xFF,
                (version >> 0) & 0xFF);

        LOG(2, "pfring:'%s': setting direction\n", adapter_name);
        err = PFRING.set_direction(adapter->ring, rx_only_direction);
        if (err) {
            fprintf(stderr, "pfring:'%s': setdirection = %d\n",
                    adapter_name, err);
        } else
            LOG(2, "pfring:'%s': direction success\n", adapter_name);

        /*
         * Activate
         *
         * PF_RING requires a separate activation step.
         */
        LOG(2, "pfring:'%s': activating\n", adapter_name);
        err = PFRING.enable_ring(adapter->ring);
        if (err != 0) {
                LOG(0, "pfring: '%s': ENABLE ERROR: %s\n",
                    adapter_name, strerror_x(errno));
                PFRING.close(adapter->ring);
                adapter->ring = 0;
                return 0;
        } else
            LOG(1, "pfring:'%s': successfully enabled\n", adapter_name);

        return adapter;
    }
Пример #4
0
/***************************************************************************
 * We return the number of packets that can be sent in a batch. Thus,
 * instead of trying to throttle each packet individually, which has a
 * high per-packet cost, we try to throttle a bunch at a time. Normally,
 * this function will return 1, only at high rates does it return larger
 * numbers.
 *
 * NOTE: The minimum value this returns is 1. When it's less than that,
 * it'll pause and wait until it's ready to send a packet.
 ***************************************************************************/
uint64_t
throttler_next_batch(struct Throttler *throttler, uint64_t packet_count)
{
    uint64_t timestamp;
    uint64_t index;
    uint64_t old_timestamp;
    uint64_t old_packet_count;
    double current_rate;
    double max_rate = throttler->max_rate;

again:

    /* NOTE: this uses CLOCK_MONOTONIC_RAW on Linux, so the timstamp doesn't
     * move forward when the machine is suspended */
    timestamp = pixie_gettime();

    /*
     * We record that last 256 buckets, and average the rate over all of
     * them.
     */
    index = (throttler->index) & 0xFF;
    throttler->buckets[index].timestamp = timestamp;
    throttler->buckets[index].packet_count = packet_count;

    index = (++throttler->index) & 0xFF;
    old_timestamp = throttler->buckets[index].timestamp;
    old_packet_count = throttler->buckets[index].packet_count;

    /*
     * If the delay is more than 1-second, then we should reset the system
     * in order to avoid transmittting too fast.
     */
    if (timestamp - old_timestamp > 1000000) {
        //throttler_start(throttler, throttler->max_rate);
        throttler->batch_size = 1;
        goto again;
    }

    /*
     * Calculate the recent rate.
     * NOTE: this isn't the rate "since start", but only the "recent" rate.
     * That's so that if the system pauses for a while, we don't flood the
     * network trying to catch up.
     */
    current_rate = 1.0*(packet_count - old_packet_count)/((timestamp - old_timestamp)/1000000.0);

    
    /*
     * If we've been going too fast, then <pause> for a moment, then
     * try again.
     */
    if (current_rate > max_rate) {
        double waittime;

        /* calculate waittime, in seconds */
        waittime = (current_rate - max_rate) / throttler->max_rate;

        /* At higher rates of speed, we don't actually need to wait the full
         * interval. It's better to have a much smaller interval, so that
         * we converge back on the true rate faster */
        waittime *= 0.1;

        /* This is in case of gross failure of the system. This should never
         * actually happen, unless there is a bug. Really, I ought to make
         * this an 'assert()' instead to fail and fix the bug rather than
         * silently continueing, but I'm too lazy */
        if (waittime > 0.1)
            waittime = 0.1;

        /* Since we've exceeded the speed limit, we should reduce the 
         * batch size slightly. We don't do it only by a little bit to
         * avoid over-correcting. We want to converge on the correct
         * speed gradually. Note that since this happens hundres or
         * thousands of times a second, the convergence is very fast
         * even with 0.1% adjustment */
        throttler->batch_size *= 0.999;

        /* Now we wait for a bit */
        pixie_usleep((uint64_t)(waittime * 1000000.0));

        /* There are two choices here. We could either return immediately,
         * or we can loop around again. Right now, the code loops around
         * again in order to support very slow rates, such as 0.5 packets
         * per second. Nobody would want to run a scanner that slowly of
         * course, but it's great for testing */
        //return (uint64_t)throttler->batch_size;
        goto again;
    }

    /*
     * Calculate how many packets are needed to catch up again to the current
     * rate, and return that.
     *
     * NOTE: this is almost always going to have the value of 1 (one). Only at
     * very high speeds (above 100,000 packets/second) will this value get
     * larger.
     */
    throttler->batch_size *= 1.005;
    if (throttler->batch_size > 10000)
        throttler->batch_size = 10000;
    throttler->current_rate = current_rate;

    throttler->test_timestamp = timestamp;
    throttler->test_packet_count = packet_count;
    return (uint64_t)throttler->batch_size;
}
Пример #5
0
/***************************************************************************
 * Print packet info, when using nmap-style --packet-trace option
 ***************************************************************************/
void
packet_trace(FILE *fp, const unsigned char *px, size_t length, unsigned is_sent)
{
    unsigned x;
    struct PreprocessedInfo parsed;
    unsigned src_ip;
    unsigned dst_ip;
    char from[32];
    char to[32];
    char sz_type[32];
    unsigned type;
    double timestamp = 1.0 * pixie_gettime() / 1000000.0;
    unsigned offset;
    const char *direction;
    
    if (is_sent)
        direction = "SENT";
    else
        direction = "RCVD";

    /* parse the packet */
    x = preprocess_frame(px, (unsigned)length, 1, &parsed);
    if (!x)
        return;
    offset = parsed.found_offset;
    
    src_ip = parsed.ip_src[0] << 24
        | parsed.ip_src[1] << 16
        | parsed.ip_src[2] << 8
        | parsed.ip_src[3];
    dst_ip = parsed.ip_dst[0] << 24
        | parsed.ip_dst[1] << 16
        | parsed.ip_dst[2] << 8
        | parsed.ip_dst[3];

    /* format the IP addresses into fixed-width fields */
    sprintf_s(from, sizeof(from), "%u.%u.%u.%u:%u",
              (src_ip>>24)&0xFF, (src_ip>>16)&0xFF,
              (src_ip>>8)&0xFF, (src_ip>>0)&0xFF,
              parsed.port_src);
    
    sprintf_s(to, sizeof(to), "%u.%u.%u.%u:%u",
              (dst_ip>>24)&0xFF, (dst_ip>>16)&0xFF,
              (dst_ip>>8)&0xFF, (dst_ip>>0)&0xFF,
              parsed.port_dst);
    
    switch (parsed.found) {
        case FOUND_ARP:
            type = px[offset+6]<<8 | px[offset+7];
			*strchr(to, ':') = '\0';
			*strchr(from, ':') = '\0';
            switch (type) {
                case 1:strcpy_s(sz_type, sizeof(sz_type), "request"); break;
                case 2:strcpy_s(sz_type, sizeof(sz_type), "response"); break;
                default: sprintf_s(sz_type, sizeof(sz_type), "unknown(%u)", type); break;
            }
            fprintf(fp, "%s (%5.4f) ARP  %-21s > %-21s %s\n", direction,
                    timestamp - global_timestamp_start, from, to, sz_type);
            break;
        case FOUND_DNS:
        case FOUND_UDP:
            fprintf(fp, "%s (%5.4f) UDP  %-21s > %-21s \n", direction,
                    timestamp - global_timestamp_start, from, to);
            break;
        case FOUND_ICMP:
            fprintf(fp, "%s (%5.4f) ICMP %-21s > %-21s \n", direction,
                    timestamp - global_timestamp_start, from, to);
            break;
        case FOUND_TCP:
            type = px[offset+13];
            switch (type) {
                case 0x00: strcpy_s(sz_type, sizeof(sz_type), "NULL"); break;
                case 0x01: strcpy_s(sz_type, sizeof(sz_type), "FIN"); break;
                case 0x11: strcpy_s(sz_type, sizeof(sz_type), "FIN-ACK"); break;
                case 0x19: strcpy_s(sz_type, sizeof(sz_type), "FIN-ACK-PSH"); break;
                case 0x02: strcpy_s(sz_type, sizeof(sz_type), "SYN"); break;
                case 0x12: strcpy_s(sz_type, sizeof(sz_type), "SYN-ACK"); break;
                case 0x04: strcpy_s(sz_type, sizeof(sz_type), "RST"); break;
                case 0x14: strcpy_s(sz_type, sizeof(sz_type), "RST-ACK"); break;
                case 0x15: strcpy_s(sz_type, sizeof(sz_type), "RST-FIN-ACK"); break;
                case 0x10: strcpy_s(sz_type, sizeof(sz_type), "ACK"); break;
                case 0x18: strcpy_s(sz_type, sizeof(sz_type), "ACK-PSH"); break;
                default:
                    sprintf_s(sz_type, sizeof(sz_type),
                              "%s%s%s%s%s%s%s%s",
                              (type&0x01)?"FIN":"",
                              (type&0x02)?"SYN":"",
                              (type&0x04)?"RST":"",
                              (type&0x08)?"PSH":"",
                              (type&0x10)?"ACK":"",
                              (type&0x20)?"URG":"",
                              (type&0x40)?"ECE":"",
                              (type&0x80)?"CWR":""
                              );
                    break;
            }
            fprintf(fp, "%s (%5.4f) TCP  %-21s > %-21s %s\n", direction,
                    timestamp - global_timestamp_start, from, to, sz_type);
            break;
        case FOUND_IPV6:
            break;
        default:
            fprintf(fp, "%s (%5.4f) UNK  %-21s > %-21s [%u]\n", direction, 
                    timestamp - global_timestamp_start, from, to, parsed.found);
            break;
    }


}
Пример #6
0
int
perftest(int argc, char *argv[])
{
    struct PerfTest perftest[1];
	struct ZoneFileParser *parser;
    struct Catalog *db;
    size_t i;
    
    
    perftest->loop_count = 10000000;
    
    /*
     * Create a pseudo-network subsystem for generating packets
     */
    perftest->server.parent = perftest;
    perftest->server.adapter = adapter_create(
                                              perftest_alloc_packet, 
                                              perftest_server_to_client_response, 
                                              &perftest->server);
    adapter_add_ipv4(perftest->server.adapter, 0xC0A80101, 0xFFFFffff);
    
    
    /* create a catalog/database, this is where all the parsed zonefile
     * records will be put */
    perftest->db = catalog_create();
    perftest->thread->catalog = perftest->db;
    db = perftest->db;
    
    /* 
     * Parse a sample zone
     */
    parser = zonefile_begin(
                            example_origin, /* origin */
                            60,             /* TTL */
                            10000,          /* filesize */
                            "<perftest>",   /* filename */
                            zonefile_load,  /* callback */
                            db,             /* callback data */
                            0
                            );
    zonefile_set_singlestep(parser);
    for (i=0; perftest_zone[i]; i++) {
        zonefile_parse(parser,
                       (const unsigned char*)perftest_zone[i],
                       strlen(perftest_zone[i])
                       );
    }
    zonefile_end(parser);
    
    /*
     * Send packets. This creates one thread per CPU processing requests.
     */
    {
        unsigned threads_desired = pixie_cpu_get_count();
        uint64_t start, stop;
        double requests_per_second;
        
        fprintf(stderr, "running %u threads\n", threads_desired);
        
        start = pixie_gettime();
        for (i=0; i<threads_desired; i++) {
            __sync_fetch_and_add(&threads_running, 1);
            pixie_begin_thread((void(*)(void*))run_perf, 0, perftest);
        }
        while (threads_running)
            pixie_usleep(1000);
        stop = pixie_gettime();
        
        requests_per_second = 1000000.0 
                                * (1.0 * threads_desired * perftest->loop_count)
                                / (stop - start);
	fprintf(stderr, "queries = %u\n", (unsigned)(threads_desired * perftest->loop_count));
	fprintf(stderr, "seconds = %5.3f\n", (stop - start)/1000000.0);
        fprintf(stderr, "queries/second = %5.3f\n", requests_per_second);
    }
    
    exit(1);
    return 0;
}