Rename tuntap package to tun

We haven't had TAP support in ages.
This commit is contained in:
Neil Alexander 2022-09-24 14:41:47 +01:00
parent 217ac39e77
commit 01c44a087b
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
18 changed files with 31 additions and 36 deletions

45
src/tun/admin.go Normal file
View file

@ -0,0 +1,45 @@
package tun
import (
"encoding/json"
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
)
type GetTUNRequest struct{}
type GetTUNResponse struct {
Enabled bool `json:"enabled"`
Name string `json:"name,omitempty"`
MTU uint64 `json:"mtu,omitempty"`
}
type TUNEntry struct {
MTU uint64 `json:"mtu"`
}
func (t *TunAdapter) getTUNHandler(req *GetTUNRequest, res *GetTUNResponse) error {
res.Enabled = t.isEnabled
if !t.isEnabled {
return nil
}
res.Name = t.Name()
res.MTU = t.MTU()
return nil
}
func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) {
_ = a.AddHandler(
"getTun", "Show information about the node's TUN interface", []string{},
func(in json.RawMessage) (interface{}, error) {
req := &GetTUNRequest{}
res := &GetTUNResponse{}
if err := json.Unmarshal(in, &req); err != nil {
return nil, err
}
if err := t.getTUNHandler(req, res); err != nil {
return nil, err
}
return res, nil
},
)
}

47
src/tun/iface.go Normal file
View file

@ -0,0 +1,47 @@
package tun
const TUN_OFFSET_BYTES = 4
func (tun *TunAdapter) read() {
var buf [TUN_OFFSET_BYTES + 65535]byte
for {
n, err := tun.iface.Read(buf[:], TUN_OFFSET_BYTES)
if n <= TUN_OFFSET_BYTES || err != nil {
tun.log.Errorln("Error reading TUN:", err)
ferr := tun.iface.Flush()
if ferr != nil {
tun.log.Errorln("Unable to flush packets:", ferr)
}
return
}
begin := TUN_OFFSET_BYTES
end := begin + n
bs := buf[begin:end]
if _, err := tun.rwc.Write(bs); err != nil {
tun.log.Debugln("Unable to send packet:", err)
}
}
}
func (tun *TunAdapter) write() {
var buf [TUN_OFFSET_BYTES + 65535]byte
for {
bs := buf[TUN_OFFSET_BYTES:]
n, err := tun.rwc.Read(bs)
if err != nil {
tun.log.Errorln("Exiting tun writer due to core read error:", err)
return
}
if !tun.isEnabled {
continue // Nothing to do, the tun isn't enabled
}
bs = buf[:TUN_OFFSET_BYTES+n]
if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil {
tun.Act(nil, func() {
if !tun.isOpen {
tun.log.Errorln("TUN iface write error:", err)
}
})
}
}
}

20
src/tun/options.go Normal file
View file

@ -0,0 +1,20 @@
package tun
func (m *TunAdapter) _applyOption(opt SetupOption) {
switch v := opt.(type) {
case InterfaceName:
m.config.name = v
case InterfaceMTU:
m.config.mtu = v
}
}
type SetupOption interface {
isSetupOption()
}
type InterfaceName string
type InterfaceMTU uint64
func (a InterfaceName) isSetupOption() {}
func (a InterfaceMTU) isSetupOption() {}

162
src/tun/tun.go Normal file
View file

