Ejemplo n.º 1
0
static enum proto_parse_status read_channel(struct skinny_parser *parser, unsigned from, struct skinny_proto_info *info, struct cursor *curs, struct timeval const *now)
{
    assert(from == FROM_MGR || from == FROM_STATION);
    if (curs->cap_len < 4+16+4) return PROTO_TOO_SHORT;
    uint32_t ip_version = cursor_read_u32le(curs);
    if (ip_version == 0) {  // v4
        uint32_t ip = cursor_read_u32(curs);
        ip_addr_ctor_from_ip4(&parser->peer[from], ip);
        cursor_drop(curs, 12);    // this field is 16 bytes in length
    } else if (ip_version == 1) {    // v16
        ip_addr_ctor_from_ip6(&parser->peer[from], (struct in6_addr const *)curs->head);
        cursor_drop(curs, 16);
    } else {
        SLOG(LOG_DEBUG, "Invalid IP version (%d)", ip_version);
        return PROTO_PARSE_ERR;
    }
    parser->port[from] = cursor_read_u32le(curs);
    parser->media_set[from] = true;
    try_cnxtrack(parser, now);

    // Copy these into the info block
    SLOG(LOG_DEBUG, "Got media info");
    info->set_values |= SKINNY_MEDIA_CNX;
    info->media_ip = parser->peer[from];
    info->media_port = parser->port[from];

    return PROTO_OK;
}
Ejemplo n.º 2
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.º 3
0
static enum proto_parse_status tns_parse_sql_query_jdbc(struct sql_proto_info *info, struct cursor *cursor)
{
    SLOG(LOG_DEBUG, "Parsing a jdbc query");
    enum proto_parse_status status;

    DROP_FIX(cursor, 1);

    uint_least64_t sql_len;
    status = cursor_read_variable_int(cursor, &sql_len);
    if (status != PROTO_OK) return status;
    SLOG(LOG_DEBUG, "Size sql %zu", sql_len);

    DROP_FIX(cursor, 1);
    // We have a number of fields at the end of the query
    uint_least64_t end_len;
    status = cursor_read_variable_int(cursor, &end_len);
    if (status != PROTO_OK) return status;

    DROP_FIX(cursor, 2);
    DROP_VARS(cursor, 3);
    DROP_FIX(cursor, 1);
    DROP_VAR(cursor);
    DROP_FIX(cursor, 6);
    DROP_VAR(cursor);

    char *sql = "";
    if (sql_len > 0) {
        // Some unknown bytes
        while (cursor->cap_len > 1 && !isprint(cursor_peek_u8(cursor, 1))) {
            cursor_drop(cursor, 1);
        }

        CHECK(1);
        if (sql_len > 0xff && 0xff == cursor_peek_u8(cursor, 0)) {
            SLOG(LOG_DEBUG, "Looks like prefixed length chunks of size 0xff...");
            status = cursor_read_chunked_string(cursor, &sql, 0xff);
        } else if (sql_len > 0x40 && 0x40 == cursor_peek_u8(cursor, 1)) {
            SLOG(LOG_DEBUG, "Looks like prefixed length chunks of size 0x40...");
            cursor_drop(cursor, 1);
            status = cursor_read_chunked_string(cursor, &sql, 0x40);
        } else {
            if (!isprint(cursor_peek_u8(cursor, 0))) {
                cursor_drop(cursor, 1);
            }
            SLOG(LOG_DEBUG, "Looks like a fixed string of size %zu", sql_len);
            status = cursor_read_fixed_string(cursor, &sql, sql_len);
        }
        if (status != PROTO_OK) return status;
    }
    SLOG(LOG_DEBUG, "Sql parsed: %s", sql);
    sql_set_query(info, "%s", sql);

    SLOG(LOG_DEBUG, "Skipping %zu end variable fields", end_len);
    DROP_VARS(cursor, end_len);
    return PROTO_OK;
}
Ejemplo n.º 4
0
static enum proto_parse_status tns_parse_connect(struct tns_parser unused_ *tns_parser, struct sql_proto_info *info, struct cursor *cursor)
{
    if (! info->is_query) return PROTO_PARSE_ERR;
    SLOG(LOG_DEBUG, "Parsing TNS connect PDU of size %zu", cursor->cap_len);

