StunClient3489Test.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. using Dns.Net.Clients;
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;
  3. using Moq;
  4. using STUN.Client;
  5. using STUN.Enums;
  6. using STUN.Messages;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using static STUN.Utils.AttributeExtensions;
  10. namespace UnitTest;
  11. [TestClass]
  12. public class StunClient3489Test
  13. {
  14. private readonly DefaultDnsClient _dnsClient = new();
  15. private const string Server = @"stun.hot-chilli.net";
  16. private const ushort Port = 3478;
  17. private static readonly IPEndPoint Any = new(IPAddress.Any, 0);
  18. private static readonly IPEndPoint IPv6Any = new(IPAddress.IPv6Any, 0);
  19. private static readonly IPEndPoint LocalAddress1 = IPEndPoint.Parse(@"127.0.0.1:114");
  20. private static readonly IPEndPoint MappedAddress1 = IPEndPoint.Parse(@"1.1.1.1:114");
  21. private static readonly IPEndPoint MappedAddress2 = IPEndPoint.Parse(@"1.1.1.1:514");
  22. private static readonly IPEndPoint ServerAddress = IPEndPoint.Parse(@"2.2.2.2:1919");
  23. private static readonly IPEndPoint ChangedAddress1 = IPEndPoint.Parse(@"3.3.3.3:23333");
  24. private static readonly IPEndPoint ChangedAddress2 = IPEndPoint.Parse(@"2.2.2.2:810");
  25. private static readonly StunMessage5389 DefaultStunMessage = new();
  26. [TestMethod]
  27. public async Task UdpBlockedTestAsync()
  28. {
  29. Mock<StunClient3489> mock = new(Any, Any, default!);
  30. StunClient3489 client = mock.Object;
  31. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(default(StunResponse?));
  32. await client.QueryAsync();
  33. Assert.AreEqual(NatType.UdpBlocked, client.State.NatType);
  34. }
  35. [TestMethod]
  36. public async Task UnsupportedServerTestAsync()
  37. {
  38. Mock<StunClient3489> mock = new(Any, Any, default!);
  39. StunClient3489 client = mock.Object;
  40. mock.Setup(x => x.LocalEndPoint).Returns(LocalAddress1);
  41. StunResponse unknownResponse = new(DefaultStunMessage, Any, LocalAddress1);
  42. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(unknownResponse);
  43. await TestAsync();
  44. StunResponse r1 = new(new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port)] }, ServerAddress, LocalAddress1);
  45. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(r1);
  46. await TestAsync();
  47. StunResponse r2 = new(new StunMessage5389 { Attributes = [BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] }, ServerAddress, LocalAddress1);
  48. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(r2);
  49. await TestAsync();
  50. StunResponse r3 = new(new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ServerAddress.Address, (ushort)ChangedAddress1.Port)] }, ServerAddress, LocalAddress1);
  51. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(r3);
  52. await TestAsync();
  53. StunResponse r4 = new(new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ServerAddress.Port)] }, ServerAddress, LocalAddress1);
  54. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(r4);
  55. await TestAsync();
  56. return;
  57. async Task TestAsync()
  58. {
  59. await client.QueryAsync();
  60. Assert.AreEqual(NatType.UnsupportedServer, client.State.NatType);
  61. }
  62. }
  63. [TestMethod]
  64. public async Task NoNatTestAsync()
  65. {
  66. Mock<StunClient3489> mock = new(Any, Any, default!);
  67. StunClient3489 client = mock.Object;
  68. StunResponse openInternetTest1Response = new(
  69. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  70. ServerAddress,
  71. MappedAddress1
  72. );
  73. StunResponse test2Response = new(
  74. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port)] },
  75. ChangedAddress1,
  76. MappedAddress1
  77. );
  78. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(openInternetTest1Response);
  79. mock.Setup(x => x.LocalEndPoint).Returns(MappedAddress1);
  80. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(test2Response);
  81. Assert.AreEqual(NatType.Unknown, client.State.NatType);
  82. await client.QueryAsync();
  83. Assert.AreEqual(NatType.OpenInternet, client.State.NatType);
  84. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(default(StunResponse?));
  85. await client.QueryAsync();
  86. Assert.AreEqual(NatType.SymmetricUdpFirewall, client.State.NatType);
  87. }
  88. [TestMethod]
  89. public async Task FullConeTestAsync()
  90. {
  91. Mock<StunClient3489> mock = new(Any, Any, default!);
  92. StunClient3489 client = mock.Object;
  93. StunResponse test1Response = new(
  94. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  95. ServerAddress,
  96. LocalAddress1
  97. );
  98. StunResponse fullConeResponse = new(
  99. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port)] },
  100. ChangedAddress1,
  101. LocalAddress1
  102. );
  103. StunResponse unsupportedResponse1 = new(
  104. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port)] },
  105. ServerAddress,
  106. LocalAddress1
  107. );
  108. StunResponse unsupportedResponse2 = new(
  109. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port)] },
  110. new IPEndPoint(ServerAddress.Address, ChangedAddress1.Port),
  111. LocalAddress1
  112. );
  113. StunResponse unsupportedResponse3 = new(
  114. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port)] },
  115. new IPEndPoint(ChangedAddress1.Address, ServerAddress.Port),
  116. LocalAddress1
  117. );
  118. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(test1Response);
  119. mock.Setup(x => x.LocalEndPoint).Returns(LocalAddress1);
  120. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(fullConeResponse);
  121. Assert.AreEqual(NatType.Unknown, client.State.NatType);
  122. await client.QueryAsync();
  123. Assert.AreEqual(NatType.FullCone, client.State.NatType);
  124. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(unsupportedResponse1);
  125. await TestUnsupportedServerAsync();
  126. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(unsupportedResponse2);
  127. await TestUnsupportedServerAsync();
  128. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(unsupportedResponse3);
  129. await TestUnsupportedServerAsync();
  130. return;
  131. async Task TestUnsupportedServerAsync()
  132. {
  133. await client.QueryAsync();
  134. Assert.AreEqual(NatType.UnsupportedServer, client.State.NatType);
  135. }
  136. }
  137. [TestMethod]
  138. public async Task SymmetricTestAsync()
  139. {
  140. Mock<StunClient3489> mock = new(Any, Any, default!);
  141. StunClient3489 client = mock.Object;
  142. StunResponse test1Response = new(
  143. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  144. ServerAddress,
  145. LocalAddress1
  146. );
  147. StunResponse test12Response = new(
  148. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress2.Address, (ushort)MappedAddress2.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  149. ServerAddress,
  150. LocalAddress1
  151. );
  152. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(test1Response);
  153. mock.Setup(x => x.LocalEndPoint).Returns(LocalAddress1);
  154. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(default(StunResponse?));
  155. mock.Setup(x => x.Test1_2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(default(StunResponse?));
  156. Assert.AreEqual(NatType.Unknown, client.State.NatType);
  157. await client.QueryAsync();
  158. Assert.AreEqual(NatType.Unknown, client.State.NatType);
  159. mock.Setup(x => x.Test1_2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(test12Response);
  160. await client.QueryAsync();
  161. Assert.AreEqual(NatType.Symmetric, client.State.NatType);
  162. }
  163. [TestMethod]
  164. public async Task RestrictedConeTestAsync()
  165. {
  166. Mock<StunClient3489> mock = new(Any, Any, default!);
  167. StunClient3489 client = mock.Object;
  168. StunResponse test1Response = new(
  169. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  170. ServerAddress,
  171. LocalAddress1
  172. );
  173. StunResponse test3Response = new(
  174. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  175. ChangedAddress2,
  176. LocalAddress1
  177. );
  178. StunResponse test3ErrorResponse = new(
  179. new StunMessage5389 { Attributes = [BuildMapping(IpFamily.IPv4, MappedAddress1.Address, (ushort)MappedAddress1.Port), BuildChangeAddress(IpFamily.IPv4, ChangedAddress1.Address, (ushort)ChangedAddress1.Port)] },
  180. ServerAddress,
  181. LocalAddress1
  182. );
  183. mock.Setup(x => x.Test1Async(It.IsAny<CancellationToken>())).ReturnsAsync(test1Response);
  184. mock.Setup(x => x.LocalEndPoint).Returns(LocalAddress1);
  185. mock.Setup(x => x.Test2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(default(StunResponse?));
  186. mock.Setup(x => x.Test1_2Async(It.IsAny<IPEndPoint>(), It.IsAny<CancellationToken>())).ReturnsAsync(test1Response);
  187. mock.Setup(x => x.Test3Async(It.IsAny<CancellationToken>())).ReturnsAsync(test3Response);
  188. Assert.AreEqual(NatType.Unknown, client.State.NatType);
  189. await client.QueryAsync();
  190. Assert.AreEqual(NatType.RestrictedCone, client.State.NatType);
  191. mock.Setup(x => x.Test3Async(It.IsAny<CancellationToken>())).ReturnsAsync(test3ErrorResponse);
  192. await client.QueryAsync();
  193. Assert.AreEqual(NatType.PortRestrictedCone, client.State.NatType);
  194. mock.Setup(x => x.Test3Async(It.IsAny<CancellationToken>())).ReturnsAsync(default(StunResponse?));
  195. await client.QueryAsync();
  196. Assert.AreEqual(NatType.PortRestrictedCone, client.State.NatType);
  197. }
  198. [TestMethod]
  199. public async Task Test1Async()
  200. {
  201. IPAddress ip = await _dnsClient.QueryAsync(Server);
  202. using StunClient3489 client = new(new IPEndPoint(ip, Port), Any);
  203. // test I
  204. StunResponse? response1 = await client.Test1Async(default);
  205. Assert.IsNotNull(response1);
  206. Assert.AreEqual(ip, response1.Remote.Address);
  207. Assert.AreEqual(Port, response1.Remote.Port);
  208. Assert.AreNotEqual(Any, client.LocalEndPoint);
  209. IPEndPoint? mappedAddress = response1.Message.GetMappedAddressAttribute();
  210. IPEndPoint? changedAddress = response1.Message.GetChangedAddressAttribute();
  211. Assert.IsNotNull(mappedAddress);
  212. Assert.IsNotNull(changedAddress);
  213. Assert.AreNotEqual(ip, changedAddress.Address);
  214. Assert.AreNotEqual(Port, changedAddress.Port);
  215. // Test I(#2)
  216. StunResponse? response12 = await client.Test1_2Async(changedAddress, default);
  217. Assert.IsNotNull(response12);
  218. Assert.AreEqual(changedAddress.Address, response12.Remote.Address);
  219. Assert.AreEqual(changedAddress.Port, response12.Remote.Port);
  220. }
  221. #if FullCone
  222. [TestMethod]
  223. #endif
  224. public async Task Test2Async()
  225. {
  226. IPAddress ip = await _dnsClient.QueryAsync(Server);
  227. using StunClient3489 client = new(new IPEndPoint(ip, Port), Any);
  228. StunResponse? response2 = await client.Test2Async(ip.AddressFamily is AddressFamily.InterNetworkV6 ? IPv6Any : Any, default);
  229. Assert.IsNotNull(response2);
  230. Assert.AreNotEqual(ip, response2.Remote.Address);
  231. Assert.AreNotEqual(Port, response2.Remote.Port);
  232. }
  233. #if FullCone
  234. [TestMethod]
  235. #endif
  236. public async Task Test3Async()
  237. {
  238. IPAddress ip = await _dnsClient.QueryAsync(Server);
  239. using StunClient3489 client = new(new IPEndPoint(ip, Port), Any);
  240. StunResponse? response = await client.Test3Async(default);
  241. Assert.IsNotNull(response);
  242. Assert.AreEqual(ip, response.Remote.Address);
  243. Assert.AreNotEqual(Port, response.Remote.Port);
  244. }
  245. }