Commit 8c184a59 authored by robertdavidgraham's avatar robertdavidgraham
Browse files

banners

parent 1ac9989a
Loading
Loading
Loading
Loading

src/event-timeout.c

0 → 100644
+114 −0
Original line number Diff line number Diff line
/*

    Event timeout

*/
#include "event-timeout.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>


/***************************************************************************
 ***************************************************************************/
struct TimeoutEntry {
    /** 
     * In units of 1/10000 of a second
     */
    uint64_t timestamp;

    struct TimeoutEntry *next;

    /**
     * A pointer to our custom data structure 
     */
    void *pointer;

    unsigned counter;
};

/***************************************************************************
 ***************************************************************************/
struct Timeouts {
    uint64_t current_index;
    unsigned mask;
    
    struct TimeoutEntry *freed_list;
    struct TimeoutEntry *entries[1024*8*16];
};

/***************************************************************************
 ***************************************************************************/
struct Timeouts *
timeouts_create(uint64_t timestamp)
{
    struct Timeouts *timeouts;

    timeouts = (struct Timeouts *)malloc(sizeof(*timeouts));
    memset(timeouts, 0, sizeof(*timeouts));

    timeouts->mask = sizeof(timeouts->entries)/sizeof(timeouts->entries[0]) - 1;

    timeouts->current_index = timestamp;

    return timeouts;
}

/***************************************************************************
 ***************************************************************************/
unsigned *
timeouts_add(struct Timeouts *timeouts, void *p, uint64_t timestamp, unsigned counter)
{
    struct TimeoutEntry *entry;
    unsigned index = timestamp & timeouts->mask;

    entry = timeouts->freed_list;
    if (entry)
        timeouts->freed_list = entry->next;
    else {
        entry = (struct TimeoutEntry *)malloc(sizeof(*entry));
    }
        
    entry->timestamp = timestamp;
    entry->pointer = p;
    entry->counter = counter;
    entry->next = timeouts->entries[index];
    timeouts->entries[index] = entry;
    return &entry->counter;
}

/***************************************************************************
 ***************************************************************************/
struct TimeoutEvent
timeouts_remove(struct Timeouts *timeouts, uint64_t timestamp)
{
    struct TimeoutEvent result;

    while (timeouts->current_index <= timestamp) {
        struct TimeoutEntry **r_entry = &timeouts->entries[timeouts->current_index & timeouts->mask];

        while (*r_entry && (*r_entry)->timestamp > timestamp)
            r_entry = &(*r_entry)->next;

        if (*r_entry) {
            struct TimeoutEntry *entry = *r_entry;
            void *p = entry->pointer;
            unsigned counter = entry->counter;
            (*r_entry) = entry->next;
            entry->next = timeouts->freed_list;
            timeouts->freed_list = entry;

            result.p = p;
            result.counter = counter;
            return result;
        } else {
            timeouts->current_index++;
        }
    }

    result.p = 0;
    result.counter = 0;
    return result;
}

src/event-timeout.h

0 → 100644
+21 −0
Original line number Diff line number Diff line
#ifndef EVENT_TIMEOUT_H
#define EVENT_TIMEOUT_H
#include <stdint.h>

struct Timeouts;
struct TimeoutEntry;

struct TimeoutEvent {
    void *p;
    unsigned counter;
};


struct Timeouts *timeouts_create(uint64_t timestamp);
unsigned *timeouts_add(struct Timeouts *timeouts, void *p, uint64_t timestamp, unsigned counter);
struct TimeoutEvent timeouts_remove(struct Timeouts *timeouts, uint64_t timestamp);

#define TICKS_FROM_SECS(secs) ((secs)*1000ULL)
#define TICKS_FROM_USECS(usecs) ((usecs)/1000ULL)
#define TICKS_FROM_TV(secs,usecs) (TICKS_FROM_SECS(secs)+TICKS_FROM_USECS(usecs))
#endif

src/packet-queue.h

0 → 100644
+14 −0
Original line number Diff line number Diff line
#ifndef PACKET_QUEUE_H
#define PACKET_QUEUE_H
#include "rte-ring.h"
#include <limits.h>

typedef struct rte_ring PACKET_QUEUE;

