From 697205932147378a050538df8a30fd2223b8c141 Mon Sep 17 00:00:00 2001 From: Vladimir Stoilov Date: Mon, 23 Jan 2023 16:33:02 +0100 Subject: [PATCH] Android support for getting network addresses and interfaces (#1056) * Replace unsupported network functions for android * Refactor default/android net addresses processing * Add default connection values, Refactor netenv * Fix compilation error * Combine network change default/android functions --- netenv/{addresses.go => adresses.go} | 4 +- netenv/network-change.go | 3 +- netenv/os_android.go | 23 ++++++++++ netenv/os_default.go | 15 +++++++ network/connection_android.go | 65 ++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 4 deletions(-) rename netenv/{addresses.go => adresses.go} (98%) create mode 100644 netenv/os_android.go create mode 100644 netenv/os_default.go create mode 100644 network/connection_android.go diff --git a/netenv/addresses.go b/netenv/adresses.go similarity index 98% rename from netenv/addresses.go rename to netenv/adresses.go index 67c4c999..b050ad33 100644 --- a/netenv/addresses.go +++ b/netenv/adresses.go @@ -12,7 +12,7 @@ import ( // GetAssignedAddresses returns the assigned IPv4 and IPv6 addresses of the host. func GetAssignedAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) { - addrs, err := net.InterfaceAddrs() + addrs, err := osGetInterfaceAddrs() if err != nil { return nil, nil, err } @@ -74,7 +74,7 @@ func refreshMyNetworks() error { myNetworksDontRefreshUntil = time.Now().Add(1 * time.Second) // Refresh assigned networks. - interfaceNetworks, err := net.InterfaceAddrs() + interfaceNetworks, err := osGetInterfaceAddrs() if err != nil { // In some cases the system blocks on this call, which piles up to // literally over thousand goroutines wanting to try this again. diff --git a/netenv/network-change.go b/netenv/network-change.go index 6a591cc8..0d83d704 100644 --- a/netenv/network-change.go +++ b/netenv/network-change.go @@ -5,7 +5,6 @@ import ( "context" "crypto/sha1" "io" - "net" "time" "github.com/safing/portbase/log" @@ -61,7 +60,7 @@ serviceLoop: // check network for changes // create hashsum of current network config hasher := sha1.New() //nolint:gosec // not used for security - interfaces, err := net.Interfaces() + interfaces, err := osGetNetworkInterfaces() if err != nil { log.Warningf("netenv: failed to get interfaces: %s", err) continue diff --git a/netenv/os_android.go b/netenv/os_android.go new file mode 100644 index 00000000..a1ec8145 --- /dev/null +++ b/netenv/os_android.go @@ -0,0 +1,23 @@ +package netenv + +import ( + "github.com/safing/portmaster-android/go/app_interface" + "net" +) + +func osGetInterfaceAddrs() ([]net.Addr, error) { + list, err := app_interface.GetNetworkAddresses() + if err != nil { + return nil, err + } + var netList []net.Addr + for _, addr := range list { + netList = append(netList, addr.ToIPNet()) + } + + return netList, nil +} + +func osGetNetworkInterfaces() ([]app_interface.NetworkInterface, error) { + return app_interface.GetNetworkInterfaces() +} diff --git a/netenv/os_default.go b/netenv/os_default.go new file mode 100644 index 00000000..351d5c4c --- /dev/null +++ b/netenv/os_default.go @@ -0,0 +1,15 @@ +//go:build !android + +package netenv + +import ( + "net" +) + +func osGetInterfaceAddrs() ([]net.Addr, error) { + return net.InterfaceAddrs() +} + +func osGetNetworkInterfaces() ([]net.Interface, error) { + return net.Interfaces() +} diff --git a/network/connection_android.go b/network/connection_android.go new file mode 100644 index 00000000..d7479e1f --- /dev/null +++ b/network/connection_android.go @@ -0,0 +1,65 @@ +package network + +import ( + "context" + "fmt" + "net" + "time" + + "github.com/safing/portmaster/intel" + "github.com/safing/portmaster/network/netutils" + "github.com/safing/portmaster/network/packet" + "github.com/safing/portmaster/process" + "github.com/safing/spn/navigator" +) + +// NewDefaultConnection creates a new connection with default values except local and remote IPs and protocols. +func NewDefaultConnection(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, ipVersion packet.IPVersion, protocol packet.IPProtocol) *Connection { + connInfo := &Connection{ + ID: fmt.Sprintf("%s-%s-%d-%s-%d", protocol.String(), localIP, localPort, remoteIP, remotePort), + Type: IPConnection, + External: false, + IPVersion: ipVersion, + Inbound: false, + IPProtocol: protocol, + LocalIP: localIP, + LocalIPScope: netutils.Global, + LocalPort: localPort, + Entity: &intel.Entity{ + Protocol: uint8(protocol), + IP: remoteIP, + Port: remotePort, + }, + Resolver: nil, + Started: time.Now().Unix(), + VerdictPermanent: false, + Tunneled: true, + Encrypted: false, + Internal: false, + addedToMetrics: true, // Metrics are not needed for now. This will mark the Connection to be ignored. + process: process.GetUnidentifiedProcess(context.Background()), + } + + // TODO: Quick fix for the SPN. + // Use inspection framework for proper encryption detection. + switch connInfo.Entity.DstPort() { + case + 22, // SSH + 443, // HTTPS + 465, // SMTP-SSL + 853, // DoT + 993, // IMAP-SSL + 995: // POP3-SSL + connInfo.Encrypted = true + } + + var layeredProfile = connInfo.process.Profile() + connInfo.TunnelOpts = &navigator.Options{ + HubPolicies: layeredProfile.StackedExitHubPolicies(), + CheckHubExitPolicyWith: connInfo.Entity, + RequireTrustedDestinationHubs: !connInfo.Encrypted, + RoutingProfile: layeredProfile.SPNRoutingAlgorithm(), + } + + return connInfo +}