    /* A connect is (in network byte order) :
     * - 2 bytes version
     * - 2 bytes back compatibility
     * - 2 bytes service options
     * - 2 bytes session data unit size
     * - 2 bytes max transm. data unit size
     * - 2 bytes proto characteristics
     * - 2 bytes line turnaround
     * - 2 bytes value of one
     * - 2 bytes connect data length
     * - 2 bytes connect data offset
     * - 4 bytes connect data max
     * - 1 byte connect flags 0
     * - 1 byte connect flags 1
     * - optionaly, 16 bytes for trace things
     * - padding until data offset
     * - then connect data */
    size_t const pdu_len = cursor->cap_len;
    if (pdu_len < 26) return PROTO_PARSE_ERR;
    unsigned version = cursor_read_u16n(cursor);
    info->version_maj = version/100;
    info->version_min = version%100;
    info->set_values |= SQL_VERSION;
    cursor_drop(cursor, 14);    // jump to connect data length
    unsigned data_length = cursor_read_u16n(cursor);
    unsigned data_offset = cursor_read_u16n(cursor);
    SLOG(LOG_DEBUG, "Connect, data length=%u, data offset=%u", data_length, data_offset);
    if (data_offset > pdu_len || data_offset < 26 + 8) return PROTO_PARSE_ERR;
    if (data_length + data_offset > pdu_len + 8) return PROTO_PARSE_ERR;
    cursor_drop(cursor, data_offset - 20 - 8);  // jump to data
    // Now look for user and dbname (ie. service_name)
#   define USER_TOKEN "(USER="******"(SERVICE_NAME="
    char const *data_end = (char const *)(cursor->head + data_length);
    char const *str;
    if (NULL != (str = strnstr((char const *)cursor->head, USER_TOKEN, data_length))) {
        str += strlen(USER_TOKEN);
        info->set_values |= SQL_USER;
        copy_token(info->u.startup.user, sizeof(info->u.startup.user), str, data_end-str);
    }
    if (NULL != (str = strnstr((char const *)cursor->head, DBNAME_TOKEN, data_length))) {
        str += strlen(DBNAME_TOKEN);
        info->set_values |= SQL_DBNAME;
        copy_token(info->u.startup.dbname, sizeof(info->u.startup.dbname), str, data_end-str);
    }
    return PROTO_OK;
}
Ejemplo n.º 5
0
/*
 * Check if query is valid.
 * @param cursor to read
 * @param candidate Filled with potential sql size candidate
 * @return True if a correct query has been found and cursor is positioned at the begin of the query
 */
static bool lookup_query(struct cursor *cursor, struct query_candidate *candidate)
{
    SLOG(LOG_DEBUG, "Start looking for query");
    uint8_t current;
    uint8_t next;

    while (cursor->cap_len > QUERY_WITH_SIZE) {
        current = cursor_peek_u8(cursor, 0);
        next = cursor_peek_u8(cursor, 1);
        if (current == TTC_ROW_DATA && next > 0 && next <= 4) {
            SLOG(LOG_DEBUG, " Looks like start of a data query row");
            return false;
        }
        if (current > 0 && current < 3 && next > MIN_QUERY_SIZE
                && candidate->num_candidate_size < NB_ELEMS(candidate->candidate_sizes)) {
            uint64_t buf = 0;
            // Copy cursor since we might have pattern like 0x01 Size Query
            struct cursor cursor_copy = *cursor;
            if (PROTO_OK == cursor_read_variable_int(&cursor_copy, &buf)) {
                SLOG(LOG_DEBUG, " Found a candidate size %"PRIu64, buf);
                insert_array_sorted(candidate, buf);
            }
        }
        if (candidate->num_candidate_size == 0 || current >= candidate->candidate_sizes[0]) {
            if (check_chuncked_query(cursor, current, next, candidate)) return true;
            if (check_fixed_query(cursor, current, next, candidate)) return true;
        } else {
            if (check_fixed_query(cursor, current, next, candidate)) return true;
            if (check_chuncked_query(cursor, current, next, candidate)) return true;
        }
        cursor_drop(cursor, 1);
    }
    return false;
}
Ejemplo n.º 6
0
static enum proto_parse_status tns_parse_sql_query_oci(struct sql_proto_info *info, struct cursor *cursor)
{
    SLOG(LOG_DEBUG, "Parsing an oci query");
    enum proto_parse_status status;
    char pattern[] = {0xfe, MAX_OCI_CHUNK};
    uint8_t const *new_head = memmem(cursor->head, cursor->cap_len, pattern, sizeof(pattern));
    if (new_head != NULL) {
        size_t gap_size = new_head - cursor->head;
        SLOG(LOG_DEBUG, "%zu bytes before sql", gap_size);
        DROP_FIX(cursor, gap_size + 1);
    } else {
        SLOG(LOG_DEBUG, "{0xfe 0x40} not found, size might be < 0x40");
        if (!lookup_query(cursor)) return PROTO_PARSE_ERR;
    }

