mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-30 13:35:19 +00:00
Drop Water, use Wireguard tun library, drop TAP support
This commit is contained in:
parent
07ce8cde7a
commit
f5517acc81
1
go.mod
1
go.mod
@ -18,4 +18,5 @@ require (
|
|||||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094
|
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-20191024172528-b4ff53e7a1cb
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
|
golang.zx2c4.com/wireguard v0.0.20191012
|
||||||
)
|
)
|
||||||
|
5
go.sum
5
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 h1:YY9Pg2BEp0jeUVU60svTOaDr+fs1ySC9RbdC1Qc6wOw=
|
||||||
github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8/go.mod h1:R0SBCsugm+Sf1katgTb2t7GXMm+nRIv43tM4VDZbaOs=
|
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-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 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
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-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 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-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-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-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 h1:ZxSglHghKPYD8WDeRUzRJrUJtDF0PxsTUSxyqr9/5BI=
|
||||||
golang.org/x/sys v0.0.0-20191024172528-b4ff53e7a1cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
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/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.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=
|
||||||
|
@ -71,7 +71,6 @@ type NodeConfig struct {
|
|||||||
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this 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."`
|
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."`
|
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."`
|
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."`
|
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."`
|
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.MulticastInterfaces = defaults.GetDefaults().DefaultMulticastInterfaces
|
||||||
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
||||||
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
|
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
|
||||||
cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode
|
|
||||||
cfg.SessionFirewall.Enable = false
|
cfg.SessionFirewall.Enable = false
|
||||||
cfg.SessionFirewall.AllowFromDirect = true
|
cfg.SessionFirewall.AllowFromDirect = true
|
||||||
cfg.SessionFirewall.AllowFromRemote = true
|
cfg.SessionFirewall.AllowFromRemote = true
|
||||||
|
@ -14,8 +14,7 @@ type platformDefaultParameters struct {
|
|||||||
DefaultMulticastInterfaces []string
|
DefaultMulticastInterfaces []string
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU int
|
MaximumIfMTU int
|
||||||
DefaultIfMTU int
|
DefaultIfMTU int
|
||||||
DefaultIfName string
|
DefaultIfName string
|
||||||
DefaultIfTAPMode bool
|
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "auto",
|
DefaultIfName: "auto",
|
||||||
DefaultIfTAPMode: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 32767,
|
MaximumIfMTU: 32767,
|
||||||
DefaultIfMTU: 32767,
|
DefaultIfMTU: 32767,
|
||||||
DefaultIfName: "/dev/tap0",
|
DefaultIfName: "/dev/tap0",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "auto",
|
DefaultIfName: "auto",
|
||||||
DefaultIfTAPMode: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 9000,
|
MaximumIfMTU: 9000,
|
||||||
DefaultIfMTU: 9000,
|
DefaultIfMTU: 9000,
|
||||||
DefaultIfName: "/dev/tap0",
|
DefaultIfName: "/dev/tun0",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 16384,
|
MaximumIfMTU: 16384,
|
||||||
DefaultIfMTU: 16384,
|
DefaultIfMTU: 16384,
|
||||||
DefaultIfName: "/dev/tap0",
|
DefaultIfName: "/dev/tun0",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "none",
|
DefaultIfName: "none",
|
||||||
DefaultIfTAPMode: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
DefaultIfMTU: 65535,
|
DefaultIfMTU: 65535,
|
||||||
DefaultIfName: "auto",
|
DefaultIfName: "auto",
|
||||||
DefaultIfTAPMode: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,8 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
return admin.Info{
|
return admin.Info{
|
||||||
t.iface.Name(): admin.Info{
|
t.Name(): admin.Info{
|
||||||
"tap_mode": t.iface.IsTAP(),
|
"mtu": t.mtu,
|
||||||
"mtu": t.mtu,
|
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
|
@ -11,32 +11,16 @@ package tuntap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/icmp"
|
"golang.org/x/net/icmp"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const len_ETHER = 14
|
const len_ETHER = 14
|
||||||
|
|
||||||
type ICMPv6 struct {
|
type ICMPv6 struct {
|
||||||
tun *TunAdapter
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal returns the binary encoding of h.
|
// Marshal returns the binary encoding of h.
|
||||||
@ -61,182 +45,6 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
|
|||||||
// addresses.
|
// addresses.
|
||||||
func (i *ICMPv6) Init(t *TunAdapter) {
|
func (i *ICMPv6) Init(t *TunAdapter) {
|
||||||
i.tun = t
|
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
|
// 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
|
// Send it back
|
||||||
return responsePacket, nil
|
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
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/songgao/packets/ethernet"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
@ -14,6 +9,8 @@ import (
|
|||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const TUN_OFFSET_BYTES = 4
|
||||||
|
|
||||||
type tunWriter struct {
|
type tunWriter struct {
|
||||||
phony.Inbox
|
phony.Inbox
|
||||||
tun *TunAdapter
|
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) {
|
func (w *tunWriter) _write(b []byte) {
|
||||||
var written int
|
var written int
|
||||||
var err error
|
var err error
|
||||||
@ -33,72 +31,17 @@ func (w *tunWriter) _write(b []byte) {
|
|||||||
if n == 0 {
|
if n == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if w.tun.iface.IsTAP() {
|
written, err = w.tun.iface.Write(append([]byte{0, 0, 0, 0}, b[:n]...), TUN_OFFSET_BYTES)
|
||||||
sendndp := func(dstAddr address.Address) {
|
util.PutBytes(b)
|
||||||
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)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.tun.Act(w, func() {
|
w.tun.Act(w, func() {
|
||||||
if !w.tun.isOpen {
|
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 {
|
if written-TUN_OFFSET_BYTES != n {
|
||||||
w.tun.log.Errorln("TUN/TAP iface write mismatch:", written, "bytes written vs", n, "bytes given")
|
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() {
|
func (r *tunReader) _read() {
|
||||||
// Get a slice to store the packet in
|
// Get a slice to store the packet in
|
||||||
recvd := util.ResizeBytes(util.GetBytes(), 65535+tun_ETHER_HEADER_LENGTH)
|
recvd := util.ResizeBytes(util.GetBytes(), r.tun.mtu+TUN_OFFSET_BYTES)
|
||||||
// Wait for a packet to be delivered to us through the TUN/TAP adapter
|
// Wait for a packet to be delivered to us through the TUN adapter
|
||||||
n, err := r.tun.iface.Read(recvd)
|
n, err := r.tun.iface.Read(recvd, TUN_OFFSET_BYTES)
|
||||||
if n <= 0 {
|
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)
|
util.PutBytes(recvd)
|
||||||
} else {
|
} else {
|
||||||
r.tun.handlePacketFrom(r, recvd[:n], err)
|
r.tun.handlePacketFrom(r, recvd[TUN_OFFSET_BYTES:n+TUN_OFFSET_BYTES], err)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Now read again
|
// 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
|
// does the work of reading a packet and sending it to the correct tunConn
|
||||||
func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("TUN/TAP iface read error:", err)
|
tun.log.Errorln("TUN iface read error:", err)
|
||||||
return
|
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
|
// Offset the buffer from now on so that we can ignore ethernet frames if
|
||||||
// they are present
|
// 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
|
// Check if the packet is long enough to detect if it's an ICMP packet or not
|
||||||
if len(bs) < 7 {
|
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
|
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
|
// 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
|
// and node IDs are. We will need these in order to work out where to send
|
||||||
// the packet
|
// the packet
|
||||||
@ -181,7 +103,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
|||||||
if bs[0]&0xf0 == 0x60 {
|
if bs[0]&0xf0 == 0x60 {
|
||||||
// Check if we have a fully-sized IPv6 header
|
// Check if we have a fully-sized IPv6 header
|
||||||
if len(bs) < 40 {
|
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
|
return
|
||||||
}
|
}
|
||||||
// Check the packet size
|
// Check the packet size
|
||||||
@ -195,7 +117,7 @@ func (tun *TunAdapter) _handlePacket(recvd []byte, err error) {
|
|||||||
} else if bs[0]&0xf0 == 0x40 {
|
} else if bs[0]&0xf0 == 0x40 {
|
||||||
// Check if we have a fully-sized IPv4 header
|
// Check if we have a fully-sized IPv4 header
|
||||||
if len(bs) < 20 {
|
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
|
return
|
||||||
}
|
}
|
||||||
// Check the packet size
|
// 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 {
|
if tc, err = tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
||||||
// Something went wrong when storing the connection, typically that
|
// Something went wrong when storing the connection, typically that
|
||||||
// something already exists for this address or subnet
|
// something already exists for this address or subnet
|
||||||
tun.log.Debugln("TUN/TAP iface wrap:", err)
|
tun.log.Debugln("TUN iface wrap:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, packet := range packets {
|
for _, packet := range packets {
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
|
|
||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
"github.com/gologme/log"
|
"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/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
@ -28,12 +28,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const tun_IPv6_HEADER_LENGTH = 40
|
const tun_IPv6_HEADER_LENGTH = 40
|
||||||
const tun_ETHER_HEADER_LENGTH = 14
|
|
||||||
|
|
||||||
// TunAdapter represents a running TUN/TAP interface and extends the
|
// TunAdapter represents a running TUN interface and extends the
|
||||||
// yggdrasil.Adapter type. In order to use the TUN/TAP adapter with Yggdrasil,
|
// yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you
|
||||||
// you should pass this object to the yggdrasil.SetRouterAdapter() function
|
// should pass this object to the yggdrasil.SetRouterAdapter() function before
|
||||||
// before calling yggdrasil.Start().
|
// calling yggdrasil.Start().
|
||||||
type TunAdapter struct {
|
type TunAdapter struct {
|
||||||
core *yggdrasil.Core
|
core *yggdrasil.Core
|
||||||
writer tunWriter
|
writer tunWriter
|
||||||
@ -48,7 +47,7 @@ type TunAdapter struct {
|
|||||||
ckr cryptokey
|
ckr cryptokey
|
||||||
icmpv6 ICMPv6
|
icmpv6 ICMPv6
|
||||||
mtu int
|
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
|
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
|
//mutex sync.RWMutex // Protects the below
|
||||||
addrToConn map[address.Address]*tunConn
|
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
|
// Gets the maximum supported MTU for the platform based on the defaults in
|
||||||
// defaults.GetDefaults().
|
// defaults.GetDefaults().
|
||||||
func getSupportedMTU(mtu int, istapmode bool) int {
|
func getSupportedMTU(mtu int) int {
|
||||||
if mtu < 1280 {
|
if mtu < 1280 {
|
||||||
return 1280
|
return 1280
|
||||||
}
|
}
|
||||||
if mtu > MaximumMTU(istapmode) {
|
if mtu > MaximumMTU() {
|
||||||
return MaximumMTU(istapmode)
|
return MaximumMTU()
|
||||||
}
|
}
|
||||||
return mtu
|
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
|
// Name returns the name of the adapter, e.g. "tun0". On Windows, this may
|
||||||
// return a canonical adapter name instead.
|
// return a canonical adapter name instead.
|
||||||
func (tun *TunAdapter) Name() string {
|
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
|
// 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
|
// the maximum value is determined by your platform. The returned value will
|
||||||
// never exceed that of MaximumMTU().
|
// never exceed that of MaximumMTU().
|
||||||
func (tun *TunAdapter) MTU() int {
|
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
|
// DefaultName gets the default TUN interface name for your platform.
|
||||||
// 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.
|
|
||||||
func DefaultName() string {
|
func DefaultName() string {
|
||||||
return defaults.GetDefaults().DefaultIfName
|
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.
|
// be as high as MaximumMTU(), depending on platform, but is never lower than 1280.
|
||||||
func DefaultMTU() int {
|
func DefaultMTU() int {
|
||||||
ehbytes := 0
|
return defaults.GetDefaults().DefaultIfMTU
|
||||||
if DefaultIsTAP() {
|
|
||||||
ehbytes = tun_ETHER_HEADER_LENGTH
|
|
||||||
}
|
|
||||||
return defaults.GetDefaults().DefaultIfMTU - ehbytes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultIsTAP returns true if the default adapter mode for the current
|
// MaximumMTU returns the maximum supported TUN interface MTU for your
|
||||||
// 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
|
|
||||||
// platform. This can be as high as 65535, depending on platform, but is never
|
// platform. This can be as high as 65535, depending on platform, but is never
|
||||||
// lower than 1280.
|
// lower than 1280.
|
||||||
func MaximumMTU(iftapmode bool) int {
|
func MaximumMTU() int {
|
||||||
ehbytes := 0
|
return defaults.GetDefaults().MaximumIfMTU
|
||||||
if iftapmode {
|
|
||||||
ehbytes = tun_ETHER_HEADER_LENGTH
|
|
||||||
}
|
|
||||||
return defaults.GetDefaults().MaximumIfMTU - ehbytes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// 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 {
|
func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log *log.Logger, options interface{}) error {
|
||||||
tunoptions, ok := options.(TunOptions)
|
tunoptions, ok := options.(TunOptions)
|
||||||
@ -145,7 +127,7 @@ func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log
|
|||||||
return nil
|
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.
|
// reader actor to handle packets on that interface.
|
||||||
func (tun *TunAdapter) Start() error {
|
func (tun *TunAdapter) Start() error {
|
||||||
var err error
|
var err error
|
||||||
@ -157,11 +139,11 @@ func (tun *TunAdapter) Start() error {
|
|||||||
|
|
||||||
func (tun *TunAdapter) _start() error {
|
func (tun *TunAdapter) _start() error {
|
||||||
if tun.isOpen {
|
if tun.isOpen {
|
||||||
return errors.New("TUN/TAP module is already started")
|
return errors.New("TUN module is already started")
|
||||||
}
|
}
|
||||||
current := tun.config.GetCurrent()
|
current := tun.config.GetCurrent()
|
||||||
if tun.config == nil || tun.listener == nil || tun.dialer == nil {
|
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
|
var boxPub crypto.BoxPubKey
|
||||||
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
||||||
@ -174,23 +156,19 @@ func (tun *TunAdapter) _start() error {
|
|||||||
tun.subnet = *address.SubnetForNodeID(nodeID)
|
tun.subnet = *address.SubnetForNodeID(nodeID)
|
||||||
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
|
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
|
||||||
if current.IfName == "none" || current.IfName == "dummy" {
|
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
|
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
|
return err
|
||||||
}
|
}
|
||||||
if tun.MTU() != current.IfMTU {
|
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.core.SetMaximumSessionMTU(uint16(tun.MTU()))
|
||||||
tun.isOpen = true
|
tun.isOpen = true
|
||||||
go tun.handler()
|
go tun.handler()
|
||||||
tun.reader.Act(nil, tun.reader._read) // Start the reader
|
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)
|
tun.ckr.init(tun)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -204,7 +182,7 @@ func (tun *TunAdapter) IsStarted() bool {
|
|||||||
return isOpen
|
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.
|
// read/write goroutines to handle packets on that interface.
|
||||||
func (tun *TunAdapter) Stop() error {
|
func (tun *TunAdapter) Stop() error {
|
||||||
var err error
|
var err error
|
||||||
@ -216,7 +194,7 @@ func (tun *TunAdapter) Stop() error {
|
|||||||
|
|
||||||
func (tun *TunAdapter) _stop() error {
|
func (tun *TunAdapter) _stop() error {
|
||||||
tun.isOpen = false
|
tun.isOpen = false
|
||||||
// by TUN/TAP, e.g. readers/writers, sessions
|
// by TUN, e.g. readers/writers, sessions
|
||||||
if tun.iface != nil {
|
if tun.iface != nil {
|
||||||
// Just in case we failed to start up the iface for some reason, this can apparently happen on Windows
|
// Just in case we failed to start up the iface for some reason, this can apparently happen on Windows
|
||||||
tun.iface.Close()
|
tun.iface.Close()
|
||||||
@ -224,16 +202,16 @@ func (tun *TunAdapter) _stop() error {
|
|||||||
return nil
|
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
|
// and then signals the various module goroutines to reconfigure themselves if
|
||||||
// needed.
|
// needed.
|
||||||
func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) {
|
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
|
// Replace the active configuration with the supplied one
|
||||||
tun.config.Replace(*config)
|
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
|
// 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
|
// 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.
|
// this doesn't actually happen in the real world yet.
|
||||||
@ -248,14 +226,14 @@ func (tun *TunAdapter) handler() error {
|
|||||||
// Accept the incoming connection
|
// Accept the incoming connection
|
||||||
conn, err := tun.listener.Accept()
|
conn, err := tun.listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("TUN/TAP connection accept error:", err)
|
tun.log.Errorln("TUN connection accept error:", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
phony.Block(tun, func() {
|
phony.Block(tun, func() {
|
||||||
if _, err := tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
if _, err := tun._wrap(conn.(*yggdrasil.Conn)); err != nil {
|
||||||
// Something went wrong when storing the connection, typically that
|
// Something went wrong when storing the connection, typically that
|
||||||
// something already exists for this address or subnet
|
// something already exists for this address or subnet
|
||||||
tun.log.Debugln("TUN/TAP handler wrap:", err)
|
tun.log.Debugln("TUN handler wrap:", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build openbsd freebsd netbsd
|
// +build openbsd freebsd
|
||||||
|
|
||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"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
|
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
|
ifru_addrlifetime in6_addrlifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the IPv6 address of the utun adapter. On all BSD platforms (FreeBSD,
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
// OpenBSD, NetBSD) an attempt is made to set the adapter properties by using
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
// a system socket and making syscalls to the kernel. This is not refined though
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
// 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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
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)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,22 +12,21 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"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.
|
// Configures the "utun" adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
if iftapmode {
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
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)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ar in6_aliasreq
|
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))
|
ar.ifra_prefixmask.sin6_len = uint8(unsafe.Sizeof(ar.ifra_prefixmask))
|
||||||
b := make([]byte, 16)
|
b := make([]byte, 16)
|
||||||
@ -104,7 +103,7 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME
|
ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME
|
||||||
|
|
||||||
var ir ifreq
|
var ir ifreq
|
||||||
copy(ir.ifr_name[:], tun.iface.Name())
|
copy(ir.ifr_name[:], tun.Name())
|
||||||
ir.ifru_mtu = uint32(tun.mtu)
|
ir.ifru_mtu = uint32(tun.mtu)
|
||||||
|
|
||||||
tun.log.Infof("Interface name: %s", ar.ifra_name)
|
tun.log.Infof("Interface name: %s", ar.ifra_name)
|
||||||
|
@ -6,31 +6,21 @@ package tuntap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
water "github.com/yggdrasil-network/water"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configures the TAP adapter with the correct IPv6 address and MTU.
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
var config water.Config
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
// Friendly output
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
tun.log.Infof("Interface name: %s", tun.iface.Name())
|
} else {
|
||||||
tun.log.Infof("Interface IPv6: %s", addr)
|
tun.mtu = 0
|
||||||
tun.log.Infof("Interface MTU: %d", tun.mtu)
|
}
|
||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,5 +46,9 @@ func (tun *TunAdapter) setupAddress(addr string) error {
|
|||||||
if err := netlink.LinkSetUp(nlintf); err != nil {
|
if err := netlink.LinkSetUp(nlintf); err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,26 @@
|
|||||||
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile
|
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!mobile
|
||||||
|
|
||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import water "github.com/yggdrasil-network/water"
|
|
||||||
|
|
||||||
// This is to catch unsupported platforms
|
// This is to catch unsupported platforms
|
||||||
// If your platform supports tun devices, you could try configuring it manually
|
// 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
|
import (
|
||||||
// no guarantees are made at this point on an unsupported platform.
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
)
|
||||||
var config water.Config
|
|
||||||
if iftapmode {
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
config = water.Config{DeviceType: water.TAP}
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
} else {
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
config = water.Config{DeviceType: water.TUN}
|
|
||||||
}
|
|
||||||
iface, err := water.New(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
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)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,69 +7,23 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
water "github.com/yggdrasil-network/water"
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is to catch Windows platforms
|
// This is to catch Windows platforms
|
||||||
|
|
||||||
// Configures the TAP adapter with the correct IPv6 address and MTU. On Windows
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
// we don't make use of a direct operating system API to do this - we instead
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
// delegate the hard work to "netsh".
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
tun.mtu = getSupportedMTU(mtu, iftapmode)
|
if mtu, err := iface.MTU(); err == nil {
|
||||||
err = tun.setupMTU(tun.mtu)
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
if err != nil {
|
} else {
|
||||||
panic(err)
|
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)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user