コード例 #1
0
ファイル: skinny.c プロジェクト: bonnefoa/junkie
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;
}
コード例 #2
0
ファイル: tds.c プロジェクト: 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;
}
コード例 #3
0
ファイル: cursor.c プロジェクト: haiwanxue/junkie
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;
}
コード例 #4
0
ファイル: skinny.c プロジェクト: haiwanxue/junkie
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;
}
コード例 #5
0
ファイル: cursor.c プロジェクト: haiwanxue/junkie
uint_least64_t cursor_read_u64le(struct cursor *cursor)
{
    uint_least64_t a = cursor_read_u32le(cursor);
    uint_least64_t b = cursor_read_u32le(cursor);
    return a | (b << 32);
}
コード例 #6
0
ファイル: cursor.c プロジェクト: haiwanxue/junkie
uint_least64_t cursor_read_u64n(struct cursor *cursor)
{
    uint_least64_t a = cursor_read_u32le(cursor);
    uint_least64_t b = cursor_read_u32le(cursor);
    return (a << 32) | b;
}
コード例 #7
0
ファイル: skinny.c プロジェクト: haiwanxue/junkie
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;
}