Peer: prefer v4 endpoints to v6

This works around DNS64 XLAT changeovers.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2018-10-01 17:13:14 +02:00
parent 49a9475c4a
commit c23d58bc27
2 changed files with 79 additions and 33 deletions

View File

@ -0,0 +1,71 @@
/*
* Copyright © 2017-2018 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
import android.annotation.SuppressLint;
import com.wireguard.android.Application;
import com.wireguard.android.R;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import javax.annotation.Nullable;
public class InetEndpoint {
private final String host;
private final int port;
@Nullable private InetAddress resolvedHost;
public InetEndpoint(@Nullable final String endpoint) {
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1)
throw new IllegalArgumentException(Application.get().getString(R.string.tunnel_error_forbidden_endpoint_chars));
final URI uri;
try {
uri = new URI("wg://" + endpoint);
} catch (final URISyntaxException e) {
throw new IllegalArgumentException(e);
}
host = uri.getHost();
port = uri.getPort();
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
@SuppressLint("DefaultLocale")
public String getResolvedEndpoint() throws UnknownHostException {
if (resolvedHost == null) {
final InetAddress[] candidates = InetAddress.getAllByName(host);
if (candidates.length == 0)
throw new UnknownHostException(host);
for (final InetAddress addr : candidates) {
if (addr instanceof Inet4Address) {
resolvedHost = addr;
break;
}
}
if (resolvedHost == null)
resolvedHost = candidates[0];
}
return String.format(resolvedHost instanceof Inet4Address ?
"[%s]:%d" : "%s:%d", resolvedHost.getHostAddress(), port);
}
@SuppressLint("DefaultLocale")
public String getEndpoint() {
return String.format(host.contains(":") && !host.contains("[") ?
"[%s]:%d" : "%s:%d", host, port);
}
}

View File

@ -37,7 +37,7 @@ import java9.lang.Iterables;
public class Peer { public class Peer {
private final List<InetNetwork> allowedIPsList; private final List<InetNetwork> allowedIPsList;
@Nullable private InetSocketAddress endpoint; @Nullable private InetEndpoint endpoint;
private int persistentKeepalive; private int persistentKeepalive;
@Nullable private String preSharedKey; @Nullable private String preSharedKey;
@Nullable private String publicKey; @Nullable private String publicKey;
@ -67,19 +67,15 @@ public class Peer {
} }
@Nullable @Nullable
public InetSocketAddress getEndpoint() { public InetEndpoint getEndpoint() {
return endpoint; return endpoint;
} }
@SuppressLint("DefaultLocale")
@Nullable @Nullable
private String getEndpointString() { private String getEndpointString() {
if (endpoint == null) if (endpoint == null)
return null; return null;
if (endpoint.getHostString().contains(":") && !endpoint.getHostString().contains("[")) return endpoint.getEndpoint();
return String.format("[%s]:%d", endpoint.getHostString(), endpoint.getPort());
else
return String.format("%s:%d", endpoint.getHostString(), endpoint.getPort());
} }
public int getPersistentKeepalive() { public int getPersistentKeepalive() {
@ -103,21 +99,10 @@ public class Peer {
return publicKey; return publicKey;
} }
@SuppressLint("DefaultLocale")
public String getResolvedEndpointString() throws UnknownHostException { public String getResolvedEndpointString() throws UnknownHostException {
if (endpoint == null) if (endpoint == null)
throw new UnknownHostException("{empty}"); throw new UnknownHostException("{empty}");
if (endpoint.isUnresolved()) return endpoint.getResolvedEndpoint();
endpoint = new InetSocketAddress(endpoint.getHostString(), endpoint.getPort());
if (endpoint.isUnresolved())
throw new UnknownHostException(endpoint.getHostString());
if (endpoint.getAddress() instanceof Inet6Address)
return String.format("[%s]:%d",
endpoint.getAddress().getHostAddress(),
endpoint.getPort());
return String.format("%s:%d",
endpoint.getAddress().getHostAddress(),
endpoint.getPort());
} }
public void parse(final String line) { public void parse(final String line) {
@ -150,24 +135,14 @@ public class Peer {
addAllowedIPs(Attribute.stringToList(allowedIPsString)); addAllowedIPs(Attribute.stringToList(allowedIPsString));
} }
private void setEndpoint(@Nullable final InetSocketAddress endpoint) { private void setEndpoint(@Nullable final InetEndpoint endpoint) {
this.endpoint = endpoint; this.endpoint = endpoint;
} }
private void setEndpointString(@Nullable final String endpoint) { private void setEndpointString(@Nullable final String endpoint) {
if (endpoint != null && !endpoint.isEmpty()) { if (endpoint != null && !endpoint.isEmpty())
final InetSocketAddress constructedEndpoint; setEndpoint(new InetEndpoint(endpoint));
if (endpoint.indexOf('/') != -1 || endpoint.indexOf('?') != -1 || endpoint.indexOf('#') != -1) else
throw new IllegalArgumentException(context.getString(R.string.tunnel_error_forbidden_endpoint_chars));
final URI uri;
try {
uri = new URI("wg://" + endpoint);
} catch (final URISyntaxException e) {
throw new IllegalArgumentException(e);
}
constructedEndpoint = InetSocketAddress.createUnresolved(uri.getHost(), uri.getPort());
setEndpoint(constructedEndpoint);
} else
setEndpoint(null); setEndpoint(null);
} }