/// <summary> /// Default constructor. /// </summary> /// <param name="uri">The STUN or TURN server URI the connection is being attempted to.</param> /// <param name="id">Needs to be set uniquely for each ICE server used in this session. Gets added to the /// transaction ID to facilitate quick matching of STUN requests and responses. Needs to be between /// 0 and 9.</param> /// <param name="username">Optional. If authentication is required the username to use.</param> /// <param name="password">Optional. If authentication is required the password to use.</param> internal IceServer(STUNUri uri, int id, string username, string password) { _uri = uri; _id = id; _username = username; _password = password; GenerateNewTransactionID(); }
/// <summary> /// Resolve method that can be used to request an AAAA result and fallback to a A /// lookup if none found. /// </summary> /// <param name="uri">The URI to lookup.</param> /// <param name="preferIPv6">True if IPv6 (AAAA record lookup) is preferred.</param> /// <returns>An IPEndPoint or null.</returns> public static Task <IPEndPoint> Resolve(STUNUri uri, bool preferIPv6 = false) { if (preferIPv6) { // Try AAAA record lookup followed by A record if none found. return(Resolve(uri, QueryType.AAAA) .ContinueWith(x => x.Result ?? Resolve(uri, QueryType.A).Result)); } else { return(Resolve(uri, QueryType.A)); } }
public static bool TryParse(string uriStr, out STUNUri uri) { try { uri = ParseSTUNUri(uriStr); return(uri != null); } catch { uri = null; return(false); } }
/// <summary> /// Resolve method that performs either an A or AAAA record lookup. If required /// a SRV record lookup will be performed prior to the A or AAAA lookup. /// </summary> /// <param name="uri">The STUN uri to lookup.</param> /// <param name="queryType">Whether the address lookup should be A or AAAA.</param> /// <returns>An IPEndPoint or null.</returns> private static async Task <IPEndPoint> Resolve(STUNUri uri, QueryType queryType) { if (uri == null || String.IsNullOrWhiteSpace(uri.Host)) { throw new ArgumentNullException("uri", "DNS resolve was supplied an empty input."); } if (IPAddress.TryParse(uri.Host, out var ipAddress)) { // Target is already an IP address, no DNS lookup required. return(new IPEndPoint(ipAddress, uri.Port)); } else { if (!uri.Host.Contains(".") || uri.Host.EndsWith(MDNS_TLD)) { AddressFamily family = (queryType == QueryType.AAAA) ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork; // The lookup is for a local network host. Use the OS DNS logic as the // main DNS client can be configured to use external DNS servers that won't // be able to lookup this hostname. IPHostEntry hostEntry = null; try { hostEntry = Dns.GetHostEntry(uri.Host); } catch (SocketException) { // Socket exception gets thrown for failed lookups, } if (hostEntry != null) { var addressList = hostEntry.AddressList; if (addressList?.Length == 0) { logger.LogWarning($"Operating System DNS lookup failed for {uri.Host}."); return(null); } else { if (addressList.Any(x => x.AddressFamily == family)) { var addressResult = addressList.First(x => x.AddressFamily == family); return(new IPEndPoint(addressResult, uri.Port)); } else { // Didn't get a result for the preferred address family so just use the // first available result. var addressResult = addressList.First(); return(new IPEndPoint(addressResult, uri.Port)); } } } else { return(null); } } else { if (uri.ExplicitPort) { return(HostQuery(uri.Host, uri.Port, queryType)); } else { try { ServiceHostEntry srvResult = null; // No explicit port so use a SRV -> (A | AAAA -> A) record lookup. var result = await _lookupClient.ResolveServiceAsync(uri.Host, uri.Scheme.ToString(), uri.Protocol.ToString().ToLower()).ConfigureAwait(false); if (result == null || result.Count() == 0) { logger.LogDebug($"STUNDns SRV lookup returned no results for {uri}."); } else { srvResult = result.OrderBy(y => y.Priority).ThenByDescending(w => w.Weight).FirstOrDefault(); } string host = uri.Host; // If no SRV results then fallback is to lookup the hostname directly. int port = uri.Port; // If no SRV results then fallback is to use the default port. if (srvResult != null) { host = srvResult.HostName; port = srvResult.Port; } return(HostQuery(host, port, queryType)); } catch (Exception e) { logger.LogDebug($"STUNDns SRV lookup failure for {uri}. {e?.InnerException?.Message}"); return(null); } } } } }
/// <summary> /// Resolve method that can be used to request an AAAA result and fallback to a A /// lookup if none found. /// </summary> /// <param name="uri">The URI to lookup.</param> /// <param name="preferIPv6">True if IPv6 (AAAA record lookup) is preferred.</param> /// <returns>An IPEndPoint or null.</returns> public static Task <IPEndPoint> Resolve(STUNUri uri, bool preferIPv6 = false) { return(Resolve(uri, preferIPv6 ? QueryType.AAAA : QueryType.A)); }
/// <summary> /// Resolve method that performs either an A or AAAA record lookup. If required /// a SRV record lookup will be performed prior to the A or AAAA lookup. /// </summary> /// <param name="uri">The STUN uri to lookup.</param> /// <param name="queryType">Whether the address lookup should be A or AAAA.</param> /// <returns>An IPEndPoint or null.</returns> public static Task <IPEndPoint> Resolve(STUNUri uri, QueryType queryType) { if (uri == null || String.IsNullOrWhiteSpace(uri.Host)) { throw new ArgumentNullException("uri", "DNS resolve was supplied an empty input."); } if (IPAddress.TryParse(uri.Host, out var ipAddress)) { // Target is already an IP address, no DNS lookup required. return(Task.FromResult(new IPEndPoint(ipAddress, uri.Port))); } else { if (!uri.Host.Contains(".") || uri.Host.EndsWith(MDNS_TLD)) { AddressFamily family = (queryType == QueryType.AAAA) ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork; // The lookup is for a local network host. Use the OS DNS logic as the // main DNS client can be configured to use external DNS servers that won't // be able to lookup this hostname. IPHostEntry hostEntry = null; try { hostEntry = Dns.GetHostEntry(uri.Host); } catch (SocketException) { // Socket exception gets thrown for failed lookups, } if (hostEntry != null) { var addressList = hostEntry.AddressList; if (addressList?.Length == 0) { logger.LogWarning($"Operating System DNS lookup failed for {uri.Host}."); return(Task.FromResult <IPEndPoint>(null)); } else { if (addressList.Any(x => x.AddressFamily == family)) { var addressResult = addressList.First(x => x.AddressFamily == family); return(Task.FromResult(new IPEndPoint(addressResult, uri.Port))); } else { return(Task.FromResult <IPEndPoint>(null)); } } } else { return(Task.FromResult <IPEndPoint>(null)); } } else { if (uri.ExplicitPort) { // If the URI has an explicit port then it indicates SRV records should not be used. return(_lookupClient.QueryAsync(uri.Host, queryType) .ContinueWith <IPEndPoint>(x => { var addrRecord = x.Result.Answers.FirstOrDefault(); return GetFromLookupResult(addrRecord, uri.Port); })); } else { // No explicit port so use a SRV -> (A | AAAA) record lookup. return(_lookupClient.ResolveServiceAsync(uri.Host, uri.Scheme.ToString(), uri.Protocol) .ContinueWith <IPEndPoint>(x => { var srvResult = x.Result.OrderBy(y => y.Priority).ThenByDescending(w => w.Weight).FirstOrDefault(); string host = uri.Host; // If no SRV results then fallback is to lookup the hostname directly. int port = uri.Port; // If no SRV results then fallback is to use the default port. if (srvResult != null) { host = srvResult.HostName; port = srvResult.Port; } var addrRecord = _lookupClient.Query(host, queryType).Answers.FirstOrDefault(); return GetFromLookupResult(addrRecord, uri.Port); })); } } } }
public static bool AreEqual(STUNUri uri1, STUNUri uri2) { return(uri1 == uri2); }
public static STUNUri ParseSTUNUri(string uri) { STUNUri stunUri = new STUNUri(); if (String.IsNullOrEmpty(uri)) { throw new ApplicationException("A STUN URI cannot be parsed from an empty string."); } else { uri = uri.Trim(); // If the scheme is included it needs to be within the first 5 characters. if (uri.Length > SCHEME_MAX_LENGTH + 2) { string schemeStr = uri.Substring(0, SCHEME_MAX_LENGTH + 1); int colonPosn = schemeStr.IndexOf(SCHEME_ADDR_SEPARATOR); if (colonPosn == -1) { // No scheme has been specified, use default. stunUri.Scheme = DefaultSTUNScheme; } else { if (!Enum.TryParse <STUNSchemesEnum>(schemeStr.Substring(0, colonPosn), true, out stunUri.Scheme)) { stunUri.Scheme = DefaultSTUNScheme; } uri = uri.Substring(colonPosn + 1); } } if (uri.IndexOf(':') != -1) { stunUri.ExplicitPort = true; if (IPSocket.TryParseIPEndPoint(uri, out var ipEndPoint)) { if (ipEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { stunUri.Host = $"[{ipEndPoint.Address}]"; } else { stunUri.Host = ipEndPoint.Address.ToString(); } stunUri.Port = ipEndPoint.Port; } else { stunUri.Host = uri.Substring(0, uri.LastIndexOf(':')); if (!Int32.TryParse(uri.Substring(uri.LastIndexOf(':') + 1), out stunUri.Port)) { stunUri.Port = STUNConstants.GetPortForScheme(stunUri.Scheme); } } } else { stunUri.Host = uri?.Trim(); stunUri.Port = STUNConstants.GetPortForScheme(stunUri.Scheme); } } return(stunUri); }