    char *sql;
    if (PROTO_OK != (status = cursor_read_chunked_string(cursor, &sql, MAX_OCI_CHUNK))) return status;
    SLOG(LOG_DEBUG, "Sql parsed: %s", sql);
    sql_set_query(info, "%s", sql);

    // Drop the rest
    if(cursor->cap_len > 0) cursor_drop(cursor, cursor->cap_len - 1);

    return PROTO_OK;
}
Ejemplo n.º 7
0
static enum proto_parse_status cursor_drop_until(struct cursor *cursor, const void *marker, size_t marker_len)
{
    uint8_t *new_head = memmem(cursor->head, cursor->cap_len, marker, marker_len);
    if (!new_head) return PROTO_PARSE_ERR;
    size_t gap_size = new_head - cursor->head;
    cursor_drop(cursor, gap_size);
    return PROTO_OK;
}
Ejemplo n.º 8
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.º 9
0
enum proto_parse_status cursor_read_fixed_string(struct cursor *cursor, char **out_str, size_t str_len)
{
    SLOG(LOG_DEBUG, "Reading string of size %zu", str_len);
    if (cursor->cap_len < str_len) return PROTO_PARSE_ERR;
    if (!out_str) {
        cursor_drop(cursor, str_len);
        return PROTO_OK;
    }
    char *str = tempstr();
    unsigned copied_len = MIN(str_len, TEMPSTR_SIZE - 1);
    cursor_copy(str, cursor, copied_len);
    str[copied_len] = '\0';
    if (copied_len < str_len) {
        cursor_drop(cursor, str_len - copied_len);
    }
    if(out_str) *out_str = str;
    return PROTO_OK;
}
Ejemplo n.º 10
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.º 11
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.º 12
0
static enum proto_parse_status rpc_parse(struct parser *parser, struct proto_info *parent, unsigned unused_ way,
        uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const unused_ *now,
        size_t unused_ tot_cap_len, uint8_t const unused_ *tot_packet)
{
    struct cursor cursor;
    cursor_ctor(&cursor, packet, cap_len);
    if (wire_len < 12) return PROTO_PARSE_ERR;
    if (cap_len < 12) return PROTO_TOO_SHORT;

    ASSIGN_INFO_OPT(tcp, parent);

    struct rpc_proto_info info;
    proto_info_ctor(&info.info, parser, parent, wire_len, 0);

    if (tcp) cursor_drop(&cursor, 4); // Drop fragment header
    cursor_drop(&cursor, 4);
    info.msg_type = cursor_read_u32n(&cursor);
    enum proto_parse_status status = PROTO_OK;
    switch (info.msg_type) {
    case RPC_CALL:
        if (wire_len < 40) return PROTO_PARSE_ERR;
        status = parse_rpc_call(&cursor, &info);
        break;
    case RPC_REPLY:
        status = parse_rpc_reply(&cursor, &info);
        break;
    default:
        return PROTO_PARSE_ERR;
    }
    SLOG(LOG_DEBUG, "Parsed rpc status %s, %s", proto_parse_status_2_str(status), rpc_info_2_str(&info.info));
    if (status == PROTO_OK) {
        // TODO We can have a nfs payload
        (void)proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);
    }
    return status;
}
Ejemplo n.º 13
0
static enum proto_parse_status read_channel(struct skinny_parser *parser, unsigned from, struct skinny_proto_info *info, struct cursor *curs, struct timeval const *now)
{
    assert(from == FROM_MGR || from == FROM_STATION);
    if (curs->cap_len < 4+16+4) return PROTO_TOO_SHORT;