struct PacketBuffer {
    size_t length;
    unsigned char px[2040];
};


#endif
 No newline at end of file

src/proto-banner1.c

0 → 100644
+441 −0
Original line number Diff line number Diff line
/*
7    state machine for receiving banners
*/
#include "smack.h"
#include "rawsock-pcapfile.h"
#include "proto-preprocess.h"
#include "proto-banner1.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>


struct Patterns {
    const char *pattern;
    unsigned pattern_length;
    unsigned id;
    unsigned is_anchored;
};

struct Patterns patterns[] = {
    {"SSH-1.",      6, PROTO_SSH1, SMACK_ANCHOR_BEGIN},
    {"SSH-2.",      6, PROTO_SSH2, SMACK_ANCHOR_BEGIN},
    {"HTTP/1.",     7, PROTO_HTTP, SMACK_ANCHOR_BEGIN},
    {"220-",        4, PROTO_FTP1, SMACK_ANCHOR_BEGIN},
    {"220 ",        4, PROTO_FTP2, SMACK_ANCHOR_BEGIN},
    {0,0}
};

enum {
    HTTPFIELD_INCOMPLETE,
    HTTPFIELD_SERVER,
    HTTPFIELD_UNKNOWN,
    HTTPFIELD_NEWLINE,
};
struct Patterns http_fields[] = {
    {"Server:",     7, HTTPFIELD_SERVER, SMACK_ANCHOR_BEGIN},
    {":",           1, HTTPFIELD_UNKNOWN, 0},
    {"\n",          1, HTTPFIELD_NEWLINE, 0}, 
    {0,0,0,0}
};

struct Banner1
{
    struct SMACK *smack;
    struct SMACK *http_fields;
};


/***************************************************************************
 ***************************************************************************/
static unsigned
b_http(  struct Banner1 *banner1,
        unsigned state,
        const unsigned char *px, size_t length,
        char *banner, unsigned *banner_offset, size_t banner_max)
{
    unsigned i;
    unsigned state2;
    size_t id;
    enum {
        FIELD_START = 9,
        FIELD_NAME,
        FIELD_COLON,
        FIELD_VALUE,

    };

    state2 = (state>>16) & 0xFFFF;
    id = (state>>8) & 0xFF;
    state = (state>>0) & 0xFF;

    for (i=0; i<length; i++)
    switch (state) {
    case 0: case 1: case 2: case 3: case 4:
        if (toupper(px[i]) != "HTTP/"[state])
            state = STATE_DONE;
        else
            state++;
        break;
    case 5:
        if (px[i] == '.')
            state++;
        else if (!isdigit(px[i]))
            state = STATE_DONE;
        break;
    case 6:
        if (isspace(px[i]))
            state++;
        else if (!isdigit(px[i]))
            state = STATE_DONE;
        break;
    case 7:
        /* TODO: look for 1xx response code */
        if (px[i] == '\n')
            state = FIELD_START;
        break;
    case FIELD_START:
        if (px[i] == '\r')
            break;
        else if (px[i] == '\n') {
            state = STATE_DONE;
            break;
        } else {
            state2 = 0;
            state = FIELD_NAME;
            /* drop down */
        }

    case FIELD_NAME:
        if (px[i] == '\r')
            break;
        id = smack_search_next(
                        banner1->http_fields,
                        &state2, 
                        px, &i, (unsigned)length);
        if (id == HTTPFIELD_NEWLINE) {
            state2 = 0;
            state = FIELD_START;
        } else if (id == SMACK_NOT_FOUND)
            ; /* continue here */
        else if (id == HTTPFIELD_UNKNOWN) {
            size_t id2;

            id2 = smack_next_match(banner1->http_fields, &state2);
            if (id2 != SMACK_NOT_FOUND)
                id = id2;
        
            state = FIELD_COLON;
        } else
            state = STATE_DONE;
        break;
    case FIELD_COLON:
        if (px[i] == '\n') {
            state = FIELD_START;
            break;
        } else if (isspace(px[i])) {
            break;
        } else {
            state = FIELD_VALUE;
            /* drop down */
        }

    case FIELD_VALUE:
        if (px[i] == '\r')
            break;
        else if (px[i] == '\n') {
            state = FIELD_START;
            break;
        }
        if (id == HTTPFIELD_SERVER) {
            if (*banner_offset < banner_max) {
                banner[(*banner_offset)++] = px[i];
            }
        }
        break;

    case STATE_DONE:
    default:
        i = (unsigned)length;
        break;
    }


    if (state == STATE_DONE)
        return state;
    else
        return (state2 & 0xFFFF) << 16
                | (id & 0xFF) << 8
                | (state & 0xFF);
}

