retrieve current DNS servers.

Add getDnsConfigAsString() to retrieve the current DNS
configuration from the Android platform. This implements
several mechanisms to retrieve DNS information, suitable
for different Android versions:

Android 7 and later use ConnectivityManager getAllNetworks(),
then iterate over each network to retrieve DNS servers and
search domains using the LinkProperties.

Android 6 and earlier can only retrieve the currently active
interface using ConnectivityManager getActiveNetwork(), but have
two additional fallback options which leverage the system
properties available in older Android releases.

--------

Also changed how LinkChange notification works, switching from
the older BroadcastReceiver of a ConnectivityManager Intent to
the newer ConnectivityManager.registerNetworkCallback. We need
this because the onAvailable event is too early, we get notified
that LTE is up before its DNS servers have been set. We need
to wait for the onLinkPropertiesChanged event instead, which is
only available with registerNetworkCallback.

Fixes https://github.com/tailscale/tailscale/issues/2116
Updates https://github.com/tailscale/tailscale/issues/988

Signed-off-by: Denton Gentry <dgentry@tailscale.com>
pull/23/head
Denton Gentry 3 years ago
parent 0c00fa3374
commit 5c9cec0064

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tailscale.ipn">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>

@ -24,6 +24,9 @@ import android.content.pm.Signature;
import android.provider.MediaStore;
import android.provider.Settings;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkRequest;
import android.net.Uri;
import android.net.VpnService;
import android.view.View;
@ -77,6 +80,9 @@ public class App extends Application {
private final static Handler mainHandler = new Handler(Looper.getMainLooper());
public DnsConfig dns = new DnsConfig(this);
public DnsConfig getDnsConfigObj() { return this.dns; }
@Override public void onCreate() {
super.onCreate();
// Load and initialize the Go library.
@ -90,13 +96,18 @@ public class App extends Application {
}
private void registerNetworkCallback() {
BroadcastReceiver connectivityChanged = new BroadcastReceiver() {
@Override public void onReceive(Context ctx, Intent intent) {
boolean noconn = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
onConnectivityChanged(!noconn);
ConnectivityManager cMgr = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
cMgr.registerNetworkCallback(new NetworkRequest.Builder().build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onLost(Network network) {
onConnectivityChanged(false);
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
onConnectivityChanged(true);
}
};
registerReceiver(connectivityChanged, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
});
}
public void startVPN() {

@ -0,0 +1,360 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package com.tailscale.ipn;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
// Tailscale DNS Config retrieval
//
// Tailscale's DNS support can either override the local DNS servers with a set of servers
// configured in the admin panel, or supplement the local DNS servers with additional
// servers for specific domains like example.com.beta.tailscale.net. In the non-override mode,
// we need to retrieve the current set of DNS servers from the platform. These will typically
// be the DNS servers received from DHCP.
//
// Importantly, after the Tailscale VPN comes up it will set a DNS server of 100.100.100.100
// but we still want to retrieve the underlying DNS servers received from DHCP. If we roam
// from Wi-Fi to LTE, we want the DNS servers received from LTE.
//
// --------------------- Android 7 and later -----------------------------------------
//
// ## getDnsConfigFromLinkProperties
// Android provides a getAllNetworks interface in the ConnectivityManager. We walk through
// each interface to pick the most appropriate one.
// - If there is an Ethernet interface active we use that.
// - If Wi-Fi is active we use that.
// - If LTE is active we use that.
// - We never use a VPN's DNS servers. That VPN is likely us. Even if not us, Android
// only allows one VPN at a time so a different VPN's DNS servers won't be available
// once Tailscale comes up.
//
// getAllNetworks() is used as the sole mechanism for retrieving the DNS config with
// Android 7 and later.
//
// --------------------- Releases older than Android 7 -------------------------------
//
// We support Tailscale back to Android 5. Android versions 5 and 6 supply a getAllNetworks()
// implementation but it always returns an empty list.
//
// ## getDnsConfigFromLinkProperties with getActiveNetwork
// ConnectivityManager also supports a getActiveNetwork() routine, which Android 5 and 6 do
// return a value for. If Tailscale isn't up yet and we can get the Wi-Fi/LTE/etc DNS
// config using getActiveNetwork(), we use that.
//
// Once Tailscale is up, getActiveNetwork() returns tailscale0 with DNS server 100.100.100.100
// and that isn't useful. So we try two other mechanisms:
//
// ## getDnsServersFromSystemProperties
// Android versions prior to 8 let us retrieve the actual system DNS servers from properties.
// Later Android versions removed the properties and only return an empty string.
//
// We check the net.dns1 - net.dns4 DNS servers. If Tailscale is up the DNS server will be
// 100.100.100.100, which isn't useful, but if we get something different we'll use that.
//
// getDnsServersFromSystemProperties can only retrieve the IPv4 or IPv6 addresses of the
// configured DNS servers. We also want to know the DNS Search Domains configured, but
// we have no way to retrieve this using these interfaces. We return an empty list of
// search domains. Sorry.
//
// ## getDnsServersFromNetworkInfo
// ConnectivityManager supports an older API called getActiveNetworkInfo to return the
// active network interface. It doesn't handle VPNs, so the interface will always be Wi-Fi
// or Cellular even if Tailscale is up.
//
// For Wi-Fi interfaces we retrieve the DHCP response from the WifiManager. For Cellular
// interfaces we check for properties populated by most of the radio drivers.
//
// getDnsServersFromNetworkInfo does not have a way to retrieve the DNS Search Domains,
// so we return an empty list. Additionally, these interfaces are so old that they only
// support IPv4. We can't retrieve IPv6 DNS server addresses this way.
public class DnsConfig {
private Context ctx;
public DnsConfig(Context ctx) {
this.ctx = ctx;
}
// getDnsConfigAsString returns the current DNS configuration as a multiline string:
// line[0] DNS server addresses separated by spaces
// line[1] search domains separated by spaces
//
// For example:
// 8.8.8.8 8.8.4.4
// example.com
//
// an empty string means the current DNS configuration could not be retrieved.
String getDnsConfigAsString() {
String s = getDnsConfigFromLinkProperties();
if (!s.trim().isEmpty()) {
return s;
}
if (android.os.Build.VERSION.SDK_INT >= 23) {
// If ConnectivityManager.getAllNetworks() works, it is the
// authoritative mechanism and we rely on it. The other methods
// which follow involve more compromises.
return "";
}
s = getDnsServersFromSystemProperties();
if (!s.trim().isEmpty()) {
return s;
}
return getDnsServersFromNetworkInfo();
}
// getDnsConfigFromLinkProperties finds the DNS servers for each Network interface
// returned by ConnectivityManager getAllNetworks().LinkProperties, and return the
// one that (heuristically) would be the primary DNS servers.
//
// on a Nexus 4 with Android 5.1 on wifi: 2602:248:7b4a:ff60::1 10.1.10.1
// on a Nexus 7 with Android 6.0 on wifi: 2602:248:7b4a:ff60::1 10.1.10.1
// on a Pixel 3a with Android 12.0 on wifi: 2602:248:7b4a:ff60::1 10.1.10.1\nlocaldomain
// on a Pixel 3a with Android 12.0 on LTE: fd00:976a::9 fd00:976a::10
//
// One odd behavior noted on Pixel3a with Android 12:
// With Wi-Fi already connected, starting Tailscale returned DNS servers 2602:248:7b4a:ff60::1 10.1.10.1
// Turning off Wi-Fi and connecting LTE returned DNS servers fd00:976a::9 fd00:976a::10.
// Turning Wi-Fi back on return DNS servers: 10.1.10.1. The IPv6 DNS server is gone.
// This appears to be the ConnectivityManager behavior, not something we are doing.
//
// This implementation can work through Android 12 (SDK 30). In SDK 31 the
// getAllNetworks() method is deprecated and we'll need to implement a
// android.net.ConnectivityManager.NetworkCallback instead to monitor
// link changes and track which DNS server to use.
String getDnsConfigFromLinkProperties() {
ConnectivityManager cMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cMgr == null) {
return "";
}
Network[] networks = cMgr.getAllNetworks();
if (networks == null) {
// Android 6 and before often returns an empty list, but we
// can try again with just the active network.
//
// Once Tailscale is connected, the active network will be Tailscale
// which will have 100.100.100.100 for its DNS server. We reject
// TYPE_VPN in getPreferabilityForNetwork, so it won't be returned.
Network active = cMgr.getActiveNetwork();
if (active == null) {
return "";
}
networks = new Network[]{active};
}
// getPreferabilityForNetwork returns an index into dnsConfigs from 0-3.
String[] dnsConfigs = new String[]{"", "", "", ""};
for (Network network : networks) {
int idx = getPreferabilityForNetwork(cMgr, network);
if ((idx < 0) || (idx > 3)) {
continue;
}
LinkProperties linkProp = cMgr.getLinkProperties(network);
NetworkCapabilities nc = cMgr.getNetworkCapabilities(network);
List<InetAddress> dnsList = linkProp.getDnsServers();
StringBuilder sb = new StringBuilder("");
for (InetAddress ip : dnsList) {
sb.append(ip.getHostAddress() + " ");
}
String d = linkProp.getDomains();
if (d != null) {
sb.append("\n");
sb.append(d);
}
dnsConfigs[idx] = sb.toString();
}
// return the lowest index DNS config which exists. If an Ethernet config
// was found, return it. Otherwise if Wi-fi was found, return it. Etc.
for (String s : dnsConfigs) {
if (!s.trim().isEmpty()) {
return s;
}
}
return "";
}
// getDnsServersFromSystemProperties returns DNS servers found in system properties.
// On Android versions prior to Android 8, we can directly query the DNS
// servers the system is using. More recent Android releases return empty strings.
//
// Once Tailscale is connected these properties will return 100.100.100.100, which we
// suppress.
//
// on a Nexus 4 with Android 5.1 on wifi: 2602:248:7b4a:ff60::1 10.1.10.1
// on a Nexus 7 with Android 6.0 on wifi: 2602:248:7b4a:ff60::1 10.1.10.1
// on a Pixel 3a with Android 12.0 on wifi:
// on a Pixel 3a with Android 12.0 on LTE:
//
// The list of DNS search domains does not appear to be available in system properties.
String getDnsServersFromSystemProperties() {
try {
Class SystemProperties = Class.forName("android.os.SystemProperties");
Method method = SystemProperties.getMethod("get", String.class);
List<String> servers = new ArrayList<String>();
for (String name : new String[]{"net.dns1", "net.dns2", "net.dns3", "net.dns4"}) {
String value = (String) method.invoke(null, name);
if (value != null && !value.isEmpty() &&
!value.equals("100.100.100.100") &&
!servers.contains(value)) {
servers.add(value);
}
}
return String.join(" ", servers);
} catch (Exception e) {
return "";
}
}
String intToInetString(int hostAddress) {
return String.format("%d.%d.%d.%d",
(byte)(0xff & hostAddress),
(byte)(0xff & (hostAddress >> 8)),
(byte)(0xff & (hostAddress >> 16)),
(byte)(0xff & (hostAddress >> 24)));
}
// getDnsServersFromNetworkInfo retrieves DNS servers using ConnectivityManager
// getActiveNetworkInfo() plus interface-specific mechanisms to retrieve the DNS servers.
// Only IPv4 DNS servers are supported by this mechanism, neither the WifiManager nor the
// interface-specific dns properties appear to populate IPv6 DNS server addresses.
//
// on a Nexus 4 with Android 5.1 on wifi: 10.1.10.1
// on a Nexus 7 with Android 6.0 on wifi: 10.1.10.1
// on a Pixel-3a with Android 12.0 on wifi: 10.1.10.1
// on a Pixel-3a with Android 12.0 on LTE:
//
// The list of DNS search domains is not available in this way.
String getDnsServersFromNetworkInfo() {
ConnectivityManager cMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cMgr == null) {
return "";
}
NetworkInfo info = cMgr.getActiveNetworkInfo();
if (info == null) {
return "";
}
Class SystemProperties;
Method method;
try {
SystemProperties = Class.forName("android.os.SystemProperties");
method = SystemProperties.getMethod("get", String.class);
} catch (Exception e) {
return "";
}
List<String> servers = new ArrayList<String>();
switch(info.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
for (String name : new String[]{
"net.wifi0.dns1", "net.wifi0.dns2", "net.wifi0.dns3", "net.wifi0.dns4",
"net.wlan0.dns1", "net.wlan0.dns2", "net.wlan0.dns3", "net.wlan0.dns4",
"net.eth0.dns1", "net.eth0.dns2", "net.eth0.dns3", "net.eth0.dns4",
"dhcp.wlan0.dns1", "dhcp.wlan0.dns2", "dhcp.wlan0.dns3", "dhcp.wlan0.dns4",
"dhcp.tiwlan0.dns1", "dhcp.tiwlan0.dns2", "dhcp.tiwlan0.dns3", "dhcp.tiwlan0.dns4"}) {
try {
String value = (String) method.invoke(null, name);
if (value != null && !value.isEmpty() && !servers.contains(value)) {
servers.add(value);
}
} catch (Exception e) {
continue;
}
}
WifiManager wMgr = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
if (wMgr != null) {
DhcpInfo dhcp = wMgr.getDhcpInfo();
if (dhcp.dns1 != 0) {
String value = intToInetString(dhcp.dns1);
if (value != null && !value.isEmpty() && !servers.contains(value)) {
servers.add(value);
}
}
if (dhcp.dns2 != 0) {
String value = intToInetString(dhcp.dns2);
if (value != null && !value.isEmpty() && !servers.contains(value)) {
servers.add(value);
}
}
}
return String.join(" ", servers);
case ConnectivityManager.TYPE_MOBILE:
case ConnectivityManager.TYPE_MOBILE_HIPRI:
for (String name : new String[]{
"net.rmnet0.dns1", "net.rmnet0.dns2", "net.rmnet0.dns3", "net.rmnet0.dns4",
"net.rmnet1.dns1", "net.rmnet1.dns2", "net.rmnet1.dns3", "net.rmnet1.dns4",
"net.rmnet2.dns1", "net.rmnet2.dns2", "net.rmnet2.dns3", "net.rmnet2.dns4",
"net.rmnet3.dns1", "net.rmnet3.dns2", "net.rmnet3.dns3", "net.rmnet3.dns4",
"net.rmnet4.dns1", "net.rmnet4.dns2", "net.rmnet4.dns3", "net.rmnet4.dns4",
"net.rmnet5.dns1", "net.rmnet5.dns2", "net.rmnet5.dns3", "net.rmnet5.dns4",
"net.rmnet6.dns1", "net.rmnet6.dns2", "net.rmnet6.dns3", "net.rmnet6.dns4",
"net.rmnet7.dns1", "net.rmnet7.dns2", "net.rmnet7.dns3", "net.rmnet7.dns4",
"net.pdp0.dns1", "net.pdp0.dns2", "net.pdp0.dns3", "net.pdp0.dns4",
"net.pdpbr0.dns1", "net.pdpbr0.dns2", "net.pdpbr0.dns3", "net.pdpbr0.dns4"}) {
try {
String value = (String) method.invoke(null, name);
if (value != null && !value.isEmpty() && !servers.contains(value)) {
servers.add(value);
}
} catch (Exception e) {
continue;
}
}
}
return "";
}
// getPreferabilityForNetwork is a utility routine which implements a priority for
// different types of network transport, used in a heuristic to pick DNS servers to use.
int getPreferabilityForNetwork(ConnectivityManager cMgr, Network network) {
NetworkCapabilities nc = cMgr.getNetworkCapabilities(network);
if (nc == null) {
return -1;
}
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
// tun0 has both VPN and WIFI set, have to check VPN first and return.
return -1;
}
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return 0;
} else if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return 1;
} else if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return 2;
} else {
return 3;
}
}
}