@ -0,0 +1,162 @@
package tun
// This manages the tun driver to send/recv packets to/from applications
// TODO: Connection timeouts (call Conn.Close() when we want to time out)
// TODO: Don't block in reader on writes that are pending searches
import (
"errors"
"fmt"
"net"
"github.com/Arceliar/phony"
"golang.zx2c4.com/wireguard/tun"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
"github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
)
type MTU uint16
// TunAdapter represents a running TUN interface and extends the
// yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you
// should pass this object to the yggdrasil.SetRouterAdapter() function before
// calling yggdrasil.Start().
type TunAdapter struct {
rwc *ipv6rwc.ReadWriteCloser
log util.Logger
addr address.Address
subnet address.Subnet
mtu uint64
iface tun.Device
phony.Inbox // Currently only used for _handlePacket from the reader, TODO: all the stuff that currently needs a mutex below
//mutex sync.RWMutex // Protects the below
isOpen bool
isEnabled bool // Used by the writer to drop sessionTraffic if not enabled
config struct {
name InterfaceName
mtu InterfaceMTU
}
}
// Gets the maximum supported MTU for the platform based on the defaults in
// defaults.GetDefaults().
func getSupportedMTU(mtu uint64) uint64 {
if mtu < 1280 {
return 1280
}
if mtu > MaximumMTU() {
return MaximumMTU()
}
return mtu
}
// Name returns the name of the adapter, e.g. "tun0". On Windows, this may
// return a canonical adapter name instead.
func (tun *TunAdapter) Name() string {
if name, err := tun.iface.Name(); err == nil {
return name
}
return ""
}
// MTU gets the adapter's MTU. This can range between 1280 and 65535, although
// the maximum value is determined by your platform. The returned value will
// never exceed that of MaximumMTU().
func (tun *TunAdapter) MTU() uint64 {
return getSupportedMTU(tun.mtu)
}
// DefaultName gets the default TUN interface name for your platform.
func DefaultName() string {
return defaults.GetDefaults().DefaultIfName
}
// DefaultMTU gets the default TUN interface MTU for your platform. This can
// be as high as MaximumMTU(), depending on platform, but is never lower than 1280.
func DefaultMTU() uint64 {
return defaults.GetDefaults().DefaultIfMTU
}
// MaximumMTU returns the maximum supported TUN interface MTU for your
// platform. This can be as high as 65535, depending on platform, but is never
// lower than 1280.
func MaximumMTU() uint64 {
return defaults.GetDefaults().MaximumIfMTU
}
// Init initialises the TUN module. You must have acquired a Listener from
// the Yggdrasil core before this point and it must not be in use elsewhere.
func New(rwc *ipv6rwc.ReadWriteCloser, log util.Logger, opts ...SetupOption) (*TunAdapter, error) {
tun := &TunAdapter{
rwc: rwc,
log: log,
}
for _, opt := range opts {
tun._applyOption(opt)
}
return tun, tun._start()
}
func (tun *TunAdapter) _start() error {
if tun.isOpen {
return errors.New("TUN module is already started")
}
tun.addr = tun.rwc.Address()
tun.subnet = tun.rwc.Subnet()
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
if tun.config.name == "none" || tun.config.name == "dummy" {
tun.log.Debugln("Not starting TUN as ifname is none or dummy")
tun.isEnabled = false
go tun.write()
return nil
}
mtu := uint64(tun.config.mtu)
if tun.rwc.MaxMTU() < mtu {
mtu = tun.rwc.MaxMTU()
}
if err := tun.setup(string(tun.config.name), addr, mtu); err != nil {
return err
}
if tun.MTU() != mtu {
tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", tun.config.mtu, tun.MTU(), MaximumMTU())
}
tun.rwc.SetMTU(tun.MTU())
tun.isOpen = true
tun.isEnabled = true
go tun.read()
go tun.write()
return nil
}
// IsStarted returns true if the module has been started.
func (tun *TunAdapter) IsStarted() bool {
var isOpen bool
phony.Block(tun, func() {
isOpen = tun.isOpen
})
return isOpen
}
// Start the setup process for the TUN adapter. If successful, starts the
// read/write goroutines to handle packets on that interface.
func (tun *TunAdapter) Stop() error {
var err error
phony.Block(tun, func() {
err = tun._stop()
})
return err
}
func (tun *TunAdapter) _stop() error {
tun.isOpen = false
// by TUN, e.g. readers/writers, sessions
if tun.iface != nil {
// Just in case we failed to start up the iface for some reason, this can apparently happen on Windows
tun.iface.Close()
}
return nil
}

