mostly finish migration of IP stuff to core, tuntap is still responsible for ICMP PacketTooBig

This commit is contained in:
Arceliar 2021-06-13 04:54:06 -05:00
parent 1147ee1934
commit 816356ea65
7 changed files with 114 additions and 185 deletions

View File

@ -222,3 +222,28 @@ func (c *Core) RemovePeer(addr string, sintf string) error {
func (c *Core) CallPeer(u *url.URL, sintf string) error { func (c *Core) CallPeer(u *url.URL, sintf string) error {
return c.links.call(u, sintf) return c.links.call(u, sintf)
} }
func (c *Core) PublicKey() ed25519.PublicKey {
return c.public
}
func (c *Core) MaxMTU() uint64 {
return c.store.maxSessionMTU()
}
// Implement io.ReadWriteCloser
func (c *Core) Read(p []byte) (n int, err error) {
n, err = c.store.readPC(p)
return
}
func (c *Core) Write(p []byte) (n int, err error) {
n, err = c.store.writePC(p)
return
}
func (c *Core) Close() error {
c.Stop()
return nil
}

View File

@ -5,6 +5,7 @@ import (
"crypto/ed25519" "crypto/ed25519"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"net/url" "net/url"
"time" "time"
@ -25,13 +26,13 @@ type Core struct {
// We're going to keep our own copy of the provided config - that way we can // We're going to keep our own copy of the provided config - that way we can
// guarantee that it will be covered by the mutex // guarantee that it will be covered by the mutex
phony.Inbox phony.Inbox
pc *iw.PacketConn pc *iw.PacketConn
config *config.NodeConfig // Config config *config.NodeConfig // Config
secret ed25519.PrivateKey secret ed25519.PrivateKey
public ed25519.PublicKey public ed25519.PublicKey
links links links links
proto protoHandler proto protoHandler
store keyStore store keyStore
log *log.Logger log *log.Logger
addPeerTimer *time.Timer addPeerTimer *time.Timer
ctx context.Context ctx context.Context
@ -43,13 +44,13 @@ func (c *Core) _init() error {
// Init sets up structs // Init sets up structs
// Start launches goroutines that depend on structs being set up // Start launches goroutines that depend on structs being set up
// This is pretty much required to completely avoid race conditions // This is pretty much required to completely avoid race conditions
c.config.RLock()
defer c.config.RUnlock()
if c.log == nil { if c.log == nil {
c.log = log.New(ioutil.Discard, "", 0) c.log = log.New(ioutil.Discard, "", 0)
} }
c.config.RLock()
sigPriv, err := hex.DecodeString(c.config.PrivateKey) sigPriv, err := hex.DecodeString(c.config.PrivateKey)
c.config.RUnlock()
if err != nil { if err != nil {
return err return err
} }
@ -65,6 +66,9 @@ func (c *Core) _init() error {
c.ctx, c.ctxCancel = context.WithCancel(context.Background()) c.ctx, c.ctxCancel = context.WithCancel(context.Background())
c.store.init(c) c.store.init(c)
c.proto.init(c) c.proto.init(c)
if err := c.proto.nodeinfo.setNodeInfo(c.config.NodeInfo, c.config.NodeInfoPrivacy); err != nil {
return fmt.Errorf("setNodeInfo: %w", err)
}
return err return err
} }
@ -177,20 +181,3 @@ func (c *Core) _stop() {
*/ */
c.log.Infoln("Stopped") c.log.Infoln("Stopped")
} }
// Implement io.ReadWriteCloser
func (c *Core) Read(p []byte) (n int, err error) {
n, err = c.store.readPC(p)
return
}
func (c *Core) Write(p []byte) (n int, err error) {
n, err = c.store.writePC(p)
return
}
func (c *Core) Close() error {
c.Stop()
return nil
}

View File

@ -17,7 +17,7 @@ const keyStoreTimeout = 2 * time.Minute
type keyArray [ed25519.PublicKeySize]byte type keyArray [ed25519.PublicKeySize]byte
type keyStore struct { type keyStore struct {
core *Core core *Core
address address.Address address address.Address
subnet address.Subnet subnet address.Subnet
mutex sync.Mutex mutex sync.Mutex
@ -26,7 +26,6 @@ type keyStore struct {
addrBuffer map[address.Address]*buffer addrBuffer map[address.Address]*buffer
subnetToInfo map[address.Subnet]*keyInfo subnetToInfo map[address.Subnet]*keyInfo
subnetBuffer map[address.Subnet]*buffer subnetBuffer map[address.Subnet]*buffer
buf []byte // scratch space to prefix with typeSessionTraffic before sending
} }
type keyInfo struct { type keyInfo struct {
@ -45,7 +44,10 @@ func (k *keyStore) init(core *Core) {
k.core = core k.core = core
k.address = *address.AddrForKey(k.core.public) k.address = *address.AddrForKey(k.core.public)
k.subnet = *address.SubnetForKey(k.core.public) k.subnet = *address.SubnetForKey(k.core.public)
k.core.pc.SetOutOfBandHandler(k.oobHandler) if err := k.core.pc.SetOutOfBandHandler(k.oobHandler); err != nil {
err = fmt.Errorf("tun.core.SetOutOfBandHander: %w", err)
panic(err)
}
k.keyToInfo = make(map[keyArray]*keyInfo) k.keyToInfo = make(map[keyArray]*keyInfo)
k.addrToInfo = make(map[address.Address]*keyInfo) k.addrToInfo = make(map[address.Address]*keyInfo)
k.addrBuffer = make(map[address.Address]*buffer) k.addrBuffer = make(map[address.Address]*buffer)
@ -204,38 +206,39 @@ func (k *keyStore) maxSessionMTU() uint64 {
} }
func (k *keyStore) readPC(p []byte) (int, error) { func (k *keyStore) readPC(p []byte) (int, error) {
for { buf := make([]byte, k.core.pc.MTU(), 65535)
bs := p for {
n, from, err := k.core.pc.ReadFrom(bs) bs := buf
if err != nil { n, from, err := k.core.pc.ReadFrom(bs)
return n, err if err != nil {
} return n, err
if n == 0 { }
continue if n == 0 {
} continue
switch bs[0] { }
case typeSessionTraffic: switch bs[0] {
// This is what we want to handle here case typeSessionTraffic:
case typeSessionProto: // This is what we want to handle here
var key keyArray case typeSessionProto:
copy(key[:], from.(iwt.Addr)) var key keyArray
data := append([]byte(nil), bs[1:n]...) copy(key[:], from.(iwt.Addr))
k.core.proto.handleProto(nil, key, data) data := append([]byte(nil), bs[1:n]...)
continue k.core.proto.handleProto(nil, key, data)
default: continue
continue default:
} continue
bs = bs[1:n] }
if len(bs) == 0 { bs = bs[1:n]
continue if len(bs) == 0 {
} continue
if bs[0]&0xf0 != 0x60 { }
continue // not IPv6 if bs[0]&0xf0 != 0x60 {
} continue // not IPv6
if len(bs) < 40 { }
continue if len(bs) < 40 {
} continue
/* TODO ICMP packet too big }
/* TODO? ICMP packet too big, for now tuntap sends this when needed
if len(bs) > int(tun.MTU()) { if len(bs) > int(tun.MTU()) {
ptb := &icmp.PacketTooBig{ ptb := &icmp.PacketTooBig{
MTU: int(tun.mtu), MTU: int(tun.mtu),
@ -246,32 +249,32 @@ func (k *keyStore) readPC(p []byte) (int, error) {
} }
continue continue
} }
*/ */
var srcAddr, dstAddr address.Address var srcAddr, dstAddr address.Address
var srcSubnet, dstSubnet address.Subnet var srcSubnet, dstSubnet address.Subnet
copy(srcAddr[:], bs[8:]) copy(srcAddr[:], bs[8:])
copy(dstAddr[:], bs[24:]) copy(dstAddr[:], bs[24:])
copy(srcSubnet[:], bs[8:]) copy(srcSubnet[:], bs[8:])
copy(dstSubnet[:], bs[24:]) copy(dstSubnet[:], bs[24:])
if dstAddr != k.address && dstSubnet != k.subnet { if dstAddr != k.address && dstSubnet != k.subnet {
continue // bad local address/subnet continue // bad local address/subnet
}
info := k.update(ed25519.PublicKey(from.(iwt.Addr)))
if srcAddr != info.address && srcSubnet != info.subnet {
continue // bad remote address/subnet
}
n = copy(p, bs)
return n, nil
} }
info := k.update(ed25519.PublicKey(from.(iwt.Addr)))
if srcAddr != info.address && srcSubnet != info.subnet {
continue // bad remote address/subnet
}
n = copy(p, bs)
return n, nil
}
} }
func (k *keyStore) writePC(bs []byte) (int, error) { func (k *keyStore) writePC(bs []byte) (int, error) {
if bs[0]&0xf0 != 0x60 { if bs[0]&0xf0 != 0x60 {
return 0, errors.New("not an IPv6 packet") // not IPv6 return 0, errors.New("not an IPv6 packet") // not IPv6
} }
if len(bs) < 40 { if len(bs) < 40 {
strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs))
return 0, errors.New(strErr) return 0, errors.New(strErr)
} }
var srcAddr, dstAddr address.Address var srcAddr, dstAddr address.Address
var srcSubnet, dstSubnet address.Subnet var srcSubnet, dstSubnet address.Subnet
@ -280,16 +283,17 @@ func (k *keyStore) writePC(bs []byte) (int, error) {
copy(srcSubnet[:], bs[8:]) copy(srcSubnet[:], bs[8:])
copy(dstSubnet[:], bs[24:]) copy(dstSubnet[:], bs[24:])
if srcAddr != k.address && srcSubnet != k.subnet { if srcAddr != k.address && srcSubnet != k.subnet {
return 0, errors.New("wrong source address") return 0, errors.New("wrong source address")
} }
k.buf = append(k.buf[:0], typeSessionTraffic) buf := make([]byte, 1+len(bs), 65535)
k.buf = append(k.buf, bs...) buf[0] = typeSessionTraffic
copy(buf[1:], bs)
if dstAddr.IsValid() { if dstAddr.IsValid() {
k.sendToAddress(dstAddr, k.buf) k.sendToAddress(dstAddr, buf)
} else if dstSubnet.IsValid() { } else if dstSubnet.IsValid() {
k.sendToSubnet(dstSubnet, k.buf) k.sendToSubnet(dstSubnet, buf)
} else { } else {
return 0, errors.New("invalid destination address") return 0, errors.New("invalid destination address")
} }
return len(bs), nil return len(bs), nil
} }

View File

@ -31,7 +31,7 @@ type reqInfo struct {
type protoHandler struct { type protoHandler struct {
phony.Inbox phony.Inbox
core *Core core *Core
nodeinfo nodeinfo nodeinfo nodeinfo
sreqs map[keyArray]*reqInfo sreqs map[keyArray]*reqInfo
preqs map[keyArray]*reqInfo preqs map[keyArray]*reqInfo

View File

@ -34,8 +34,8 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) {
} }
return res, nil return res, nil
}) })
_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) //_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler)
_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) //_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler)
_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) //_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler)
_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler)
} }

