RFC3489ViewModel.cs 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using Dns.Net.Abstractions;
  2. using JetBrains.Annotations;
  3. using Microsoft;
  4. using NatTypeTester.Models;
  5. using ReactiveUI;
  6. using Socks5.Models;
  7. using STUN;
  8. using STUN.Client;
  9. using STUN.Proxy;
  10. using STUN.StunResult;
  11. using System;
  12. using System.Net;
  13. using System.Net.Sockets;
  14. using System.Reactive;
  15. using System.Reactive.Linq;
  16. using System.Threading;
  17. using System.Threading.Tasks;
  18. namespace NatTypeTester.ViewModels;
  19. [UsedImplicitly]
  20. public class RFC3489ViewModel : ViewModelBase, IRoutableViewModel
  21. {
  22. public string UrlPathSegment => @"RFC3489";
  23. public IScreen HostScreen => LazyServiceProvider.LazyGetRequiredService<IScreen>();
  24. private Config Config => LazyServiceProvider.LazyGetRequiredService<Config>();
  25. private IDnsClient DnsClient => LazyServiceProvider.LazyGetRequiredService<IDnsClient>();
  26. public ClassicStunResult Result3489 { get; set; }
  27. public ReactiveCommand<Unit, Unit> TestClassicNatType { get; }
  28. private static readonly IPEndPoint DefaultLocalEndpoint = new(IPAddress.Any, 0);
  29. public RFC3489ViewModel()
  30. {
  31. Result3489 = new ClassicStunResult
  32. {
  33. LocalEndPoint = DefaultLocalEndpoint
  34. };
  35. TestClassicNatType = ReactiveCommand.CreateFromTask(TestClassicNatTypeAsync);
  36. }
  37. private async Task TestClassicNatTypeAsync(CancellationToken token)
  38. {
  39. Verify.Operation(StunServer.TryParse(Config.StunServer, out var server), @"Wrong STUN Server!");
  40. if (!HostnameEndpoint.TryParse(Config.ProxyServer, out var proxyIpe))
  41. {
  42. throw new NotSupportedException(@"Unknown proxy address");
  43. }
  44. var socks5Option = new Socks5CreateOption
  45. {
  46. Address = await DnsClient.QueryAsync(proxyIpe.Hostname, token),
  47. Port = proxyIpe.Port,
  48. UsernamePassword = new UsernamePassword
  49. {
  50. UserName = Config.ProxyUser,
  51. Password = Config.ProxyPassword
  52. }
  53. };
  54. Result3489.LocalEndPoint ??= DefaultLocalEndpoint;
  55. using var proxy = ProxyFactory.CreateProxy(Config.ProxyType, Result3489.LocalEndPoint, socks5Option);
  56. var ip = await DnsClient.QueryAsync(server.Hostname, token);
  57. using var client = new StunClient3489(new IPEndPoint(ip, server.Port), Result3489.LocalEndPoint, proxy);
  58. Result3489 = client.State;
  59. using (Observable.Interval(TimeSpan.FromSeconds(0.1))
  60. .ObserveOn(RxApp.MainThreadScheduler)
  61. .Subscribe(_ => this.RaisePropertyChanged(nameof(Result3489))))
  62. {
  63. await client.ConnectProxyAsync(token);
  64. try
  65. {
  66. await client.QueryAsync(token);
  67. Result3489.LocalEndPoint = new IPEndPoint(client.LocalEndPoint.AddressFamily is AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, client.LocalEndPoint.Port);
  68. }
  69. finally
  70. {
  71. await client.CloseProxyAsync(token);
  72. }
  73. }
  74. Result3489 = new ClassicStunResult();
  75. Result3489.Clone(client.State);
  76. this.RaisePropertyChanged(nameof(Result3489));
  77. }
  78. }