/***************************************************************************
 ***************************************************************************/
static unsigned
b_ssh(  struct Banner1 *banner1,
        unsigned state,
        const unsigned char *px, size_t length,
        char *banner, unsigned *banner_offset, size_t banner_max)
{
    unsigned i;

    banner1=banner1;

    for (i=0; i<length; i++)
    switch (state) {
    case 0:
        if (px[i] == '\r')
            continue;
        if (px[i] == '\n' || px[i] == '\0' || !isprint(px[i])) {
            state = STATE_DONE;
            continue;
        }
        if (*banner_offset < banner_max)
            banner[(*banner_offset)++] = px[i];
        break;
    default:
        i = (unsigned)length;
        break;
    }
    return state;
}

/***************************************************************************
 ***************************************************************************/
unsigned
banner1_parse(
        struct Banner1 *banner1,
        unsigned state, unsigned *proto,
        const unsigned char *px, size_t length,
        char *banner, unsigned *banner_offset, size_t banner_max)
{
    size_t x;
    unsigned offset = 0;

    switch (*proto) {
    case PROTO_UNKNOWN:
        x = smack_search_next(
                        banner1->smack,
                        &state, 
                        px, &offset, (unsigned)length);
        if (x != SMACK_NOT_FOUND) {
            unsigned i;
            *proto = (unsigned)x;

            /* reset the state back again */
            state = 0;

            /* re-read the stuff that we missed */
            for (i=0; patterns[i].id != *proto; i++)
                ;

            state = banner1_parse(
                            banner1, 
                            state, proto, 
                            (const unsigned char*)patterns[i].pattern, patterns[i].pattern_length,
                            banner, banner_offset, banner_max);
            state = banner1_parse(
                            banner1, 
                            state, proto, 
                            px+offset, length-offset,
                            banner, banner_offset, banner_max);
        }
        break;
    case PROTO_SSH1:
    case PROTO_SSH2:
    case PROTO_FTP1:
    case PROTO_FTP2:
        state = b_ssh(banner1, state,
                        px, length,
                        banner, banner_offset, banner_max);
        break;
    case PROTO_HTTP:
        state = b_http(banner1, state,
                        px, length,
                        banner, banner_offset, banner_max);
        break;
    default:
        fprintf(stderr, "banner1: internal error\n");
        break;

    }

    return state;
}

/***************************************************************************
 ***************************************************************************/
struct Banner1 *
banner1_create(void)
{
    struct Banner1 *b;
    unsigned i;

    b = (struct Banner1 *)malloc(sizeof(*b));
    memset(b, 0, sizeof(*b));

    /*
     * These patterns match the start of the TCP stream
     */
    b->smack = smack_create("banner1", SMACK_CASE_INSENSITIVE);
    for (i=0; patterns[i].pattern; i++)
        smack_add_pattern(
                    b->smack,
                    patterns[i].pattern,
                    patterns[i].pattern_length,
                    patterns[i].id,
                    patterns[i].is_anchored);
    smack_compile(b->smack);

    /*
     * These match HTTP Header-Field: names
     */
    b->http_fields = smack_create("http", SMACK_CASE_INSENSITIVE);
    for (i=0; http_fields[i].pattern; i++)
        smack_add_pattern(
                    b->http_fields,
                    http_fields[i].pattern,
                    http_fields[i].pattern_length,
                    http_fields[i].id,
                    http_fields[i].is_anchored);
    smack_compile(b->http_fields);

    return b;
}

/***************************************************************************
 ***************************************************************************/
