Ejemplo n.º 1
0
uint_least32_t cursor_read_u24n(struct cursor *cursor)
{
    uint_least32_t a = cursor_read_u8(cursor);
    uint_least32_t b = cursor_read_u8(cursor);
    uint_least32_t c = cursor_read_u8(cursor);
    return (a << 16) | (b << 8) | c;
}
Ejemplo n.º 2
0
uint_least32_t cursor_read_u24le(struct cursor *cursor)
{
    uint_least32_t a = cursor_read_u8(cursor);
    uint_least32_t b = cursor_read_u8(cursor);
    uint_least32_t c = cursor_read_u8(cursor);
    return a | (b << 8) | (c << 16);
}
Ejemplo n.º 3
0
static enum proto_parse_status read_string(char *dest, size_t max_size, struct cursor *curs)
{
    // This is an error to not reach '\0' before the end of the cursor
    while (curs->cap_len > 0 && curs->head[0] != '\0') {
        if (max_size > 1) {
            max_size --;
            *dest ++ = cursor_read_u8(curs);
        } else {    // we suppose, if this does not fit in max_size, that we are not parsing Skinny
            return PROTO_PARSE_ERR;
        }
    }
    if (! curs->cap_len) return PROTO_TOO_SHORT;
    *dest ++ = cursor_read_u8(curs);    // the nul
    return PROTO_OK;
}
Ejemplo n.º 4
0
/* TNS PDU have a header consisting of (in network byte order) :
 *
 * | 2 bytes | 2 bytes  | 1 byte | 1 byte | 2 bytes         |
 * | Length  | Checksum | Type   | a zero | Header checksum |
 */
static enum proto_parse_status cursor_read_tns_hdr(struct cursor *cursor, size_t *out_len, unsigned *out_type, size_t wire_len)
{
    SLOG(LOG_DEBUG, "Reading a TNS PDU");

    CHECK_LEN(cursor, 8, 0);
    size_t len = cursor_read_u16n(cursor);
    if (len < 8 || len < wire_len) return PROTO_PARSE_ERR;
    len -= 8;
    SLOG(LOG_DEBUG, "TNS PDU len == %zu", len);
    // Checksum should be 0
    uint_least16_t checksum = cursor_read_u16n(cursor);
    if (checksum > 0) {
        SLOG(LOG_DEBUG, "Tns checksum should be 0, got %u", checksum);
        return PROTO_PARSE_ERR;
    }
    unsigned type = cursor_read_u8(cursor);
    if (type >= TNS_TYPE_MAX) {
        SLOG(LOG_DEBUG, "Tns type invalid, sould be < %u, got %u", TNS_TYPE_MAX, type);
        return PROTO_PARSE_ERR;
    }
    // reserved byte and header checksum should be 0
    uint_least32_t head_checksum =cursor_read_u24(cursor);
    if (head_checksum  > 0) {
        SLOG(LOG_DEBUG, "Reserved byte and checksum should be 0, got %u", head_checksum);
        return PROTO_PARSE_ERR;
    }

    if (out_len) *out_len = len;
    if (out_type) *out_type = type;

    // Check we have the msg payload
    CHECK(len);

    return PROTO_OK;
}
Ejemplo n.º 5
0
/* Read a message header, return type and msg length, and advance the cursor to the msg payload.
 * if type is NULL that means no type are read from the cursor.
 * return PROTO_TOO_SHORT if the msg content is not available. */
static enum proto_parse_status cursor_read_msg(struct cursor *cursor, uint8_t *type, size_t *len_)
{
    SLOG(LOG_DEBUG, "Reading new message");
    unsigned rollback = 0;

    if (type) { // read type first
        CHECK_LEN(cursor, 1, rollback);
        *type = cursor_read_u8(cursor);
        rollback++;
        SLOG(LOG_DEBUG, "... of type %u ('%c')", (unsigned)*type, *type);
    }

    // read length
    CHECK_LEN(cursor, 4, rollback);
    size_t len = cursor_read_u32n(cursor);
    rollback += 4;
    if (len < 4) return PROTO_PARSE_ERR;    // as length includes itself
    len -= 4;
    SLOG(LOG_DEBUG, "... of length %zu", len);