    uint32_t ip_version = 0;
    // The ip field has a 16 byte lenght on CM7 headers. We
    // need to drop some bytes before parsing remote port
    short offset_ip_port = 0;
    switch (info->header_ver) {
        case SKINNY_BASIC:
            break;
        case SKINNY_CM7_TYPE_A:
        case SKINNY_CM7_TYPE_B:
        case SKINNY_CM7_TYPE_C:
            ip_version = cursor_read_u32le(curs);
            // We drop (16 - 4) for ipv4 and (16 - 8) for ipv6
            offset_ip_port = ip_version ? 8 : 12;
            break;
    }

    if (ip_version == 0) {  // v4
        uint32_t ip = cursor_read_u32(curs);
        ip_addr_ctor_from_ip4(&parser->peer[from], ip);
    } else if (ip_version == 1) {    // v6
        ip_addr_ctor_from_ip6(&parser->peer[from], (struct in6_addr const *)curs->head);
    } else {
        SLOG(LOG_DEBUG, "Invalid IP version (%d)", ip_version);
        return PROTO_PARSE_ERR;
    }

    cursor_drop(curs, offset_ip_port);
    parser->port[from] = cursor_read_u32le(curs);
    parser->media_set[from] = true;
    try_cnxtrack(parser, now);

    // Copy these into the info block
    SLOG(LOG_DEBUG, "Got media info");
    info->set_values |= SKINNY_MEDIA_CNX;
    info->media_ip = parser->peer[from];
    info->media_port = parser->port[from];

    return PROTO_OK;
}
Ejemplo n.º 14
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.º 15
0
static enum proto_parse_status tns_parse_login_property(struct sql_proto_info *info, struct cursor *cursor)
{
    SLOG(LOG_DEBUG, "Parsing tns login property");
    // We are only interested in response
    if (info->is_query) return PROTO_OK;
    if (info->msg_type != SQL_UNKNOWN && info->msg_type != SQL_STARTUP) return PROTO_PARSE_ERR;

    // Drop Server version
    DROP_FIX(cursor, 3);
    // Drop Server version text
    uint8_t marker = 0x00;
    enum proto_parse_status status = cursor_drop_until(cursor, &marker, sizeof(marker));
    if (status != PROTO_OK) return status;
    // Drop Null byte
    DROP_FIX(cursor, 1);
    CHECK(2);
    uint16_t charset = cursor_read_u16le(cursor);
    SLOG(LOG_DEBUG, "Found a charset of 0x%02x", charset);
    switch (charset) {
        case 0x01:
        case 0x02:
        case 0x1f:
        case 0xb2:
            sql_set_encoding(info, SQL_ENCODING_LATIN1);
            break;
        case 0x366:
        case 0x367:
        case 0x369:
            sql_set_encoding(info, SQL_ENCODING_UTF8);
            break;
        default:
            SLOG(LOG_DEBUG, "Unknown charset");
            break;
    }
    // We don't care of the rest...
    cursor_drop(cursor, cursor->cap_len);
    return PROTO_OK;
}
Ejemplo n.º 16
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.º 17
0
static enum proto_parse_status tns_parse_sql_query_oci(struct sql_proto_info *info, struct cursor *cursor)
{
    SLOG(LOG_DEBUG, "Parsing an oci query");
    uint8_t query_size = parse_query_header(cursor);
    struct query_candidate candidate = {.num_candidate_size = 0};
    if (query_size > 0) {
        candidate.candidate_sizes[candidate.num_candidate_size++] = query_size;
    }

    bool has_query = lookup_query(cursor, &candidate);
    info->u.query.sql[0] = '\0';
    info->u.query.truncated = 0;
    if (has_query) {
        SLOG(LOG_DEBUG, "Found a query, parsing it");
        if (candidate.is_chunked) {
            cursor_read_chunked_string(cursor, info->u.query.sql, sizeof(info->u.query.sql), MAX_OCI_CHUNK);
        } else {
            cursor_read_fixed_string(cursor, info->u.query.sql, sizeof(info->u.query.sql), candidate.query_size);
        }
    }
    SLOG(LOG_DEBUG, "Sql parsed: %s", info->u.query.sql);
    info->set_values |= SQL_SQL;
    // Drop the rest
    if(cursor->cap_len > 0) cursor_drop(cursor, cursor->cap_len - 1);
    return PROTO_OK;
}

