Skip to content

Commit cd3ba18

Browse files
committed
Conditionally calculate allowed IP range for older devices, but keep using excludeRoute on API 33+
Signed-off-by: Pawloland <59684145+Pawloland@users.noreply.github.com>
1 parent 61f2d53 commit cd3ba18

5 files changed

Lines changed: 359 additions & 226 deletions

File tree

android/src/main/java/com/tailscale/ipn/App.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ class App : UninitializedApp(), libtailscale.AppContext, ViewModelStoreOwner {
300300

301301
override fun getOSVersion(): String = Build.VERSION.RELEASE
302302

303+
override fun getSDKInt(): Int = Build.VERSION.SDK_INT
304+
303305
override fun isChromeOS(): Boolean {
304306
return packageManager.hasSystemFeature("android.hardware.type.pc")
305307
}

libtailscale/interfaces.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ type AppContext interface {
3636
// GetOSVersion gets the Android version.
3737
GetOSVersion() (string, error)
3838

39+
// GetSDKInt returns the Android SDK_INT (android.os.Build.VERSION.SDK_INT).
40+
GetSDKInt() (int, error)
41+
3942
// GetDeviceName gets the Android device's user-set name, or hardware model name as a fallback.
4043
GetDeviceName() (string, error)
4144

libtailscale/net.go

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"syscall"
1414

1515
"github.com/tailscale/tailscale-android/libtailscale/ifaceparse"
16+
rangescalc "github.com/tailscale/tailscale-android/libtailscale/ranges_calc"
1617
"github.com/tailscale/wireguard-go/tun"
1718
"tailscale.com/net/dns"
1819
"tailscale.com/net/netmon"
@@ -117,36 +118,69 @@ func (b *backend) updateTUN(rcfg *router.Config, dcfg *dns.OSConfig) error {
117118
b.logger.Logf("updateTUN: set nameservers")
118119
}
119120

120-
// Calculate effective allowed routes (Routes minus LocalRoutes) and add them to the builder.
121-
prefixesV4, prefixesV6 := newRangesCalc(rcfg.Routes, rcfg.LocalRoutes).calculate()
121+
// Decide whether to use ExcludeRoute (API 33+) or compute included prefixes
122+
// and pass them to AddRoute (older APIs).
123+
useExclude := false
124+
if sdk, err := b.appCtx.GetSDKInt(); err == nil && sdk >= 33 {
125+
useExclude = true
126+
}
122127

123-
for _, route := range prefixesV4 {
124-
// Normalize route address; Builder.addRoute does not accept non-zero masked bits.
125-
route = route.Masked()
126-
if err := builder.AddRoute(route.Addr().String(), int32(route.Bits())); err != nil {
127-
return err
128+
if useExclude {
129+
// For API 33+, use ExcludeRoute for LocalRoutes and AddRoute for Routes.
130+
for _, route := range rcfg.Routes {
131+
// Normalize route address; Builder.addRoute does not accept non-zero masked bits.
132+
route = route.Masked()
133+
if err := builder.AddRoute(route.Addr().String(), int32(route.Bits())); err != nil {
134+
return err
135+
}
128136
}
129-
}
130-
for _, route := range prefixesV6 {
131-
// Normalize route address; Builder.addRoute does not accept non-zero masked bits.
132-
route = route.Masked()
133-
if err := builder.AddRoute(route.Addr().String(), int32(route.Bits())); err != nil {
137+
138+
for _, route := range rcfg.LocalRoutes {
139+
addr := route.Addr()
140+
if addr.IsLoopback() {
141+
continue // Skip the loopback addresses since VpnService throws an exception for those (both IPv4 and IPv6) - see https://android.googlesource.com/platform/frameworks/base/+/c741553/core/java/android/net/VpnService.java#303
142+
}
143+
route = route.Masked()
144+
if err := builder.ExcludeRoute(route.Addr().String(), int32(route.Bits())); err != nil {
145+
return err
146+
}
147+
}
148+
149+
b.logger.Logf("updateTUN: added %d routes (exclude-mode), localRoutes=%d", len(rcfg.Routes), len(rcfg.LocalRoutes))
150+
} else {
151+
// Older APIs: compute allowed-minus-disallowed prefixes and AddRoute them.
152+
prefixesV4, prefixesV6, err := rangescalc.Calculate(rcfg.Routes, rcfg.LocalRoutes)
153+
if err != nil {
154+
b.logger.Logf("updateTUN: route calculation error: %v", err)
134155
return err
135156
}
136-
}
137157

138-
b.logger.Logf(
139-
"updateTUN: added routes: v4=%d v6=%d total=%d (input routes=%d, localRoutes=%d)",
140-
len(prefixesV4),
141-
len(prefixesV6),
142-
len(prefixesV4)+len(prefixesV6),
143-
len(rcfg.Routes),
144-
len(rcfg.LocalRoutes),
145-
)
146-
b.logger.Logf("updateTUN: input routes: %v", rcfg.Routes)
147-
b.logger.Logf("updateTUN: input local routes: %v", rcfg.LocalRoutes)
148-
b.logger.Logf("updateTUN: effective routes v4: %v", prefixesV4)
149-
b.logger.Logf("updateTUN: effective routes v6: %v", prefixesV6)
158+
for _, route := range prefixesV4 {
159+
route = route.Masked()
160+
if err := builder.AddRoute(route.Addr().String(), int32(route.Bits())); err != nil {
161+
return err
162+
}
163+
}
164+
for _, route := range prefixesV6 {
165+
route = route.Masked()
166+
if err := builder.AddRoute(route.Addr().String(), int32(route.Bits())); err != nil {
167+
return err
168+
}
169+
}
170+
171+
b.logger.Logf(
172+
"updateTUN: added routes: v4=%d v6=%d total=%d (input routes=%d, localRoutes=%d)",
173+
len(prefixesV4),
174+
len(prefixesV6),
175+
len(prefixesV4)+len(prefixesV6),
176+
len(rcfg.Routes),
177+
len(rcfg.LocalRoutes),
178+
)
179+
b.logger.Logf("updateTUN: input routes: %v", rcfg.Routes)
180+
b.logger.Logf("updateTUN: input local routes: %v", rcfg.LocalRoutes)
181+
b.logger.Logf("updateTUN: effective routes v4: %v", prefixesV4)
182+
b.logger.Logf("updateTUN: effective routes v6: %v", prefixesV6)
183+
}
150184

151185
for _, addr := range rcfg.LocalAddrs {
152186
if err := builder.AddAddress(addr.Addr().String(), int32(addr.Bits())); err != nil {

0 commit comments

Comments
 (0)