void
banner1_destroy(struct Banner1 *b)
{
    if (b == NULL)
        return;
    if (b->smack)
        smack_destroy(b->smack);
    if (b->http_fields)
        smack_destroy(b->http_fields);
    free(b);
}


/***************************************************************************
 * Test the banner1 detection system by throwing random frames at it
 ***************************************************************************/
void
banner1_test(const char *filename)
{
    struct PcapFile *cap;
    unsigned link_type;
    
    cap = pcapfile_openread(filename);
    if (cap == NULL) {
        fprintf(stderr, "%s: can't open capture file\n", filename);
        return;
    }

    link_type = pcapfile_datalink(cap);

    for (;;) {
        int packets_read;
        unsigned secs;
        unsigned usecs;
        unsigned origlength;
        unsigned length;
        unsigned char px[65536];
        struct PreprocessedInfo parsed;
        unsigned x;

        
        packets_read = pcapfile_readframe(
                    cap,    /* capture dump file */
                    &secs, &usecs,
                    &origlength, &length,
                    px, sizeof(px));
        if (packets_read == 0)
            break;

        
        x = preprocess_frame(px, length, link_type, &parsed);
        if (x == 0)
            continue;

    }

    pcapfile_close(cap);
}

/***************************************************************************
 ***************************************************************************/
int banner1_selftest()
{
    unsigned i;
    struct Banner1 *b;
    char banner[128];
    unsigned banner_offset;
    unsigned state;
    unsigned proto;
    const unsigned char *px;
    unsigned length;
    static const char *http_header =
        "HTTP/1.0 302 Redirect\r\n"
        "Date: Tue, 03 Sep 2013 06:50:01 GMT\r\n"
        "Connection: close\r\n"
        "Via: HTTP/1.1 ir14.fp.bf1.yahoo.com (YahooTrafficServer/1.2.0.13 [c s f ])\r\n"
        "Server: YTS/1.20.13\r\n"
        "Cache-Control: no-store\r\n"
        "Content-Type: text/html\r\n"
        "Content-Language: en\r\n"
        "Location: http://failsafe.fp.yahoo.com/404.html\r\n"
        "Content-Length: 227\r\n"
        "\r\n";
    px = (const unsigned char *)http_header;
    length = (unsigned)strlen(http_header);


    /*
     * Test one character at a time
     */
    b = banner1_create();
    memset(banner, 0xa3, sizeof(banner));
    state = 0;
    proto = 0;
    banner_offset = 0;
    for (i=0; i<length; i++)
    state = banner1_parse(
                    b,
                    state,
                    &proto,
                    px+i, 1,
                    banner, &banner_offset, sizeof(banner)
                    );
    if (memcmp(banner, "YTS/1.20.13", 11) != 0) {
        printf("banner1: test failed\n");
        return 1;
    }
    banner1_destroy(b);

    /*
     * Test whole buffer
     */
    b = banner1_create();
    memset(banner, 0xa3, sizeof(banner));
    state = 0;
    proto = 0;
    banner_offset = 0;
    state = banner1_parse(
                    b,
                    state,
                    &proto,
                    px, length,
                    banner, &banner_offset, sizeof(banner)
                    );
    if (memcmp(banner, "YTS/1.20.13", 11) != 0) {
        printf("banner1: test failed\n");
        return 1;
    }
    banner1_destroy(b);


    return 0;
}

src/proto-banner1.h

0 → 100644
+36 −0
Original line number Diff line number Diff line
#ifndef PROTO_BANNER1_H
#define PROTO_BANNER1_H

#define STATE_DONE 0xFFFFFFFF

enum {
    PROTO_UNKNOWN,
    PROTO_SSH1,
    PROTO_SSH2,
    PROTO_HTTP,
    PROTO_FTP1,
    PROTO_FTP2,
};

struct Banner1 *
banner1_create(void);

void
banner1_destroy(struct Banner1 *b);

unsigned
banner1_parse(
        struct Banner1 *banner1,
        unsigned state, unsigned *proto,
        const unsigned char *px, size_t length,
        char *banner, unsigned *banner_offset, size_t banner_max);

/**
 * Test the banner protocol-parsing system by reading
 * in a capture file
 */
void banner1_test(const char *filename);

int banner1_selftest(void);

#endif
Loading