/*
 * | 1 byte | 1 + 0-8 bytes | 1 byte | 1 + 0-4 bytes  | Lots of unknown bytes | variable  |
 * | Unk    | Sql len       | Unk    | Num end fields | Unk                   | sql query |
 */
static enum proto_parse_status tns_parse_sql_query_jdbc(struct sql_proto_info *info, struct cursor *cursor)
{
    SLOG(LOG_DEBUG, "Parsing a jdbc query");
    enum proto_parse_status status = PROTO_OK;

    DROP_FIX(cursor, 1);

    uint_least64_t sql_len;
    if (PROTO_OK != (status = cursor_read_variable_int(cursor, &sql_len))) return status;
    SLOG(LOG_DEBUG, "Size sql %zu", sql_len);

    DROP_FIX(cursor, 1);
    DROP_VAR(cursor);
    DROP_FIX(cursor, 2);

    info->u.query.sql[0] = '\0';
    info->u.query.truncated = 0; // TODO Handle truncated
    if (sql_len > 0) {
        // Some unknown bytes
        while (cursor->cap_len > 1 && PROTO_OK != is_range_print(cursor, MIN(MIN_QUERY_SIZE, sql_len), 1)) {
            // TODO drop to the first non printable
            cursor_drop(cursor, 1);
        }
        CHECK(1);
        if (sql_len > 0xff && 0xff == cursor_peek_u8(cursor, 0)) {
            SLOG(LOG_DEBUG, "Looks like prefixed length chunks of size 0xff...");
            status = cursor_read_chunked_string(cursor, info->u.query.sql, sizeof(info->u.query.sql), 0xff);
        } else if (sql_len > MAX_OCI_CHUNK && MAX_OCI_CHUNK == cursor_peek_u8(cursor, 0)) {
            SLOG(LOG_DEBUG, "Looks like prefixed length chunks of size 0x40...");
            status = cursor_read_chunked_string(cursor, info->u.query.sql, sizeof(info->u.query.sql),
                    MAX_OCI_CHUNK);
        } else {
            // We don't care about the first non printable character
            cursor_drop(cursor, 1);
            CHECK(1);
            // In rare occurrence where sql_len == first character, we check the byte after the expected query,
            // if it's printable, the first character is probably the prefixed size.
            if (cursor_peek_u8(cursor, 0) == sql_len && sql_len < cursor->cap_len && is_print(cursor_peek_u8(cursor, sql_len)))
                cursor_drop(cursor, 1);
            SLOG(LOG_DEBUG, "Looks like a fixed string of size %zu", sql_len);
            int written_bytes = cursor_read_fixed_string(cursor, info->u.query.sql,
                    sizeof(info->u.query.sql), sql_len);
            if (written_bytes < 0) return PROTO_TOO_SHORT;
        }
        if (status != PROTO_OK) return status;
    }
    SLOG(LOG_DEBUG, "Sql parsed: %s", info->u.query.sql);
    info->set_values |= SQL_SQL;

