public static IPEndPoint GetMappedAddress(this StunAttribute attribute) { var variable = attribute.Variable; if (variable[0] != 0) { Debug.LogWarning($"MAPPED-ADDRESS first byte must be 0x00, got 0x{variable[0].ToString("X2")}"); } var family = (AddressFamily)variable[1]; var port = (ushort)((variable[2] << 8) | variable[3]); var addressSize = variable.Length - sizeof(ushort) * 2; if (family == AddressFamily.IPv4 && addressSize != 4) { Debug.LogWarning($"MAPPED-ADDRESS with family {family} needs to have 32 bits, got {addressSize * 8} bits"); } else if (family == AddressFamily.IPv6 && addressSize != 16) { Debug.LogWarning($"MAPPED-ADDRESS with family {family} needs to have 128 bits, got {addressSize * 8} bits"); } var addressBytes = new byte[addressSize]; Array.Copy(variable, 4, addressBytes, 0, addressBytes.Length); var ipAddress = new IPAddress(addressBytes); return(new IPEndPoint(ipAddress, port)); }
private async void Start() { var hosts = new string[] { "stun://localhost:3478", "stun://127.0.0.1:3478", // Google "stun://stun.l.google.com:19302", "stun://stun1.l.google.com:19302", "stun://stun2.l.google.com:19302", "stun://stun3.l.google.com:19302", "stun://stun4.l.google.com:19302", // Other "stun://stun.voip.blackberry.com:3478", "stun://stun.voipgate.com:3478", "stun://stun.voys.nl:3478", "stun://stun1.faktortel.com.au:3478", // TCP "stun://stun.sipnet.net:3478", "stun://stun.sipnet.ru:3478", "stun://stun.stunprotocol.org:3478", }; var req = new StunMessage(); var software = new StunAttribute(StunAttributeType.SOFTWARE, req); software.SetSoftware("Ice Cold Mirror"); req.attributes.Add(software); var clientUdp = new StunClientUdp(); var clientTcp = new StunClientTcp(); await Task.WhenAll(hosts.Select(async(host) => { try { var res = await clientUdp.SendRequest(req, host).AwaitWithTimeout(1500); Debug.Log("UDP: " + res); var indication = res.attributes.First(a => a.Type == StunAttributeType.XOR_MAPPED_ADDRESS).GetXorMappedAddress(); Debug.LogWarning($"UDP: {host} STUN indication is {indication}"); } catch (Exception e) { Debug.LogException(new Exception($"UDP: STUN host \"{host}\" failed", e)); } }).ToArray()); await Task.WhenAll(hosts.Select(async(host) => { try { var res = await clientTcp.SendRequest(req, host).AwaitWithTimeout(1500); Debug.Log("TCP: " + res); var indication = res.attributes.First(a => a.Type == StunAttributeType.XOR_MAPPED_ADDRESS).GetXorMappedAddress(); Debug.LogWarning($"TCP: {host} STUN indication is {indication}"); } catch (Exception e) { Debug.LogException(new Exception($"TCP: STUN host \"{host}\" failed", e)); } }).ToArray()); }
public static IPEndPoint GetXorMappedAddress(this StunAttribute attribute) { var variable = attribute.Variable; if (variable[0] != 0) { Debug.LogWarning($"XOR-MAPPED-ADDRESS first byte must be 0x00, got 0x{variable[0].ToString("X2")}"); } var family = (AddressFamily)variable[1]; var xPort = (ushort)((variable[2] << 8) | variable[3]); // xor port with 16 most significant bit of magic cookie var port = (ushort)(xPort ^ ((magicCookieBytes[0] << 8) | magicCookieBytes[1])); var addressSize = variable.Length - sizeof(ushort) * 2; if (family == AddressFamily.IPv4 && addressSize != 4) { Debug.LogWarning($"XOR-MAPPED-ADDRESS with family {family} needs to have 32 bits, got {addressSize * 8} bits"); } else if (family == AddressFamily.IPv6 && addressSize != 16) { Debug.LogWarning($"XOR-MAPPED-ADDRESS with family {family} needs to have 128 bits, got {addressSize * 8} bits"); } var addressBytes = new byte[addressSize]; Array.Copy(variable, 4, addressBytes, 0, addressBytes.Length); // xor each address byte with the magic cookie byte for (int i = 0; i < 4; i++) { addressBytes[i] ^= magicCookieBytes[i]; } if (family == AddressFamily.IPv6) { var header = attribute.Owner.header; // getting the transaction id generates GC, only call when ipv6 var transactionID = header.TransactionId; // xor each byte with the concatenation of magic cookie and transaction id for (int i = 0; i < transactionID.Length; i++) { addressBytes[i + 4] ^= transactionID[i]; } } var ipAddress = new IPAddress(addressBytes); return(new IPEndPoint(ipAddress, port)); }
public StunMessage(Stream stream) { this.header = new StunMessageHeader(stream); var pos = 0; while (pos < header.Length) { var attr = new StunAttribute(stream, this); pos += attr.AttrbiuteLength; this.attributes.Add(attr); } }
public static void SetSoftware(this StunAttribute attribute, string info) { if (info.Length >= 128) { throw new ArgumentException("String must be less than 128 characteres", nameof(info)); } var bytes = Encoding.UTF8.GetBytes(info); if (bytes.Length >= 763) { throw new ArgumentException("String must be less than 763 bytes", nameof(info)); } attribute.Variable = bytes; }
public static void SetMappedAddress(this StunAttribute attribute, IPEndPoint endPoint) { throw new NotImplementedException(); }
public static string GetSoftware(this StunAttribute attribute) { return(Encoding.UTF8.GetString(attribute.Variable)); }