mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-12-23 04:05:39 +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/sys v0.0.0-20191024172528-b4ff53e7a1cb
|
||||
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/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=
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -19,9 +19,8 @@ func GetDefaults() platformDefaultParameters {
|
||||
},
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "auto",
|
||||
DefaultIfTAPMode: false,
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "auto",
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
||||
},
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "auto",
|
||||
DefaultIfTAPMode: false,
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "auto",
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
||||
},
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "none",
|
||||
DefaultIfTAPMode: false,
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "none",
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,8 @@ func GetDefaults() platformDefaultParameters {
|
||||
},
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "auto",
|
||||
DefaultIfTAPMode: true,
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
||||
DefaultIfName: "auto",
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user