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; }
static enum proto_parse_status parse_rpc_reply(struct cursor *cursor, struct rpc_proto_info *info) { CHECK(4); info->u.reply_msg.reply_status = cursor_read_u32(cursor); switch (info->u.reply_msg.reply_status) { case RPC_MSG_ACCEPTED: { RPC_CHECK_AUTH(credential); break; } case RPC_MSG_DENIED: { CHECK(4); enum rejected_status rejected_status = cursor_read_u32(cursor); if (rejected_status > RPC_AUTH_ERROR) return PROTO_PARSE_ERR; break; } } return PROTO_OK; }
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); }
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; }