156
src/tun/tun_bsd.go Normal file
View file

@ -0,0 +1,156 @@
//go:build openbsd || freebsd
// +build openbsd freebsd
package tun
import (
"encoding/binary"
"os/exec"
"strconv"
"strings"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
wgtun "golang.zx2c4.com/wireguard/tun"
)
const SIOCSIFADDR_IN6 = (0x80000000) | ((288 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 12
type in6_addrlifetime struct {
ia6t_expire float64
ia6t_preferred float64
ia6t_vltime uint32
ia6t_pltime uint32
}
type sockaddr_in6 struct {
sin6_len uint8
sin6_family uint8
sin6_port uint8
sin6_flowinfo uint32
sin6_addr [8]uint16
sin6_scope_id uint32
}
/*
from <netinet6/in6_var.h>
struct in6_ifreq {
277 char ifr_name[IFNAMSIZ];
278 union {
279 struct sockaddr_in6 ifru_addr;
280 struct sockaddr_in6 ifru_dstaddr;
281 int ifru_flags;
282 int ifru_flags6;
283 int ifru_metric;
284 caddr_t ifru_data;
285 struct in6_addrlifetime ifru_lifetime;
286 struct in6_ifstat ifru_stat;
287 struct icmp6_ifstat ifru_icmp6stat;
288 u_int32_t ifru_scope_id[16];
289 } ifr_ifru;
290 };
*/
type in6_ifreq_mtu struct {
ifr_name [syscall.IFNAMSIZ]byte
ifru_mtu int
}
type in6_ifreq_addr struct {
ifr_name [syscall.IFNAMSIZ]byte
ifru_addr sockaddr_in6
}
type in6_ifreq_flags struct {
ifr_name [syscall.IFNAMSIZ]byte
flags int
}
type in6_ifreq_lifetime struct {
ifr_name [syscall.IFNAMSIZ]byte
ifru_addrlifetime in6_addrlifetime
}
// Configures the TUN adapter with the correct IPv6 address and MTU.
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
iface, err := wgtun.CreateTUN(ifname, int(mtu))
if err != nil {
panic(err)
}
tun.iface = iface
if mtu, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(mtu))
} else {
tun.mtu = 0
}
return tun.setupAddress(addr)
}
func (tun *TunAdapter) setupAddress(addr string) error {
var sfd int
var err error
// Create system socket
if sfd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0); err != nil {
tun.log.Printf("Create AF_INET socket failed: %v.", err)
return err
}
// Friendly output
tun.log.Infof("Interface name: %s", tun.Name())
tun.log.Infof("Interface IPv6: %s", addr)
tun.log.Infof("Interface MTU: %d", tun.mtu)
// Create the MTU request
var ir in6_ifreq_mtu
copy(ir.ifr_name[:], tun.Name())
ir.ifru_mtu = int(tun.mtu)
// Set the MTU
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
err = errno
tun.log.Errorf("Error in SIOCSIFMTU: %v", errno)
// Fall back to ifconfig to set the MTU
cmd := exec.Command("ifconfig", tun.Name(), "mtu", string(tun.mtu))
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
output, err := cmd.CombinedOutput()
if err != nil {
tun.log.Errorf("SIOCSIFMTU fallback failed: %v.", err)
tun.log.Traceln(string(output))
}
}
// Create the address request
// FIXME: I don't work!
var ar in6_ifreq_addr
copy(ar.ifr_name[:], tun.Name())
ar.ifru_addr.sin6_len = uint8(unsafe.Sizeof(ar.ifru_addr))
ar.ifru_addr.sin6_family = unix.AF_INET6
parts := strings.Split(strings.Split(addr, "/")[0], ":")
for i := 0; i < 8; i++ {
addr, _ := strconv.ParseUint(parts[i], 16, 16)
b := make([]byte, 16)
binary.LittleEndian.PutUint16(b, uint16(addr))
ar.ifru_addr.sin6_addr[i] = uint16(binary.BigEndian.Uint16(b))
}
// Set the interface address
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(sfd), uintptr(SIOCSIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
err = errno
tun.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno)
// Fall back to ifconfig to set the address
cmd := exec.Command("ifconfig", tun.Name(), "inet6", addr)
tun.log.Warnf("Using ifconfig as fallback: %v", strings.Join(cmd.Args, " "))
output, err := cmd.CombinedOutput()
if err != nil {
tun.log.Errorf("SIOCSIFADDR_IN6 fallback failed: %v.", err)
tun.log.Traceln(string(output))
}
}
return nil
}