    if (len_) *len_ = len;

    // read payload
    CHECK_LEN(cursor, len, rollback);

    return PROTO_OK;
}
Ejemplo n.º 6
0
/*
 * After a query, server sends a list of column name with their types
 *
 * | 1 byte | 1 byte                | 0-8 bytes     | variable bytes           |
 * | Length | Size number of fields | Number fields | unknown flags and fields |
 */
static enum proto_parse_status tns_parse_row_description_prefix(struct tns_parser *tns_parser, struct sql_proto_info *info, struct cursor *cursor)
{
    enum proto_parse_status status;
    SLOG(LOG_DEBUG, "Parsing row description prefix");

    CHECK(1);
    unsigned length = cursor_read_u8(cursor);
    DROP_FIX(cursor, length);
    DROP_VAR(cursor);

    if (PROTO_OK != (status = read_field_count(tns_parser, info, cursor))) return status;

    DROP_FIX(cursor, 1);
    for (unsigned i = 0; i < info->u.query.nb_fields; i++) {
        DROP_FIX(cursor, 3);
        DROP_VARS(cursor, 4);
        DROP_DALC(cursor);
        DROP_VARS(cursor, 2);
        DROP_FIX(cursor, 1);
        DROP_VAR(cursor);
        DROP_FIX(cursor, 2);
        for (unsigned i = 0; i < 3; ++i) {
            DROP_DALC(cursor);
        }
        DROP_VAR(cursor);
    }
    DROP_DALC(cursor);
    DROP_VARS(cursor, 2);
    return PROTO_OK;
}
Ejemplo n.º 7
0
/* Read an int prefixed by 1 byte size
 * | Size | Int------ |
 * | 0x02 | 0x01 0xdd |
 */
static enum proto_parse_status cursor_read_variable_int(struct cursor *cursor, uint_least64_t *res)
{
    CHECK(1);
    unsigned len = cursor_read_u8(cursor);
    SLOG(LOG_DEBUG, "Variable len has size %d", len);
    return cursor_read_fixed_int_n(cursor, res, len);
}
Ejemplo n.º 8
0
enum proto_parse_status cursor_read_fixed_int_le(struct cursor *cursor, uint_least64_t *out_res, unsigned len)
{
    uint_least64_t res;
    if (cursor->cap_len < len) return PROTO_TOO_SHORT;
    switch (len) {
        case 0:
            res = 0;
            break;
        case 1:
            res = cursor_read_u8(cursor);
            break;
        case 2:
            res = cursor_read_u16le(cursor);
            break;
        case 3:
            res = cursor_read_u24le(cursor);
            break;
        case 4:
            res = cursor_read_u32le(cursor);
            break;
        case 8:
            res = cursor_read_u64le(cursor);
            break;
        default:
            SLOG(LOG_DEBUG, "Can't read a %d bytes long number", len);
            return PROTO_PARSE_ERR;
    }
    if (out_res) *out_res = res;
    return PROTO_OK;
}
Ejemplo n.º 9
0
static enum proto_parse_status cursor_read_tns_hdr(struct cursor *cursor, size_t *out_len, unsigned *out_type)
{
    /* TNS PDU have a header consisting of (in network byte order) :
     * - a 2 bytes length
     * - a 2 bytes checksum
     * - a one byte type
     * - a one byte 0
     * - a 2 bytes header checksum (or 0) */
    SLOG(LOG_DEBUG, "Reading a TNS PDU");

    CHECK_LEN(cursor, 8, 0);
    size_t len = cursor_read_u16n(cursor);
    if (len < 8) return PROTO_PARSE_ERR;
    len -= 8;
    SLOG(LOG_DEBUG, "TNS PDU len == %zu", len);
    // skip packet checksum (2 bytes)
    cursor_drop(cursor, 2);
    unsigned type = cursor_read_u8(cursor);
    // Skip Reserved byte and header checksum (1 + 2 bytes)
    cursor_drop(cursor, 3);
    if (type > TNS_TYPE_MAX) return PROTO_PARSE_ERR;

    // Check we have the msg payload
    CHECK_LEN(cursor, len, 8);

