diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.c b/src/gst-plugins/webrtcendpoint/kmswebrtcbaseconnection.c index 6960e616..d1f731f3 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 43b44db6..7439a88d 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_ice_tcp (KmsWebRtcBaseConnection *self, gboolean ice_tcp); void kms_webrtc_base_connection_set_stun_server_info (KmsWebRtcBaseConnection * self, diff --git a/src/gst-plugins/webrtcendpoint/kmswebrtcendpoint.c b/src/gst-plugins/webrtcendpoint/kmswebrtcendpoint.c index c4017f66..0bbeb620 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 @@ -68,6 +69,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, @@ -104,6 +106,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; @@ -338,6 +341,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", @@ -352,6 +357,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, @@ -530,6 +536,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); @@ -577,6 +587,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; @@ -625,6 +638,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); @@ -810,6 +824,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", @@ -967,6 +987,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 767b0304..61b97645 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 @@ -92,6 +93,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, @@ -803,7 +805,7 @@ kms_webrtc_session_set_network_ifs_info (KmsWebrtcSession * self, self->network_interfaces); kms_webrtc_base_connection_set_network_ifs_info (conn, - self->network_interfaces); + self->network_interfaces, self->ip_ignore_list); } static void @@ -1757,6 +1759,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); @@ -1807,6 +1813,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; @@ -1845,6 +1854,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); @@ -1956,6 +1966,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; @@ -2059,6 +2070,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 4f016d1f..2b2a64b5 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 def81997..de16b1a5 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 f91bfee2..d19cfed5 100644 --- a/src/server/implementation/objects/WebRtcEndpointImpl.cpp +++ b/src/server/implementation/objects/WebRtcEndpointImpl.cpp @@ -56,12 +56,14 @@ 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 PARAM_ICE_TCP "iceTcp" #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" #define PROP_ICE_TCP "ice-tcp" namespace kurento @@ -560,6 +562,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"); + } + gboolean iceTcp; if (getConfigValue (&iceTcp, PARAM_ICE_TCP)) { GST_INFO ("ICE-TCP candidate gathering is %s", @@ -774,6 +786,31 @@ WebRtcEndpointImpl::setIceTcp (bool iceTcp) g_object_set (G_OBJECT (element), "ice-tcp", iceTcp, 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 63fca4c7..1822fa68 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; + bool getIceTcp () override; void setIceTcp (bool iceTcp) override; diff --git a/src/server/interface/elements.WebRtcEndpoint.kmd.json b/src/server/interface/elements.WebRtcEndpoint.kmd.json index c84ddc2d..3370538f 100644 --- a/src/server/interface/elements.WebRtcEndpoint.kmd.json +++ b/src/server/interface/elements.WebRtcEndpoint.kmd.json @@ -303,6 +303,11 @@ ", "type": "String" }, + { + "name": "ipIgnoreList", + "doc": "List of IP addresses to be ignored in the gathering phase when networkInterfaces is set", + "type": "String" + }, { "name": "iceTcp", "doc": "Enable ICE-TCP candidate gathering.