mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-08 07:51:28 +02:00
Android 16+ local network protection derives the blocked prefixes from the interface address prefix. A /16 address turns the whole overlay into a local network, so apps without ACCESS_LOCAL_NETWORK cannot reach any peer. Pass the address as /32 and /128 and add the overlay networks to the route list that the Android side turns into VPN routes, on both the initial create and the renew path.
194 lines
4.7 KiB
Go
194 lines
4.7 KiB
Go
//go:build android
|
|
|
|
package device
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/unix"
|
|
"golang.zx2c4.com/wireguard/device"
|
|
"golang.zx2c4.com/wireguard/tun"
|
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
|
|
|
"github.com/netbirdio/netbird/client/iface/bind"
|
|
"github.com/netbirdio/netbird/client/iface/configurer"
|
|
"github.com/netbirdio/netbird/client/iface/udpmux"
|
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
|
)
|
|
|
|
// WGTunDevice ignore the WGTunDevice interface on Android because the creation of the tun device is different on this platform
|
|
type WGTunDevice struct {
|
|
address wgaddr.Address
|
|
port int
|
|
key string
|
|
mtu uint16
|
|
iceBind *bind.ICEBind
|
|
// todo: review if we can eliminate the TunAdapter
|
|
tunAdapter TunAdapter
|
|
disableDNS bool
|
|
|
|
name string
|
|
device *device.Device
|
|
filteredDevice *FilteredDevice
|
|
udpMux *udpmux.UniversalUDPMuxDefault
|
|
configurer WGConfigurer
|
|
renewableTun *RenewableTUN
|
|
}
|
|
|
|
func NewTunDevice(address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, tunAdapter TunAdapter, disableDNS bool) *WGTunDevice {
|
|
return &WGTunDevice{
|
|
address: address,
|
|
port: port,
|
|
key: key,
|
|
mtu: mtu,
|
|
iceBind: iceBind,
|
|
tunAdapter: tunAdapter,
|
|
disableDNS: disableDNS,
|
|
renewableTun: NewRenewableTUN(),
|
|
}
|
|
}
|
|
|
|
func (t *WGTunDevice) Create(routes []string, dns string, searchDomains []string) (WGConfigurer, error) {
|
|
log.Info("create tun interface")
|
|
|
|
routesString := routesToString(routes)
|
|
searchDomainsToString := searchDomainsToString(searchDomains)
|
|
|
|
// Skip DNS configuration when DisableDNS is enabled
|
|
if t.disableDNS {
|
|
log.Info("DNS is disabled, skipping DNS and search domain configuration")
|
|
dns = ""
|
|
searchDomainsToString = ""
|
|
}
|
|
|
|
ipv6Host := ""
|
|
if t.address.HasIPv6() {
|
|
ipv6Host = t.address.IPv6HostPrefix().String()
|
|
}
|
|
|
|
fd, err := t.tunAdapter.ConfigureInterface(t.address.HostPrefix().String(), ipv6Host, int(t.mtu), dns, searchDomainsToString, routesString)
|
|
if err != nil {
|
|
log.Errorf("failed to create Android interface: %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
unmonitoredTUN, name, err := tun.CreateUnmonitoredTUNFromFD(fd)
|
|
if err != nil {
|
|
_ = unix.Close(fd)
|
|
log.Errorf("failed to create Android interface: %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
t.renewableTun.AddDevice(unmonitoredTUN)
|
|
|
|
t.name = name
|
|
t.filteredDevice = newDeviceFilter(t.renewableTun)
|
|
|
|
log.Debugf("attaching to interface %v", name)
|
|
t.device = device.NewDevice(t.filteredDevice, t.iceBind, device.NewLogger(wgLogLevel(), "[netbird] "))
|
|
// without this property mobile devices can discover remote endpoints if the configured one was wrong.
|
|
// this helps with support for the older NetBird clients that had a hardcoded direct mode
|
|
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
|
|
|
|
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
|
err = t.configurer.ConfigureInterface(t.key, t.port)
|
|
if err != nil {
|
|
t.device.Close()
|
|
t.configurer.Close()
|
|
return nil, err
|
|
}
|
|
return t.configurer, nil
|
|
}
|
|
func (t *WGTunDevice) Up() (*udpmux.UniversalUDPMuxDefault, error) {
|
|
err := t.device.Up()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
udpMux, err := t.iceBind.GetICEMux()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.udpMux = udpMux
|
|
log.Debugf("device is ready to use: %s", t.name)
|
|
return udpMux, nil
|
|
}
|
|
|
|
func (t *WGTunDevice) RenewTun(fd int) error {
|
|
if t.device == nil {
|
|
return fmt.Errorf("device not initialized")
|
|
}
|
|
|
|
unmonitoredTUN, _, err := tun.CreateUnmonitoredTUNFromFD(fd)
|
|
if err != nil {
|
|
_ = unix.Close(fd)
|
|
log.Errorf("failed to renew Android interface: %s", err)
|
|
return err
|
|
}
|
|
|
|
t.renewableTun.AddDevice(unmonitoredTUN)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *WGTunDevice) UpdateAddr(addr wgaddr.Address) error {
|
|
// todo implement
|
|
return nil
|
|
}
|
|
|
|
func (t *WGTunDevice) Close() error {
|
|
if t.configurer != nil {
|
|
t.configurer.Close()
|
|
}
|
|
|
|
if t.device != nil {
|
|
t.device.Close()
|
|
t.device = nil
|
|
}
|
|
|
|
if t.udpMux != nil {
|
|
return t.udpMux.Close()
|
|
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *WGTunDevice) Device() *device.Device {
|
|
return t.device
|
|
}
|
|
|
|
func (t *WGTunDevice) DeviceName() string {
|
|
return t.name
|
|
}
|
|
|
|
func (t *WGTunDevice) WgAddress() wgaddr.Address {
|
|
return t.address
|
|
}
|
|
|
|
func (t *WGTunDevice) MTU() uint16 {
|
|
return t.mtu
|
|
}
|
|
|
|
func (t *WGTunDevice) FilteredDevice() *FilteredDevice {
|
|
return t.filteredDevice
|
|
}
|
|
|
|
func (t *WGTunDevice) GetNet() *netstack.Net {
|
|
return nil
|
|
}
|
|
|
|
// GetICEBind returns the ICEBind instance
|
|
func (t *WGTunDevice) GetICEBind() EndpointManager {
|
|
return t.iceBind
|
|
}
|
|
|
|
func routesToString(routes []string) string {
|
|
return strings.Join(routes, ";")
|
|
}
|
|
|
|
func searchDomainsToString(searchDomains []string) string {
|
|
return strings.Join(searchDomains, ";")
|
|
}
|