    if (out_len) *out_len = len;
    if (out_type) *out_type = type;
    return PROTO_OK;
}
Ejemplo n.º 10
0
static enum proto_parse_status pg_parse_error(struct sql_proto_info *info, struct cursor *cursor, size_t len)
{
    enum proto_parse_status status;
    info->set_values |= SQL_REQUEST_STATUS;
    info->request_status = SQL_REQUEST_ERROR;

    size_t size = 0;
    char *str;

    while (size <= len) {
        size++;
        if (size > len) return PROTO_PARSE_ERR;
        char type = cursor_read_u8(cursor);
        if (type == 0x00) {
            break;
        }
        status = cursor_read_string(cursor, &str, len - size);
        if (status != PROTO_OK) return status;
        size += strlen(str) + 1;
        switch (type) {
            case 'C':
                info->set_values |= SQL_ERROR_SQL_STATUS;
                snprintf(info->error_sql_status, sizeof(info->error_sql_status), "%s", str);
                break;
            case 'M':
                info->set_values |= SQL_ERROR_MESSAGE;
                snprintf(info->error_message, sizeof(info->error_message), "%s", str);
                break;
        }
    }
    return PROTO_OK;
}
Ejemplo n.º 11
0
static enum proto_parse_status tds_parse_header(struct cursor *cursor, struct tds_header *out_header, bool *unknown_token)
{
#   define TDS_PKT_HDR_LEN 8
    CHECK_LEN(cursor, TDS_PKT_HDR_LEN, 0);

    struct tds_header header;
    header.type = cursor_read_u8(cursor);
    header.status = cursor_read_u8(cursor);
    header.len = cursor_read_u16n(cursor);
    header.channel = cursor_read_u16n(cursor);
    header.pkt_number = cursor_read_u8(cursor);
    header.window = cursor_read_u8(cursor);
    SLOG(LOG_DEBUG, "Reading new TDS packet %s", tds_header_2_str(&header));

    // sanity check
    if (header.len < TDS_PKT_HDR_LEN) return PROTO_PARSE_ERR;
    switch (header.type) {
    case TDS_PKT_TYPE_SQL_BATCH:
    case TDS_PKT_TYPE_LOGIN:
    case TDS_PKT_TYPE_RPC:
    case TDS_PKT_TYPE_RESULT:
    case TDS_PKT_TYPE_ATTENTION:
    case TDS_PKT_TYPE_BULK_LOAD:
    case TDS_PKT_TYPE_MANAGER_REQ:
    case TDS_PKT_TYPE_TDS7_LOGIN:
    case TDS_PKT_TYPE_SSPI:
    case TDS_PKT_TYPE_PRELOGIN:
        break;
    default:
        SLOG(LOG_DEBUG, "Unknown tds type %u", header.type);
        if (unknown_token) *unknown_token = true;
        return PROTO_PARSE_ERR;
    }
    if (header.window != 0) {
        SLOG(LOG_DEBUG, "Window is %"PRIu8" instead of 0", header.window);
        return PROTO_PARSE_ERR;
    }
    size_t data_left = header.len - TDS_PKT_HDR_LEN;
    if ((data_left > 0) != tds_packet_has_data(header.type)) {
        SLOG(LOG_DEBUG, "This TDS packet of type %s has %zu bytes of data, but should%s have data",
             tds_packet_type_2_str(header.type), data_left, tds_packet_has_data(header.type) ? "":" not");
        return PROTO_PARSE_ERR;
    }
    if (out_header) *out_header = header;
    return PROTO_OK;
}
Ejemplo n.º 12
0
/*
 * If oci, we will fallback on start query guesstimation
 * | 1 byte                        |
 * | Some flags (generally > 0x04) |
 *
 * If jdbc:
 * | 1 byte      | 0-4 bytes | 1 byte   | 0-4 bytes |
 * | Option size | Options   | Var size | Var value |
 */
