Skip to content

Commit 604c012

Browse files
committed
feat: Support hostname in proxy address #59
1 parent f89021b commit 604c012

File tree

5 files changed

+113
-57
lines changed

5 files changed

+113
-57
lines changed

NatTypeTester.ViewModels/RFC3489ViewModel.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@ private async Task TestClassicNatTypeAsync(CancellationToken token)
4747
{
4848
Verify.Operation(StunServer.TryParse(Config.StunServer, out var server), @"Wrong STUN Server!");
4949

50-
var proxyIpe = IPEndPoint.Parse(Config.ProxyServer);
50+
if (!HostnameEndpoint.TryParse(Config.ProxyServer, out var proxyIpe))
51+
{
52+
throw new NotSupportedException(@"Unknown proxy address");
53+
}
54+
5155
var socks5Option = new Socks5CreateOption
5256
{
53-
Address = proxyIpe.Address,
54-
Port = (ushort)proxyIpe.Port,
57+
Address = await DnsClient.QueryAsync(proxyIpe.Hostname, token),
58+
Port = proxyIpe.Port,
5559
UsernamePassword = new UsernamePassword
5660
{
5761
UserName = Config.ProxyUser,

NatTypeTester.ViewModels/RFC5780ViewModel.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,15 @@ private async Task DiscoveryNatTypeAsync(CancellationToken token)
4444
{
4545
Verify.Operation(StunServer.TryParse(Config.StunServer, out var server), @"Wrong STUN Server!");
4646

47-
var proxyIpe = IPEndPoint.Parse(Config.ProxyServer);
47+
if (!HostnameEndpoint.TryParse(Config.ProxyServer, out var proxyIpe))
48+
{
49+
throw new NotSupportedException(@"Unknown proxy address");
50+
}
51+
4852
var socks5Option = new Socks5CreateOption
4953
{
50-
Address = proxyIpe.Address,
51-
Port = (ushort)proxyIpe.Port,
54+
Address = await DnsClient.QueryAsync(proxyIpe.Hostname, token),
55+
Port = proxyIpe.Port,
5256
UsernamePassword = new UsernamePassword
5357
{
5458
UserName = Config.ProxyUser,

STUN/HostnameEndpoint.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Net;
4+
using System.Net.Sockets;
5+
6+
namespace STUN
7+
{
8+
public class HostnameEndpoint
9+
{
10+
public string Hostname { get; }
11+
public ushort Port { get; }
12+
13+
private HostnameEndpoint(string host, ushort port)
14+
{
15+
Hostname = host;
16+
Port = port;
17+
}
18+
19+
public static bool TryParse(string s, [NotNullWhen(true)] out HostnameEndpoint? result, ushort defaultPort = 0)
20+
{
21+
result = null;
22+
if (string.IsNullOrEmpty(s))
23+
{
24+
return false;
25+
}
26+
27+
var hostLength = s.Length;
28+
var pos = s.LastIndexOf(':');
29+
30+
if (pos > 0)
31+
{
32+
if (s[pos - 1] is ']')
33+
{
34+
hostLength = pos;
35+
}
36+
else if (s.AsSpan(0, pos).LastIndexOf(':') is -1)
37+
{
38+
hostLength = pos;
39+
}
40+
}
41+
42+
var host = s[..hostLength];
43+
var type = Uri.CheckHostName(host);
44+
switch (type)
45+
{
46+
case UriHostNameType.Dns:
47+
case UriHostNameType.IPv4:
48+
case UriHostNameType.IPv6:
49+
{
50+
break;
51+
}
52+
default:
53+
{
54+
return false;
55+
}
56+
}
57+
58+
if (hostLength == s.Length || ushort.TryParse(s.AsSpan(hostLength + 1), out defaultPort))
59+
{
60+
result = new HostnameEndpoint(host, defaultPort);
61+
return true;
62+
}
63+
64+
return false;
65+
}
66+
67+
public override string ToString()
68+
{
69+
if (IPAddress.TryParse(Hostname, out var ip) && ip.AddressFamily is AddressFamily.InterNetworkV6)
70+
{
71+
return $@"[{ip}]:{Port}";
72+
}
73+
74+
return $@"{Hostname}:{Port}";
75+
}
76+
}
77+
}

STUN/StunServer.cs

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Diagnostics.CodeAnalysis;
32
using System.Net;
43
using System.Net.Sockets;
@@ -18,64 +17,22 @@ public StunServer()
1817
Port = DefaultPort;
1918
}
2019

21-
private StunServer(string host, ushort port)
20+
private StunServer(string hostname, ushort port)
2221
{
23-
Hostname = host;
22+
Hostname = hostname;
2423
Port = port;
2524
}
2625

27-
public static bool TryParse(string str, [NotNullWhen(true)] out StunServer? server)
26+
public static bool TryParse(string s, [NotNullWhen(true)] out StunServer? result)
2827
{
29-
server = null;
30-
if (string.IsNullOrEmpty(str))
28+
if (!HostnameEndpoint.TryParse(s, out var host, DefaultPort))
3129
{
30+
result = null;
3231
return false;
3332
}
3433

35-
var hostLength = str.Length;
36-
var pos = str.LastIndexOf(':');
37-
38-
if (pos > 0)
39-
{
40-
if (str[pos - 1] is ']')
41-
{
42-
hostLength = pos;
43-
}
44-
else if (str.AsSpan(0, pos).LastIndexOf(':') is -1)
45-
{
46-
hostLength = pos;
47-
}
48-
}
49-
50-
var host = str[..hostLength];
51-
var type = Uri.CheckHostName(host);
52-
switch (type)
53-
{
54-
case UriHostNameType.Dns:
55-
case UriHostNameType.IPv4:
56-
case UriHostNameType.IPv6:
57-
{
58-
break;
59-
}
60-
default:
61-
{
62-
return false;
63-
}
64-
}
65-
66-
if (hostLength == str.Length)
67-
{
68-
server = new StunServer(host, DefaultPort);
69-
return true;
70-
}
71-
72-
if (ushort.TryParse(str.AsSpan(hostLength + 1), out var port))
73-
{
74-
server = new StunServer(host, port);
75-
return true;
76-
}
77-
78-
return false;
34+
result = new StunServer(host.Hostname, host.Port);
35+
return true;
7936
}
8037

8138
public override string ToString()

UnitTest/StunServerTest.cs renamed to UnitTest/HostnameEndpointTest.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace UnitTest
55
{
66
[TestClass]
7-
public class StunServerTest
7+
public class HostnameEndpointTest
88
{
99
[TestMethod]
1010
[DataRow(@"www.google.com", ushort.MinValue)]
@@ -66,5 +66,19 @@ public void DefaultServer()
6666
Assert.AreEqual(@"stun.syncthing.net", server.Hostname);
6767
Assert.AreEqual(3478, server.Port);
6868
}
69+
70+
[TestMethod]
71+
[DataRow(@"stun.syncthing.net:114", @"stun.syncthing.net:114")]
72+
[DataRow(@"stun.syncthing.net:3478", @"stun.syncthing.net:3478")]
73+
[DataRow(@"[2001:db8:1234:5678:11:2233:4455:6677]", @"[2001:db8:1234:5678:11:2233:4455:6677]:0")]
74+
[DataRow(@"[2001:db8:1234:5678:11:2233:4455:6677]:3478", @"[2001:db8:1234:5678:11:2233:4455:6677]:3478")]
75+
[DataRow(@"1.1.1.1:3478", @"1.1.1.1:3478")]
76+
[DataRow(@"1.1.1.1:1919", @"1.1.1.1:1919")]
77+
public void HostnameEndpointToString(string str, string expected)
78+
{
79+
Assert.IsTrue(HostnameEndpoint.TryParse(str, out var server));
80+
Assert.IsNotNull(server);
81+
Assert.AreEqual(expected, server.ToString());
82+
}
6983
}
7084
}

0 commit comments

Comments
 (0)