Fix routing loop prevention, MagicDNS forwarding over Tailscale.

Fixes tailscale/tailscale#2102
Updates tailscale/tailscale#1809

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/13/head
Brad Fitzpatrick 3 years ago committed by Brad Fitzpatrick
parent ac8ec020b8
commit b97cc703d8

@ -62,12 +62,6 @@ public class IPNService extends VpnService {
.setConfigureIntent(configIntent()) .setConfigureIntent(configIntent())
.allowFamily(OsConstants.AF_INET) .allowFamily(OsConstants.AF_INET)
.allowFamily(OsConstants.AF_INET6); .allowFamily(OsConstants.AF_INET6);
try {
b.addDisallowedApplication(BuildConfig.APPLICATION_ID);
} catch (PackageManager.NameNotFoundException e) {
// This error means com.tailscale.ipn isn't
// installed. That shouldn't happen, so pretend it didn't.
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
b.setMetered(false); // Inherit the metered status from the underlying networks. b.setMetered(false); // Inherit the metered status from the underlying networks.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)

@ -22,6 +22,7 @@ import (
"github.com/tailscale/tailscale-android/jni" "github.com/tailscale/tailscale-android/jni"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/netns"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/wgengine/router" "tailscale.com/wgengine/router"
@ -221,7 +222,7 @@ func (a *App) runBackend() error {
var ( var (
cfg configPair cfg configPair
state BackendState state BackendState
service jni.Object service jni.Object // of IPNService
signingIn bool signingIn bool
) )
for { for {
@ -328,6 +329,27 @@ func (a *App) runBackend() error {
if service != 0 { if service != 0 {
jni.DeleteGlobalRef(env, service) jni.DeleteGlobalRef(env, service)
} }
netns.SetAndroidProtectFunc(func(fd int) error {
return jni.Do(a.jvm, func(env *jni.Env) error {
// Call https://developer.android.com/reference/android/net/VpnService#protect(int)
// to mark fd as a socket that should bypass the VPN and use the underlying network.
cls := jni.GetObjectClass(env, s)
m := jni.GetMethodID(env, cls, "protect", "(I)Z")
ok, err := jni.CallBooleanMethod(env, s, m, jni.Value(fd))
// TODO(bradfitz): return an error back up to netns if this fails, once
// we've had some experience with this and analyzed the logs over a wide
// range of Android phones. For now we're being paranoid and conservative
// and do the JNI call to protect best effort, only logging if it fails.
// The risk of returning an error is that it breaks users on some Android
// versions even when they're not using exit nodes. I'd rather the
// relatively few number of exit node users file bug reports if Tailscale
// doesn't work and then we can look for this log print.
if err != nil || !ok {
log.Printf("[unexpected] VpnService.protect(%d) = %v, %v", fd, ok, err)
}
return nil // even on error. see big TODO above.
})
})
service = s service = s
return nil return nil
}) })
@ -352,6 +374,7 @@ func (a *App) runBackend() error {
jni.Do(a.jvm, func(env *jni.Env) error { jni.Do(a.jvm, func(env *jni.Env) error {
defer jni.DeleteGlobalRef(env, s) defer jni.DeleteGlobalRef(env, s)
if jni.IsSameObject(env, service, s) { if jni.IsSameObject(env, service, s) {
netns.SetAndroidProtectFunc(nil)
jni.DeleteGlobalRef(env, service) jni.DeleteGlobalRef(env, service)
service = 0 service = 0
} }

Loading…
Cancel
Save