static bool is_oci(struct cursor *cursor)
{
    CHECK(1);
    unsigned option_size = cursor_read_u8(cursor);
    CHECK(MAX(option_size, 2));
    if (option_size > 0x04 || cursor_peek_u8(cursor, 1) == 0x00) return true;
    cursor_drop(cursor, option_size);

    // Should be a var here
    CHECK(1);
    unsigned var_size = cursor_read_u8(cursor);
    CHECK(MAX(var_size, 2));
    if (var_size > 0x04 || cursor_peek_u8(cursor, 1) == 0x00) return true;
    cursor_drop(cursor, var_size);

    return false;
}
Ejemplo n.º 13
0
/* Read a string prefixed by 1 byte size
 * Size  String-------------
 * 0x04  0x41 0x42 0x42 0x40
 */
static enum proto_parse_status cursor_read_variable_string(struct cursor *cursor, char **out_str, unsigned *out_str_len)
{
    unsigned str_len;
    CHECK(1);
    str_len = cursor_read_u8(cursor);
    SLOG(LOG_DEBUG, "Reading variable str of length %d", str_len);
    if (out_str_len) *out_str_len = str_len;
    return cursor_read_fixed_string(cursor, out_str, str_len);
}
Ejemplo n.º 14
0
/* Read a string prefixed by 1 byte size
 * Size  String-------------
 * 0x04  0x41 0x42 0x42 0x40
 */
static enum proto_parse_status cursor_read_variable_string(struct cursor *cursor,
        char *buf, size_t size_buf, unsigned *out_str_len)
{
    unsigned str_len;
    CHECK(1);
    str_len = cursor_read_u8(cursor);
    SLOG(LOG_DEBUG, "Reading variable str of length %d", str_len);
    if (out_str_len) *out_str_len = str_len;
    int ret = cursor_read_fixed_string(cursor, buf, size_buf, str_len);
    if (ret == -1) return PROTO_TOO_SHORT;
    else return PROTO_OK;
}
Ejemplo n.º 15
0
static void cursor_check(void)
{
    struct cursor cursor;

    static uint8_t const data[] = { 1, 2 };
    cursor_ctor(&cursor, data, sizeof(data));
    assert(cursor_peek_u8(&cursor, 0) == 0x01U);
    assert(cursor_peek_u8(&cursor, 1) == 0x02U);
    assert(cursor_read_u8(&cursor) == 0x01U);
    assert(cursor_read_u8(&cursor) == 0x02U);

    static uint16_t const data16[] = { 0x0102, 0x0304 };
    cursor_ctor(&cursor, (uint8_t *)data16, sizeof(data16));
    assert(cursor_peek_u16le(&cursor, 0) == 0x0102U);
    assert(cursor_peek_u16le(&cursor, 2) == 0x0304U);
    assert(cursor_read_u16(&cursor) == 0x0102U);
    assert(cursor_read_u16(&cursor) == 0x0304U);

    static uint32_t const data32[] = { 0x01020304U, 0x05060708U };
    cursor_ctor(&cursor, (uint8_t *)data32, sizeof(data32));
    assert(cursor_peek_u32le(&cursor, 0) == 0x01020304U);
    assert(cursor_peek_u32le(&cursor, 4) == 0x05060708U);
    assert(cursor_read_u32(&cursor) == 0x01020304U);
    assert(cursor_read_u32(&cursor) == 0x05060708U);

    static uint64_t const data64[] = { 0x0102030405060708ULL };
    cursor_ctor(&cursor, (uint8_t *)data64, sizeof(data64));
    assert(cursor_peek_u64le(&cursor, 0) == 0x0102030405060708ULL);
    assert(cursor_read_u64(&cursor) == 0x0102030405060708ULL);

    static uint8_t const datan[] = { 1, 2, 3, 4 };
    cursor_ctor(&cursor, datan, sizeof(datan));
    assert(cursor_peek_u32n(&cursor, 0) == 0x01020304);
    assert(cursor_read_u32n(&cursor) == 0x01020304);

    cursor_ctor(&cursor, datan, sizeof(datan));
    assert(cursor_peek_u16n(&cursor, 0) == 0x0102);
    assert(cursor_read_u16n(&cursor) == 0x0102);
}
Ejemplo n.º 16
0
Archivo: tds.c Proyecto: iHaD/junkie
// | 1 byte      | 1 byte | 2 bytes | 4 bytes | 4 bytes | 4 bytes |
// | SMID (0x53) | Flag   | SID     | Length  | Seq num | Window  |
static enum proto_parse_status tds_parse_smp_header(struct cursor *cursor, struct smp_header *out_header)
{
#   define SMP_PKT_HDR_LEN 0x10
#   define SMP_SMID 0x53
    if (cursor_peek_u8(cursor, 0) == SMP_SMID) {
        CHECK_LEN(cursor, SMP_PKT_HDR_LEN, 0);
        cursor_drop(cursor, 1);
        out_header->flags   = cursor_read_u8(cursor);
        out_header->sid     = cursor_read_u16le(cursor);
        out_header->length  = cursor_read_u32le(cursor);
        out_header->seq_num = cursor_read_u32le(cursor);
        out_header->window  = cursor_read_u32le(cursor);
    }
    return PROTO_OK;
}
Ejemplo n.º 17
0
/*
 *  Sometimes, we have up to 10 {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} patterns.
 *  Skip them to avoid breaking on an eventual 0x07 (TTC_ROW_DATA)
 *  The query size seems to be at the end of the first pattern
 */
