diff --git a/go.mod b/go.mod index a45600a3..417e6fa3 100644 --- a/go.mod +++ b/go.mod @@ -18,4 +18,5 @@ require ( golang.org/x/net v0.0.0-20191021144547-ec77196f6094 golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb golang.org/x/text v0.3.2 + golang.zx2c4.com/wireguard v0.0.20191012 ) diff --git a/go.sum b/go.sum index ecfa4626..222728a1 100644 --- a/go.sum +++ b/go.sum @@ -21,16 +21,21 @@ github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmF github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8 h1:YY9Pg2BEp0jeUVU60svTOaDr+fs1ySC9RbdC1Qc6wOw= github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8/go.mod h1:R0SBCsugm+Sf1katgTb2t7GXMm+nRIv43tM4VDZbaOs= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8= golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb h1:ZxSglHghKPYD8WDeRUzRJrUJtDF0PxsTUSxyqr9/5BI= golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.zx2c4.com/wireguard v0.0.20191012 h1:sdX+y3hrHkW8KJkjY7ZgzpT5Tqo8XnBkH55U1klphko= +golang.zx2c4.com/wireguard v0.0.20191012/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= diff --git a/src/config/config.go b/src/config/config.go index ac88bfc5..bacf9003 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -71,7 +71,6 @@ type NodeConfig struct { SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"` LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` IfName string `comment:"Local network interface name for TUN/TAP adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN/TAP."` - IfTAPMode bool `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."` IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."` TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."` @@ -127,7 +126,6 @@ func GenerateConfig() *NodeConfig { cfg.MulticastInterfaces = defaults.GetDefaults().DefaultMulticastInterfaces cfg.IfName = defaults.GetDefaults().DefaultIfName cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU - cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode cfg.SessionFirewall.Enable = false cfg.SessionFirewall.AllowFromDirect = true cfg.SessionFirewall.AllowFromRemote = true diff --git a/src/defaults/defaults.go b/src/defaults/defaults.go index a5784198..ceb58ba8 100644 --- a/src/defaults/defaults.go +++ b/src/defaults/defaults.go @@ -14,8 +14,7 @@ type platformDefaultParameters struct { DefaultMulticastInterfaces []string // TUN/TAP - MaximumIfMTU int - DefaultIfMTU int - DefaultIfName string - DefaultIfTAPMode bool + MaximumIfMTU int + DefaultIfMTU int + DefaultIfName string } diff --git a/src/defaults/defaults_darwin.go b/src/defaults/defaults_darwin.go index 47683bf9..9fbe6d8e 100644 --- a/src/defaults/defaults_darwin.go +++ b/src/defaults/defaults_darwin.go @@ -19,9 +19,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 65535, - DefaultIfMTU: 65535, - DefaultIfName: "auto", - DefaultIfTAPMode: false, + MaximumIfMTU: 65535, + DefaultIfMTU: 65535, + DefaultIfName: "auto", } } diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index 0e523483..d7dc43b9 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 32767, - DefaultIfMTU: 32767, - DefaultIfName: "/dev/tap0", - DefaultIfTAPMode: true, + MaximumIfMTU: 32767, + DefaultIfMTU: 32767, + DefaultIfName: "/dev/tap0", } } diff --git a/src/defaults/defaults_linux.go b/src/defaults/defaults_linux.go index b0aaf855..5f3f12a8 100644 --- a/src/defaults/defaults_linux.go +++ b/src/defaults/defaults_linux.go @@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 65535, - DefaultIfMTU: 65535, - DefaultIfName: "auto", - DefaultIfTAPMode: false, + MaximumIfMTU: 65535, + DefaultIfMTU: 65535, + DefaultIfName: "auto", } } diff --git a/src/defaults/defaults_netbsd.go b/src/defaults/defaults_netbsd.go index 52a487b7..bc9d7a39 100644 --- a/src/defaults/defaults_netbsd.go +++ b/src/defaults/defaults_netbsd.go @@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 9000, - DefaultIfMTU: 9000, - DefaultIfName: "/dev/tap0", - DefaultIfTAPMode: true, + MaximumIfMTU: 9000, + DefaultIfMTU: 9000, + DefaultIfName: "/dev/tun0", } } diff --git a/src/defaults/defaults_openbsd.go b/src/defaults/defaults_openbsd.go index d44e5714..20741ee8 100644 --- a/src/defaults/defaults_openbsd.go +++ b/src/defaults/defaults_openbsd.go @@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 16384, - DefaultIfMTU: 16384, - DefaultIfName: "/dev/tap0", - DefaultIfTAPMode: true, + MaximumIfMTU: 16384, + DefaultIfMTU: 16384, + DefaultIfName: "/dev/tun0", } } diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index 0ba825c5..763a7f89 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 65535, - DefaultIfMTU: 65535, - DefaultIfName: "none", - DefaultIfTAPMode: false, + MaximumIfMTU: 65535, + DefaultIfMTU: 65535, + DefaultIfName: "none", } } diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index 6d53225a..ade833d4 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters { }, // TUN/TAP - MaximumIfMTU: 65535, - DefaultIfMTU: 65535, - DefaultIfName: "auto", - DefaultIfTAPMode: true, + MaximumIfMTU: 65535, + DefaultIfMTU: 65535, + DefaultIfName: "auto", } } diff --git a/src/tuntap/admin.go b/src/tuntap/admin.go index 778c03ae..c7fc20b0 100644 --- a/src/tuntap/admin.go +++ b/src/tuntap/admin.go @@ -19,9 +19,8 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) { }() return admin.Info{ - t.iface.Name(): admin.Info{ - "tap_mode": t.iface.IsTAP(), - "mtu": t.mtu, + t.Name(): admin.Info{ + "mtu": t.mtu, }, }, nil }) diff --git a/src/tuntap/icmpv6.go b/src/tuntap/icmpv6.go index e601acb5..67c10e54 100644 --- a/src/tuntap/icmpv6.go +++ b/src/tuntap/icmpv6.go @@ -11,32 +11,16 @@ package tuntap import ( "encoding/binary" - "errors" "net" - "sync" - "time" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" - - "github.com/yggdrasil-network/yggdrasil-go/src/address" ) const len_ETHER = 14 type ICMPv6 struct { - tun *TunAdapter - mylladdr net.IP - mymac net.HardwareAddr - peermacs map[address.Address]neighbor - peermacsmutex sync.RWMutex -} - -type neighbor struct { - mac net.HardwareAddr - learned bool - lastadvertisement time.Time - lastsolicitation time.Time + tun *TunAdapter } // Marshal returns the binary encoding of h. @@ -61,182 +45,6 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) { // addresses. func (i *ICMPv6) Init(t *TunAdapter) { i.tun = t - i.peermacsmutex.Lock() - i.peermacs = make(map[address.Address]neighbor) - i.peermacsmutex.Unlock() - - // Our MAC address and link-local address - i.mymac = net.HardwareAddr{ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x02} - i.mylladdr = net.IP{ - 0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE} - copy(i.mymac[:], i.tun.addr[:]) - copy(i.mylladdr[9:], i.tun.addr[1:]) -} - -// Parses an incoming ICMPv6 packet. The packet provided may be either an -// ethernet frame containing an IP packet, or the IP packet alone. This is -// determined by whether the TUN/TAP adapter is running in TUN (layer 3) or -// TAP (layer 2) mode. Returns an error condition which is nil if the ICMPv6 -// module handled the packet or contains the error if not. -func (i *ICMPv6) ParsePacket(datain []byte) error { - var response []byte - var err error - - // Parse the frame/packet - if i.tun.IsTAP() { - response, err = i.UnmarshalPacketL2(datain) - } else { - response, err = i.UnmarshalPacket(datain, nil) - } - - if err != nil { - return err - } - - // Write the packet to TUN/TAP - i.tun.iface.Write(response) - return nil -} - -// Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off -// the IP packet to the ParsePacket function for further processing. -// A response buffer is also created for the response message, also complete -// with ethernet headers. -func (i *ICMPv6) UnmarshalPacketL2(datain []byte) ([]byte, error) { - // Ignore non-IPv6 frames - if binary.BigEndian.Uint16(datain[12:14]) != uint16(0x86DD) { - return nil, errors.New("Ignoring non-IPv6 frame") - } - - // Hand over to ParsePacket to interpret the IPv6 packet - mac := datain[6:12] - ipv6packet, err := i.UnmarshalPacket(datain[len_ETHER:], &mac) - if err != nil { - return nil, err - } - - // Create the response buffer - dataout := make([]byte, len_ETHER+ipv6.HeaderLen+32) - - // Populate the response ethernet headers - copy(dataout[:6], datain[6:12]) - copy(dataout[6:12], i.mymac[:]) - binary.BigEndian.PutUint16(dataout[12:14], uint16(0x86DD)) - - // Copy the returned packet to our response ethernet frame - copy(dataout[len_ETHER:], ipv6packet) - return dataout, nil -} - -// Unwraps the IP headers of an incoming IPv6 packet and performs various -// sanity checks on the packet - i.e. is the packet an ICMPv6 packet, does the -// ICMPv6 message match a known expected type. The relevant handler function -// is then called and a response packet may be returned. -func (i *ICMPv6) UnmarshalPacket(datain []byte, datamac *[]byte) ([]byte, error) { - // Parse the IPv6 packet headers - ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen]) - if err != nil { - return nil, err - } - - // Check if the packet is IPv6 - if ipv6Header.Version != ipv6.Version { - return nil, errors.New("Ignoring non-IPv6 packet") - } - - // Check if the packet is ICMPv6 - if ipv6Header.NextHeader != 58 { - return nil, errors.New("Ignoring non-ICMPv6 packet") - } - - // Parse the ICMPv6 message contents - icmpv6Header, err := icmp.ParseMessage(58, datain[ipv6.HeaderLen:]) - if err != nil { - return nil, err - } - - // Check for a supported message type - switch icmpv6Header.Type { - case ipv6.ICMPTypeNeighborSolicitation: - if !i.tun.IsTAP() { - return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode") - } - response, err := i.HandleNDP(datain[ipv6.HeaderLen:]) - if err == nil { - // Create our ICMPv6 response - responsePacket, err := CreateICMPv6( - ipv6Header.Src, i.mylladdr, - ipv6.ICMPTypeNeighborAdvertisement, 0, - &icmp.DefaultMessageBody{Data: response}) - if err != nil { - return nil, err - } - // Send it back - return responsePacket, nil - } else { - return nil, err - } - case ipv6.ICMPTypeNeighborAdvertisement: - if !i.tun.IsTAP() { - return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode") - } - if datamac != nil { - var addr address.Address - var target address.Address - mac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - copy(addr[:], ipv6Header.Src[:]) - copy(target[:], datain[48:64]) - copy(mac[:], (*datamac)[:]) - i.peermacsmutex.Lock() - neighbor := i.peermacs[target] - neighbor.mac = mac - neighbor.learned = true - neighbor.lastadvertisement = time.Now() - i.peermacs[target] = neighbor - i.peermacsmutex.Unlock() - i.tun.log.Debugln("Learned peer MAC", mac.String(), "for", net.IP(target[:]).String()) - /* - i.tun.log.Debugln("Peer MAC table:") - i.peermacsmutex.RLock() - for t, n := range i.peermacs { - if n.learned { - i.tun.log.Debugln("- Target", net.IP(t[:]).String(), "has MAC", n.mac.String()) - } else { - i.tun.log.Debugln("- Target", net.IP(t[:]).String(), "is not learned yet") - } - } - i.peermacsmutex.RUnlock() - */ - } - return nil, errors.New("No response needed") - } - - return nil, errors.New("ICMPv6 type not matched") -} - -// Creates an ICMPv6 packet based on the given icmp.MessageBody and other -// parameters, complete with ethernet and IP headers, which can be written -// directly to a TAP adapter. -func (i *ICMPv6) CreateICMPv6L2(dstmac net.HardwareAddr, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { - // Pass through to CreateICMPv6 - ipv6packet, err := CreateICMPv6(dst, src, mtype, mcode, mbody) - if err != nil { - return nil, err - } - - // Create the response buffer - dataout := make([]byte, len_ETHER+len(ipv6packet)) - - // Populate the response ethernet headers - copy(dataout[:6], dstmac[:6]) - copy(dataout[6:12], i.mymac[:]) - binary.BigEndian.PutUint16(dataout[12:14], uint16(0x86DD)) - - // Copy the returned packet to our response ethernet frame - copy(dataout[len_ETHER:], ipv6packet) - return dataout, nil } // Creates an ICMPv6 packet based on the given icmp.MessageBody and other @@ -281,106 +89,3 @@ func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody // Send it back return responsePacket, nil } - -func (i *ICMPv6) Solicit(addr address.Address) { - retries := 5 - for retries > 0 { - retries-- - i.peermacsmutex.RLock() - if n, ok := i.peermacs[addr]; ok && n.learned { - i.tun.log.Debugln("MAC learned for", net.IP(addr[:]).String()) - i.peermacsmutex.RUnlock() - return - } - i.peermacsmutex.RUnlock() - i.tun.log.Debugln("Sending neighbor solicitation for", net.IP(addr[:]).String()) - i.peermacsmutex.Lock() - if n, ok := i.peermacs[addr]; !ok { - i.peermacs[addr] = neighbor{ - lastsolicitation: time.Now(), - } - } else { - n.lastsolicitation = time.Now() - } - i.peermacsmutex.Unlock() - request, err := i.createNDPL2(addr) - if err != nil { - panic(err) - } - if _, err := i.tun.iface.Write(request); err != nil { - panic(err) - } - i.tun.log.Debugln("Sent neighbor solicitation for", net.IP(addr[:]).String()) - time.Sleep(time.Second) - } -} - -func (i *ICMPv6) getNeighbor(addr address.Address) (neighbor, bool) { - i.peermacsmutex.RLock() - defer i.peermacsmutex.RUnlock() - - n, ok := i.peermacs[addr] - return n, ok -} - -func (i *ICMPv6) createNDPL2(dst address.Address) ([]byte, error) { - // Create the ND payload - var payload [28]byte - copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00}) // Flags - copy(payload[4:20], dst[:]) // Destination - copy(payload[20:22], []byte{0x01, 0x01}) // Type & length - copy(payload[22:28], i.mymac[:6]) // Link layer address - - // Create the ICMPv6 solicited-node address - var dstaddr address.Address - copy(dstaddr[:13], []byte{ - 0xFF, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF}) - copy(dstaddr[13:], dst[13:16]) - - // Create the multicast MAC - dstmac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - copy(dstmac[:2], []byte{0x33, 0x33}) - copy(dstmac[2:6], dstaddr[12:16]) - - // Create the ND request - requestPacket, err := i.CreateICMPv6L2( - dstmac, dstaddr[:], i.mylladdr, - ipv6.ICMPTypeNeighborSolicitation, 0, - &icmp.DefaultMessageBody{Data: payload[:]}) - if err != nil { - return nil, err - } - - return requestPacket, nil -} - -// Generates a response to an NDP discovery packet. This is effectively called -// when the host operating system generates an NDP request for any address in -// the fd00::/8 range, so that the operating system knows to route that traffic -// to the Yggdrasil TAP adapter. -func (i *ICMPv6) HandleNDP(in []byte) ([]byte, error) { - // Ignore NDP requests for anything outside of fd00::/8 - var source address.Address - copy(source[:], in[8:]) - var snet address.Subnet - copy(snet[:], in[8:]) - switch { - case source.IsValid(): - case snet.IsValid(): - default: - return nil, errors.New("Not an NDP for 0200::/7") - } - - // Create our NDP message body response - body := make([]byte, 28) - binary.BigEndian.PutUint32(body[:4], uint32(0x40000000)) // Flags - copy(body[4:20], in[8:24]) // Target address - body[20] = uint8(2) // Type: Target link-layer address - body[21] = uint8(1) // Length: 1x address (8 bytes) - copy(body[22:28], i.mymac[:6]) - - // Send it back - return body, nil -} diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 3d788b1a..9cb5e370 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -1,11 +1,6 @@ package tuntap import ( - "bytes" - "net" - "time" - - "github.com/songgao/packets/ethernet" "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/util" @@ -14,6 +9,8 @@ import ( "github.com/Arceliar/phony" ) +const TUN_OFFSET_BYTES = 4 + type tunWriter struct { phony.Inbox tun *TunAdapter @@ -25,7 +22,8 @@ func (w *tunWriter) writeFrom(from phony.Actor, b []byte) { }) } -// write is pretty loose with the memory safety rules, e.g. it assumes it can read w.tun.iface.IsTap() safely +// write is pretty loose with the memory safety rules, e.g. it assumes it can +// read w.tun.iface.IsTap() safely func (w *tunWriter) _write(b []byte) { var written int var err error @@ -33,72 +31,17 @@ func (w *tunWriter) _write(b []byte) { if n == 0 { return } - if w.tun.iface.IsTAP() { - sendndp := func(dstAddr address.Address) { - neigh, known := w.tun.icmpv6.getNeighbor(dstAddr) - known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30) - if !known { - w.tun.icmpv6.Solicit(dstAddr) - } - } - peermac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - var dstAddr address.Address - var peerknown bool - if b[0]&0xf0 == 0x40 { - dstAddr = w.tun.addr - } else if b[0]&0xf0 == 0x60 { - if !bytes.Equal(w.tun.addr[:16], dstAddr[:16]) && !bytes.Equal(w.tun.subnet[:8], dstAddr[:8]) { - dstAddr = w.tun.addr - } - } - if neighbor, ok := w.tun.icmpv6.getNeighbor(dstAddr); ok && neighbor.learned { - // If we've learned the MAC of a 300::/7 address, for example, or a CKR - // address, use the MAC address of that - peermac = neighbor.mac - peerknown = true - } else if neighbor, ok := w.tun.icmpv6.getNeighbor(w.tun.addr); ok && neighbor.learned { - // Otherwise send directly to the MAC address of the host if that's - // known instead - peermac = neighbor.mac - peerknown = true - } else { - // Nothing has been discovered, try to discover the destination - sendndp(w.tun.addr) - } - if peerknown { - var proto ethernet.Ethertype - switch { - case b[0]&0xf0 == 0x60: - proto = ethernet.IPv6 - case b[0]&0xf0 == 0x40: - proto = ethernet.IPv4 - } - var frame ethernet.Frame - frame.Prepare( - peermac[:6], // Destination MAC address - w.tun.icmpv6.mymac[:6], // Source MAC address - ethernet.NotTagged, // VLAN tagging - proto, // Ethertype - len(b)) // Payload length - copy(frame[tun_ETHER_HEADER_LENGTH:], b[:n]) - n += tun_ETHER_HEADER_LENGTH - written, err = w.tun.iface.Write(frame[:n]) - } else { - w.tun.log.Errorln("TUN/TAP iface write error: no peer MAC known for", net.IP(dstAddr[:]).String(), "- dropping packet") - } - } else { - written, err = w.tun.iface.Write(b[:n]) - util.PutBytes(b) - } + written, err = w.tun.iface.Write(append([]byte{0, 0, 0, 0}, b[:n]...), TUN_OFFSET_BYTES) + util.PutBytes(b) if err != nil { w.tun.Act(w, func() { if !w.tun.isOpen { - w.tun.log.Errorln("TUN/TAP iface write error:", err) + w.tun.log.Errorln("TUN iface write error:", err) } }) } - if written != n { - w.tun.log.Errorln("TUN/TAP iface write mismatch:", written, "bytes written vs", n, "bytes given") + if written-TUN_OFFSET_BYTES != n { + w.tun.log.Errorln("TUN iface write mismatch:", written-TUN_OFFSET_BYTES, "bytes written vs", n, "bytes given") } } @@ -109,13 +52,18 @@ type tunReader struct { func (r *tunReader) _read() { // Get a slice to store the packet in - recvd := util.ResizeBytes(util.GetBytes(), 65535+tun_ETHER_HEADER_LENGTH) - // Wait for a packet to be delivered to us through the TUN/TAP adapter - n, err := r.tun.iface.Read(recvd) - if n <= 0 { + recvd := util.ResizeBytes(util.GetBytes(), r.tun.mtu+TUN_OFFSET_BYTES) + // Wait for a packet to be delivered to us through the TUN adapter + n, err := r.tun.iface.Read(recvd, TUN_OFFSET_BYTES) + if n <= TUN_OFFSET_BYTES || err != nil { + r.tun.log.Errorln("Error reading TUN:", err) + err = r.tun.iface.Flush() + if err != nil { + r.tun.log.Errorln("Unable to flush packets:", err) + } util.PutBytes(recvd) } else { - r.tun.handlePacketFrom(r, recvd[:n], err) + r.tun.handlePacketFrom(r, recvd[TUN_OFFSET_BYTES:n+TUN_OFFSET_BYTES], err) } if err == nil { // Now read again @@ -132,43 +80,17 @@ func (tun *TunAdapter) handlePacketFrom(from phony.Actor, packet []byte, err err // does the work of reading a packet and sending it to the correct tunConn func (tun *TunAdapter) _handlePacket(recvd []byte, err error) { if err != nil { - tun.log.Errorln("TUN/TAP iface read error:", err) + tun.log.Errorln("TUN iface read error:", err) return } - // If it's a TAP adapter, update the buffer slice so that we no longer - // include the ethernet headers - offset := 0 - if tun.iface.IsTAP() { - // Set our offset to beyond the ethernet headers - offset = tun_ETHER_HEADER_LENGTH - // Check first of all that we can go beyond the ethernet headers - if len(recvd) <= offset { - return - } - } // Offset the buffer from now on so that we can ignore ethernet frames if // they are present - bs := recvd[offset:] + bs := recvd[:] // Check if the packet is long enough to detect if it's an ICMP packet or not if len(bs) < 7 { - tun.log.Traceln("TUN/TAP iface read undersized unknown packet, length:", len(bs)) + tun.log.Traceln("TUN iface read undersized unknown packet, length:", len(bs)) return } - // If we detect an ICMP packet then hand it to the ICMPv6 module - if bs[6] == 58 { - // Found an ICMPv6 packet - we need to make sure to give ICMPv6 the full - // Ethernet frame rather than just the IPv6 packet as this is needed for - // NDP to work correctly - if err := tun.icmpv6.ParsePacket(recvd); err == nil { - // We acted on the packet in the ICMPv6 module so don't forward or do - // anything else with it - return - } - } - if offset != 0 { - // Shift forward to avoid leaking bytes off the front of the slice when we eventually store it - bs = append(recvd[:0], bs...) - } // From the IP header, work out what our source and destination addresses // and node IDs are. We will need these in order to work out where to send // the packet @@ -181,7 +103,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) { if bs[0]&0xf0 == 0x60 { // Check if we have a fully-sized IPv6 header if len(bs) < 40 { - tun.log.Traceln("TUN/TAP iface read undersized ipv6 packet, length:", len(bs)) + tun.log.Traceln("TUN iface read undersized ipv6 packet, length:", len(bs)) return } // Check the packet size @@ -195,7 +117,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) { } else if bs[0]&0xf0 == 0x40 { // Check if we have a fully-sized IPv4 header if len(bs) < 20 { - tun.log.Traceln("TUN/TAP iface read undersized ipv4 packet, length:", len(bs)) + tun.log.Traceln("TUN iface read undersized ipv4 packet, length:", len(bs)) return } // Check the packet size @@ -267,7 +189,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) { if tc, err = tun._wrap(conn.(*yggdrasil.Conn)); err != nil { // Something went wrong when storing the connection, typically that // something already exists for this address or subnet - tun.log.Debugln("TUN/TAP iface wrap:", err) + tun.log.Debugln("TUN iface wrap:", err) return } for _, packet := range packets { diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 1e994ea5..807ce7fb 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -18,7 +18,7 @@ import ( "github.com/Arceliar/phony" "github.com/gologme/log" - "github.com/yggdrasil-network/water" + "golang.zx2c4.com/wireguard/tun" "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" @@ -28,12 +28,11 @@ import ( ) const tun_IPv6_HEADER_LENGTH = 40 -const tun_ETHER_HEADER_LENGTH = 14 -// TunAdapter represents a running TUN/TAP interface and extends the -// yggdrasil.Adapter type. In order to use the TUN/TAP adapter with Yggdrasil, -// you should pass this object to the yggdrasil.SetRouterAdapter() function -// before calling yggdrasil.Start(). +// 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 { core *yggdrasil.Core writer tunWriter @@ -48,7 +47,7 @@ type TunAdapter struct { ckr cryptokey icmpv6 ICMPv6 mtu int - iface *water.Interface + 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 addrToConn map[address.Address]*tunConn @@ -64,12 +63,12 @@ type TunOptions struct { // Gets the maximum supported MTU for the platform based on the defaults in // defaults.GetDefaults(). -func getSupportedMTU(mtu int, istapmode bool) int { +func getSupportedMTU(mtu int) int { if mtu < 1280 { return 1280 } - if mtu > MaximumMTU(istapmode) { - return MaximumMTU(istapmode) + if mtu > MaximumMTU() { + return MaximumMTU() } return mtu } @@ -77,55 +76,38 @@ func getSupportedMTU(mtu int, istapmode bool) int { // 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 { - return tun.iface.Name() + 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() int { - return getSupportedMTU(tun.mtu, tun.IsTAP()) + return getSupportedMTU(tun.mtu) } -// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it -// is a TUN adapter (Layer 3). -func (tun *TunAdapter) IsTAP() bool { - return tun.iface.IsTAP() -} - -// DefaultName gets the default TUN/TAP interface name for your platform. +// DefaultName gets the default TUN interface name for your platform. func DefaultName() string { return defaults.GetDefaults().DefaultIfName } -// DefaultMTU gets the default TUN/TAP interface MTU for your platform. This can +// 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() int { - ehbytes := 0 - if DefaultIsTAP() { - ehbytes = tun_ETHER_HEADER_LENGTH - } - return defaults.GetDefaults().DefaultIfMTU - ehbytes + return defaults.GetDefaults().DefaultIfMTU } -// DefaultIsTAP returns true if the default adapter mode for the current -// platform is TAP (Layer 2) and returns false for TUN (Layer 3). -func DefaultIsTAP() bool { - return defaults.GetDefaults().DefaultIfTAPMode -} - -// MaximumMTU returns the maximum supported TUN/TAP interface MTU for your +// 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(iftapmode bool) int { - ehbytes := 0 - if iftapmode { - ehbytes = tun_ETHER_HEADER_LENGTH - } - return defaults.GetDefaults().MaximumIfMTU - ehbytes +func MaximumMTU() int { + return defaults.GetDefaults().MaximumIfMTU } -// Init initialises the TUN/TAP module. You must have acquired a Listener from +// 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 (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log *log.Logger, options interface{}) error { tunoptions, ok := options.(TunOptions) @@ -145,7 +127,7 @@ func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log return nil } -// Start the setup process for the TUN/TAP adapter. If successful, starts the +// Start the setup process for the TUN adapter. If successful, starts the // reader actor to handle packets on that interface. func (tun *TunAdapter) Start() error { var err error @@ -157,11 +139,11 @@ func (tun *TunAdapter) Start() error { func (tun *TunAdapter) _start() error { if tun.isOpen { - return errors.New("TUN/TAP module is already started") + return errors.New("TUN module is already started") } current := tun.config.GetCurrent() if tun.config == nil || tun.listener == nil || tun.dialer == nil { - return errors.New("no configuration available to TUN/TAP") + return errors.New("no configuration available to TUN") } var boxPub crypto.BoxPubKey boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey) @@ -174,23 +156,19 @@ func (tun *TunAdapter) _start() error { tun.subnet = *address.SubnetForNodeID(nodeID) addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) if current.IfName == "none" || current.IfName == "dummy" { - tun.log.Debugln("Not starting TUN/TAP as ifname is none or dummy") + tun.log.Debugln("Not starting TUN as ifname is none or dummy") return nil } - if err := tun.setup(current.IfName, current.IfTAPMode, addr, current.IfMTU); err != nil { + if err := tun.setup(current.IfName, addr, current.IfMTU); err != nil { return err } if tun.MTU() != current.IfMTU { - tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", current.IfMTU, tun.MTU(), MaximumMTU(tun.IsTAP())) + tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", current.IfMTU, tun.MTU(), MaximumMTU()) } tun.core.SetMaximumSessionMTU(uint16(tun.MTU())) tun.isOpen = true go tun.handler() tun.reader.Act(nil, tun.reader._read) // Start the reader - tun.icmpv6.Init(tun) - if tun.IsTAP() { - go tun.icmpv6.Solicit(tun.addr) - } tun.ckr.init(tun) return nil } @@ -204,7 +182,7 @@ func (tun *TunAdapter) IsStarted() bool { return isOpen } -// Start the setup process for the TUN/TAP adapter. If successful, starts the +// 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 @@ -216,7 +194,7 @@ func (tun *TunAdapter) Stop() error { func (tun *TunAdapter) _stop() error { tun.isOpen = false - // by TUN/TAP, e.g. readers/writers, sessions + // 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() @@ -224,16 +202,16 @@ func (tun *TunAdapter) _stop() error { return nil } -// UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig +// UpdateConfig updates the TUN module with the provided config.NodeConfig // and then signals the various module goroutines to reconfigure themselves if // needed. func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) { - tun.log.Debugln("Reloading TUN/TAP configuration...") + tun.log.Debugln("Reloading TUN configuration...") // Replace the active configuration with the supplied one tun.config.Replace(*config) - // If the MTU has changed in the TUN/TAP module then this is where we would + // If the MTU has changed in the TUN module then this is where we would // tell the router so that updated session pings can be sent. However, we // don't currently update the MTU of the adapter once it has been created so // this doesn't actually happen in the real world yet. @@ -248,14 +226,14 @@ func (tun *TunAdapter) handler() error { // Accept the incoming connection conn, err := tun.listener.Accept() if err != nil { - tun.log.Errorln("TUN/TAP connection accept error:", err) + tun.log.Errorln("TUN connection accept error:", err) return err } phony.Block(tun, func() { if _, err := tun._wrap(conn.(*yggdrasil.Conn)); err != nil { // Something went wrong when storing the connection, typically that // something already exists for this address or subnet - tun.log.Debugln("TUN/TAP handler wrap:", err) + tun.log.Debugln("TUN handler wrap:", err) } }) } diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 78a4adab..7ad89edc 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -1,4 +1,4 @@ -// +build openbsd freebsd netbsd +// +build openbsd freebsd package tuntap @@ -12,7 +12,7 @@ import ( "golang.org/x/sys/unix" - "github.com/yggdrasil-network/water" + wgtun "golang.zx2c4.com/wireguard/tun" ) const SIOCSIFADDR_IN6 = (0x80000000) | ((288 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 12 @@ -72,34 +72,18 @@ type in6_ifreq_lifetime struct { ifru_addrlifetime in6_addrlifetime } -// Sets the IPv6 address of the utun adapter. On all BSD platforms (FreeBSD, -// OpenBSD, NetBSD) an attempt is made to set the adapter properties by using -// a system socket and making syscalls to the kernel. This is not refined though -// and often doesn't work (if at all), therefore if a call fails, it resorts -// to calling "ifconfig" instead. -func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { - var config water.Config - if ifname[:4] == "auto" { - ifname = "/dev/tap0" - } - if len(ifname) < 9 { - panic("TUN/TAP name must be in format /dev/tunX or /dev/tapX") - } - switch { - case iftapmode || ifname[:8] == "/dev/tap": - config = water.Config{DeviceType: water.TAP} - case !iftapmode || ifname[:8] == "/dev/tun": - panic("TUN mode is not currently supported on this platform, please use TAP instead") - default: - panic("TUN/TAP name must be in format /dev/tunX or /dev/tapX") - } - config.Name = ifname - iface, err := water.New(config) +// Configures the TUN adapter with the correct IPv6 address and MTU. +func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) } tun.iface = iface - tun.mtu = getSupportedMTU(mtu, iftapmode) + if mtu, err := iface.MTU(); err == nil { + tun.mtu = getSupportedMTU(mtu) + } else { + tun.mtu = 0 + } return tun.setupAddress(addr) } diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index ab6f34e3..c9b8bceb 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -12,22 +12,21 @@ import ( "golang.org/x/sys/unix" - water "github.com/yggdrasil-network/water" + wgtun "golang.zx2c4.com/wireguard/tun" ) // Configures the "utun" adapter with the correct IPv6 address and MTU. -func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { - if iftapmode { - tun.log.Warnln("Warning: TAP mode is not supported on this platform, defaulting to TUN") - iftapmode = false - } - config := water.Config{DeviceType: water.TUN} - iface, err := water.New(config) +func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) } tun.iface = iface - tun.mtu = getSupportedMTU(mtu, iftapmode) + if mtu, err := iface.MTU(); err == nil { + tun.mtu = getSupportedMTU(mtu) + } else { + tun.mtu = 0 + } return tun.setupAddress(addr) } @@ -80,7 +79,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { } var ar in6_aliasreq - copy(ar.ifra_name[:], tun.iface.Name()) + copy(ar.ifra_name[:], tun.Name()) ar.ifra_prefixmask.sin6_len = uint8(unsafe.Sizeof(ar.ifra_prefixmask)) b := make([]byte, 16) @@ -104,7 +103,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME var ir ifreq - copy(ir.ifr_name[:], tun.iface.Name()) + copy(ir.ifr_name[:], tun.Name()) ir.ifru_mtu = uint32(tun.mtu) tun.log.Infof("Interface name: %s", ar.ifra_name) diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index b5918328..1129cfad 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -6,31 +6,21 @@ package tuntap import ( "github.com/vishvananda/netlink" - - water "github.com/yggdrasil-network/water" + wgtun "golang.zx2c4.com/wireguard/tun" ) -// Configures the TAP adapter with the correct IPv6 address and MTU. -func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { - var config water.Config - if iftapmode { - config = water.Config{DeviceType: water.TAP} - } else { - config = water.Config{DeviceType: water.TUN} - } - if ifname != "" && ifname != "auto" { - config.Name = ifname - } - iface, err := water.New(config) +// Configures the TUN adapter with the correct IPv6 address and MTU. +func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) } tun.iface = iface - tun.mtu = getSupportedMTU(mtu, iftapmode) - // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) - tun.log.Infof("Interface IPv6: %s", addr) - tun.log.Infof("Interface MTU: %d", tun.mtu) + if mtu, err := iface.MTU(); err == nil { + tun.mtu = getSupportedMTU(mtu) + } else { + tun.mtu = 0 + } return tun.setupAddress(addr) } @@ -56,5 +46,9 @@ func (tun *TunAdapter) setupAddress(addr string) error { if err := netlink.LinkSetUp(nlintf); err != nil { return err } + // Friendly output + tun.log.Infof("Interface name: %s", tun.iface.Name()) + tun.log.Infof("Interface IPv6: %s", addr) + tun.log.Infof("Interface MTU: %d", tun.mtu) return nil } diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index 7d4f0643..c5ff58fb 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -1,27 +1,26 @@ -// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile +// +build !linux,!darwin,!windows,!openbsd,!freebsd,!mobile package tuntap -import water "github.com/yggdrasil-network/water" - // This is to catch unsupported platforms // If your platform supports tun devices, you could try configuring it manually -// Creates the TUN/TAP adapter, if supported by the Water library. Note that -// no guarantees are made at this point on an unsupported platform. -func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { - var config water.Config - if iftapmode { - config = water.Config{DeviceType: water.TAP} - } else { - config = water.Config{DeviceType: water.TUN} - } - iface, err := water.New(config) +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 int) error { + iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) } tun.iface = iface - tun.mtu = getSupportedMTU(mtu, iftapmode) + if mtu, err := iface.MTU(); err == nil { + tun.mtu = getSupportedMTU(mtu) + } else { + tun.mtu = 0 + } return tun.setupAddress(addr) } diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index d4fd1c3d..65417546 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -7,69 +7,23 @@ import ( "strings" "time" - water "github.com/yggdrasil-network/water" + wgtun "golang.zx2c4.com/wireguard/tun" ) // This is to catch Windows platforms -// Configures the TAP adapter with the correct IPv6 address and MTU. On Windows -// we don't make use of a direct operating system API to do this - we instead -// delegate the hard work to "netsh". -func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { - if !iftapmode { - tun.log.Warnln("Warning: TUN mode is not supported on this platform, defaulting to TAP") - iftapmode = true - } - config := water.Config{DeviceType: water.TAP} - config.PlatformSpecificParams.ComponentID = "tap0901" - config.PlatformSpecificParams.Network = "169.254.0.1/32" - if ifname == "auto" { - config.PlatformSpecificParams.InterfaceName = "" - } else { - config.PlatformSpecificParams.InterfaceName = ifname - } - iface, err := water.New(config) - if err != nil { - return err - } - if iface.Name() == "" { - return errors.New("unable to find TAP adapter with component ID " + config.PlatformSpecificParams.ComponentID) - } - // Reset the adapter - this invalidates iface so we'll need to get a new one - cmd := exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=DISABLED") - tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " ")) - output, err := cmd.CombinedOutput() - if err != nil { - tun.log.Errorln("Windows netsh failed:", err) - tun.log.Traceln(string(output)) - return err - } - time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect - // Bring the interface back up - cmd = exec.Command("netsh", "interface", "set", "interface", iface.Name(), "admin=ENABLED") - tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " ")) - output, err = cmd.CombinedOutput() - if err != nil { - tun.log.Errorln("Windows netsh failed:", err) - tun.log.Traceln(string(output)) - return err - } - time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect - // Get a new iface - iface, err = water.New(config) +// Configures the TUN adapter with the correct IPv6 address and MTU. +func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) } tun.iface = iface - tun.mtu = getSupportedMTU(mtu, iftapmode) - err = tun.setupMTU(tun.mtu) - if err != nil { - panic(err) + if mtu, err := iface.MTU(); err == nil { + tun.mtu = getSupportedMTU(mtu) + } else { + tun.mtu = 0 } - // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) - tun.log.Infof("Interface IPv6: %s", addr) - tun.log.Infof("Interface MTU: %d", tun.mtu) return tun.setupAddress(addr) }