133
src/tun/tun_darwin.go Normal file
View file

@ -0,0 +1,133 @@
//go:build !mobile
// +build !mobile
package tun
// The darwin platform specific tun parts
import (
"encoding/binary"
"strconv"
"strings"
"unsafe"
"golang.org/x/sys/unix"
wgtun "golang.zx2c4.com/wireguard/tun"
)
// Configures the "utun" adapter with the correct IPv6 address and MTU.
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if ifname == "auto" {
ifname = "utun"
}
iface, err := wgtun.CreateTUN(ifname, int(mtu))
if err != nil {
panic(err)
}
tun.iface = iface
if m, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(m))
} else {
tun.mtu = 0
}
return tun.setupAddress(addr)
}
const (
darwin_SIOCAIFADDR_IN6 = 2155899162 // netinet6/in6_var.h
darwin_IN6_IFF_NODAD = 0x0020 // netinet6/in6_var.h
darwin_IN6_IFF_SECURED = 0x0400 // netinet6/in6_var.h
darwin_ND6_INFINITE_LIFETIME = 0xFFFFFFFF // netinet6/nd6.h
)
// nolint:structcheck
type in6_addrlifetime struct {
ia6t_expire float64 // nolint:unused
ia6t_preferred float64 // nolint:unused
ia6t_vltime uint32
ia6t_pltime uint32
}
// nolint:structcheck
type sockaddr_in6 struct {
sin6_len uint8
sin6_family uint8
sin6_port uint8 // nolint:unused
sin6_flowinfo uint32 // nolint:unused
sin6_addr [8]uint16
sin6_scope_id uint32 // nolint:unused
}
// nolint:structcheck
type in6_aliasreq struct {
ifra_name [16]byte
ifra_addr sockaddr_in6
ifra_dstaddr sockaddr_in6 // nolint:unused
ifra_prefixmask sockaddr_in6
ifra_flags uint32
ifra_lifetime in6_addrlifetime
}
type ifreq struct {
ifr_name [16]byte
ifru_mtu uint32
}
// Sets the IPv6 address of the utun adapter. On Darwin/macOS this is done using
// a system socket and making direct syscalls to the kernel.
func (tun *TunAdapter) setupAddress(addr string) error {
var fd int
var err error
if fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil {
tun.log.Printf("Create AF_SYSTEM socket failed: %v.", err)
return err
}
var ar in6_aliasreq
copy(ar.ifra_name[:], tun.Name())
ar.ifra_prefixmask.sin6_len = uint8(unsafe.Sizeof(ar.ifra_prefixmask))
b := make([]byte, 16)
binary.LittleEndian.PutUint16(b, uint16(0xFE00))
ar.ifra_prefixmask.sin6_addr[0] = binary.BigEndian.Uint16(b)
ar.ifra_addr.sin6_len = uint8(unsafe.Sizeof(ar.ifra_addr))
ar.ifra_addr.sin6_family = unix.AF_INET6
parts := strings.Split(strings.Split(addr, "/")[0], ":")
for i := 0; i < 8; i++ {
addr, _ := strconv.ParseUint(parts[i], 16, 16)
b := make([]byte, 16)
binary.LittleEndian.PutUint16(b, uint16(addr))
ar.ifra_addr.sin6_addr[i] = binary.BigEndian.Uint16(b)
}
ar.ifra_flags |= darwin_IN6_IFF_NODAD
ar.ifra_flags |= darwin_IN6_IFF_SECURED
ar.ifra_lifetime.ia6t_vltime = darwin_ND6_INFINITE_LIFETIME
ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME
var ir ifreq
copy(ir.ifr_name[:], tun.Name())
ir.ifru_mtu = uint32(tun.mtu)
tun.log.Infof("Interface name: %s", ar.ifra_name)
tun.log.Infof("Interface IPv6: %s", addr)
tun.log.Infof("Interface MTU: %d", ir.ifru_mtu)
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
err = errno
tun.log.Errorf("Error in darwin_SIOCAIFADDR_IN6: %v", errno)
return err
}
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.SIOCSIFMTU), uintptr(unsafe.Pointer(&ir))); errno != 0 {
err = errno
tun.log.Errorf("Error in SIOCSIFMTU: %v", errno)
return err
}
return err
}