static uint8_t parse_query_header(struct cursor *cursor)
{
    uint8_t const *new_head = cursor->head;
    uint8_t query_size = 0;
    for (unsigned i = 0; i < 10 && new_head; i++) {
        char pattern[8] = {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
        new_head = memmem(cursor->head, cursor->cap_len, pattern, sizeof(pattern));
        if (new_head) {
            size_t gap_size = new_head - cursor->head;
            DROP_FIX(cursor, gap_size + sizeof(pattern));
            if (i == 0) {
                CHECK(1);
                query_size = cursor_read_u8(cursor);
                SLOG(LOG_DEBUG, "Found potential query size: %d", query_size);
            }
        }
    };
    return query_size;
}
Ejemplo n.º 18
0
/* Read a string splitted in chunk prefixed by 1 byte size
 * Chunk have a maximum size of 0x40 bytes
 * If there are more than one chunk, a 0x00 end it
 *
 * a multi chunked string
 *
 * Size  String---------    Size  String  End
 * 0x40  0x41 0x42 0x..     0x01  0x49    0x00
 *
 * a single chunked string
 *
 * Size  String---------
 * 0x20  0x41 0x42 0x..
 *
 * The global size might be unknown, so we try to guess it. We will have a parse problem
 * for string of size 0x40
 */
static enum proto_parse_status cursor_read_chunked_string(struct cursor *cursor,
        char *buf, size_t size_buf, size_t max_chunk)
{
    unsigned str_len = 0;
    struct string_buffer string_buf;
    if (buf) string_buffer_ctor(&string_buf, buf, size_buf);
    do {
        if (cursor->cap_len < 1) break;
        str_len = cursor_read_u8(cursor);
        SLOG(LOG_DEBUG, "Chunk of size of %u", str_len);
        size_t available_bytes = MIN(cursor->cap_len, str_len);
        if (buf) buffer_append_stringn(&string_buf, (char const *)cursor->head, available_bytes);
        cursor_drop(cursor, available_bytes);
    } while (str_len >= max_chunk);
    // There seems to be an null terminator when string length is > 0x40
    // However, it can be a flag after the string. Ignore it for now.
    if (buf) buffer_get_string(&string_buf);
    return PROTO_OK;
}
Ejemplo n.º 19
0
enum proto_parse_status cursor_read_string(struct cursor *cursor, char **out_str, size_t max_len)
{
    char *str = tempstr();
    unsigned len;
    if (max_len > TEMPSTR_SIZE-1) max_len = TEMPSTR_SIZE-1;
    for (len = 0; len < max_len; len ++) {
        CHECK_LEN(cursor, 1, len);
        uint8_t c = cursor_read_u8(cursor);
        if (c == '\0') break;
        str[len] = c;
    }
    if (len == max_len) {
        cursor_rollback(cursor, len);
        return PROTO_TOO_SHORT;
    }
    str[len] = '\0';
    SLOG(LOG_DEBUG, "Reading string '%s' of size %u", str, len);
    if (out_str) *out_str = str;
    return PROTO_OK;
}
Ejemplo n.º 20
0
/* Read a string splitted in chunk prefixed by 1 byte size
 * Chunk have a maximum size of 0x40 bytes
 * If there are more than one chunk, a 0x00 end it
 *
 * a multi chunked string
 *
 * Size  String---------    Size  String  End
 * 0x40  0x41 0x42 0x..     0x01  0x49    0x00
 *
 * a single chunked string
 *
 * Size  String---------
 * 0x20  0x41 0x42 0x..
 *
 * The global size might be unknown, so we try to guess it. We will have a parse problem
 * for string of size 0x40
 */
static enum proto_parse_status cursor_read_chunked_string(struct cursor *cursor, char **out_str, size_t max_chunk)
{
    char *str = tempstr();
    unsigned pos = 0;
    while (pos < TEMPSTR_SIZE) {
        CHECK(1);
        unsigned str_len = cursor_read_u8(cursor);
        SLOG(LOG_DEBUG, "Chunk of size of %u", str_len);

        CHECK(str_len);
        size_t copied_len = MIN(TEMPSTR_SIZE - (pos + str_len + 1), str_len);
        cursor_copy(str + pos, cursor, copied_len);
        pos += str_len;
        if (str_len < max_chunk) break;
    }
    // There seems to be an null terminator when string length is > 0x40
    // However, it can be a flag after the string. Ignore it for now.
    if (out_str) *out_str = str;
    str[MIN(pos, TEMPSTR_SIZE)] = 0;
    SLOG(LOG_DEBUG, "Chunk parsed of size %u", pos);
    return PROTO_OK;
}
Ejemplo n.º 21
0
static enum proto_parse_status tns_parse_query(struct tns_parser *tns_parser, struct sql_proto_info *info, struct cursor *cursor)
{
    enum proto_parse_status status = PROTO_OK;
    CHECK(1);
    enum query_subcode query_subcode = cursor_read_u8(cursor);
    SLOG(LOG_DEBUG, "Parsing tns query, subcode is %u", query_subcode);
    switch (query_subcode) {
        case TTC_QUERY_SQL:
            tns_parser->nb_fields = UNSET;
            status = tns_parse_sql_query(info, cursor);
            cursor_drop(cursor, cursor->cap_len);
            break;
        case TTC_QUERY_FETCH:
            cursor_drop(cursor, cursor->cap_len);
            break;
        default:
            // Probably initialization queries
            cursor_drop(cursor, cursor->cap_len);
            break;
    }
    return status;
}
Ejemplo n.º 22
0
static enum proto_parse_status tns_parse_query(struct tns_parser *tns_parser, struct sql_proto_info *info,
        struct cursor *cursor)
{
    enum proto_parse_status status = PROTO_OK;
    CHECK(1);
    enum query_subcode query_subcode = cursor_read_u8(cursor);
    SLOG(LOG_DEBUG, "Parsing tns query, subcode is %u", query_subcode);
    switch (query_subcode) {
        case TTC_QUERY_SQL:
        case TTC_QUERY_ALL_7:
            tns_parser->nb_fields = UNSET;
            status = tns_parse_sql_query(info, cursor);
            break;
        case TTC_QUERY_FETCH:
            break;
        default:
            // Probably initialization queries. Since we are unsure, don't
            // return PROTO_OK to avoid fix of c2s_way
            return PROTO_PARSE_ERR;
    }
    cursor_drop(cursor, cursor->cap_len);
    return status;
}
Ejemplo n.º 23
0
static bool lookup_query(struct cursor *cursor)
{
    #define MIN_QUERY_SIZE 10
    #define QUERY_WITH_SIZE 12
    while (cursor->cap_len > QUERY_WITH_SIZE) {
        uint8_t c;
        uint8_t potential_size = 0;
        do {
            c = cursor_peek_u8(cursor, 1);
            potential_size = cursor_read_u8(cursor);
        } while (cursor->cap_len > QUERY_WITH_SIZE && !isprint(c));
        SLOG(LOG_DEBUG, "Found potential size 0x%02x and first printable %c", potential_size, c);
        // Check on found size
        if (potential_size < MIN_QUERY_SIZE || potential_size > cursor->cap_len) continue;
        // We check if last character is printable
        if (!isprint(cursor_peek_u8(cursor, potential_size - 1))) continue;
        // We check if first characters are printable
        if (PROTO_OK == is_range_print(cursor, MIN_QUERY_SIZE)) {
            cursor_rollback(cursor, 1);
            return true;
        }
    }
    return false;
}
Ejemplo n.º 24
0
uint_least16_t cursor_read_u16le(struct cursor *cursor)
{
    uint_least32_t a = cursor_read_u8(cursor);
    uint_least32_t b = cursor_read_u8(cursor);
    return a | (b << 8);
}
Ejemplo n.º 25
0
uint_least16_t cursor_read_u16n(struct cursor *cursor)
{
    uint_least32_t a = cursor_read_u8(cursor);
    uint_least32_t b = cursor_read_u8(cursor);
    return (a << 8) | b;
}
Ejemplo n.º 26
0
static enum proto_parse_status dhcp_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    struct dhcp const *dhcp = (struct dhcp *)payload;

    // Sanity Checks

    // Check that we have at least the size of an DHCP packet for IP protocol
    if (wire_len < sizeof(*dhcp)) return PROTO_PARSE_ERR;
    // And that we have enough data to parse it
    if (cap_len < sizeof(*dhcp)) return PROTO_TOO_SHORT;

    if (0 != memcmp(dhcp->cookie, &magic_cookie, sizeof(magic_cookie))) {
        SLOG(LOG_DEBUG, "Bad magic Cookie");
        return PROTO_PARSE_ERR;
    }

    struct dhcp_proto_info info;
    proto_info_ctor(&info.info, parser, parent, wire_len, 0);
    info.opcode = READ_U8(&dhcp->op);
    if (info.opcode != BOOTP_REQUEST && info.opcode != BOOTP_REPLY) {
        SLOG(LOG_DEBUG, "Unknown DHCP opcode (%u)", info.opcode);
        return PROTO_PARSE_ERR;
    }
    uint8_t const hlen = READ_U8(&dhcp->hlen);
    if (hlen > sizeof(dhcp->chaddr)) {
        SLOG(LOG_DEBUG, "Bad hlen in DHCP (%u)", hlen);
        return PROTO_PARSE_ERR;
    }
    info.xid = READ_U32N(&dhcp->xid);
    info.set_values = 0;
    uint32_t const addr = READ_U32(&dhcp->yiaddr);
    if (addr) {
        info.set_values |= DHCP_CLIENT_SET;
        ip_addr_ctor_from_ip4(&info.client, addr);
    }
    uint8_t const htype = READ_U8(&dhcp->htype);
    info.hw_addr_is_eth = htype == 1;
    if (info.hw_addr_is_eth) {
        if (hlen != sizeof(info.client_mac)) {
            SLOG(LOG_DEBUG, "Bad hlen (%u) for Eth type", hlen);
            return PROTO_PARSE_ERR;
        }
        memcpy(info.client_mac, dhcp->chaddr, sizeof(info.client_mac));
    } else {
        memset(info.client_mac, 0, sizeof(info.client_mac));
    }

    memcpy(info.server_name, dhcp->sname, sizeof(info.server_name));

    SLOG(LOG_DEBUG, "New DHCP %s", dhcp_opcode_2_str(info.opcode));

    // parse options
    info.msg_type = 0;  // mandatory
    struct cursor c;
    cursor_ctor(&c, dhcp->options, cap_len - offsetof(struct dhcp, options));
    while (c.cap_len >= 2) {
        uint8_t const type = cursor_read_u8(&c);
        uint8_t const len  = cursor_read_u8(&c);
        if (c.cap_len < len) {
            SLOG(LOG_DEBUG, "Cannot read options");
            return PROTO_PARSE_ERR;
        }
        switch (type) {
            case 53:    // msg type
                if (len != 1) {
                    SLOG(LOG_DEBUG, "Bad length (%"PRIu8") for msg type DHCP option", len);
                    return PROTO_PARSE_ERR;
                }
                info.msg_type = cursor_read_u8(&c);
                if (info.msg_type > DHCP_INFORM) {
                    SLOG(LOG_DEBUG, "Bad DHCP msg type (%u)", info.msg_type);
                    return PROTO_PARSE_ERR;
                }
                break;
            default:
                cursor_drop(&c, len);
                break;
        }
    }
    if (0 == info.msg_type) {   // not found
        SLOG(LOG_DEBUG, "DHCP msg without msg type");
        return PROTO_PARSE_ERR;
    }

    return proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);
}
Ejemplo n.º 27
0
/*
 * | 2 bytes | 1 byte   | Variable |
 * | Flags   | TTC code | TTC body |
 */