View File

@ -1,20 +1,8 @@
package tuntap package tuntap
import ( import (
"crypto/ed25519"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"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/crypto"
//"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
//"golang.org/x/net/icmp"
//"golang.org/x/net/ipv6"
iwt "github.com/Arceliar/ironwood/types"
//"github.com/Arceliar/phony"
) )
const TUN_OFFSET_BYTES = 4 const TUN_OFFSET_BYTES = 4
@ -34,28 +22,8 @@ func (tun *TunAdapter) read() {
begin := TUN_OFFSET_BYTES begin := TUN_OFFSET_BYTES
end := begin + n end := begin + n
bs := buf[begin:end] bs := buf[begin:end]
if bs[0]&0xf0 != 0x60 { if _, err := tun.core.Write(bs); err != nil {
continue // not IPv6 tun.log.Errorln("Unable to send packet:", err)
}
if len(bs) < 40 {
tun.log.Traceln("TUN iface read undersized ipv6 packet, length:", len(bs))
continue
}
var srcAddr, dstAddr address.Address
var srcSubnet, dstSubnet address.Subnet
copy(srcAddr[:], bs[8:])
copy(dstAddr[:], bs[24:])
copy(srcSubnet[:], bs[8:])
copy(dstSubnet[:], bs[24:])
if srcAddr != tun.addr && srcSubnet != tun.subnet {
continue // Wrong source address
}
bs = buf[begin-1 : end]
bs[0] = typeSessionTraffic
if dstAddr.IsValid() {
tun.store.sendToAddress(dstAddr, bs)
} else if dstSubnet.IsValid() {
tun.store.sendToSubnet(dstSubnet, bs)
} }
} }
} }
@ -63,63 +31,23 @@ func (tun *TunAdapter) read() {
func (tun *TunAdapter) write() { func (tun *TunAdapter) write() {
var buf [TUN_OFFSET_BYTES + 65535]byte var buf [TUN_OFFSET_BYTES + 65535]byte
for { for {
bs := buf[TUN_OFFSET_BYTES-1:] bs := buf[TUN_OFFSET_BYTES:]
n, from, err := tun.core.ReadFrom(bs) n, err := tun.core.Read(bs)
if err != nil { if err != nil {
tun.log.Errorln("Exiting tun writer due to core read error:", err)
return return
} }
if n == 0 { if n > int(tun.MTU()) {
continue
}
switch bs[0] {
case typeSessionTraffic:
// This is what we want to handle here
if !tun.isEnabled {
continue // Drop traffic if the tun is disabled
}
case typeSessionProto:
var key keyArray
copy(key[:], from.(iwt.Addr))
data := append([]byte(nil), bs[1:n]...)
tun.proto.handleProto(nil, key, data)
continue
default:
continue
}
bs = bs[1:n]
if len(bs) == 0 {
continue
}
if bs[0]&0xf0 != 0x60 {
continue // not IPv6
}
if len(bs) < 40 {
continue
}
if len(bs) > int(tun.MTU()) {
ptb := &icmp.PacketTooBig{ ptb := &icmp.PacketTooBig{
MTU: int(tun.mtu), MTU: int(tun.mtu),
Data: bs[:40], Data: bs[:40],
} }
if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil {
_, _ = tun.core.WriteTo(packet, from) _, _ = tun.core.Write(packet)
} }
continue continue
} }
var srcAddr, dstAddr address.Address bs = buf[:TUN_OFFSET_BYTES+n]
var srcSubnet, dstSubnet address.Subnet
copy(srcAddr[:], bs[8:])
copy(dstAddr[:], bs[24:])
copy(srcSubnet[:], bs[8:])
copy(dstSubnet[:], bs[24:])
if dstAddr != tun.addr && dstSubnet != tun.subnet {
continue // bad local address/subnet
}
info := tun.store.update(ed25519.PublicKey(from.(iwt.Addr)))
if srcAddr != info.address && srcSubnet != info.subnet {
continue // bad remote address/subnet
}
bs = buf[:TUN_OFFSET_BYTES+len(bs)]
if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil { if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil {
tun.Act(nil, func() { tun.Act(nil, func() {
if !tun.isOpen { if !tun.isOpen {

View File

@ -9,7 +9,6 @@ package tuntap
// TODO: Don't block in reader on writes that are pending searches // TODO: Don't block in reader on writes that are pending searches
import ( import (
"crypto/ed25519"
"errors" "errors"
"fmt" "fmt"
"net" "net"
@ -34,7 +33,6 @@ type MTU uint16
// calling yggdrasil.Start(). // calling yggdrasil.Start().
type TunAdapter struct { type TunAdapter struct {
core *core.Core core *core.Core
store keyStore
config *config.NodeConfig config *config.NodeConfig
log *log.Logger log *log.Logger
addr address.Address addr address.Address
@ -45,7 +43,6 @@ type TunAdapter struct {
//mutex sync.RWMutex // Protects the below //mutex sync.RWMutex // Protects the below
isOpen bool isOpen bool
isEnabled bool // Used by the writer to drop sessionTraffic if not enabled isEnabled bool // Used by the writer to drop sessionTraffic if not enabled
proto protoHandler
} }
// 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
@ -98,18 +95,8 @@ func MaximumMTU() uint64 {
// 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 *core.Core, config *config.NodeConfig, log *log.Logger, options interface{}) error { func (tun *TunAdapter) Init(core *core.Core, config *config.NodeConfig, log *log.Logger, options interface{}) error {
tun.core = core tun.core = core
tun.store.init(tun)
tun.config = config tun.config = config
tun.log = log tun.log = log
tun.proto.init(tun)
tun.config.RLock()
if err := tun.proto.nodeinfo.setNodeInfo(tun.config.NodeInfo, tun.config.NodeInfoPrivacy); err != nil {
return fmt.Errorf("tun.proto.nodeinfo.setNodeInfo: %w", err)
}
tun.config.RUnlock()
if err := tun.core.SetOutOfBandHandler(tun.oobHandler); err != nil {
return fmt.Errorf("tun.core.SetOutOfBandHander: %w", err)
}
return nil return nil
} }
@ -132,8 +119,7 @@ func (tun *TunAdapter) _start() error {
if tun.config == nil { if tun.config == nil {
return errors.New("no configuration available to TUN") return errors.New("no configuration available to TUN")
} }
sk := tun.core.PrivateKey() pk := tun.core.PublicKey()
pk := sk.Public().(ed25519.PublicKey)
tun.addr = *address.AddrForKey(pk) tun.addr = *address.AddrForKey(pk)
tun.subnet = *address.SubnetForKey(pk) tun.subnet = *address.SubnetForKey(pk)
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)
@ -144,8 +130,8 @@ func (tun *TunAdapter) _start() error {
return nil return nil
} }
mtu := tun.config.IfMTU mtu := tun.config.IfMTU
if tun.maxSessionMTU() < mtu { if tun.core.MaxMTU() < mtu {
mtu = tun.maxSessionMTU() mtu = tun.core.MaxMTU()
} }
if err := tun.setup(tun.config.IfName, addr, mtu); err != nil { if err := tun.setup(tun.config.IfName, addr, mtu); err != nil {
return err return err
@ -188,4 +174,3 @@ func (tun *TunAdapter) _stop() error {
} }
return nil return nil
} }