58
src/tun/tun_linux.go Normal file
View file

@ -0,0 +1,58 @@
//go:build !mobile
// +build !mobile
package tun
// The linux platform specific tun parts
import (
"github.com/vishvananda/netlink"
wgtun "golang.zx2c4.com/wireguard/tun"
)
// Configures the TUN adapter with the correct IPv6 address and MTU.
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if ifname == "auto" {
ifname = "\000"
}
iface, err := wgtun.CreateTUN(ifname, int(mtu))
if err != nil {
panic(err)
}
tun.iface = iface
if mtu, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(mtu))
} else {
tun.mtu = 0
}
return tun.setupAddress(addr)
}
// Configures the TUN adapter with the correct IPv6 address and MTU. Netlink
// is used to do this, so there is not a hard requirement on "ip" or "ifconfig"
// to exist on the system, but this will fail if Netlink is not present in the
// kernel (it nearly always is).
func (tun *TunAdapter) setupAddress(addr string) error {
nladdr, err := netlink.ParseAddr(addr)
if err != nil {
return err
}
nlintf, err := netlink.LinkByName(tun.Name())
if err != nil {
return err
}
if err := netlink.AddrAdd(nlintf, nladdr); err != nil {
return err
}
if err := netlink.LinkSetMTU(nlintf, int(tun.mtu)); err != nil {
return err
}
if err := netlink.LinkSetUp(nlintf); err != nil {
return err
}
// Friendly output
tun.log.Infof("Interface name: %s", tun.Name())
tun.log.Infof("Interface IPv6: %s", addr)
tun.log.Infof("Interface MTU: %d", tun.mtu)
return nil
}

33
src/tun/tun_other.go Normal file
View file

@ -0,0 +1,33 @@
//go:build !linux && !darwin && !windows && !openbsd && !freebsd && !mobile
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!mobile
package tun
// This is to catch unsupported platforms
// If your platform supports tun devices, you could try configuring it manually
import (
wgtun "golang.zx2c4.com/wireguard/tun"
)
// Configures the TUN adapter with the correct IPv6 address and MTU.
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
iface, err := wgtun.CreateTUN(ifname, mtu)
if err != nil {
panic(err)
}
tun.iface = iface
if mtu, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(mtu))
} else {
tun.mtu = 0
}
return tun.setupAddress(addr)
}
// We don't know how to set the IPv6 address on an unknown platform, therefore
// write about it to stdout and don't try to do anything further.
func (tun *TunAdapter) setupAddress(addr string) error {
tun.log.Warnln("Warning: Platform not supported, you must set the address of", tun.Name(), "to", addr)
return nil
}

151
src/tun/tun_windows.go Normal file
View file