    return PROTO_OK;
}
Ejemplo n.º 18
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.º 19
0
static enum proto_parse_status pg_parse_query(struct pgsql_parser *pg_parser, struct sql_proto_info *info, unsigned way, uint8_t const *payload, size_t cap_len, size_t unused_ wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    enum proto_parse_status status;
    info->msg_type = SQL_QUERY;

    struct cursor cursor;
    cursor_ctor(&cursor, payload, cap_len);
    uint8_t type;
    size_t len;

    /* In this phase, we are looking for SimpleQuery from the client and Data from the server.
     * This is very simplistic, to be completed later with more interresting query types.
     * Also, the client can send a termination request. */
    if (info->is_query) {
        status = cursor_read_msg(&cursor, &type, &len);
        if (status != PROTO_OK) return status;

        if (type == 'Q') {  // simple query
            char *sql;
            status = cursor_read_string(&cursor, &sql, len);
            if (status != PROTO_OK) return status;
            info->set_values |= SQL_SQL;
            snprintf(info->u.query.sql, sizeof(info->u.query.sql), "%s", sql);
        } else if (type == 'X') {
            info->msg_type = SQL_EXIT;
            info->set_values |= SQL_REQUEST_STATUS;
            info->request_status = SQL_REQUEST_COMPLETE;
            pg_parser->phase = EXIT;
        } else return PROTO_PARSE_ERR;
    } else {
        while (! cursor_is_empty(&cursor)) {
            uint8_t const *const msg_start = cursor.head;
            status = cursor_read_msg(&cursor, &type, &len);
            if (status == PROTO_PARSE_ERR) return status;
            else if (status == PROTO_TOO_SHORT) {
                SLOG(LOG_DEBUG, "Payload too short for parsing message, will restart");
                status = proto_parse(NULL, &info->info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);    // ack what we had so far
                streambuf_set_restart(&pg_parser->sbuf, way, msg_start, true);
                return PROTO_OK;
            }

            uint8_t const *const msg_end = cursor.head + len;
            if (type == 'T') {  // row description (fetch nb_fields)
                if (len < 2) return PROTO_PARSE_ERR;
                info->u.query.nb_fields = cursor_read_u16n(&cursor);
                info->set_values |= SQL_NB_FIELDS;
                SLOG(LOG_DEBUG, "Setting nb_fields to %u", info->u.query.nb_fields);
            } else if (type == 'D') {   // data row
                if (len < 2) return PROTO_PARSE_ERR;
                if (! (info->set_values & SQL_NB_ROWS)) {
                    info->set_values |= SQL_NB_ROWS;
                    info->u.query.nb_rows = 0;
                }
                info->u.query.nb_rows ++;
                SLOG(LOG_DEBUG, "Incrementing nb_rows (now %u)", info->u.query.nb_rows);
            } else if (type == 'C') {   // command complete (fetch nb rows)
                char *result;
                info->set_values |= SQL_REQUEST_STATUS;
                info->request_status = SQL_REQUEST_COMPLETE;
                status = cursor_read_string(&cursor, &result, len);
                if (status != PROTO_OK) return status;
                status = fetch_nb_rows(result, &info->u.query.nb_rows);
                if (status == PROTO_OK) {
                    info->set_values |= SQL_NB_ROWS;
                } else {
                    //return status;    // Do not use this as the actual protocol does not seam to implement the doc :-<
                }
            } else if (type == 'E') {   // error
                status = pg_parse_error(info, &cursor, len);
                if (status != PROTO_OK) return status;
            }
            // Skip what's left of this message and go for the next
            assert(msg_end >= cursor.head);
            cursor_drop(&cursor, msg_end - cursor.head);
        }
    }

    return proto_parse(NULL, &info->info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);
}
Ejemplo n.º 20
0
static enum proto_parse_status skinny_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    struct skinny_parser *skinny_parser = DOWNCAST(parser, parser, skinny_parser);

