static enum proto_parse_status sdp_parse(struct parser *parser, struct proto_layer *parent, unsigned way, uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const *now, proto_okfn_t *okfn) { struct sdp_parser *sdp_parser = DOWNCAST(parser, parser, sdp_parser); static struct sdper_field const fields[] = { { 1, "c", sdp_extract_host }, { 1, "m", sdp_extract_port }, }; static struct sdper const sdper = { .nb_fields = NB_ELEMS(fields), .fields = fields }; SLOG(LOG_DEBUG, "Starting SDP analysis"); /* Parse */ struct sdp_proto_info info; sdp_proto_info_ctor(&info, wire_len, 0); struct proto_layer layer; proto_layer_ctor(&layer, parent, parser, &info.info); if (0 != sdper_parse(&sdper, &cap_len, packet, cap_len, &info)) return PROTO_PARSE_ERR; if ( (info.set_values & SDP_PORT_SET) && (info.set_values & SDP_HOST_SET) ) { SLOG(LOG_DEBUG, "SDP@%p, connect info is %s:%"PRIu16, sdp_parser, ip_addr_2_str(&info.host), info.port); if (! sdp_parser->host_set) { sdp_parser->host_set = true; sdp_parser->host = info.host; sdp_parser->port = info.port; ASSIGN_LAYER_AND_INFO_OPT(ip, parent); if (layer_ip) { sdp_parser->sender = ip->key.addr[0]; sdp_parser->sender_set = true; } else { sdp_parser->sender_set = false; } } else if (0 != ip_addr_cmp(&sdp_parser->host, &info.host)) { // Start conntracking between the advertized hosts spawn_subparsers(&sdp_parser->host, sdp_parser->port, &info.host, info.port, parent, now); ASSIGN_LAYER_AND_INFO_OPT(ip, parent); bool may_use_stun[2] = { 0 != ip_addr_cmp(&sdp_parser->sender, &sdp_parser->host), ip && 0 != ip_addr_cmp(&ip->key.addr[0], &info.host), }; // If the sender IP was different from the advertized host, start conntracking on this socket also if (may_use_stun[0]) { spawn_subparsers(&sdp_parser->sender, sdp_parser->port, &info.host, info.port, parent, now); } // If _this_ sender IP is different from this advertized host, start conntracking on this socket as well if (may_use_stun[1]) { spawn_subparsers(&sdp_parser->host, sdp_parser->port, &ip->key.addr[0], info.port, parent, now); } // If both senders IP were different from advertized ones then start conntracking between these two senders IP as well if (may_use_stun[0] && may_use_stun[1]) { spawn_subparsers(&sdp_parser->sender, sdp_parser->port, &ip->key.addr[0], info.port, parent, now); } // TODO: terminate this parser. meanwhile, reset its state : sdp_parser->host_set = false; sdp_parser->sender_set = false; } } return proto_parse(NULL, &layer, way, NULL, 0, 0, now, okfn); }
static enum proto_parse_status sdp_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 sdp_parser *sdp_parser = DOWNCAST(parser, parser, sdp_parser); static struct sdper_field const fields[] = { { 1, "c", sdp_extract_host }, { 1, "m", sdp_extract_port }, }; static struct sdper const sdper = { .nb_fields = NB_ELEMS(fields), .fields = fields }; SLOG(LOG_DEBUG, "Starting SDP analysis"); /* Parse */ struct sdp_proto_info info; sdp_proto_info_ctor(&info, parser, parent, wire_len, 0); if (0 != sdper_parse(&sdper, &cap_len, packet, cap_len, &info)) return PROTO_PARSE_ERR; // Start conntracking of RT(C)P streams if we have all required informations if ( (info.set_values & SDP_PORT_SET) && (info.set_values & SDP_HOST_SET) ) { SLOG(LOG_DEBUG, "SDP@%p, connect info is %s:%"PRIu16, sdp_parser, ip_addr_2_str(&info.host), info.port); /* FIXME: store both peers of the SDP tunnel and respawn the RT(C)Ps as soon as * one of the end changes. Problem is: we don't know which peer this is! */ if (! sdp_parser->host_set) { sdp_parser->host_set = true; sdp_parser->host = info.host; sdp_parser->port = info.port; ASSIGN_INFO_OPT(ip, parent); if (ip) { sdp_parser->sender = ip->key.addr[0]; sdp_parser->sender_set = true; } else { sdp_parser->sender_set = false; } } else if (0 != ip_addr_cmp(&sdp_parser->host, &info.host)) { /* Start conntracking between the advertized hosts * Notice that we request RT(C)P on behalf of our parent! */ spawn_rtp_subparsers(&sdp_parser->host, sdp_parser->port, &info.host, info.port, now, parent->parser->proto); ASSIGN_INFO_OPT(ip, parent); bool may_use_stun[2] = { 0 != ip_addr_cmp(&sdp_parser->sender, &sdp_parser->host), ip && 0 != ip_addr_cmp(&ip->key.addr[0], &info.host), }; // If the sender IP was different from the advertized host, start conntracking on this socket too if (may_use_stun[0]) { spawn_rtp_subparsers(&sdp_parser->sender, sdp_parser->port, &info.host, info.port, now, parent->parser->proto); } // If _this_ sender IP is different from this advertized host, start conntracking on this socket as well if (may_use_stun[1]) { spawn_rtp_subparsers(&sdp_parser->host, sdp_parser->port, &ip->key.addr[0], info.port, now, parent->parser->proto); } // If both senders IP were different from advertized ones then start conntracking between these two senders IP as well if (may_use_stun[0] && may_use_stun[1]) { spawn_rtp_subparsers(&sdp_parser->sender, sdp_parser->port, &ip->key.addr[0], info.port, now, parent->parser->proto); } // TODO: terminate this parser. meanwhile, reset its state : sdp_parser->host_set = false; sdp_parser->sender_set = false; } } return proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet); }