@ -0,0 +1,151 @@
//go:build windows
// +build windows
package tun
import (
"bytes"
"errors"
"log"
"net"
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
"golang.org/x/sys/windows"
wgtun "golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/windows/elevate"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
// This is to catch Windows platforms
// Configures the TUN adapter with the correct IPv6 address and MTU.
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if ifname == "auto" {
ifname = defaults.GetDefaults().DefaultIfName
}
return elevate.DoAsSystem(func() error {
var err error
var iface wgtun.Device
var guid windows.GUID
if guid, err = windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); err != nil {
return err
}
if iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu)); err != nil {
return err
}
tun.iface = iface
if err = tun.setupAddress(addr); err != nil {
tun.log.Errorln("Failed to set up TUN address:", err)
return err
}
if err = tun.setupMTU(getSupportedMTU(mtu)); err != nil {
tun.log.Errorln("Failed to set up TUN MTU:", err)
return err
}
if mtu, err := iface.MTU(); err == nil {
tun.mtu = uint64(mtu)
}
return nil
})
}
// Sets the MTU of the TUN adapter.
func (tun *TunAdapter) setupMTU(mtu uint64) error {
if tun.iface == nil || tun.Name() == "" {
return errors.New("Can't configure MTU as TUN adapter is not present")
}
if intf, ok := tun.iface.(*wgtun.NativeTun); ok {
luid := winipcfg.LUID(intf.LUID())
ipfamily, err := luid.IPInterface(windows.AF_INET6)
if err != nil {
return err
}
ipfamily.NLMTU = uint32(mtu)
intf.ForceMTU(int(ipfamily.NLMTU))
ipfamily.UseAutomaticMetric = false
ipfamily.Metric = 0
ipfamily.DadTransmits = 0
ipfamily.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
if err := ipfamily.Set(); err != nil {
return err
}
}
return nil
}
// Sets the IPv6 address of the TUN adapter.
func (tun *TunAdapter) setupAddress(addr string) error {
if tun.iface == nil || tun.Name() == "" {
return errors.New("Can't configure IPv6 address as TUN adapter is not present")
}
if intf, ok := tun.iface.(*wgtun.NativeTun); ok {
if ipaddr, ipnet, err := net.ParseCIDR(addr); err == nil {
luid := winipcfg.LUID(intf.LUID())
addresses := append([]net.IPNet{}, net.IPNet{
IP: ipaddr,
Mask: ipnet.Mask,
})
err := luid.SetIPAddressesForFamily(windows.AF_INET6, addresses)
if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
cleanupAddressesOnDisconnectedInterfaces(windows.AF_INET6, addresses)
err = luid.SetIPAddressesForFamily(windows.AF_INET6, addresses)
}
if err != nil {
return err
}
} else {
return err
}
} else {
return errors.New("unable to get NativeTUN")
}
return nil
}
/*
* cleanupAddressesOnDisconnectedInterfaces
* SPDX-License-Identifier: MIT
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
*/
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []net.IPNet) {
if len(addresses) == 0 {
return
}
includedInAddresses := func(a net.IPNet) bool {
// TODO: this makes the whole algorithm O(n^2). But we can't stick net.IPNet in a Go hashmap. Bummer!
for _, addr := range addresses {
ip := addr.IP
if ip4 := ip.To4(); ip4 != nil {
ip = ip4
}
mA, _ := addr.Mask.Size()
mB, _ := a.Mask.Size()
if bytes.Equal(ip, a.IP) && mA == mB {
return true
}
}
return false
}
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault)
if err != nil {
return
}
for _, iface := range interfaces {
if iface.OperStatus == winipcfg.IfOperStatusUp {
continue
}
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
ip := address.Address.IP()
ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
if includedInAddresses(ipnet) {
log.Printf("Cleaning up stale address %s from interface %s", ipnet.String(), iface.FriendlyName())
iface.LUID.DeleteIPAddress(ipnet)
}
}
}
}