@@ -9,34 +9,33 @@ import android.net.NetworkCapabilities
9
9
import android.net.NetworkRequest
10
10
import android.util.Log
11
11
import libtailscale.Libtailscale
12
- import java.net.InetAddress
13
12
import java.util.concurrent.locks.ReentrantLock
14
13
import kotlin.concurrent.withLock
15
14
16
15
object NetworkChangeCallback {
17
16
18
17
private const val TAG = " NetworkChangeCallback"
19
18
20
- private data class NetworkInfo (
21
- var caps : NetworkCapabilities ,
22
- var linkProps : LinkProperties
23
- )
19
+ private data class NetworkInfo (var caps : NetworkCapabilities , var linkProps : LinkProperties )
24
20
25
21
private val lock = ReentrantLock ()
22
+
26
23
private val activeNetworks = mutableMapOf<Network , NetworkInfo >() // keyed by Network
27
24
28
25
// monitorDnsChanges sets up a network callback to monitor changes to the
29
26
// system's network state and update the DNS configuration when interfaces
30
27
// become available or properties of those interfaces change.
31
28
fun monitorDnsChanges (connectivityManager : ConnectivityManager , dns : DnsConfig ) {
32
29
val networkConnectivityRequest =
33
- NetworkRequest .Builder ()
34
- .addCapability(NetworkCapabilities .NET_CAPABILITY_INTERNET )
35
- .addCapability(NetworkCapabilities .NET_CAPABILITY_NOT_VPN )
36
- .build()
30
+ NetworkRequest .Builder ()
31
+ .addCapability(NetworkCapabilities .NET_CAPABILITY_INTERNET )
32
+ .addCapability(NetworkCapabilities .NET_CAPABILITY_NOT_VPN )
33
+ .build()
37
34
38
35
// Use registerNetworkCallback to listen for updates from all networks, and
39
- // then update DNS configs for the best network.
36
+ // then update DNS configs for the best network when LinkProperties are changed.
37
+ // Per
38
+ // https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onAvailable(android.net.Network), this happens after all other updates.
40
39
//
41
40
// Note that we can't use registerDefaultNetworkCallback because the
42
41
// default network used by Tailscale will always show up with capability
@@ -51,23 +50,19 @@ object NetworkChangeCallback {
51
50
Log .d(TAG , " onAvailable: network ${network} " )
52
51
lock.withLock {
53
52
activeNetworks[network] = NetworkInfo (NetworkCapabilities (), LinkProperties ())
54
- maybeUpdateDNSConfigLocked(" onAvailable" , dns)
55
53
}
56
54
}
57
55
58
56
override fun onCapabilitiesChanged (network : Network , capabilities : NetworkCapabilities ) {
59
57
super .onCapabilitiesChanged(network, capabilities)
60
- lock.withLock {
61
- activeNetworks[network]?.caps = capabilities
62
- maybeUpdateDNSConfigLocked(" onCapabilitiesChanged" , dns)
63
- }
58
+ lock.withLock { activeNetworks[network]?.caps = capabilities }
64
59
}
65
60
66
61
override fun onLinkPropertiesChanged (network : Network , linkProperties : LinkProperties ) {
67
62
super .onLinkPropertiesChanged(network, linkProperties)
68
63
lock.withLock {
69
64
activeNetworks[network]?.linkProps = linkProperties
70
- maybeUpdateDNSConfigLocked (" onLinkPropertiesChanged" , dns)
65
+ maybeUpdateDNSConfig (" onLinkPropertiesChanged" , dns)
71
66
}
72
67
}
73
68
@@ -77,7 +72,7 @@ object NetworkChangeCallback {
77
72
Log .d(TAG , " onLost: network ${network} " )
78
73
lock.withLock {
79
74
activeNetworks.remove(network)
80
- maybeUpdateDNSConfigLocked (" onLost" , dns)
75
+ maybeUpdateDNSConfig (" onLost" , dns)
81
76
}
82
77
}
83
78
})
@@ -101,11 +96,12 @@ object NetworkChangeCallback {
101
96
// Filter the list of all networks to those that have the INTERNET
102
97
// capability, are not VPNs, and have a non-zero number of DNS servers
103
98
// available.
104
- val networks = activeNetworks.filter { (_, info) ->
105
- info.caps.hasCapability(NetworkCapabilities .NET_CAPABILITY_INTERNET ) &&
106
- info.caps.hasCapability(NetworkCapabilities .NET_CAPABILITY_NOT_VPN ) &&
107
- info.linkProps.dnsServers.isNotEmpty() == true
108
- }
99
+ val networks =
100
+ activeNetworks.filter { (_, info) ->
101
+ info.caps.hasCapability(NetworkCapabilities .NET_CAPABILITY_INTERNET ) &&
102
+ info.caps.hasCapability(NetworkCapabilities .NET_CAPABILITY_NOT_VPN ) &&
103
+ info.linkProps.dnsServers.isNotEmpty() == true
104
+ }
109
105
110
106
// If we have one; just return it; otherwise, prefer networks that are also
111
107
// not metered (i.e. cell modems).
@@ -122,7 +118,9 @@ object NetworkChangeCallback {
122
118
for ((network, info) in activeNetworks) {
123
119
if (info.caps.hasCapability(NetworkCapabilities .NET_CAPABILITY_INTERNET ) &&
124
120
info.caps.hasCapability(NetworkCapabilities .NET_CAPABILITY_NOT_VPN )) {
125
- Log .w(TAG , " no networks available that also have DNS servers set; falling back to first network ${network} " )
121
+ Log .w(
122
+ TAG ,
123
+ " no networks available that also have DNS servers set; falling back to first network ${network} " )
126
124
return network
127
125
}
128
126
}
@@ -136,17 +134,17 @@ object NetworkChangeCallback {
136
134
137
135
// maybeUpdateDNSConfig will maybe update our DNS configuration based on the
138
136
// current set of active Networks.
139
- //
140
- // 'lock' must be held.
141
- private fun maybeUpdateDNSConfigLocked (why : String , dns : DnsConfig ) {
137
+ private fun maybeUpdateDNSConfig (why : String , dns : DnsConfig ) {
142
138
val defaultNetwork = pickDefaultNetwork()
143
139
if (defaultNetwork == null ) {
144
140
Log .d(TAG , " ${why} : no default network available; not updating DNS config" )
145
141
return
146
142
}
147
143
val info = activeNetworks[defaultNetwork]
148
144
if (info == null ) {
149
- Log .w(TAG , " ${why} : [unexpected] no info available for default network; not updating DNS config" )
145
+ Log .w(
146
+ TAG ,
147
+ " ${why} : [unexpected] no info available for default network; not updating DNS config" )
150
148
return
151
149
}
152
150
@@ -160,7 +158,9 @@ object NetworkChangeCallback {
160
158
sb.append(searchDomains)
161
159
}
162
160
if (dns.updateDNSFromNetwork(sb.toString())) {
163
- Log .d(TAG , " ${why} : updated DNS config for network ${defaultNetwork} (${info.linkProps.interfaceName} )" )
161
+ Log .d(
162
+ TAG ,
163
+ " ${why} : updated DNS config for network ${defaultNetwork} (${info.linkProps.interfaceName} )" )
164
164
Libtailscale .onDNSConfigChanged(info.linkProps.interfaceName)
165
165
}
166
166
}
0 commit comments