-
Notifications
You must be signed in to change notification settings - Fork 447
ui: support DNS SRV lookup & show resolved inetendpoint #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,16 @@ | |
|
||
import com.wireguard.util.NonNullForAll; | ||
|
||
import org.xbill.DNS.DClass; | ||
import org.xbill.DNS.ExtendedResolver; | ||
import org.xbill.DNS.Lookup; | ||
import org.xbill.DNS.Record; | ||
import org.xbill.DNS.Resolver; | ||
import org.xbill.DNS.SRVRecord; | ||
import org.xbill.DNS.SimpleResolver; | ||
import org.xbill.DNS.TextParseException; | ||
import org.xbill.DNS.Type; | ||
|
||
import java.net.Inet4Address; | ||
import java.net.InetAddress; | ||
import java.net.URI; | ||
|
@@ -15,6 +25,7 @@ | |
import java.time.Duration; | ||
import java.time.Instant; | ||
import java.util.Optional; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.regex.Pattern; | ||
|
||
import androidx.annotation.Nullable; | ||
|
@@ -46,6 +57,11 @@ private InetEndpoint(final String host, final boolean isResolved, final int port | |
public static InetEndpoint parse(final String endpoint) throws ParseException { | ||
if (FORBIDDEN_CHARACTERS.matcher(endpoint).find()) | ||
throw new ParseException(InetEndpoint.class, endpoint, "Forbidden characters"); | ||
if (endpoint.contains("_")) { | ||
// SRV records | ||
final String host = endpoint.split(":")[0]; | ||
return new InetEndpoint(host, false, 0); | ||
} | ||
final URI uri; | ||
try { | ||
uri = new URI("wg://" + endpoint); | ||
|
@@ -92,21 +108,60 @@ public Optional<InetEndpoint> getResolved() { | |
return Optional.of(this); | ||
synchronized (lock) { | ||
//TODO(zx2c4): Implement a real timeout mechanism using DNS TTL | ||
if (Duration.between(lastResolution, Instant.now()).toMinutes() > 1) { | ||
try { | ||
// Prefer v4 endpoints over v6 to work around DNS64 and IPv6 NAT issues. | ||
final InetAddress[] candidates = InetAddress.getAllByName(host); | ||
InetAddress address = candidates[0]; | ||
for (final InetAddress candidate : candidates) { | ||
if (candidate instanceof Inet4Address) { | ||
address = candidate; | ||
break; | ||
final long ttlTimeout = Duration.between(lastResolution, Instant.now()).toSeconds(); | ||
if (ttlTimeout > 60) { | ||
resolved = null; | ||
final String[] target = {host}; | ||
final int[] targetPort = {port}; | ||
if (host.contains("_")) { | ||
// SRV records | ||
try { | ||
final Lookup lookup = new Lookup(host, Type.SRV, DClass.IN); | ||
final Resolver resolver1 = new SimpleResolver("223.5.5.5"); | ||
final Resolver resolver2 = new SimpleResolver("223.6.6.6"); | ||
final Resolver[] resolvers = {resolver1, resolver2}; | ||
final Resolver extendedResolver = new ExtendedResolver(resolvers); | ||
lookup.setResolver(extendedResolver); | ||
lookup.setCache(null); | ||
final Record[] records = lookup.run(); | ||
if (lookup.getResult() == Lookup.SUCCESSFUL) { | ||
for (final Record record : records) { | ||
final SRVRecord srv = (SRVRecord) record; | ||
try { | ||
target[0] = srv.getTarget().toString(true); | ||
targetPort[0] = srv.getPort(); | ||
InetAddresses.parse(target[0]); | ||
// Parsing ths host as a numeric address worked, so we don't need to do DNS lookups. | ||
resolved = new InetEndpoint(target[0], true, targetPort[0]); | ||
} catch (final ParseException ignored) { | ||
// Failed to parse the host as a numeric address, so it must be a DNS hostname/FQDN. | ||
} | ||
// use the first SRV record and break out of loop | ||
break; | ||
} | ||
} else { | ||
System.out.println("SRV lookup failed: " + lookup.getErrorString()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be using |
||
} | ||
} catch (final TextParseException | UnknownHostException e) { | ||
System.out.println("SRV lookup failed: " + e.getMessage()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
} | ||
} | ||
if (resolved == null) { | ||
try { | ||
// Prefer v4 endpoints over v6 to work around DNS64 and IPv6 NAT issues. | ||
final InetAddress[] candidates = InetAddress.getAllByName(target[0]); | ||
InetAddress address = candidates[0]; | ||
for (final InetAddress candidate : candidates) { | ||
if (candidate instanceof Inet4Address) { | ||
address = candidate; | ||
break; | ||
} | ||
} | ||
resolved = new InetEndpoint(address.getHostAddress(), true, targetPort[0]); | ||
lastResolution = Instant.now(); | ||
} catch (final UnknownHostException e) { | ||
System.out.println("DNS lookup failed: " + e.getMessage()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
} | ||
resolved = new InetEndpoint(address.getHostAddress(), true, port); | ||
lastResolution = Instant.now(); | ||
} catch (final UnknownHostException e) { | ||
resolved = null; | ||
} | ||
} | ||
return Optional.ofNullable(resolved); | ||
|
@@ -121,6 +176,9 @@ public int hashCode() { | |
@Override | ||
public String toString() { | ||
final boolean isBareIpv6 = isResolved && BARE_IPV6.matcher(host).matches(); | ||
return (isBareIpv6 ? '[' + host + ']' : host) + ':' + port; | ||
// Only show the port if it's non-zero | ||
if (port > 0) | ||
return (isBareIpv6 ? '[' + host + ']' : host) + ':' + port; | ||
return (isBareIpv6 ? '[' + host + ']' : host); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,13 @@ | ||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= | ||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= | ||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= | ||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= | ||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= | ||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= | ||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= | ||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= | ||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= | ||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= | ||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= | ||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= | ||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= | ||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= | ||
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 h1:/J/RVnr7ng4fWPRH3xa4WtBJ1Jp+Auu4YNLmGiPv5QU= | ||
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675/go.mod h1:whfbyDBt09xhCYQWtO2+3UVjlaq6/9hDZrjg2ZE6SyA= | ||
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb h1:c5tyN8sSp8jSDxdCCDXVOpJwYXXhmTkNMt+g0zTSOic= | ||
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= | ||
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure we want Alibaba Cloud to be the DNS resolver for everyone