Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ android {
compileSdkVersion 30
defaultConfig {
minSdkVersion 22
targetSdkVersion 29
targetSdkVersion 30
versionCode 69
versionName "1.15.210-tbabd163aa-g9b52c6b357b"
}
Expand Down
60 changes: 60 additions & 0 deletions android/src/main/java/com/tailscale/ipn/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,18 @@
import java.io.File;
import java.io.FileOutputStream;

import java.lang.StringBuilder;

import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;

import java.security.GeneralSecurityException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

Expand Down Expand Up @@ -312,4 +322,54 @@ private void createNotificationChannel(String id, String name, int importance) {
private static native void onConnectivityChanged(boolean connected);
static native void onShareIntent(int nfiles, int[] types, String[] mimes, String[] items, String[] names, long[] sizes);
static native void onWriteStorageGranted();

// Returns details of the interfaces in the system, encoded as a single string for ease
// of JNI transfer over to the Go environment.
//
// Example:
// rmnet_data0 10 2000 true false false false false | fe80::4059:dc16:7ed3:9c6e%rmnet_data0/64
// dummy0 3 1500 true false false false false | fe80::1450:5cff:fe13:f891%dummy0/64
// wlan0 30 1500 true true false false true | fe80::2f60:2c82:4163:8389%wlan0/64 10.1.10.131/24
// r_rmnet_data0 21 1500 true false false false false | fe80::9318:6093:d1ad:ba7f%r_rmnet_data0/64
// rmnet_data2 12 1500 true false false false false | fe80::3c8c:44dc:46a9:9907%rmnet_data2/64
// r_rmnet_data1 22 1500 true false false false false | fe80::b6cd:5cb0:8ae6:fe92%r_rmnet_data1/64
// rmnet_data1 11 1500 true false false false false | fe80::51f2:ee00:edce:d68b%rmnet_data1/64
// lo 1 65536 true false true false false | ::1/128 127.0.0.1/8
// v4-rmnet_data2 68 1472 true true false true true | 192.0.0.4/32
//
// Where the fields are:
// name ifindex mtu isUp hasBroadcast isLoopback isPointToPoint hasMulticast | ip1/N ip2/N ip3/N;
String getInterfacesAsString() {
List<NetworkInterface> interfaces;
try {
interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
} catch (Exception e) {
return "";
}

StringBuilder sb = new StringBuilder("");
for (NetworkInterface nif : interfaces) {
try {
// Android doesn't have a supportsBroadcast() but the Go net.Interface wants
// one, so we say the interface has broadcast if it has multicast.
sb.append(String.format("%s %d %d %b %b %b %b %b |", nif.getName(),
nif.getIndex(), nif.getMTU(), nif.isUp(), nif.supportsMulticast(),
nif.isLoopback(), nif.isPointToPoint(), nif.supportsMulticast()));

for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
// InterfaceAddress == hostname + "/" + IP
String[] parts = ia.toString().split("/", 0);
if (parts.length > 1) {
sb.append(String.format("%s/%d ", parts[1], ia.getNetworkPrefixLength()));
}
}
} catch (Exception e) {
// TODO(dgentry) should log the exception not silently suppress it.
continue;
}
sb.append("\n");
}

return sb.toString();
}
}
83 changes: 83 additions & 0 deletions cmd/tailscale/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io"
"log"
"mime"
"net"
"net/http"
"net/url"
"os"
Expand All @@ -33,6 +34,7 @@ import (
"tailscale.com/ipn"
"tailscale.com/ipn/ipnlocal"
"tailscale.com/net/dns"
"tailscale.com/net/interfaces"
"tailscale.com/net/netns"
"tailscale.com/paths"
"tailscale.com/tailcfg"
Expand Down Expand Up @@ -218,6 +220,7 @@ func main() {
fatalErr(err)
}
a.store = newStateStore(a.jvm, a.appCtx)
interfaces.RegisterInterfaceGetter(a.getInterfaces)
go func() {
if err := a.runBackend(); err != nil {
fatalErr(err)
Expand Down Expand Up @@ -1251,6 +1254,86 @@ func (a *App) contextForView(view jni.Object) jni.Object {
return ctx
}

// Report interfaces in the device in net.Interface format.
func (a *App) getInterfaces() ([]interfaces.Interface, error) {
var ifaceString string
err := jni.Do(a.jvm, func(env *jni.Env) error {
cls := jni.GetObjectClass(env, a.appCtx)
m := jni.GetMethodID(env, cls, "getInterfacesAsString", "()Ljava/lang/String;")
n, err := jni.CallObjectMethod(env, a.appCtx, m)
ifaceString = jni.GoString(env, jni.String(n))
return err

})
var ifaces []interfaces.Interface
if err != nil {
return ifaces, err
}

for _, iface := range strings.Split(ifaceString, "\n") {
// Example of the strings we're processing:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you go with newline-separated lines:

if strings.TrimSpace(line) == "" {
    continue
}

So you don't need to worry about the final empty element and still use Split here.

(strings.Split is generally not my friend, since it allocates, but this is no worse than the Java side's allocs, so it's fine for now.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went with TrimSpace().

Java now uses a StringBuilder, we can revisit the Go code later.

// wlan0 30 1500 true true false false true | fe80::2f60:2c82:4163:8389%wlan0/64 10.1.10.131/24
// r_rmnet_data0 21 1500 true false false false false | fe80::9318:6093:d1ad:ba7f%r_rmnet_data0/64
// mnet_data2 12 1500 true false false false false | fe80::3c8c:44dc:46a9:9907%rmnet_data2/64

if strings.TrimSpace(iface) == "" {
continue
}

fields := strings.Split(iface, "|")
if len(fields) != 2 {
log.Printf("getInterfaces: unable to split %q", iface)
continue
}

var name string
var index, mtu int
var up, broadcast, loopback, pointToPoint, multicast bool
_, err := fmt.Sscanf(fields[0], "%s %d %d %t %t %t %t %t",
&name, &index, &mtu, &up, &broadcast, &loopback, &pointToPoint, &multicast)
if err != nil {
log.Printf("getInterfaces: unable to parse %q: %v", iface, err)
continue
}

newIf := interfaces.Interface{
Interface: &net.Interface{
Name: name,
Index: index,
MTU: mtu,
},
AltAddrs: []net.Addr{}, // non-nil to avoid Go using netlink
}
if up {
newIf.Flags |= net.FlagUp
}
if broadcast {
newIf.Flags |= net.FlagBroadcast
}
if loopback {
newIf.Flags |= net.FlagLoopback
}
if pointToPoint {
newIf.Flags |= net.FlagPointToPoint
}
if multicast {
newIf.Flags |= net.FlagMulticast
}

addrs := strings.Trim(fields[1], " \n")
for _, addr := range strings.Split(addrs, " ") {
ip, err := netaddr.ParseIPPrefix(addr)
if err == nil {
newIf.AltAddrs = append(newIf.AltAddrs, ip.IPNet())
}
}

ifaces = append(ifaces, newIf)
}

return ifaces, nil
}

func fatalErr(err error) {
// TODO: expose in UI.
log.Printf("fatal error: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c
inet.af/netaddr v0.0.0-20210721214506-ce7a8ad02cc1
tailscale.com v1.1.1-0.20211005220235-67e5fabdbdba
tailscale.com v1.1.1-0.20211008004653-1f506d23514a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.6.0 now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used a release-branch for 1.14 in tailscale-android and it worked well.
Will update to 1.16.0 when release-branch/1.16 is created.

)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1013,3 +1013,5 @@ software.sslmate.com/src/go-pkcs12 v0.0.0-20180114231543-2291e8f0f237/go.mod h1:
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
tailscale.com v1.1.1-0.20211005220235-67e5fabdbdba h1:szGUzQIThyKAKJDxXuL5lgUmEU4hzWUW+noas/MYD8M=
tailscale.com v1.1.1-0.20211005220235-67e5fabdbdba/go.mod h1:2ordBMiDa1Gx6r8ci5EtSS3Wl0RanS46+l8T2vwqUtI=
tailscale.com v1.1.1-0.20211008004653-1f506d23514a h1:htyjSQ+1+YeW+aapSMq8hlCPk+dJlkbWvIuWIVgbWP4=
tailscale.com v1.1.1-0.20211008004653-1f506d23514a/go.mod h1:+dISSbd6iiY6F6/dRGQRgshjYXMkhMzVvRd9En8RLfQ=