static enum proto_parse_status tns_parse_data(struct tns_parser *tns_parser, struct sql_proto_info *info, struct cursor *cursor,
        unsigned way)
{
    SLOG(LOG_DEBUG, "Parsing TNS data PDU of size %zu", cursor->cap_len);
    enum proto_parse_status status = PROTO_OK;

    // First, read the data flags
    CHECK(2);
    unsigned flags = cursor_read_u16n(cursor);
    SLOG(LOG_DEBUG, "Data flags = 0x%x", flags);
    if (flags & 0x40) { // End Of File
        if (cursor->cap_len != 0) return PROTO_PARSE_ERR;   // This may be wrong, maybe a command is allowed anyway
        info->msg_type = SQL_EXIT;
        sql_set_request_status(info, SQL_REQUEST_COMPLETE);
        return PROTO_OK;
    }
    info->msg_type = tns_parser->msg_type;
    while (status == PROTO_OK && cursor->cap_len) {
        CHECK(1);
        enum ttc_code ttc_code = cursor_read_u8(cursor);
        SLOG(LOG_DEBUG, "Ttc code = 0x%02x, msg type %s", ttc_code, sql_msg_type_2_str(tns_parser->msg_type));
        switch (ttc_code) {
            case TTC_ROW_PREFIX:
                status = tns_parse_row_prefix(tns_parser, info, cursor);
                break;
            case TTC_ROW_DATA:
                status = tns_parse_row_data(tns_parser, info, cursor);
                break;
            case TTC_ROW_DESCRIPTION_PREFIX:
                status = tns_parse_row_description_prefix(tns_parser, info, cursor);
                break;
            case TTC_ROW_RECAP:
                status = tns_parse_row_recap(cursor);
                break;
            case TTC_ROW_DESCRIPTION:
                status = tns_parse_row_description(cursor);
                break;
            case TTC_LOGIN_PROPERTY:
                status = tns_parse_login_property(info, cursor);
                break;
            case TTC_QUERY:
                status = tns_parse_query(tns_parser, info, cursor);
                break;
            case TTC_END_MESSAGE:
                status = tns_parse_end(info, cursor);
                break;
            case TTC_CLOSE:
                status = tns_parse_close_statement(cursor);
                break;
            default:
                SLOG(LOG_DEBUG, "Unknown ttc_code = %u", ttc_code);
                return PROTO_OK;
        }
        if (status == PROTO_OK) {
            enum sql_msg_type ttc_msg_type = ttc_to_msg_type(tns_parser, ttc_code);
            if (ttc_msg_type != SQL_UNKNOWN) {
                info->msg_type = ttc_msg_type;
                tns_parser->msg_type = ttc_msg_type;
            }
            // Fix c2s_way
            bool old_c2s_way = tns_parser->c2s_way;
            switch (ttc_code) {
                case TTC_ROW_DESCRIPTION_PREFIX:
                case TTC_ROW_RECAP:
                case TTC_ROW_DESCRIPTION:
                case TTC_END_MESSAGE:
                    tns_parser->c2s_way = !way;
                    break;
                case TTC_QUERY:
                case TTC_CLOSE:
                    tns_parser->c2s_way = way;
                    break;
                default:
                    break;
            }
            if (old_c2s_way != tns_parser->c2s_way) {
                SLOG(LOG_DEBUG, "Fix c2s way from %d to %d", old_c2s_way, tns_parser->c2s_way);
            }
            info->is_query = way == tns_parser->c2s_way;
        }
    }
    return status;
}