From f5517acc81911cf4477d939fe91fff97ecae3f56 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 16:43:50 +0000 Subject: [PATCH 01/32] Drop Water, use Wireguard tun library, drop TAP support --- go.mod | 1 + go.sum | 5 + src/config/config.go | 2 - src/defaults/defaults.go | 7 +- src/defaults/defaults_darwin.go | 7 +- src/defaults/defaults_freebsd.go | 7 +- src/defaults/defaults_linux.go | 7 +- src/defaults/defaults_netbsd.go | 7 +- src/defaults/defaults_openbsd.go | 7 +- src/defaults/defaults_other.go | 7 +- src/defaults/defaults_windows.go | 7 +- src/tuntap/admin.go | 5 +- src/tuntap/icmpv6.go | 297 +------------------------------ src/tuntap/iface.go | 128 +++---------- src/tuntap/tun.go | 90 ++++------ src/tuntap/tun_bsd.go | 36 ++-- src/tuntap/tun_darwin.go | 21 ++- src/tuntap/tun_linux.go | 32 ++-- src/tuntap/tun_other.go | 27 ++- src/tuntap/tun_windows.go | 62 +------ 20 files changed, 146 insertions(+), 616 deletions(-) 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) } From 235b64345e16d87ee173352aa44705a697911b89 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 18:34:43 +0000 Subject: [PATCH 02/32] Configure addresses and MTUs, fix bugs --- src/tuntap/iface.go | 4 +- src/tuntap/tun_windows.go | 237 +++++++++++++++++++++++++++++++------- 2 files changed, 197 insertions(+), 44 deletions(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 9cb5e370..fbb7c86d 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -40,8 +40,8 @@ func (w *tunWriter) _write(b []byte) { } }) } - if written-TUN_OFFSET_BYTES != n { - w.tun.log.Errorln("TUN iface write mismatch:", written-TUN_OFFSET_BYTES, "bytes written vs", n, "bytes given") + if written != n { + w.tun.log.Errorln("TUN iface write mismatch:", written, "bytes written vs", n, "bytes given") } } diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 65417546..8b4f92cf 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -1,70 +1,223 @@ package tuntap import ( + "bytes" "errors" - "fmt" - "os/exec" + "log" + "net" + "runtime" "strings" - "time" + "unsafe" + + "golang.org/x/sys/windows" wgtun "golang.zx2c4.com/wireguard/tun" + "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 int) 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(mtu) - } else { - tun.mtu = 0 - } - return tun.setupAddress(addr) + var err error + err = doAsSystem(func() { + iface, err := wgtun.CreateTUN(ifname, mtu) + if err != nil { + panic(err) + } + tun.iface = iface + + if err := tun.setupAddress(addr); err != nil { + tun.log.Errorln("Failed to set up TUN address:", err) + } + if err := tun.setupMTU(getSupportedMTU(mtu)); err != nil { + tun.log.Errorln("Failed to set up TUN MTU:", err) + } + + if mtu, err = iface.MTU(); err == nil { + tun.mtu = mtu + } + }) + return err } // Sets the MTU of the TAP adapter. func (tun *TunAdapter) setupMTU(mtu int) error { - if tun.iface == nil || tun.iface.Name() == "" { - return errors.New("Can't configure MTU as TAP adapter is not present") + if tun.iface == nil || tun.Name() == "" { + return errors.New("Can't configure MTU as TUN adapter is not present") } - // Set MTU - cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface", - fmt.Sprintf("interface=%s", tun.iface.Name()), - fmt.Sprintf("mtu=%d", mtu), - "store=active") - 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 + 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 + } } - time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect + return nil } // Sets the IPv6 address of the TAP adapter. func (tun *TunAdapter) setupAddress(addr string) error { - if tun.iface == nil || tun.iface.Name() == "" { - return errors.New("Can't configure IPv6 address as TAP adapter is not present") + if tun.iface == nil || tun.Name() == "" { + return errors.New("Can't configure IPv6 address as TUN adapter is not present") } - // Set address - cmd := exec.Command("netsh", "interface", "ipv6", "add", "address", - fmt.Sprintf("interface=%s", tun.iface.Name()), - fmt.Sprintf("addr=%s", addr), - "store=active") - 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 + 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") } - time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect return nil } + +/* + * doAsSystem + * SPDX-License-Identifier: LGPL-3.0 + * Copyright (C) 2017-2019 Jason A. Donenfeld . All Rights Reserved. + */ +func doAsSystem(f func()) error { + runtime.LockOSThread() + defer func() { + windows.RevertToSelf() + runtime.UnlockOSThread() + }() + privileges := windows.Tokenprivileges{ + PrivilegeCount: 1, + Privileges: [1]windows.LUIDAndAttributes{ + { + Attributes: windows.SE_PRIVILEGE_ENABLED, + }, + }, + } + err := windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr("SeDebugPrivilege"), &privileges.Privileges[0].Luid) + if err != nil { + return err + } + err = windows.ImpersonateSelf(windows.SecurityImpersonation) + if err != nil { + return err + } + var threadToken windows.Token + err = windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES, false, &threadToken) + if err != nil { + return err + } + defer threadToken.Close() + err = windows.AdjustTokenPrivileges(threadToken, false, &privileges, uint32(unsafe.Sizeof(privileges)), nil, nil) + if err != nil { + return err + } + + processes, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) + if err != nil { + return err + } + defer windows.CloseHandle(processes) + + processEntry := windows.ProcessEntry32{Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{}))} + pid := uint32(0) + for err = windows.Process32First(processes, &processEntry); err == nil; err = windows.Process32Next(processes, &processEntry) { + if strings.ToLower(windows.UTF16ToString(processEntry.ExeFile[:])) == "winlogon.exe" { + pid = processEntry.ProcessID + break + } + } + if pid == 0 { + return errors.New("unable to find winlogon.exe process") + } + + winlogonProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid) + if err != nil { + return err + } + defer windows.CloseHandle(winlogonProcess) + var winlogonToken windows.Token + err = windows.OpenProcessToken(winlogonProcess, windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE, &winlogonToken) + if err != nil { + return err + } + defer winlogonToken.Close() + var duplicatedToken windows.Token + err = windows.DuplicateTokenEx(winlogonToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken) + if err != nil { + return err + } + defer duplicatedToken.Close() + err = windows.SetThreadToken(nil, duplicatedToken) + if err != nil { + return err + } + f() + 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) + } + } + } +} From b27ada91910f60baa39187b00b87f9891c267eb9 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 18:39:27 +0000 Subject: [PATCH 03/32] Fix bad Name() calls --- src/tuntap/tun_bsd.go | 10 +++++----- src/tuntap/tun_linux.go | 4 ++-- src/tuntap/tun_other.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 7ad89edc..219e3485 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -98,13 +98,13 @@ func (tun *TunAdapter) setupAddress(addr string) error { } // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) + 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.iface.Name()) + copy(ir.ifr_name[:], tun.Name()) ir.ifru_mtu = int(tun.mtu) // Set the MTU @@ -113,7 +113,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { tun.log.Errorf("Error in SIOCSIFMTU: %v", errno) // Fall back to ifconfig to set the MTU - cmd := exec.Command("ifconfig", tun.iface.Name(), "mtu", string(tun.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 { @@ -125,7 +125,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { // Create the address request // FIXME: I don't work! var ar in6_ifreq_addr - copy(ar.ifr_name[:], tun.iface.Name()) + 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], ":") @@ -142,7 +142,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { tun.log.Errorf("Error in SIOCSIFADDR_IN6: %v", errno) // Fall back to ifconfig to set the address - cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr) + 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 { diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index 1129cfad..7935e7cf 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -33,7 +33,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { if err != nil { return err } - nlintf, err := netlink.LinkByName(tun.iface.Name()) + nlintf, err := netlink.LinkByName(tun.Name()) if err != nil { return err } @@ -47,7 +47,7 @@ func (tun *TunAdapter) setupAddress(addr string) error { return err } // Friendly output - tun.log.Infof("Interface name: %s", tun.iface.Name()) + 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 diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index c5ff58fb..8a27f57b 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -27,6 +27,6 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { // 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.iface.Name(), "to", addr) + tun.log.Warnln("Warning: Platform not supported, you must set the address of", tun.Name(), "to", addr) return nil } From 15726fe90d9f1cf71df30eaba3e7219f2ad4c1a4 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 18:52:12 +0000 Subject: [PATCH 04/32] Don't build for NetBSD (not supported by the TUN package right now) --- .circleci/config.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 17cbfade..3e223e55 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -174,13 +174,6 @@ jobs: GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-amd64; GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-i386; - - run: - name: Build for NetBSD - command: | - rm -f {yggdrasil,yggdrasilctl} - GOOS=netbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-netbsd-amd64; - GOOS=netbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-netbsd-i386; - - run: name: Build for Windows command: | From 7d00206f4bde6de34dfd84ac4d9e092a98ce57de Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 20:07:08 +0000 Subject: [PATCH 05/32] Update platform defaults, handling of 'auto' on Linux/Darwin --- src/defaults/defaults_freebsd.go | 2 +- src/defaults/defaults_netbsd.go | 25 ------------------------- src/defaults/defaults_other.go | 2 +- src/defaults/defaults_windows.go | 2 +- src/tuntap/tun_darwin.go | 3 +++ src/tuntap/tun_linux.go | 3 +++ 6 files changed, 9 insertions(+), 28 deletions(-) delete mode 100644 src/defaults/defaults_netbsd.go diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index d7dc43b9..b08d80d0 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -20,6 +20,6 @@ func GetDefaults() platformDefaultParameters { // TUN/TAP MaximumIfMTU: 32767, DefaultIfMTU: 32767, - DefaultIfName: "/dev/tap0", + DefaultIfName: "/dev/tun0", } } diff --git a/src/defaults/defaults_netbsd.go b/src/defaults/defaults_netbsd.go deleted file mode 100644 index bc9d7a39..00000000 --- a/src/defaults/defaults_netbsd.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build netbsd - -package defaults - -// Sane defaults for the BSD platforms. The "default" options may be -// may be replaced by the running configuration. -func GetDefaults() platformDefaultParameters { - return platformDefaultParameters{ - // Admin - DefaultAdminListen: "unix:///var/run/yggdrasil.sock", - - // Configuration (used for yggdrasilctl) - DefaultConfigFile: "/etc/yggdrasil.conf", - - // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", - }, - - // TUN/TAP - MaximumIfMTU: 9000, - DefaultIfMTU: 9000, - DefaultIfName: "/dev/tun0", - } -} diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index 763a7f89..3b035537 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd +// +build !linux,!darwin,!windows,!openbsd,!freebsd package defaults diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index ade833d4..305a2ffe 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -20,6 +20,6 @@ func GetDefaults() platformDefaultParameters { // TUN/TAP MaximumIfMTU: 65535, DefaultIfMTU: 65535, - DefaultIfName: "auto", + DefaultIfName: "Yggdrasil", } } diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index c9b8bceb..cf2fbfb4 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -17,6 +17,9 @@ import ( // Configures the "utun" adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + if ifname == "auto" { + ifname = "utun" + } iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index 7935e7cf..4206b26a 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -11,6 +11,9 @@ import ( // Configures the TUN adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + if ifname == "auto" { + ifname = "\000" + } iface, err := wgtun.CreateTUN(ifname, mtu) if err != nil { panic(err) From f95ebeb8216748a5914d9f0fca9eb602f7b16cbe Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 20:08:19 +0000 Subject: [PATCH 06/32] Remove references to TAP --- src/config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index bacf9003..3e1438b8 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -5,7 +5,7 @@ Yggdrasil node. The configuration contains, amongst other things, encryption keys which are used to derive a node's identity, information about peerings and node information that is shared with the network. There are also some module-specific options -related to TUN/TAP, multicast and the admin socket. +related to TUN, multicast and the admin socket. In order for a node to maintain the same identity across restarts, you should persist the configuration onto the filesystem or into some configuration storage @@ -70,8 +70,8 @@ type NodeConfig struct { SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."` 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."` - 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."` + IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` + IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN 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."` SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."` From 3a0870a448f0c1b43a4438a3b2ec9a92d4a4aec4 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 20:11:39 +0000 Subject: [PATCH 07/32] Fix IfName 'auto' behaviour on Windows --- src/tuntap/tun_windows.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 8b4f92cf..2afe2da6 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -9,6 +9,7 @@ import ( "strings" "unsafe" + "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "golang.org/x/sys/windows" wgtun "golang.zx2c4.com/wireguard/tun" @@ -19,6 +20,9 @@ import ( // Configures the TUN adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { + if ifname == "auto" { + ifname = defaults.GetDefaults().IfName + } var err error err = doAsSystem(func() { iface, err := wgtun.CreateTUN(ifname, mtu) From baebaabc437cbe697abae3fcc3d00c25fd48efa0 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 22 Nov 2019 20:16:24 +0000 Subject: [PATCH 08/32] Fix typo --- src/tuntap/tun_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 2afe2da6..7cedfc85 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -21,7 +21,7 @@ import ( // Configures the TUN adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { if ifname == "auto" { - ifname = defaults.GetDefaults().IfName + ifname = defaults.GetDefaults().DefaultIfName } var err error err = doAsSystem(func() { From 0529910b01015332b0568342f82830baf52fe158 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 23 Nov 2019 13:34:27 +0000 Subject: [PATCH 09/32] Reuse GUID so Windows no longer keeps creating new networks each time Yggdrasil starts --- src/tuntap/tun_windows.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 7cedfc85..73ab398d 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -24,8 +24,13 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { ifname = defaults.GetDefaults().DefaultIfName } var err error + var iface wgtun.Device err = doAsSystem(func() { - iface, err := wgtun.CreateTUN(ifname, mtu) + if guid, gerr := windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); gerr == nil { + iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, mtu) + } else { + panic(gerr) + } if err != nil { panic(err) } From d0a307db97a7a6418844aa882cd9e52d25a575c2 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 23 Nov 2019 13:46:05 +0000 Subject: [PATCH 10/32] Use Wireguard's DoAsSystem, fix build tags and go.mod/go.sum --- go.mod | 8 ++-- go.sum | 21 ++++----- src/tuntap/tun_windows.go | 89 ++------------------------------------- 3 files changed, 18 insertions(+), 100 deletions(-) diff --git a/go.mod b/go.mod index 417e6fa3..6e57de50 100644 --- a/go.mod +++ b/go.mod @@ -9,14 +9,12 @@ require ( github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 github.com/mitchellh/mapstructure v1.1.2 - github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 - github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b // indirect github.com/vishvananda/netlink v1.0.0 github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect - github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/net v0.0.0-20191021144547-ec77196f6094 - golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb + golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339 golang.org/x/text v0.3.2 - golang.zx2c4.com/wireguard v0.0.20191012 + golang.zx2c4.com/wireguard v0.0.20191013-0.20191022095125-f7d0edd2ecf5 + golang.zx2c4.com/wireguard/windows v0.0.35 ) diff --git a/go.sum b/go.sum index 222728a1..c1dc2b78 100644 --- a/go.sum +++ b/go.sum @@ -8,18 +8,16 @@ github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible h1:b github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 h1:YnZmFjg0Nvk8851WTVWlqMC1ecJH07Ctz+Ezxx4u54g= github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0/go.mod h1:rUi0/YffDo1oXBOGn1KRq7Fr07LX48XEBecQnmwjsAo= +github.com/lxn/walk v0.0.0-20191024161928-0ee7d2cded97 h1:3zBUhgnxeLyaImKEtPfKWipiHyI5zYp/V2NN967zPFo= +github.com/lxn/walk v0.0.0-20191024161928-0ee7d2cded97/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20191024121223-cc00c7492fe1 h1:h0wbuSK8xUNmMwDdCxZx2OLdkVck6Bb31zj4CxCN5I4= +github.com/lxn/win v0.0.0-20191024121223-cc00c7492fe1/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w= -github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY= -github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c= -github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM= github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I= github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -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= @@ -30,12 +28,15 @@ golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+T 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-20190904154756-749cb33beabd/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/sys v0.0.0-20191025090151-53bf42e6b339 h1:zSqWKgm/o7HAnlAzBQ+aetp9fpuyytsXnKA8eiLHYQM= +golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/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= +golang.zx2c4.com/wireguard v0.0.20191013-0.20191022095125-f7d0edd2ecf5 h1:tijV0YMbg6JbCA9TNaNVjAK2+6KefpNwF4coc6UkNkQ= +golang.zx2c4.com/wireguard v0.0.20191013-0.20191022095125-f7d0edd2ecf5/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= +golang.zx2c4.com/wireguard/windows v0.0.35 h1:egyV5IRbpKr78b+9gkB8AMQ32TtCo0NO//rfh10OSDg= +golang.zx2c4.com/wireguard/windows v0.0.35/go.mod h1:A3MmRXpatlao+Zty3Zxe2nqZ/sQCGYvnMVZ4z7TQY2w= diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 73ab398d..0a14768d 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -1,3 +1,5 @@ +// +build windows + package tuntap import ( @@ -5,14 +7,12 @@ import ( "errors" "log" "net" - "runtime" - "strings" - "unsafe" "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" ) @@ -25,7 +25,7 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { } var err error var iface wgtun.Device - err = doAsSystem(func() { + err = elevate.DoAsSystem(func() { if guid, gerr := windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); gerr == nil { iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, mtu) } else { @@ -107,87 +107,6 @@ func (tun *TunAdapter) setupAddress(addr string) error { return nil } -/* - * doAsSystem - * SPDX-License-Identifier: LGPL-3.0 - * Copyright (C) 2017-2019 Jason A. Donenfeld . All Rights Reserved. - */ -func doAsSystem(f func()) error { - runtime.LockOSThread() - defer func() { - windows.RevertToSelf() - runtime.UnlockOSThread() - }() - privileges := windows.Tokenprivileges{ - PrivilegeCount: 1, - Privileges: [1]windows.LUIDAndAttributes{ - { - Attributes: windows.SE_PRIVILEGE_ENABLED, - }, - }, - } - err := windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr("SeDebugPrivilege"), &privileges.Privileges[0].Luid) - if err != nil { - return err - } - err = windows.ImpersonateSelf(windows.SecurityImpersonation) - if err != nil { - return err - } - var threadToken windows.Token - err = windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES, false, &threadToken) - if err != nil { - return err - } - defer threadToken.Close() - err = windows.AdjustTokenPrivileges(threadToken, false, &privileges, uint32(unsafe.Sizeof(privileges)), nil, nil) - if err != nil { - return err - } - - processes, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) - if err != nil { - return err - } - defer windows.CloseHandle(processes) - - processEntry := windows.ProcessEntry32{Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{}))} - pid := uint32(0) - for err = windows.Process32First(processes, &processEntry); err == nil; err = windows.Process32Next(processes, &processEntry) { - if strings.ToLower(windows.UTF16ToString(processEntry.ExeFile[:])) == "winlogon.exe" { - pid = processEntry.ProcessID - break - } - } - if pid == 0 { - return errors.New("unable to find winlogon.exe process") - } - - winlogonProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid) - if err != nil { - return err - } - defer windows.CloseHandle(winlogonProcess) - var winlogonToken windows.Token - err = windows.OpenProcessToken(winlogonProcess, windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE, &winlogonToken) - if err != nil { - return err - } - defer winlogonToken.Close() - var duplicatedToken windows.Token - err = windows.DuplicateTokenEx(winlogonToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken) - if err != nil { - return err - } - defer duplicatedToken.Close() - err = windows.SetThreadToken(nil, duplicatedToken) - if err != nil { - return err - } - f() - return nil -} - /* * cleanupAddressesOnDisconnectedInterfaces * SPDX-License-Identifier: MIT From 746fac6594217d3a3cef7379e0fb8636b6498ad2 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 23 Nov 2019 13:56:48 +0000 Subject: [PATCH 11/32] Fix go.mod/go.sum again and update DoAsSystem call --- go.mod | 10 +++++----- go.sum | 26 ++++++++++++++------------ src/tuntap/tun_windows.go | 27 +++++++++++++-------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 6e57de50..c11ccdf7 100644 --- a/go.mod +++ b/go.mod @@ -11,10 +11,10 @@ require ( github.com/mitchellh/mapstructure v1.1.2 github.com/vishvananda/netlink v1.0.0 github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 - golang.org/x/net v0.0.0-20191021144547-ec77196f6094 - golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339 + golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c + golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914 + golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e golang.org/x/text v0.3.2 - golang.zx2c4.com/wireguard v0.0.20191013-0.20191022095125-f7d0edd2ecf5 - golang.zx2c4.com/wireguard/windows v0.0.35 + golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1 + golang.zx2c4.com/wireguard/windows v0.0.35-0.20191123133119-cb4a03094c25 ) diff --git a/go.sum b/go.sum index c1dc2b78..9a61fd2c 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,7 @@ github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible h1:b github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 h1:YnZmFjg0Nvk8851WTVWlqMC1ecJH07Ctz+Ezxx4u54g= github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0/go.mod h1:rUi0/YffDo1oXBOGn1KRq7Fr07LX48XEBecQnmwjsAo= -github.com/lxn/walk v0.0.0-20191024161928-0ee7d2cded97 h1:3zBUhgnxeLyaImKEtPfKWipiHyI5zYp/V2NN967zPFo= -github.com/lxn/walk v0.0.0-20191024161928-0ee7d2cded97/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/walk v0.0.0-20191031081659-c0bb82ae46cb/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= github.com/lxn/win v0.0.0-20191024121223-cc00c7492fe1 h1:h0wbuSK8xUNmMwDdCxZx2OLdkVck6Bb31zj4CxCN5I4= github.com/lxn/win v0.0.0-20191024121223-cc00c7492fe1/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -20,23 +19,26 @@ github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHS github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= 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/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914 h1:MlY3mEfbnWGmUi4rtHOtNnnnN4UJRGSyLPx+DXA5Sq4= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339 h1:zSqWKgm/o7HAnlAzBQ+aetp9fpuyytsXnKA8eiLHYQM= -golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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.20191013-0.20191022095125-f7d0edd2ecf5 h1:tijV0YMbg6JbCA9TNaNVjAK2+6KefpNwF4coc6UkNkQ= -golang.zx2c4.com/wireguard v0.0.20191013-0.20191022095125-f7d0edd2ecf5/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= -golang.zx2c4.com/wireguard/windows v0.0.35 h1:egyV5IRbpKr78b+9gkB8AMQ32TtCo0NO//rfh10OSDg= -golang.zx2c4.com/wireguard/windows v0.0.35/go.mod h1:A3MmRXpatlao+Zty3Zxe2nqZ/sQCGYvnMVZ4z7TQY2w= +golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1 h1:KxtBKNgJUQG8vwZzJKkwBGOcqp95xLu6A6KIMde1kl0= +golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= +golang.zx2c4.com/wireguard/windows v0.0.35-0.20191123133119-cb4a03094c25 h1:TreP+furSwdqoSToFrwb1S5cwxb7jhOsnwj2MsDeT+4= +golang.zx2c4.com/wireguard/windows v0.0.35-0.20191123133119-cb4a03094c25/go.mod h1:EO8KCpT944a9CnwHJLZ1sl84FfIrY42fP/fcXUuYhKM= diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 0a14768d..9b5f7b0c 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -23,31 +23,30 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { if ifname == "auto" { ifname = defaults.GetDefaults().DefaultIfName } - var err error - var iface wgtun.Device - err = elevate.DoAsSystem(func() { - if guid, gerr := windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); gerr == nil { - iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, mtu) - } else { - panic(gerr) + 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 err != nil { - panic(err) + if iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, mtu); err != nil { + return err } tun.iface = iface - - if err := tun.setupAddress(addr); err != nil { + 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 { + 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 = mtu } + return nil }) - return err } // Sets the MTU of the TAP adapter. From 6560aac1e9eb3b3d3c1f0ef29ae8ecdf8a34a767 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 24 Nov 2019 13:42:56 -0600 Subject: [PATCH 12/32] fix error spam on shutdown --- src/tuntap/iface.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index fbb7c86d..f80ea4f4 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -57,9 +57,9 @@ func (r *tunReader) _read() { 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) + ferr := r.tun.iface.Flush() + if ferr != nil { + r.tun.log.Errorln("Unable to flush packets:", ferr) } util.PutBytes(recvd) } else { From f6f9b3ef76bd967ac7ef7fa1a957eb6b3f0c2b82 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 24 Nov 2019 15:01:20 -0600 Subject: [PATCH 13/32] include offset in expected bytes written --- src/tuntap/iface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index f80ea4f4..f1ca0add 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -40,7 +40,7 @@ func (w *tunWriter) _write(b []byte) { } }) } - if written != n { + if written != n+TUN_OFFSET_BYTES { w.tun.log.Errorln("TUN iface write mismatch:", written, "bytes written vs", n, "bytes given") } } From 85c5bc61ac39169f96b9c853d63e165823a014e1 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 24 Nov 2019 21:03:02 +0000 Subject: [PATCH 14/32] TUN_OFFSET_BYTES per platform --- src/tuntap/iface.go | 2 -- src/tuntap/tun_bsd.go | 2 ++ src/tuntap/tun_darwin.go | 2 ++ src/tuntap/tun_linux.go | 2 ++ src/tuntap/tun_other.go | 2 ++ src/tuntap/tun_windows.go | 4 +++- 6 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index f1ca0add..633903da 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -9,8 +9,6 @@ import ( "github.com/Arceliar/phony" ) -const TUN_OFFSET_BYTES = 4 - type tunWriter struct { phony.Inbox tun *TunAdapter diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 219e3485..79184cb9 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -15,6 +15,8 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) +const TUN_OFFSET_BYTES = 0 + const SIOCSIFADDR_IN6 = (0x80000000) | ((288 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 12 type in6_addrlifetime struct { diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index cf2fbfb4..4dab6f31 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -15,6 +15,8 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) +const TUN_OFFSET_BYTES = 0 + // Configures the "utun" adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { if ifname == "auto" { diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index 4206b26a..ca402522 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -9,6 +9,8 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) +const TUN_OFFSET_BYTES = 0 + // Configures the TUN adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { if ifname == "auto" { diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index 8a27f57b..85934f39 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -9,6 +9,8 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) +const TUN_OFFSET_BYTES = 0 + // 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) diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 9b5f7b0c..e611af76 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -2,6 +2,8 @@ package tuntap +// This is to catch Windows platforms + import ( "bytes" "errors" @@ -16,7 +18,7 @@ import ( "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" ) -// This is to catch Windows platforms +const TUN_OFFSET_BYTES = 4 // Configures the TUN adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { From 2982b53555c54eb1952a52ad3788f9375ad9fe52 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 24 Nov 2019 15:09:28 -0600 Subject: [PATCH 15/32] make offset generic over TUN_OFFSET_BYTES so we can make this platform dependent --- src/tuntap/iface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index f1ca0add..5eca3aed 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -31,7 +31,7 @@ func (w *tunWriter) _write(b []byte) { if n == 0 { return } - written, err = w.tun.iface.Write(append([]byte{0, 0, 0, 0}, b[:n]...), TUN_OFFSET_BYTES) + written, err = w.tun.iface.Write(append(make([]byte, TUN_OFFSET_BYTES), b[:n]...), TUN_OFFSET_BYTES) util.PutBytes(b) if err != nil { w.tun.Act(w, func() { From 8f323b740d7171120b6619b320a77973b2ea7d6b Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 24 Nov 2019 21:09:29 +0000 Subject: [PATCH 16/32] Revert "TUN_OFFSET_BYTES per platform" This reverts commit 85c5bc61ac39169f96b9c853d63e165823a014e1. --- src/tuntap/iface.go | 2 ++ src/tuntap/tun_bsd.go | 2 -- src/tuntap/tun_darwin.go | 2 -- src/tuntap/tun_linux.go | 2 -- src/tuntap/tun_other.go | 2 -- src/tuntap/tun_windows.go | 4 +--- 6 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 633903da..f1ca0add 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -9,6 +9,8 @@ import ( "github.com/Arceliar/phony" ) +const TUN_OFFSET_BYTES = 4 + type tunWriter struct { phony.Inbox tun *TunAdapter diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 79184cb9..219e3485 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -15,8 +15,6 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) -const TUN_OFFSET_BYTES = 0 - const SIOCSIFADDR_IN6 = (0x80000000) | ((288 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 12 type in6_addrlifetime struct { diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index 4dab6f31..cf2fbfb4 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -15,8 +15,6 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) -const TUN_OFFSET_BYTES = 0 - // Configures the "utun" adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { if ifname == "auto" { diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index ca402522..4206b26a 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -9,8 +9,6 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) -const TUN_OFFSET_BYTES = 0 - // Configures the TUN adapter with the correct IPv6 address and MTU. func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error { if ifname == "auto" { diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index 85934f39..8a27f57b 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -9,8 +9,6 @@ import ( wgtun "golang.zx2c4.com/wireguard/tun" ) -const TUN_OFFSET_BYTES = 0 - // 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) diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index e611af76..9b5f7b0c 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -2,8 +2,6 @@ package tuntap -// This is to catch Windows platforms - import ( "bytes" "errors" @@ -18,7 +16,7 @@ import ( "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" ) -const TUN_OFFSET_BYTES = 4 +// 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 int) error { From 2e95a3131c86389ff2e49c1d5e2c534a50d4eb97 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 24 Nov 2019 15:37:37 -0600 Subject: [PATCH 17/32] comment out pointless error that prints on some platforms and not others --- src/tuntap/iface.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 5eca3aed..463f48f0 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -31,7 +31,7 @@ func (w *tunWriter) _write(b []byte) { if n == 0 { return } - written, err = w.tun.iface.Write(append(make([]byte, TUN_OFFSET_BYTES), b[:n]...), TUN_OFFSET_BYTES) + written, err = w.tun.iface.Write(append(make([]byte, TUN_OFFSET_BYTES), b...), TUN_OFFSET_BYTES) util.PutBytes(b) if err != nil { w.tun.Act(w, func() { @@ -41,7 +41,8 @@ func (w *tunWriter) _write(b []byte) { }) } if written != n+TUN_OFFSET_BYTES { - w.tun.log.Errorln("TUN iface write mismatch:", written, "bytes written vs", n, "bytes given") + // FIXME some platforms return the wrong number of bytes written, causing error spam + //w.tun.log.Errorln("TUN iface write mismatch:", written, "bytes written vs", n+TUN_OFFSET_BYTES, "bytes given") } } From 837e7da7921d78aa58f6e1a10220184d99d3f6e7 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 25 Nov 2019 20:13:41 +0000 Subject: [PATCH 18/32] Force packets through the switch to be buffered (seems to help the reordering problem on Windows) --- src/yggdrasil/switch.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index ba30758c..5d355041 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -718,8 +718,14 @@ func (t *switchTable) _handleIn(packet []byte, idle map[switchPort]struct{}, sen if best != nil { if _, isIdle := idle[best.elem.port]; isIdle { delete(idle, best.elem.port) - ports[best.elem.port].sendPacketsFrom(t, [][]byte{packet}) - return true + + // FIXME: This was causing the out-of-order packets on Windows but forcing + // all packets to buffer might have a mild performance penalty + //ports[best.elem.port].sendPacketsFrom(t, [][]byte{packet}) + //return true + t.Act(nil, func() { + t._idleIn(best.elem.port) + }) } } // Didn't find anyone idle to send it to From ad8d30ce74bc90eb9363bf5a341933a2972b892a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 26 Nov 2019 09:44:35 +0000 Subject: [PATCH 19/32] Revert "Force packets through the switch to be buffered (seems to help the reordering problem on Windows)" This reverts commit 837e7da7921d78aa58f6e1a10220184d99d3f6e7. --- src/yggdrasil/switch.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index d0a9f4e0..ab888a76 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -718,14 +718,8 @@ func (t *switchTable) _handleIn(packet []byte, idle map[switchPort]struct{}, sen if best != nil { if _, isIdle := idle[best.elem.port]; isIdle { delete(idle, best.elem.port) - - // FIXME: This was causing the out-of-order packets on Windows but forcing - // all packets to buffer might have a mild performance penalty - //ports[best.elem.port].sendPacketsFrom(t, [][]byte{packet}) - //return true - t.Act(nil, func() { - t._idleIn(best.elem.port) - }) + ports[best.elem.port].sendPacketsFrom(t, [][]byte{packet}) + return true } } // Didn't find anyone idle to send it to From e1b0d0f20c546a905a701bbfef181fe109791a2a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 00:35:29 +0000 Subject: [PATCH 20/32] Appveyor MSI builds for Windows (#621) * Try appveyor for MSI (not finished) * build-msi.sh * Don't shallow clone * Don't set clone depth * Build Yggdrasil for each arch * Try to get rest of branches * Allow upgrades (hopefully) * Try using MajorUpgrade * AllowDowngrades * Try harder to build x86 :-) * Bugfix * Bugfix * AllowSameVersionUpgrades * AllowSameVersionUpgrades * Generate new GUID for each build (might fix upgrades) --- appveyor.yml | 23 +++++ contrib/msi/build-msi.sh | 189 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 appveyor.yml create mode 100644 contrib/msi/build-msi.sh diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..1389bebe --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +version: '{build}' +pull_requests: + do_not_increment_build_number: true +os: Visual Studio 2017 +shallow_clone: false + +environment: + MSYS2_PATH_TYPE: inherit + CHERE_INVOKING: enabled_from_arguments + +install: +- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S curl unzip" + +build_script: +- cmd: >- + cd \projects\yggdrasil-go +- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x64" +- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x86" + +test: off + +artifacts: +- path: '*.msi' diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh new file mode 100644 index 00000000..d314b0c6 --- /dev/null +++ b/contrib/msi/build-msi.sh @@ -0,0 +1,189 @@ +#!/bin/sh + +# Get arch from command line if given +PKGARCH=$1 +if [ "${PKGARCH}" == "" ]; +then + echo "tell me the architecture: x86 or x64" + exit 1 +fi + +# Get the rest of the repository history +if [ "${APPVEYOR_REPO_BRANCH}" != "" ]; +then + git fetch --all + git checkout ${APPVEYOR_REPO_BRANCH} +fi + +# Install prerequisites +pacman -S --needed --noconfirm unzip git curl +# export PATH=$PATH:/c/go/bin/ + +# Download the wix tools! +if [ ! -d wixbin ]; +then + curl -LO https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip + if [ `md5sum wix311-binaries.zip | cut -f 1 -d " "` != "47a506f8ab6666ee3cc502fb07d0ee2a" ]; + then + echo "wix package didn't match expected checksum" + exit 1 + fi + mkdir -p wixbin + unzip -o wix311-binaries.zip -d wixbin || ( + echo "failed to unzip WiX" + exit 1 + ) +fi + +# Check the prerequisite files are in place +[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build + +# Create the postinstall script +cat > config.bat << EOF +if exist yggdrasil.conf ( + move yggdrasil.conf yggdrasil.conf.backup + yggdrasil.exe -useconffile yggdrasil.conf.backup -normaliseconf > yggdrasil.conf +) else ( + yggdrasil.exe -genconf > yggdrasil.conf +) +EOF + +# Work out metadata for the package info +PKGNAME=$(sh contrib/semver/name.sh) +PKGVERSION=$(sh contrib/semver/version.sh --bare) +PKGVERSIONMS=$(echo $PKGVERSION | tr - .) +[ "${PKGARCH}" == "x64" ] && \ + PKGGUID="77757838-1a23-40a5-a720-c3b43e0260cc" PKGINSTFOLDER="ProgramFiles64Folder" || \ + PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder" + +# Download the Wintun driver +if [ $PKGARCH = "x64" ]; then + PKGMSMNAME=wintun-x64.msm + curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-amd64-0.7.msm || (echo "couldn't get wintun"; exit 1) +elif [ $PKGARCH = "x86" ]; then + PKGMSMNAME=wintun-x86.msm + curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-x86-0.7.msm || (echo "couldn't get wintun"; exit 1) +else + echo "wasn't sure which architecture to get wintun for" + exit 1 +fi + +# Generate the wix.xml file +cat > wix.xml << EOF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EOF + +# Generate the MSI +CANDLEFLAGS="-nologo" +LIGHTFLAGS="-nologo -spdb -sice:ICE71 -sice:ICE61" +wixbin/candle $CANDLEFLAGS -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj -arch ${PKGARCH} wix.xml && \ +wixbin/light $LIGHTFLAGS -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.msi ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj From 41a2e731eb61a274b16b16f4a764fc2665d460d7 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 09:52:14 +0000 Subject: [PATCH 21/32] More MSI updates (#622) * Try embedding config script * Update config when installing * Don't update config on uninstall --- contrib/msi/build-msi.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index d314b0c6..de459e54 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -147,7 +147,7 @@ cat > wix.xml << EOF @@ -168,14 +168,16 @@ cat > wix.xml << EOF + ExeCommand="cmd.exe /c updateconfig.bat" + Execute="immediate" + Return="asyncWait" /> + After="InstallFiles"> + NOT Installed AND NOT REMOVE + From b88a623a9f79414e8375e813d50ce6c92f9c1f8c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 09:56:14 +0000 Subject: [PATCH 22/32] Handle pull request branch --- contrib/msi/build-msi.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index de459e54..aecd034f 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -9,7 +9,11 @@ then fi # Get the rest of the repository history -if [ "${APPVEYOR_REPO_BRANCH}" != "" ]; +if [ "${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH}" != "" ]; +then + git fetch --all + git checkout ${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH} +elif [ "${APPVEYOR_REPO_BRANCH}" != "" ]; then git fetch --all git checkout ${APPVEYOR_REPO_BRANCH} From a673625e82516c13e7514a9fd607b9a2c42d0c09 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 10:08:01 +0000 Subject: [PATCH 23/32] Configure service with -useconffile --- contrib/msi/build-msi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index aecd034f..22eab223 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -128,7 +128,7 @@ cat > wix.xml << EOF Name="yggdrasil" Start="auto" Type="ownProcess" - Arguments="-autoconf" + Arguments='-useconffile "[YggdrasilInstallFolder]yggdrasil.conf"' Vital="yes" /> Date: Thu, 28 Nov 2019 10:19:47 +0000 Subject: [PATCH 24/32] Fix update action --- contrib/msi/build-msi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 22eab223..ed2b6815 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -173,7 +173,7 @@ cat > wix.xml << EOF Id="UpdateGenerateConfig" Directory="YggdrasilInstallFolder" ExeCommand="cmd.exe /c updateconfig.bat" - Execute="immediate" + Execute="commit" Return="asyncWait" /> From 724446bb04f487455d69f08a0abe1b59814dd444 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 10:42:57 +0000 Subject: [PATCH 25/32] Defer updateconfig --- contrib/msi/build-msi.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index ed2b6815..20f9e9b8 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -45,6 +45,7 @@ fi # Create the postinstall script cat > config.bat << EOF + if exist yggdrasil.conf ( move yggdrasil.conf yggdrasil.conf.backup yggdrasil.exe -useconffile yggdrasil.conf.backup -normaliseconf > yggdrasil.conf @@ -173,8 +174,8 @@ cat > wix.xml << EOF Id="UpdateGenerateConfig" Directory="YggdrasilInstallFolder" ExeCommand="cmd.exe /c updateconfig.bat" - Execute="commit" - Return="asyncWait" /> + Execute="deferred" + Return="check" /> Date: Thu, 28 Nov 2019 10:56:22 +0000 Subject: [PATCH 26/32] Set output logging --- contrib/msi/build-msi.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 20f9e9b8..3f2501d5 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -129,7 +129,7 @@ cat > wix.xml << EOF Name="yggdrasil" Start="auto" Type="ownProcess" - Arguments='-useconffile "[YggdrasilInstallFolder]yggdrasil.conf"' + Arguments='-useconffile "[YggdrasilInstallFolder]yggdrasil.conf" -logto "[YggdrasilInstallFolder]yggdrasil.log"' Vital="yes" /> wix.xml << EOF - + + - Date: Thu, 28 Nov 2019 11:16:36 +0000 Subject: [PATCH 27/32] Don't impersonate user for updateconfig.bat --- contrib/msi/build-msi.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 3f2501d5..c4646ae5 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -179,12 +179,13 @@ cat > wix.xml << EOF Directory="YggdrasilInstallFolder" ExeCommand="cmd.exe /c updateconfig.bat" Execute="deferred" + Impersonate="no" Return="check" /> + Before="InstallServices"> NOT Installed AND NOT REMOVE From 9c113c05bf462b96e4d69ea0b569cb4da6a57e3c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 12:57:19 +0000 Subject: [PATCH 28/32] Use appveyor build folder in case slugs are different --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1389bebe..bd0948de 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ install: build_script: - cmd: >- - cd \projects\yggdrasil-go + cd %APPVEYOR_BUILD_FOLDER% - c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x64" - c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x86" From 3f29a2ff0566879e421c93a0c879a094ff9b29d8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 13:00:52 +0000 Subject: [PATCH 29/32] Some comments --- contrib/msi/build-msi.sh | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index c4646ae5..5daa003b 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -1,5 +1,12 @@ #!/bin/sh +# This script generates an MSI file for Yggdrasil for a given architecture. It +# needs to run on Windows within MSYS2 and Go 1.13 or later must be installed on +# the system and within the PATH. This is ran currently by Appveyor (see +# appveyor.yml in the repository root) for both x86 and x64. +# +# Author: Neil Alexander + # Get arch from command line if given PKGARCH=$1 if [ "${PKGARCH}" == "" ]; @@ -8,7 +15,9 @@ then exit 1 fi -# Get the rest of the repository history +# Get the rest of the repository history. This is needed within Appveyor because +# otherwise we don't get all of the branch histories and therefore the semver +# scripts don't work properly. if [ "${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH}" != "" ]; then git fetch --all @@ -19,9 +28,8 @@ then git checkout ${APPVEYOR_REPO_BRANCH} fi -# Install prerequisites +# Install prerequisites within MSYS2 pacman -S --needed --noconfirm unzip git curl -# export PATH=$PATH:/c/go/bin/ # Download the wix tools! if [ ! -d wixbin ]; @@ -39,13 +47,12 @@ then ) fi -# Check the prerequisite files are in place +# Build Yggdrasil! [ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build [ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build # Create the postinstall script cat > config.bat << EOF - if exist yggdrasil.conf ( move yggdrasil.conf yggdrasil.conf.backup yggdrasil.exe -useconffile yggdrasil.conf.backup -normaliseconf > yggdrasil.conf From c17c4af26d9c0a41ce7a6dd23aa35d4eb762ce09 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 13:08:56 +0000 Subject: [PATCH 30/32] Don't normalise on upgrade --- contrib/msi/build-msi.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 5daa003b..5d8eb7db 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -53,10 +53,7 @@ fi # Create the postinstall script cat > config.bat << EOF -if exist yggdrasil.conf ( - move yggdrasil.conf yggdrasil.conf.backup - yggdrasil.exe -useconffile yggdrasil.conf.backup -normaliseconf > yggdrasil.conf -) else ( +if not exist yggdrasil.conf ( yggdrasil.exe -genconf > yggdrasil.conf ) EOF From 71404f5270174d157aa624235713033ef2926f3d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 28 Nov 2019 15:17:49 +0000 Subject: [PATCH 31/32] Clean up appveyor.yml --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index bd0948de..58724a24 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,9 +8,6 @@ environment: MSYS2_PATH_TYPE: inherit CHERE_INVOKING: enabled_from_arguments -install: -- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S curl unzip" - build_script: - cmd: >- cd %APPVEYOR_BUILD_FOLDER% From c2a8b4bb5767b35974d45dad6777187616553131 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 28 Nov 2019 12:00:00 -0600 Subject: [PATCH 32/32] get rid of an allocation in tunWriter's _write --- src/tuntap/iface.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 463f48f0..5efbc8a7 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -25,14 +25,16 @@ 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 func (w *tunWriter) _write(b []byte) { + defer util.PutBytes(b) var written int var err error n := len(b) if n == 0 { return } - written, err = w.tun.iface.Write(append(make([]byte, TUN_OFFSET_BYTES), b...), TUN_OFFSET_BYTES) - util.PutBytes(b) + temp := append(util.ResizeBytes(util.GetBytes(), TUN_OFFSET_BYTES), b...) + defer util.PutBytes(temp) + written, err = w.tun.iface.Write(temp, TUN_OFFSET_BYTES) if err != nil { w.tun.Act(w, func() { if !w.tun.isOpen {