#   define SKINNY_HDR_SIZE 8
#   define SKINNY_MIN_MSG_SIZE 12
    if (wire_len < SKINNY_MIN_MSG_SIZE) {
        streambuf_set_restart(&skinny_parser->sbuf, way, packet, true); // wait for more
        return PROTO_OK;
    }
    if (cap_len < SKINNY_MIN_MSG_SIZE) return PROTO_TOO_SHORT;

    struct cursor curs;
    cursor_ctor(&curs, packet, cap_len);
    uint32_t msg_len = cursor_read_u32le(&curs);
    enum skinny_header_version header_ver = cursor_read_u32le(&curs);
    enum skinny_msgid msg_id = cursor_read_u32le(&curs);
    SLOG(LOG_DEBUG, "New SKINNY msg of size %"PRIu32", msgid=0x%"PRIx32, msg_len, msg_id);
    if (header_ver != SKINNY_BASIC && header_ver != SKINNY_CM7_TYPE_A && header_ver != SKINNY_CM7_TYPE_B && header_ver != SKINNY_CM7_TYPE_C) return PROTO_PARSE_ERR;
    if (msg_len < 4 || msg_len > SKINNY_MAX_HDR_SIZE /* guestimated */) return PROTO_PARSE_ERR;
    if (wire_len < msg_len + SKINNY_HDR_SIZE) return PROTO_TOO_SHORT; // wait for the message to be complete
    // Ok we have what looks like a skinny message in there
    struct skinny_proto_info info;
    skinny_proto_info_ctor(&info, parser, parent, SKINNY_HDR_SIZE, msg_len, msg_id, header_ver);
    switch (msg_id) {
        case SKINNY_STATION_KEY_PAD_BUTTON:
            if (curs.cap_len < 12) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_NEW_KEY_PAD | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            info.new_key_pad = cursor_read_u32le(&curs);
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_CALL_STATE:
            if (curs.cap_len < 12) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CALL_STATE | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            info.call_state = cursor_read_u32le(&curs);
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            SLOG(LOG_DEBUG, "New call state: %s", skinny_call_state_2_str(info.call_state));
            break;
        case SKINNY_MGR_CLOSE_RECV_CHANNEL:
        case SKINNY_MGR_STOP_MEDIA_TRANSMIT:
            if (curs.cap_len < 8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CONFERENCE_ID | SKINNY_PASS_THRU_ID;
            info.conf_id = cursor_read_u32le(&curs);
            info.pass_thru_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_START_MEDIA_TRANSMIT:
            if (curs.cap_len < 8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CONFERENCE_ID | SKINNY_PASS_THRU_ID;
            info.conf_id = cursor_read_u32le(&curs);
            info.pass_thru_id = cursor_read_u32le(&curs);
            enum proto_parse_status status = read_channel(skinny_parser, FROM_MGR, &info, &curs, now);
            if (PROTO_OK != status) return status;
            break;
        case SKINNY_STATION_OPEN_RECV_CHANNEL_ACK:
            if (curs.cap_len < 4) return PROTO_TOO_SHORT;
            uint32_t open_status = cursor_read_u32le(&curs);
            if (open_status == 0 /* Ok */) {
                enum proto_parse_status status = read_channel(skinny_parser, FROM_STATION, &info, &curs, now);
                if (PROTO_OK != status) return status;
                info.set_values |= SKINNY_PASS_THRU_ID;
                if (curs.cap_len < 4) return PROTO_TOO_SHORT;
                info.pass_thru_id = cursor_read_u32le(&curs);
            }
            break;
        case SKINNY_MGR_OPEN_RECV_CHANNEL:
            if (curs.cap_len < 8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CONFERENCE_ID | SKINNY_PASS_THRU_ID;
            info.conf_id = cursor_read_u32le(&curs);
            info.pass_thru_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_DIALED_NUMBER:
#           define DIALED_NUMBER_SIZE 24
            if (curs.cap_len < DIALED_NUMBER_SIZE+8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CALLED_PARTY | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            // 24 chars, terminated with 0 (if fits)
            snprintf(info.called_party, sizeof(info.called_party), "%.*s", (int)DIALED_NUMBER_SIZE, curs.head);
            cursor_drop(&curs, DIALED_NUMBER_SIZE);
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_CALL_INFO:
            if (curs.cap_len < 8 + 4 + 5*4) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CALLING_PARTY | SKINNY_CALLED_PARTY | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            cursor_drop(&curs, 4 + 5*4);  // drop Call Type and 5 unknown fields
            // From now on, informations are nul terminated strings
            if (PROTO_OK != (status = read_string(info.calling_party, sizeof(info.calling_party), &curs))) return status; // Calling party
            if (header_ver == SKINNY_CM7_TYPE_A || header_ver == SKINNY_CM7_TYPE_B || header_ver == SKINNY_CM7_TYPE_C) {
                    cursor_read_string(&curs, NULL, 24); // Drop calling party voice mailbox
            }
            if (PROTO_OK != (status = read_string(info.called_party,  sizeof(info.called_party),  &curs))) return status; // Called party
            // discard the rest of informations
            break;
        default:
            break;
    }
    (void)proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);

    streambuf_set_restart(&skinny_parser->sbuf, way, packet + SKINNY_HDR_SIZE + msg_len, false); // go to next msg

    return PROTO_OK;
}