@ -11,6 +11,7 @@ import (
"net/http"
"path/filepath"
"reflect"
"strings"
"time"
"github.com/tailscale/tailscale-android/jni"
@ -23,8 +24,10 @@ import (
"tailscale.com/logtail"
"tailscale.com/logtail/filch"
"tailscale.com/net/dns"
"tailscale.com/net/tsdial"
"tailscale.com/smallzstd"
"tailscale.com/types/logger"
"tailscale.com/util/dnsname"
"tailscale.com/wgengine"
"tailscale.com/wgengine/router"
)
@ -41,7 +44,8 @@ type backend struct {
// when no nameservers are provided by Tailscale.
avoidEmptyDNS bool
jvm *jni.JVM
jvm *jni.JVM
appCtx jni.Object
}
type settingsFunc func(*router.Config, *dns.OSConfig) error
@ -58,19 +62,27 @@ const (
loginMethodWeb = "web"
)
var fallbackNameservers = []netaddr.IP{netaddr.IPv4(8, 8, 8, 8), netaddr.IPv4(8, 8, 4, 4)}
// googleDnsServers are used on ChromeOS, where an empty VpnBuilder DNS setting results
// in erasing the platform DNS servers. The developer docs say this is not supposed to happen,
// but nonetheless it does.
var googleDnsServers = []netaddr.IP{netaddr.MustParseIP("8.8.8.8"), netaddr.MustParseIP("8.8.4.4"),
netaddr.MustParseIP("2001:4860:4860::8888"), netaddr.MustParseIP("2001:4860:4860::8844"),
}
// errVPNNotPrepared is used when VPNService.Builder.establish returns
// null, either because the VPNService is not yet prepared or because
// VPN status was revoked.
var errVPNNotPrepared = errors.New("VPN service not prepared or was revoked")
func newBackend(dataDir string, jvm *jni.JVM, store *stateStore, settings settingsFunc) (*backend, error) {
func newBackend(dataDir string, jvm *jni.JVM, appCtx jni.Object, store *stateStore,
settings settingsFunc) (*backend, error) {
logf := logger.RusagePrefixLog(log.Printf)
b := &backend{
jvm: jvm,
devices: newTUNDevices(),
settings: settings,
appCtx: appCtx,
}
var logID logtail.PrivateID
logID.UnmarshalText([]byte("dead0000dead0000dead0000dead0000dead0000dead0000dead0000dead0000"))
@ -90,19 +102,23 @@ func newBackend(dataDir string, jvm *jni.JVM, store *stateStore, settings settin
logID.UnmarshalText([]byte(storedLogID))
}
b.SetupLogs(dataDir, logID)
dialer := new(tsdial.Dialer)
cb := &router.CallbackRouter{
SetBoth: b.setCfg,
SplitDNS: false, // TODO: https://github.com/tailscale/tailscale/issues/1695
SetBoth: b.setCfg,
SplitDNS: false,
GetBaseConfigFunc: b.getDNSBaseConfig,
}
engine, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
Tun: b.devices,
Router: cb,
DNS: cb,
Dialer: dialer,
})
if err != nil {
return nil, fmt.Errorf("runBackend: NewUserspaceEngine: %v", err)
}
local, err := ipnlocal.NewLocalBackend(logf, logID.Public().String(), store, engine)
local, err := ipnlocal.NewLocalBackend(logf, logID.Public().String(), store, dialer, engine)
if err != nil {
engine.Close()
return nil, fmt.Errorf("runBackend: NewLocalBackend: %v", err)
@ -170,7 +186,7 @@ func (b *backend) updateTUN(service jni.Object, rcfg *router.Config, dcfg *dns.O
if dcfg != nil {
nameservers := dcfg.Nameservers
if b.avoidEmptyDNS && len(nameservers) == 0 {
nameservers = fallbackNameservers
nameservers = googleDnsServers
}
for _, dns := range nameservers {
_, err = jni.CallObjectMethod(env,
@ -324,3 +340,89 @@ func (b *backend) SetupLogs(logDir string, logID logtail.PrivateID) {
log.Printf("SetupLogs: filch setup failed: %v", filchErr)
}
}
// We log the result of each of the DNS configuration discovery mechanisms, as we're
// expecting a long tail of obscure Android devices with interesting behavior.
func (b *backend) logDNSConfigMechanisms() {
err := jni.Do(b.jvm, func(env *jni.Env) error {
cls := jni.GetObjectClass(env, b.appCtx)
m := jni.GetMethodID(env, cls, "getDnsConfigObj", "()Lcom/tailscale/ipn/DnsConfig;")
dns, err := jni.CallObjectMethod(env, b.appCtx, m)
if err != nil {
return fmt.Errorf("getDnsConfigObj JNI: %v", err)
}
dnsCls := jni.GetObjectClass(env, dns)
for _, impl := range []string{"getDnsConfigFromLinkProperties",
"getDnsServersFromSystemProperties",
"getDnsServersFromNetworkInfo"} {
m = jni.GetMethodID(env, dnsCls, impl, "()Ljava/lang/String;")
n, err := jni.CallObjectMethod(env, dns, m)
baseConfig := jni.GoString(env, jni.String(n))
if err != nil {
log.Printf("%s JNI: %v", impl, err)
} else {
oneLine := strings.Replace(baseConfig, "\n", ";", -1)
log.Printf("%s: %s", impl, oneLine)
}
}
return nil
})
if err != nil {
log.Printf("logDNSConfigMechanisms: %v", err)
}
}
func (b *backend) getPlatformDNSConfig() string {
var baseConfig string
err := jni.Do(b.jvm, func(env *jni.Env) error {
cls := jni.GetObjectClass(env, b.appCtx)
m := jni.GetMethodID(env, cls, "getDnsConfigObj", "()Lcom/tailscale/ipn/DnsConfig;")
dns, err := jni.CallObjectMethod(env, b.appCtx, m)
if err != nil {
return fmt.Errorf("getDnsConfigObj: %v", err)
}
dnsCls := jni.GetObjectClass(env, dns)
m = jni.GetMethodID(env, dnsCls, "getDnsConfigAsString", "()Ljava/lang/String;")
n, err := jni.CallObjectMethod(env, dns, m)
baseConfig = jni.GoString(env, jni.String(n))
return err
})
if err != nil {
log.Printf("getPlatformDNSConfig JNI: %v", err)
return ""
}
return baseConfig
}
func (b *backend) getDNSBaseConfig() (dns.OSConfig, error) {
b.logDNSConfigMechanisms()
baseConfig := b.getPlatformDNSConfig()
lines := strings.Split(baseConfig, "\n")
if len(lines) == 0 {
return dns.OSConfig{}, nil
}
config := dns.OSConfig{}
addrs := strings.Trim(lines[0], " \n")
for _, addr := range strings.Split(addrs, " ") {
ip, err := netaddr.ParseIP(addr)
if err == nil {
config.Nameservers = append(config.Nameservers, ip)
}
}
if len(lines) > 1 {
for _, s := range strings.Split(strings.Trim(lines[1], " \n"), " ") {
domain, err := dnsname.ToFQDN(s)
if err != nil {
log.Printf("getDNSBaseConfig: unable to parse %q: %v", s, err)
continue
}
config.SearchDomains = append(config.SearchDomains, domain)
}
}
return config, nil
}

@ -256,7 +256,7 @@ func (a *App) runBackend() error {
}
configs := make(chan configPair)
configErrs := make(chan error)
b, err := newBackend(appDir, a.jvm, a.store, func(rcfg *router.Config, dcfg *dns.OSConfig) error {
b, err := newBackend(appDir, a.jvm, a.appCtx, a.store, func(rcfg *router.Config, dcfg *dns.OSConfig) error {
if rcfg == nil {
return nil
}

@ -10,7 +10,7 @@ require (
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08
golang.zx2c4.com/wireguard v0.0.0-20211116201604-de7c702ace45
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6
tailscale.com v1.1.1-0.20211125200034-e24f89efad22
tailscale.com v1.1.1-0.20211206024951-b3810e3b1b93
)
require (

@ -636,5 +636,19 @@ nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
software.sslmate.com/src/go-pkcs12 v0.0.0-20180114231543-2291e8f0f237 h1:iAEkCBPbRaflBgZ7o9gjVUuWuvWeV4sytFWg9o+Pj2k=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
tailscale.com v1.1.1-0.20211103210016-0532eb30dbba h1:UJfsplfXBBJb2d2Sj3G+Uwq4cZqNQUOM04K+aWavumM=
tailscale.com v1.1.1-0.20211103210016-0532eb30dbba/go.mod h1:KpeWAuozkb9G2RharSOmrtLh8nfUsJNI9Ml1hUSjk1U=
tailscale.com v1.1.1-0.20211108154433-eccc2ac6ee91 h1:cfV2IJg5dc6BfxzX3W+GAZ/veXgvuoKUxHyuxrXM4iE=
tailscale.com v1.1.1-0.20211108154433-eccc2ac6ee91/go.mod h1:+3SVDKPct8EqzwfYDQ3RpRwwBodKP7kNs49WXoM7wiw=
tailscale.com v1.1.1-0.20211109021509-d6dde5a1aca7 h1:gfDJ/zqR+hPeL3JCOY6akU2VHvmRz+lv3OpwkPgBbFA=
tailscale.com v1.1.1-0.20211109021509-d6dde5a1aca7/go.mod h1:+3SVDKPct8EqzwfYDQ3RpRwwBodKP7kNs49WXoM7wiw=
tailscale.com v1.1.1-0.20211116231549-773af7292b95 h1:gyWNQkqxuUbdumPC5XH5rGRQG1iomkTblYVC8A7L7Jw=
tailscale.com v1.1.1-0.20211116231549-773af7292b95/go.mod h1:XzG4o2vtYFkVvmJWPaTGSaOzqlKSRx2WU+aJbrxaVE0=
tailscale.com v1.1.1-0.20211119125307-221a18f4f07c h1:XVV1hEdNdLT2md2XkTBtD1oFBSPs/A/FcDZrRxbuN9A=
tailscale.com v1.1.1-0.20211119125307-221a18f4f07c/go.mod h1:XzG4o2vtYFkVvmJWPaTGSaOzqlKSRx2WU+aJbrxaVE0=
tailscale.com v1.1.1-0.20211125200034-e24f89efad22 h1:BCCsNwOxI+Oo4E7GCWcIrOCfVmyYkQDI/iYBYyj/kpA=
tailscale.com v1.1.1-0.20211125200034-e24f89efad22/go.mod h1:i+JH48j9W4tCWOzunNJfrEZcZRQgavPQXO57oh3cwGE=
tailscale.com v1.1.1-0.20211205233917-7f5171030f07 h1:3zeQUManu3redjOkkcvoa5nCPD8Q3hZV0B5RvGiNK28=
tailscale.com v1.1.1-0.20211205233917-7f5171030f07/go.mod h1:L3DiIyJXiHO4r8/6y+G2axGMdYAI/VERGMhGftHfP4U=
tailscale.com v1.1.1-0.20211206024951-b3810e3b1b93 h1:7AWRaSMyCYl8/wAruUelHPnFSqK4hSRwXUFHG9lDRbY=
tailscale.com v1.1.1-0.20211206024951-b3810e3b1b93/go.mod h1:L3DiIyJXiHO4r8/6y+G2axGMdYAI/VERGMhGftHfP4U=

Loading…
Cancel
Save