From 298e454678d5d4deca5f2e6f51c7a8ab4c7c5159 Mon Sep 17 00:00:00 2001 From: prlanzarin Date: Wed, 16 Sep 2020 18:58:29 +0000 Subject: [PATCH] Make networkInterfaces work with dual stack environments, add ipIgnoreList This makes networkInterfaces dual stack compatible by removing the usage of nice_interfaces_get_ip_for_interface, which used ioctl and SIOCGIFADDR which are not AF_INET6 compatible This was done via glibc`s getifaddrs. The pitfall here is that, differently from ioctl, this fetches link local and private IPs from interfaces, which brought in the need of manually filtering link local addresses and the introduction of the ipIgnoreList configuration The ipIgnoreList config is a list of IP addresses (v4-6) to be ignored during the gathering phase. With that, you can prevent adding IPs from the desired interfaces you know are useless to libnice`s agent --- .../webrtcendpoint/kmswebrtcbaseconnection.c | 139 +++++++++++++++--- .../webrtcendpoint/kmswebrtcbaseconnection.h | 2 +- .../webrtcendpoint/kmswebrtcendpoint.c | 21 +++ .../webrtcendpoint/kmswebrtcsession.c | 19 ++- .../webrtcendpoint/kmswebrtcsession.h | 1 + src/server/config/WebRtcEndpoint.conf.ini | 18 +++ .../objects/WebRtcEndpointImpl.cpp | 37 +++++ .../objects/WebRtcEndpointImpl.hpp | 3 + .../elements.WebRtcEndpoint.kmd.json | 5 + 9 files changed, 224 insertions(+), 21 deletions(-) diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.c b/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.c index e5a020438..92927348e 100644 --- a/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.c +++ b/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.c @@ -21,6 +21,10 @@ #include // strlen() +// Network interfaces and IP fetching for NiceAgent +#include +#include + #define GST_CAT_DEFAULT kmswebrtcbaseconnection GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); #define GST_DEFAULT_NAME "kmswebrtcbaseconnection" @@ -213,43 +217,140 @@ kms_webrtc_base_connection_split_comma (const gchar * str) return list; } +gint +kms_webrtc_base_connection_cmp_ifa (const gchar * n1, const gchar * n2) { + return strcmp(n1, n2); +} + +gboolean +kms_webrtc_base_connection_agent_is_network_interface_valid (struct ifaddrs * ifa) { + gboolean is_valid = FALSE; + int sa_family; + + // No IP address assigned to interface, skip + if (ifa->ifa_addr == NULL) { + goto end; + } + + // Interface is either down of not running + if (!(ifa->ifa_flags && IFF_UP) || !(ifa->ifa_flags && IFF_RUNNING)) { + goto end; + } + + sa_family = ifa->ifa_addr->sa_family; + + // Only traverse through interfaces which are from the AF_INET/AF_INET6 families + if (sa_family != AF_INET && sa_family != AF_INET6) { + goto end; + } + + is_valid = TRUE; + +end: + return is_valid; +}; + +gboolean +kms_webrtc_base_connection_agent_is_interface_ip_valid (const gchar * ip_address, + GSList * ip_ignore_list) { + gboolean is_valid = FALSE; + + // Link local IPv4, ignore + if (!strncmp(ip_address, "169.254.", 8)) { + goto end; + } + + // Link local IPv6, ignore + if (!strncmp(ip_address, "fe80:", 5)) { + goto end; + } + + // Check if there's an IP ignore list defined and see if the IP address matches + // one of them + if (ip_ignore_list != NULL) { + if (g_slist_find_custom (ip_ignore_list, ip_address, + (GCompareFunc) kms_webrtc_base_connection_cmp_ifa)) { + goto end; + } + } + + is_valid = TRUE; + +end: + return is_valid; +}; + /** * Add new local IP address to NiceAgent instance. */ -static void -kms_webrtc_base_connection_agent_add_net_addr (const gchar * net_name, - NiceAgent * agent) + static void +kms_webrtc_base_connection_agent_add_net_ifs_addrs (NiceAgent * agent, + GSList * net_list, GSList * ip_ignore_list) { - NiceAddress *nice_address = nice_address_new (); - gchar *ip_address = nice_interfaces_get_ip_for_interface ((gchar *)net_name); + struct ifaddrs *ifaddr, *ifa; + gchar ip_address[INET6_ADDRSTRLEN]; + GSList *it; + NiceAddress *nice_address; + + if (getifaddrs(&ifaddr) == -1) { + GST_ERROR ("Failed to fetch system network interfaces"); + return; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!kms_webrtc_base_connection_agent_is_network_interface_valid(ifa)) { + continue; + } + + // See if the network interface is in the configuration list + it = g_slist_find_custom (net_list, ifa->ifa_name, + (GCompareFunc) kms_webrtc_base_connection_cmp_ifa); - nice_address_set_from_string (nice_address, ip_address); - nice_agent_add_local_address (agent, nice_address); + // Current interface is not present in config, skip. + if (it == NULL) { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *in4 = (struct sockaddr_in*) ifa->ifa_addr; + inet_ntop(AF_INET, &in4->sin_addr, ip_address, sizeof (ip_address)); + } else { + struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr; + inet_ntop(AF_INET6, &in6->sin6_addr, ip_address, sizeof (ip_address)); + } - GST_INFO_OBJECT (agent, "Added local address: %s", ip_address); + // Check if the IP in the ignore list or is link local + if (!kms_webrtc_base_connection_agent_is_interface_ip_valid(ip_address, + ip_ignore_list)) { + continue; + } - nice_address_free (nice_address); - g_free (ip_address); + nice_address = nice_address_new (); + nice_address_set_from_string (nice_address, ip_address); + nice_agent_add_local_address (agent, nice_address); + nice_address_free (nice_address); + + GST_DEBUG_OBJECT (agent, "Added interface %s's IP address: %s", + ifa->ifa_name, ip_address); + } + + freeifaddrs(ifaddr); } void kms_webrtc_base_connection_set_network_ifs_info (KmsWebRtcBaseConnection * - self, const gchar * net_names) + self, const gchar * net_names, const gchar * ip_ignore_list) { if (KMS_IS_ICE_NICE_AGENT (self->agent)) { KmsIceNiceAgent *nice_agent = KMS_ICE_NICE_AGENT (self->agent); NiceAgent *agent = kms_ice_nice_agent_get_agent (nice_agent); - GSList *net_list = kms_webrtc_base_connection_split_comma ( - net_names); - - if (net_list != NULL) { - g_slist_foreach (net_list, - (GFunc) kms_webrtc_base_connection_agent_add_net_addr, - agent); - } + GSList *net_list = kms_webrtc_base_connection_split_comma (net_names); + GSList *ip_ignore_glist = kms_webrtc_base_connection_split_comma (ip_ignore_list); + kms_webrtc_base_connection_agent_add_net_ifs_addrs (agent, net_list, ip_ignore_glist); g_slist_free_full (net_list, g_free); + g_slist_free_full (ip_ignore_glist, g_free); } } diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.h b/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.h index 63f1183b4..2cf394c82 100644 --- a/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.h +++ b/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.h @@ -80,7 +80,7 @@ GType kms_webrtc_base_connection_get_type (void); gchar *kms_webrtc_base_connection_get_certificate_pem (KmsWebRtcBaseConnection * self); void kms_webrtc_base_connection_set_network_ifs_info (KmsWebRtcBaseConnection * - self, const gchar * net_names); + self, const gchar * net_names, const gchar * ip_ignore_list); void kms_webrtc_base_connection_set_stun_server_info (KmsWebRtcBaseConnection * self, const gchar * stun_server_ip, guint stun_server_port); void kms_webrtc_base_connection_set_relay_info (KmsWebRtcBaseConnection * self, diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcendpoint.c b/src/gst-plugins/webrtcendpoint/kmswebrtcendpoint.c index f6a559040..57ddd1c5d 100644 --- a/src/gst-plugins/webrtcendpoint/kmswebrtcendpoint.c +++ b/src/gst-plugins/webrtcendpoint/kmswebrtcendpoint.c @@ -55,6 +55,7 @@ G_DEFINE_TYPE (KmsWebrtcEndpoint, kms_webrtc_endpoint, #define DEFAULT_STUN_TURN_URL NULL #define DEFAULT_PEM_CERTIFICATE NULL #define DEFAULT_NETWORK_INTERFACES NULL +#define DEFAULT_IP_IGNORE_LIST NULL #define DEFAULT_EXTERNAL_ADDRESS NULL #define DEFAULT_EXTERNAL_IPV4 NULL #define DEFAULT_EXTERNAL_IPV6 NULL @@ -67,6 +68,7 @@ enum PROP_TURN_URL, /* user:password@address:port?transport=[udp|tcp|tls] */ PROP_PEM_CERTIFICATE, PROP_NETWORK_INTERFACES, + PROP_IP_IGNORE_LIST, PROP_EXTERNAL_ADDRESS, PROP_EXTERNAL_IPV4, PROP_EXTERNAL_IPV6, @@ -102,6 +104,7 @@ struct _KmsWebrtcEndpointPrivate gchar *turn_url; gchar *pem_certificate; gchar *network_interfaces; + gchar *ip_ignore_list; gchar *external_address; gchar *external_ipv4; gchar *external_ipv6; @@ -333,6 +336,8 @@ kms_webrtc_endpoint_create_session_internal (KmsBaseSdpEndpoint * base_sdp, webrtc_sess, "pem-certificate", G_BINDING_DEFAULT); g_object_bind_property (self, "network-interfaces", webrtc_sess, "network-interfaces", G_BINDING_DEFAULT); + g_object_bind_property (self, "ip-ignore-list", + webrtc_sess, "ip-ignore-list", G_BINDING_DEFAULT); g_object_bind_property (self, "external-address", webrtc_sess, "external-address", G_BINDING_DEFAULT); g_object_bind_property (self, "external-ipv4", @@ -345,6 +350,7 @@ kms_webrtc_endpoint_create_session_internal (KmsBaseSdpEndpoint * base_sdp, "turn-url", self->priv->turn_url, "pem-certificate", self->priv->pem_certificate, "network-interfaces", self->priv->network_interfaces, + "ip-ignore-list", self->priv->ip_ignore_list, "external-address", self->priv->external_address, "external-ipv4", self->priv->external_ipv4, "external-ipv6", self->priv->external_ipv6, NULL); @@ -519,6 +525,10 @@ kms_webrtc_endpoint_set_property (GObject * object, guint prop_id, g_free (self->priv->network_interfaces); self->priv->network_interfaces = g_value_dup_string (value); break; + case PROP_IP_IGNORE_LIST: + g_free (self->priv->ip_ignore_list); + self->priv->ip_ignore_list = g_value_dup_string (value); + break; case PROP_EXTERNAL_ADDRESS: g_free (self->priv->external_address); self->priv->external_address = g_value_dup_string (value); @@ -563,6 +573,9 @@ kms_webrtc_endpoint_get_property (GObject * object, guint prop_id, case PROP_NETWORK_INTERFACES: g_value_set_string (value, self->priv->network_interfaces); break; + case PROP_IP_IGNORE_LIST: + g_value_set_string (value, self->priv->ip_ignore_list); + break; case PROP_EXTERNAL_ADDRESS: g_value_set_string (value, self->priv->external_address); break; @@ -608,6 +621,7 @@ kms_webrtc_endpoint_finalize (GObject * object) g_free (self->priv->turn_url); g_free (self->priv->pem_certificate); g_free (self->priv->network_interfaces); + g_free (self->priv->ip_ignore_list); g_free (self->priv->external_address); g_free (self->priv->external_ipv4); g_free (self->priv->external_ipv6); @@ -793,6 +807,12 @@ kms_webrtc_endpoint_class_init (KmsWebrtcEndpointClass * klass) "Local network interfaces used for ICE gathering", DEFAULT_NETWORK_INTERFACES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_IP_IGNORE_LIST, + g_param_spec_string ("ip-ignore-list", + "ipIgnoreList", + "IPs to be ignored during libnice's gathering phase", + DEFAULT_IP_IGNORE_LIST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EXTERNAL_ADDRESS, g_param_spec_string ("external-address", "externalAddress", @@ -944,6 +964,7 @@ kms_webrtc_endpoint_init (KmsWebrtcEndpoint * self) self->priv->turn_url = DEFAULT_STUN_TURN_URL; self->priv->pem_certificate = DEFAULT_PEM_CERTIFICATE; self->priv->network_interfaces = DEFAULT_NETWORK_INTERFACES; + self->priv->ip_ignore_list = DEFAULT_IP_IGNORE_LIST; self->priv->external_address = DEFAULT_EXTERNAL_ADDRESS; self->priv->external_ipv4 = DEFAULT_EXTERNAL_IPV4; self->priv->external_ipv6 = DEFAULT_EXTERNAL_IPV6; diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcsession.c b/src/gst-plugins/webrtcendpoint/kmswebrtcsession.c index 8d7649a17..507b138c0 100644 --- a/src/gst-plugins/webrtcendpoint/kmswebrtcsession.c +++ b/src/gst-plugins/webrtcendpoint/kmswebrtcsession.c @@ -55,6 +55,7 @@ G_DEFINE_TYPE (KmsWebrtcSession, kms_webrtc_session, KMS_TYPE_BASE_RTP_SESSION); #define DEFAULT_DATA_CHANNELS_SUPPORTED FALSE #define DEFAULT_PEM_CERTIFICATE NULL #define DEFAULT_NETWORK_INTERFACES NULL +#define DEFAULT_IP_IGNORE_LIST NULL #define DEFAULT_EXTERNAL_ADDRESS NULL #define DEFAULT_EXTERNAL_IPV4 NULL #define DEFAULT_EXTERNAL_IPV6 NULL @@ -91,6 +92,7 @@ enum PROP_DATA_CHANNEL_SUPPORTED, PROP_PEM_CERTIFICATE, PROP_NETWORK_INTERFACES, + PROP_IP_IGNORE_LIST, PROP_EXTERNAL_ADDRESS, PROP_EXTERNAL_IPV4, PROP_EXTERNAL_IPV6, @@ -804,7 +806,7 @@ kms_webrtc_session_set_network_ifs_info (KmsWebrtcSession * self, } kms_webrtc_base_connection_set_network_ifs_info (conn, - self->network_interfaces); + self->network_interfaces, self->ip_ignore_list); } static void @@ -1744,6 +1746,10 @@ kms_webrtc_session_set_property (GObject * object, guint prop_id, g_free (self->network_interfaces); self->network_interfaces = g_value_dup_string (value); break; + case PROP_IP_IGNORE_LIST: + g_free (self->ip_ignore_list); + self->ip_ignore_list = g_value_dup_string (value); + break; case PROP_EXTERNAL_ADDRESS: g_free (self->external_address); self->external_address = g_value_dup_string (value); @@ -1791,6 +1797,9 @@ kms_webrtc_session_get_property (GObject * object, guint prop_id, case PROP_NETWORK_INTERFACES: g_value_set_string (value, self->network_interfaces); break; + case PROP_IP_IGNORE_LIST: + g_value_set_string (value, self->ip_ignore_list); + break; case PROP_EXTERNAL_ADDRESS: g_value_set_string (value, self->external_address); break; @@ -1826,6 +1835,7 @@ kms_webrtc_session_finalize (GObject * object) g_free (self->turn_address); g_free (self->pem_certificate); g_free (self->network_interfaces); + g_free (self->ip_ignore_list); g_free (self->external_address); g_free (self->external_ipv4); g_free (self->external_ipv6); @@ -1937,6 +1947,7 @@ kms_webrtc_session_init (KmsWebrtcSession * self) self->turn_url = DEFAULT_STUN_TURN_URL; self->pem_certificate = DEFAULT_PEM_CERTIFICATE; self->network_interfaces = DEFAULT_NETWORK_INTERFACES; + self->ip_ignore_list = DEFAULT_IP_IGNORE_LIST; self->external_address = DEFAULT_EXTERNAL_ADDRESS; self->external_ipv4= DEFAULT_EXTERNAL_IPV4; self->external_ipv6 = DEFAULT_EXTERNAL_IPV6; @@ -2039,6 +2050,12 @@ kms_webrtc_session_class_init (KmsWebrtcSessionClass * klass) "Local network interfaces used for ICE gathering", DEFAULT_NETWORK_INTERFACES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_IP_IGNORE_LIST, + g_param_spec_string ("ip-ignore-list", + "ipIgnoreList", + "IPs to be ignored during libnice's gathering phase", + DEFAULT_IP_IGNORE_LIST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EXTERNAL_ADDRESS, g_param_spec_string ("external-address", "externalAddress", diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcsession.h b/src/gst-plugins/webrtcendpoint/kmswebrtcsession.h index 7575f860b..f79d6a92d 100644 --- a/src/gst-plugins/webrtcendpoint/kmswebrtcsession.h +++ b/src/gst-plugins/webrtcendpoint/kmswebrtcsession.h @@ -71,6 +71,7 @@ struct _KmsWebrtcSession TurnProtocol turn_transport; gchar *pem_certificate; gchar *network_interfaces; + gchar *ip_ignore_list; gchar *external_address; gchar *external_ipv4; gchar *external_ipv6; diff --git a/src/server/config/WebRtcEndpoint.conf.ini b/src/server/config/WebRtcEndpoint.conf.ini index 145044dbd..bd2085cee 100644 --- a/src/server/config/WebRtcEndpoint.conf.ini +++ b/src/server/config/WebRtcEndpoint.conf.ini @@ -22,6 +22,24 @@ ;; ;networkInterfaces=eth0 +;; List of IPs to be ignored during the gathering phase when networkInterfaces +;; is enabled. +;; +;; If you set up the networkInterfaces option and the desired interfaces have +;; IPs that you don't wish to be used by libnice's NiceAgent, you +;; you can define them here. +;; +;; The general use case is filtering out IP addresses which are in the private +;; address ranges in environments where they aren't needed. This allows a fine +;; tuning to the number of server-side candidates generated by Kurento, reducing +;; signalling overhead and potentially speeding up connectivity checks. +;; +;; is a comma-separated list of IP (IPv4 and IPV6) addresses +;; +;; Examples: +;; ipIgnoreList=10.10.0.254 +;; ipIgnoreList=fd12:3456:789a:1::1 + ;; STUN server IP address. ;; ;; The ICE process uses STUN to punch holes through NAT firewalls. diff --git a/src/server/implementation/objects/WebRtcEndpointImpl.cpp b/src/server/implementation/objects/WebRtcEndpointImpl.cpp index 7cd29fa57..49c1fd6cd 100644 --- a/src/server/implementation/objects/WebRtcEndpointImpl.cpp +++ b/src/server/implementation/objects/WebRtcEndpointImpl.cpp @@ -56,11 +56,13 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); #define PARAM_EXTERNAL_IPV4 "externalIPv4" #define PARAM_EXTERNAL_IPV6 "externalIPv6" #define PARAM_NETWORK_INTERFACES "networkInterfaces" +#define PARAM_IP_IGNORE_LIST "ipIgnoreList" #define PROP_EXTERNAL_ADDRESS "external-address" #define PROP_EXTERNAL_IPV4 "external-ipv4" #define PROP_EXTERNAL_IPV6 "external-ipv6" #define PROP_NETWORK_INTERFACES "network-interfaces" +#define PROP_IP_IGNORE_LIST "ip-ignore-list" namespace kurento { @@ -558,6 +560,16 @@ WebRtcEndpointImpl::WebRtcEndpointImpl (const boost::property_tree::ptree &conf, " you can set one or default to ICE automatic discovery"); } + std::string ipIgnoreList; + if (getConfigValue (&ipIgnoreList, + PARAM_IP_IGNORE_LIST)) { + GST_INFO ("IP ignore list: %s", ipIgnoreList.c_str()); + g_object_set (G_OBJECT (element), PROP_IP_IGNORE_LIST, + ipIgnoreList.c_str(), NULL); + } else { + GST_DEBUG ("No IP ignore list found in config"); + } + uint stunPort = 0; if (!getConfigValue (&stunPort, "stunServerPort", @@ -746,6 +758,31 @@ WebRtcEndpointImpl::setNetworkInterfaces (const std::string &networkInterfaces) networkInterfaces.c_str(), NULL); } +std::string +WebRtcEndpointImpl::getIpIgnoreList() +{ + std::string ipIgnoreList; + gchar *ret; + + g_object_get (G_OBJECT (element), PROP_IP_IGNORE_LIST, &ret, NULL); + + if (ret != nullptr) { + ipIgnoreList = std::string (ret); + g_free (ret); + } + + return ipIgnoreList; +} + +void +WebRtcEndpointImpl::setIpIgnoreList (const std::string &ipIgnoreList) +{ + GST_INFO ("Set IP ignore list: %s", ipIgnoreList.c_str()); + g_object_set (G_OBJECT (element), PROP_IP_IGNORE_LIST, + ipIgnoreList.c_str(), NULL); +} + + std::string WebRtcEndpointImpl::getStunServerAddress () { diff --git a/src/server/implementation/objects/WebRtcEndpointImpl.hpp b/src/server/implementation/objects/WebRtcEndpointImpl.hpp index b3f0586b7..cca7e9390 100644 --- a/src/server/implementation/objects/WebRtcEndpointImpl.hpp +++ b/src/server/implementation/objects/WebRtcEndpointImpl.hpp @@ -58,6 +58,9 @@ class WebRtcEndpointImpl : public BaseRtpEndpointImpl, std::string getNetworkInterfaces () override; void setNetworkInterfaces (const std::string &networkInterfaces) override; + std::string getIpIgnoreList () override; + void setIpIgnoreList (const std::string &ipIgnoreList) override; + std::string getStunServerAddress () override; void setStunServerAddress (const std::string &stunServerAddress) override; diff --git a/src/server/interface/elements.WebRtcEndpoint.kmd.json b/src/server/interface/elements.WebRtcEndpoint.kmd.json index 2938cd367..538a2836b 100644 --- a/src/server/interface/elements.WebRtcEndpoint.kmd.json +++ b/src/server/interface/elements.WebRtcEndpoint.kmd.json @@ -304,6 +304,11 @@ ", "type": "String" }, + { + "name": "ipIgnoreList", + "doc": "List of IP addresses to be ignored in the gathering phase when networkInterfaces is set", + "type": "String" + }, { "name": "stunServerAddress", "doc": "STUN server IP address.