diff --git a/conf/vanilla/autoload_configs/verto.conf.xml b/conf/vanilla/autoload_configs/verto.conf.xml index a62fd706d7..b69777ac0a 100644 --- a/conf/vanilla/autoload_configs/verto.conf.xml +++ b/conf/vanilla/autoload_configs/verto.conf.xml @@ -5,9 +5,9 @@ - - - + + + @@ -21,7 +21,28 @@ - + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 37631fce70..bc25817225 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -125,6 +125,9 @@ typedef struct switch_core_media_params_s { char *extrtpip; char *rtpip; + char *rtpip4; + char *rtpip6; + char *remote_ip; int remote_port; diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 6dfa1e2531..4bb140c83d 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -105,6 +105,7 @@ typedef struct ice_s { icand_t cands[MAX_CAND][2]; int cand_idx; int chosen[2]; + int is_chosen[2]; char *ufrag; char *pwd; char *options; diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.c b/src/mod/endpoints/mod_verto/mcast/mcast.c index e37ac08efc..617553bcc4 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast.c +++ b/src/mod/endpoints/mod_verto/mcast/mcast.c @@ -58,16 +58,29 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags) { uint32_t one = 1; + int family = AF_INET; memset(handle, 0, sizeof(*handle)); - if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0 ) { - return -1; + if (strchr(host, ':')) { + family = AF_INET6; } - handle->send_addr.sin_family = AF_INET; - handle->send_addr.sin_addr.s_addr = inet_addr(host); - handle->send_addr.sin_port = htons(port); + if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(family, SOCK_DGRAM, 0)) <= 0 ) { + return -1; + } + + if (family == AF_INET6) { + handle->send_addr6.sin6_family = AF_INET6; + handle->send_addr6.sin6_port = htons(port); + inet_pton(AF_INET6, host, &(handle->send_addr6.sin6_addr)); + handle->family = AF_INET6; + } else { + handle->send_addr.sin_family = AF_INET; + handle->send_addr.sin_addr.s_addr = inet_addr(host); + handle->send_addr.sin_port = htons(port); + handle->family = AF_INET; + } if ( setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0 ) { close(handle->sock); @@ -76,28 +89,61 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, if ((flags & MCAST_RECV)) { - struct ip_mreq mreq; + if (handle->family == AF_INET) { + struct ip_mreq mreq; + + handle->recv_addr.sin_family = AF_INET; + handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + handle->recv_addr.sin_port = htons(port); - handle->recv_addr.sin_family = AF_INET; - handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - handle->recv_addr.sin_port = htons(port); + mreq.imr_multiaddr.s_addr = inet_addr(host); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); - mreq.imr_multiaddr.s_addr = inet_addr(host); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { + close(handle->sock); + handle->sock = -1; + return -1; + } - if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { - close(handle->sock); - handle->sock = -1; - return -1; + if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) { + close(handle->sock); + handle->sock = -1; + return -1; + } + + } else { + struct ipv6_mreq mreq; + struct addrinfo addr_criteria; + struct addrinfo *mcast_addr; + char service[80] = ""; + + memset(&addr_criteria, 0, sizeof(addr_criteria)); + addr_criteria.ai_family = AF_UNSPEC; + addr_criteria.ai_socktype = SOCK_DGRAM; + addr_criteria.ai_protocol = IPPROTO_UDP; + addr_criteria.ai_flags |= AI_NUMERICHOST; + + snprintf(service, sizeof(service), "%d", port); + getaddrinfo(host, service, &addr_criteria, &mcast_addr); + + + memset(&handle->recv_addr6, 0, sizeof(handle->recv_addr6)); + handle->recv_addr6.sin6_family = AF_INET6; + handle->recv_addr6.sin6_port = htons(port); + inet_pton(AF_INET6, "::0", &(handle->recv_addr6.sin6_addr)); + + memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *)mcast_addr->ai_addr)->sin6_addr, sizeof(struct in6_addr)); + + mreq.ipv6mr_interface = 0; + setsockopt(handle->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)); + + if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr6, sizeof(handle->recv_addr6)) < 0) { + printf("FUCK (%s) %s\n", host, strerror(errno)); + close(handle->sock); + handle->sock = -1; + return -1; + } } - - if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) { - close(handle->sock); - handle->sock = -1; - return -1; - } - - } handle->ttl = 1; @@ -155,7 +201,11 @@ ssize_t mcast_socket_send(mcast_handle_t *handle, void *data, size_t datalen) datalen = sizeof(handle->buffer); } - return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr)); + if (handle->family == AF_INET6) { + return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr6, sizeof(handle->send_addr6)); + } else { + return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr)); + } } ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, int ms) @@ -175,6 +225,9 @@ ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, in } } - - return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen); + if (handle->family == AF_INET6) { + return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr6, &addrlen); + } else { + return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen); + } } diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.h b/src/mod/endpoints/mod_verto/mcast/mcast.h index 915f803fe8..bc9114abce 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast.h +++ b/src/mod/endpoints/mod_verto/mcast/mcast.h @@ -71,6 +71,9 @@ typedef struct { unsigned char ttl; struct sockaddr_in send_addr; struct sockaddr_in recv_addr; + struct sockaddr_in6 send_addr6; + struct sockaddr_in6 recv_addr6; + int family; unsigned char buffer[65536]; int ready; } mcast_handle_t; diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 1d422a53ad..57faa8e38a 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -1803,12 +1803,6 @@ error: static void client_run(jsock_t *jsock) { - - jsock->local_addr.sin_family = AF_INET; - jsock->local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - jsock->local_addr.sin_port = 0; - - if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) { if (jsock->profile->vhosts) { http_run(jsock); @@ -2259,10 +2253,30 @@ static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *prof { uint32_t i; - tech_pvt->mparams->rtpip = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]); + if (!zstr(profile->rtpip[profile->rtpip_cur])) { + tech_pvt->mparams->rtpip4 = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]); + tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip4; + if (profile->rtpip_cur == profile->rtpip_index) { + profile->rtpip_cur = 0; + } + } - if (profile->rtpip_cur == profile->rtpip_index) { - profile->rtpip_cur = 0; + if (!zstr(profile->rtpip6[profile->rtpip_cur6])) { + tech_pvt->mparams->rtpip6 = switch_core_session_strdup(tech_pvt->session, profile->rtpip6[profile->rtpip_cur6++]); + + if (zstr(tech_pvt->mparams->rtpip)) { + tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip6; + } + + if (profile->rtpip_cur6 == profile->rtpip_index6) { + profile->rtpip_cur6 = 0; + } + } + + if (zstr(tech_pvt->mparams->rtpip)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s has no media ip, check your configuration\n", + switch_channel_get_name(tech_pvt->channel)); + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL); } tech_pvt->mparams->extrtpip = tech_pvt->mparams->extsipip = profile->extrtpip; @@ -3376,7 +3390,7 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock switch_either(jsock->dialplan, jsock->profile->dialplan), caller_id_name, caller_id_number, - inet_ntoa(jsock->remote_addr.sin_addr), + jsock->remote_host, cJSON_GetObjectCstr(dialog, "ani"), cJSON_GetObjectCstr(dialog, "aniii"), cJSON_GetObjectCstr(dialog, "rdnis"), @@ -3778,7 +3792,7 @@ static void jrpc_init(void) -static int start_jsock(verto_profile_t *profile, ws_socket_t sock) +static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family) { jsock_t *jsock = NULL; int flag = 1; @@ -3798,11 +3812,20 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock) jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock)); jsock->pool = pool; + jsock->family = family; - len = sizeof(jsock->remote_addr); + if (family == PF_INET) { + len = sizeof(jsock->remote_addr); - if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) { - die("ACCEPT FAILED\n"); + if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) { + die("ACCEPT FAILED\n"); + } + } else { + len = sizeof(jsock->remote_addr6); + + if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr6, &len)) < 0) { + die("ACCEPT FAILED\n"); + } } for (i = 0; i < profile->i; i++) { @@ -3818,7 +3841,15 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock) jsock->profile = profile; if (zstr(jsock->name)) { - jsock->name = switch_core_sprintf(pool, "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port)); + if (family == PF_INET) { + jsock->remote_port = ntohs(jsock->remote_addr.sin_port); + inet_ntop(AF_INET, &jsock->remote_addr.sin_addr, jsock->remote_host, sizeof(jsock->remote_host)); + jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port); + } else { + jsock->remote_port = ntohs(jsock->remote_addr6.sin6_port); + inet_ntop(AF_INET6, &jsock->remote_addr6.sin6_addr, jsock->remote_host, sizeof(jsock->remote_host)); + jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port); + } } jsock->ptype = ptype; @@ -3826,7 +3857,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Client Connect.\n", jsock->name); if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_CLIENT_CONNECT) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", profile->name); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port)); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", jsock->remote_host, jsock->remote_port); switch_event_fire(&s_event); } @@ -3873,7 +3904,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock) return -1; } -static ws_socket_t prepare_socket(int ip, uint16_t port) +static ws_socket_t prepare_socket(ips_t *ips) { ws_socket_t sock = ws_sock_invalid; #ifndef WIN32 @@ -3881,29 +3912,48 @@ static ws_socket_t prepare_socket(int ip, uint16_t port) #else char reuse_addr = 1; #endif + int family; struct sockaddr_in addr; + struct sockaddr_in6 addr6; - if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + if (strchr(ips->local_ip, ':')) { + family = PF_INET6; + } else { + family = PF_INET; + } + + if ((sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) { die("Socket Error!\n"); } if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) { die("Socket setsockopt Error!\n"); } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = ip; - addr.sin_port = htons(port); - - if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - die("Bind Error!\n"); - } + if (family == PF_INET) { + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(ips->local_ip); + addr.sin_port = htons(ips->local_port); + if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + die("Bind Error!\n"); + } + } else { + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(ips->local_port); + inet_pton(AF_INET6, ips->local_ip, &(addr6.sin6_addr)); + if (bind(sock, (struct sockaddr *) &addr6, sizeof(addr6)) < 0) { + die("Bind Error!\n"); + } + } + if (listen(sock, MAXPENDING) < 0) { die("Listen error\n"); } + ips->family = family; + return sock; error: @@ -3979,7 +4029,7 @@ static int profile_one_loop(verto_profile_t *profile) if (profile->mcast_ip && pfds[x].sock == (switch_os_socket_t)profile->mcast_sub.sock) { handle_mcast_sub(profile); } else { - start_jsock(profile, pfds[x].sock); + start_jsock(profile, pfds[x].sock, profile->ip[x].family); } } } @@ -3991,52 +4041,6 @@ static int profile_one_loop(verto_profile_t *profile) } -static int runtime(verto_profile_t *profile) -{ - int i; - - for (i = 0; i < profile->i; i++) { - if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) { - die("Client Socket Error!\n"); - } - } - - if (profile->mcast_ip) { - if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) { - die("mcast recv socket create"); - } - - if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) { - mcast_socket_close(&profile->mcast_sub); - die("mcast send socket create"); - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1); - } - - - while(profile->running) { - if (profile_one_loop(profile) < 0) { - goto error; - } - } - - if (profile->mcast_sub.sock > -1) { - mcast_socket_close(&profile->mcast_sub); - } - - if (profile->mcast_pub.sock > -1) { - mcast_socket_close(&profile->mcast_pub); - } - - return 0; - - error: - - return -1; - -} - static void kill_profile(verto_profile_t *profile) { jsock_t *p; @@ -4092,6 +4096,58 @@ static void kill_profiles(void) } +static int runtime(verto_profile_t *profile) +{ + int i; + int r = 0; + + for (i = 0; i < profile->i; i++) { + //if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) { + if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) < 0) { + die("Client Socket Error!\n"); + } + } + + if (profile->mcast_ip) { + if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) { + r = -1; + die("mcast recv socket create\n"); + } + + if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) { + mcast_socket_close(&profile->mcast_sub); + r = -1; + die("mcast send socket create\n"); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1); + } + + + while(profile->running) { + if (profile_one_loop(profile) < 0) { + goto error; + } + } + + error: + + if (profile->mcast_sub.sock > -1) { + mcast_socket_close(&profile->mcast_sub); + } + + if (profile->mcast_pub.sock > -1) { + mcast_socket_close(&profile->mcast_pub); + } + + if (r) { + kill_profile(profile); + } + + return r; + +} + static void do_shutdown(void) { globals.running = 0; @@ -4105,20 +4161,35 @@ static void do_shutdown(void) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n"); } -static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input) + +static void parse_ip(char *host, switch_size_t host_len, uint16_t *port, char *input) { char *p; - struct hostent *hent; + //struct hostent *hent; - strncpy(host, input, 255); - - host[255] = 0; - - if ((p = strchr(host, ':')) != NULL) { - *p++ = '\0'; - *port = (uint16_t)atoi(p); + if ((p = strchr(input, '['))) { + char *end = switch_find_end_paren(p, '[', ']'); + if (end) { + p++; + strncpy(host, p, end - p); + if (*(end+1) == ':' && end + 2 < end_of_p(input)) { + end += 2; + if (end) { + *port = (uint16_t)atoi(end); + } + } + } else { + strncpy(host, "::", host_len); + } + } else { + strncpy(host, input, host_len); + if ((p = strrchr(host, ':')) != NULL) { + *p++ = '\0'; + *port = (uint16_t)atoi(p); + } } +#if 0 if ( host[0] < '0' || host[0] > '9' ) { // Non-numeric host (at least it doesn't start with one). Convert it to ip addr first if ((hent = gethostbyname(host)) != NULL) { @@ -4130,8 +4201,10 @@ static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input) } else { *addr = inet_addr(host); } +#endif } + static verto_profile_t *find_profile(const char *name) { verto_profile_t *p, *r = NULL; @@ -4264,7 +4337,7 @@ static switch_status_t parse_config(const char *cf) if (!strcasecmp(var, "bind-local")) { const char *secure = switch_xml_attr_soft(param, "secure"); if (i < MAX_BIND) { - parse_ip(profile->ip[profile->i].local_ip, &profile->ip[profile->i].local_port, &profile->ip[profile->i].local_ip_addr, val); + parse_ip(profile->ip[profile->i].local_ip, sizeof(profile->ip[profile->i].local_ip), &profile->ip[profile->i].local_port, val); if (switch_true(secure)) { profile->ip[profile->i].secure = 1; } @@ -4316,10 +4389,18 @@ static switch_status_t parse_config(const char *cf) if (zstr(val)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n"); } else { - if (profile->rtpip_index < MAX_RTPIP -1) { - profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val); + if (strchr(val, ':')) { + if (profile->rtpip_index6 < MAX_RTPIP -1) { + profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n"); + } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n"); + if (profile->rtpip_index < MAX_RTPIP -1) { + profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n"); + } } } } else if (!strcasecmp(var, "ext-rtp-ip")) { diff --git a/src/mod/endpoints/mod_verto/mod_verto.h b/src/mod/endpoints/mod_verto/mod_verto.h index 11614926a6..eccd095369 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.h +++ b/src/mod/endpoints/mod_verto/mod_verto.h @@ -106,9 +106,8 @@ struct jsock_s { unsigned char buf[65535]; char *name; jsock_type_t ptype; - struct sockaddr_in local_addr; struct sockaddr_in remote_addr; - struct sockaddr_in send_addr; + struct sockaddr_in6 remote_addr6; #ifndef WIN32 struct passwd pw; #endif @@ -132,6 +131,11 @@ struct jsock_s { char *dialplan; char *context; + + char remote_host[256]; + int remote_port; + int family; + struct verto_profile_s *profile; switch_thread_rwlock_t *rwlock; @@ -155,12 +159,12 @@ typedef struct jsock_s jsock_t; #define MAX_BIND 25 #define MAX_RTPIP 25 -struct ips { +typedef struct ips { char local_ip[256]; - in_addr_t local_ip_addr; uint16_t local_port; int secure; -}; + int family; +} ips_t; typedef enum { TFLAG_SENT_MEDIA = (1 << 0), @@ -240,6 +244,10 @@ struct verto_profile_s { int rtpip_index; int rtpip_cur; + char *rtpip6[MAX_RTPIP]; + int rtpip_index6; + int rtpip_cur6; + char *cand_acl[SWITCH_MAX_CAND_ACL]; uint32_t cand_acl_count; diff --git a/src/mod/endpoints/mod_verto/ws.c b/src/mod/endpoints/mod_verto/ws.c index 8a46b65502..6e9a69d025 100644 --- a/src/mod/endpoints/mod_verto/ws.c +++ b/src/mod/endpoints/mod_verto/ws.c @@ -691,6 +691,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data) ssize_t need = 2; char *maskp; int ll = 0; + int frag = 0; again: need = 2; @@ -741,8 +742,16 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data) case WSOC_PING: case WSOC_PONG: { - //int fin = (wsh->buffer[0] >> 7) & 1; + int fin = (wsh->buffer[0] >> 7) & 1; int mask = (wsh->buffer[1] >> 7) & 1; + + if (fin) { + if (*oc == WSOC_CONTINUATION) { + frag = 1; + } else { + frag = 0; + } + } if (mask) { need += 4; @@ -837,6 +846,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data) ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen); goto again; } + + if (frag) { + goto again; + } *(wsh->payload+wsh->rplen) = '\0'; diff --git a/src/switch_core.c b/src/switch_core.c index 753dfa5a26..5ed8ad83a1 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1331,7 +1331,12 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_ free(list_name_dup); } else { switch_parse_cidr(list_name, &net, &mask, &bits); - ok = switch_test_subnet(ip.v4, net.v4, mask.v4); + + if (ipv6) { + ok = switch_testv6_subnet(ip, net, mask); + } else { + ok = switch_test_subnet(ip.v4, net.v4, mask.v4); + } } } switch_mutex_unlock(runtime.global_mutex); @@ -1395,6 +1400,26 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE); switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); + tmp_name = "wan_v6.auto"; + switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name); + switch_network_list_add_cidr(rfc_list, "0.0.0.0/0", SWITCH_FALSE); + switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE); + switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); + + + tmp_name = "wan_v4.auto"; + switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name); + switch_network_list_add_cidr(rfc_list, "0.0.0.0/8", SWITCH_FALSE); + switch_network_list_add_cidr(rfc_list, "10.0.0.0/8", SWITCH_FALSE); + switch_network_list_add_cidr(rfc_list, "172.16.0.0/12", SWITCH_FALSE); + switch_network_list_add_cidr(rfc_list, "192.168.0.0/16", SWITCH_FALSE); + switch_network_list_add_cidr(rfc_list, "169.254.0.0/16", SWITCH_FALSE); + switch_network_list_add_cidr(rfc_list, "::/0", SWITCH_FALSE); + switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); + + tmp_name = "nat.auto"; switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 7a469575d4..d20af51290 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -2885,6 +2885,8 @@ static void clear_ice(switch_core_session_t *session, switch_media_type_t type) engine->ice_in.chosen[0] = 0; engine->ice_in.chosen[1] = 0; + engine->ice_in.is_chosen[0] = 0; + engine->ice_in.is_chosen[1] = 0; engine->ice_in.cand_idx = 0; memset(&engine->ice_in, 0, sizeof(engine->ice_in)); engine->remote_rtcp_port = 0; @@ -3047,6 +3049,52 @@ SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session return r; } +//? +static switch_status_t ip_choose_family(switch_media_handle_t *smh, const char *ip) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + if (zstr(ip)) { + return status; + } + + if (strchr(ip, ':')) { + if (!zstr(smh->mparams->rtpip6)) { + smh->mparams->rtpip = smh->mparams->rtpip6; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v6\n", + switch_channel_get_name(smh->session->channel)); + status = SWITCH_STATUS_SUCCESS; + } + } else { + if (!zstr(smh->mparams->rtpip4)) { + smh->mparams->rtpip = smh->mparams->rtpip4; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v4\n", + switch_channel_get_name(smh->session->channel)); + status = SWITCH_STATUS_SUCCESS; + } + } + + return status; +} + +//? +static switch_bool_t ip_possible(switch_media_handle_t *smh, const char *ip) +{ + switch_bool_t r = SWITCH_FALSE; + + if (zstr(ip)) { + return r; + } + + if (strchr(ip, ':')) { + r = (switch_bool_t) !zstr(smh->mparams->rtpip6); + } else { + r = (switch_bool_t) !zstr(smh->mparams->rtpip4); + } + + return r; +} + //? static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m) { @@ -3055,12 +3103,14 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ int i = 0, got_rtcp_mux = 0; const char *val; - if (engine->ice_in.chosen[0] && engine->ice_in.chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) { + if (engine->ice_in.is_chosen[0] && engine->ice_in.is_chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) { return; } engine->ice_in.chosen[0] = 0; engine->ice_in.chosen[1] = 0; + engine->ice_in.is_chosen[0] = 0; + engine->ice_in.is_chosen[1] = 0; engine->ice_in.cand_idx = 0; if (m) { @@ -3074,6 +3124,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ char *fields[15]; int argc = 0, j = 0; int cid = 0; + int pass_acl = 0; if (zstr(attr->a_name)) { continue; @@ -3150,55 +3201,61 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Checking Candidate cid: %d proto: %s type: %s addr: %s:%s\n", cid+1, fields[2], fields[7], fields[4], fields[5]); - - - engine->ice_in.cand_idx++; + + pass_acl = 0; for (i = 0; i < engine->cand_acl_count; i++) { - if (!engine->ice_in.chosen[cid] && !strchr(fields[4], ':') && switch_check_network_list_ip(fields[4], engine->cand_acl[i])) { - engine->ice_in.chosen[cid] = engine->ice_in.cand_idx; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, - "Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n", - type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", - cid+1, fields[2], fields[7], fields[4], fields[5]); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, - "Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n", - type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", - cid+1, fields[2], fields[7], fields[4], fields[5]); + if (switch_check_network_list_ip(fields[4], engine->cand_acl[i])) { + pass_acl = 1; + break; } - - engine->ice_in.cands[engine->ice_in.cand_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]); - engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]); - engine->ice_in.cands[engine->ice_in.cand_idx][cid].transport = switch_core_session_strdup(smh->session, fields[2]); - engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]); - engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]); - engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]); - - - j = 6; - - while(j < argc && fields[j+1]) { - if (!strcasecmp(fields[j], "typ")) { - engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]); - } else if (!strcasecmp(fields[j], "raddr")) { - engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]); - } else if (!strcasecmp(fields[j], "rport")) { - engine->ice_in.cands[engine->ice_in.cand_idx][cid].rport = (switch_port_t)atoi(fields[j+1]); - } else if (!strcasecmp(fields[j], "generation")) { - engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]); - } - - j += 2; - } - - - if (engine->ice_in.chosen[cid]) { - engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++; - } - - break; } + + if (!engine->ice_in.is_chosen[cid] && ip_possible(smh, fields[4]) && pass_acl) { + engine->ice_in.chosen[cid] = engine->ice_in.cand_idx; + engine->ice_in.is_chosen[cid] = 1; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, + "Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n", + type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", + cid+1, fields[2], fields[7], fields[4], fields[5]); + ip_choose_family(smh, fields[4]); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, + "Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n", + type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", + cid+1, fields[2], fields[7], fields[4], fields[5]); + } + + engine->ice_in.cands[engine->ice_in.cand_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]); + engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]); + engine->ice_in.cands[engine->ice_in.cand_idx][cid].transport = switch_core_session_strdup(smh->session, fields[2]); + engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]); + engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]); + engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]); + + j = 6; + + while(j < argc && fields[j+1]) { + if (!strcasecmp(fields[j], "typ")) { + engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]); + } else if (!strcasecmp(fields[j], "raddr")) { + engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]); + } else if (!strcasecmp(fields[j], "rport")) { + engine->ice_in.cands[engine->ice_in.cand_idx][cid].rport = (switch_port_t)atoi(fields[j+1]); + } else if (!strcasecmp(fields[j], "generation")) { + engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]); + } + + j += 2; + } + + + if (engine->ice_in.is_chosen[cid]) { + engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++; + } + + engine->ice_in.cand_idx++; } } @@ -3206,18 +3263,23 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ /* still no candidates, so start searching for some based on sane deduction */ /* look for candidates on the same network */ - if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) { - for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) { - if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && - !engine->ice_in.cands[i][0].rport && switch_check_network_list_ip(engine->ice_in.cands[i][0].con_addr, "localnet.auto")) { + if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) { + for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]); i++) { + if (!engine->ice_in.is_chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && + !engine->ice_in.cands[i][0].rport && ip_possible(smh, engine->ice_in.cands[i][0].con_addr) && + switch_check_network_list_ip(engine->ice_in.cands[i][0].con_addr, "localnet.auto")) { engine->ice_in.chosen[0] = i; + engine->ice_in.is_chosen[0] = 1; engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++; + ip_choose_family(smh, engine->ice_in.cands[i][0].con_addr); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, "No %s RTP candidate found; defaulting to the first local one.\n", type2str(type)); } - if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && - !engine->ice_in.cands[i][1].rport && switch_check_network_list_ip(engine->ice_in.cands[i][1].con_addr, "localnet.auto")) { + if (!engine->ice_in.is_chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && + !engine->ice_in.cands[i][1].rport && ip_possible(smh, engine->ice_in.cands[i][1].con_addr) && + switch_check_network_list_ip(engine->ice_in.cands[i][1].con_addr, "localnet.auto")) { engine->ice_in.chosen[1] = i; + engine->ice_in.is_chosen[1] = 1; engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE, "No %s RTCP candidate found; defaulting to the first local one.\n", type2str(type)); @@ -3226,16 +3288,21 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ } /* look for candidates with srflx */ - if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) { - for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) { - if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && engine->ice_in.cands[i][0].rport) { + if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) { + for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]); i++) { + if (!engine->ice_in.is_chosen[0] && + engine->ice_in.cands[i][0].component_id == 1 && engine->ice_in.cands[i][0].rport && ip_possible(smh, engine->ice_in.cands[i][0].con_addr)) { engine->ice_in.chosen[0] = i; + engine->ice_in.chosen[1] = 1; engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++; + ip_choose_family(smh, engine->ice_in.cands[i][0].con_addr); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, "No %s RTP candidate found; defaulting to the first srflx one.\n", type2str(type)); } - if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && engine->ice_in.cands[i][1].rport) { + if (!engine->ice_in.is_chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && engine->ice_in.cands[i][1].rport && + ip_possible(smh, engine->ice_in.cands[i][1].con_addr)) { engine->ice_in.chosen[1] = i; + engine->ice_in.is_chosen[1] = 1; engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE, "No %s RTCP candidate found; defaulting to the first srflx one.\n", type2str(type)); @@ -3244,8 +3311,9 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ } /* Got RTP but not RTCP, probably mux */ - if (engine->ice_in.chosen[0] && !engine->ice_in.chosen[1] && got_rtcp_mux) { + if (engine->ice_in.is_chosen[0] && !engine->ice_in.is_chosen[1] && got_rtcp_mux) { engine->ice_in.chosen[1] = engine->ice_in.chosen[0]; + engine->ice_in.is_chosen[1] = 1; memcpy(&engine->ice_in.cands[engine->ice_in.chosen[1]][1], &engine->ice_in.cands[engine->ice_in.chosen[0]][0], sizeof(engine->ice_in.cands[engine->ice_in.chosen[0]][0])); @@ -3257,16 +3325,19 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ } /* look for any candidates and hope for auto-adjust */ - if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) { - for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) { - if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1) { + if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) { + for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]); i++) { + if (!engine->ice_in.is_chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && ip_possible(smh, engine->ice_in.cands[i][0].con_addr)) { engine->ice_in.chosen[0] = i; + engine->ice_in.is_chosen[0] = 1; engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++; + ip_choose_family(smh, engine->ice_in.cands[i][0].con_addr); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, "No %s RTP candidate found; defaulting to the first one.\n", type2str(type)); } - if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2) { + if (!engine->ice_in.is_chosen[1] && engine->ice_in.cands[i][1].component_id == 2) { engine->ice_in.chosen[1] = i; + engine->ice_in.is_chosen[1] = 1; engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, "No %s RTCP candidate found; defaulting to the first one.\n", type2str(type)); @@ -3274,6 +3345,13 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ } } + if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) { + /* PUNT */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s no suitable candidates found.\n", + switch_channel_get_name(smh->session->channel)); + return; + } + for (i = 0; i < 2; i++) { if (engine->ice_in.cands[engine->ice_in.chosen[i]][i].ready) { if (zstr(engine->ice_in.ufrag) || zstr(engine->ice_in.pwd)) { @@ -5476,6 +5554,20 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video) { switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + + if (zstr(smh->mparams->rtpip)) { + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no media ip\n", + switch_channel_get_name(smh->session->channel)); + switch_channel_hangup(smh->session->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL); + + return SWITCH_STATUS_FALSE; + } if (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) { if (video) { @@ -6316,7 +6408,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n", switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) ? "PROXY " : "", switch_channel_get_name(session->channel), - a_engine->cur_payload_map->remote_sdp_ip, + a_engine->local_sdp_ip, v_engine->local_sdp_port, v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt, diff --git a/src/switch_utils.c b/src/switch_utils.c index e53c66d079..59b474045c 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -431,7 +431,8 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_netw for (node = list->node_head; node; node = node->next) { if (node->family == AF_INET) continue; - if (node->bits > bits && switch_testv6_subnet(ip, node->ip, node->mask)) { + + if (node->bits >= bits && switch_testv6_subnet(ip, node->ip, node->mask)) { if (node->ok) { ok = SWITCH_TRUE; } else { @@ -457,7 +458,7 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo for (node = list->node_head; node; node = node->next) { if (node->family == AF_INET6) continue; /* want AF_INET */ - if (node->bits > bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) { + if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) { if (node->ok) { ok = SWITCH_TRUE; } else {