diff --git a/src/core/api.go b/src/core/api.go index bfccd66..c886edf 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -222,3 +222,28 @@ func (c *Core) RemovePeer(addr string, sintf string) error { func (c *Core) CallPeer(u *url.URL, sintf string) error { 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 +} diff --git a/src/core/core.go b/src/core/core.go index cb34d89..89d4917 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -5,6 +5,7 @@ import ( "crypto/ed25519" "encoding/hex" "errors" + "fmt" "io/ioutil" "net/url" "time" @@ -25,13 +26,13 @@ type Core struct { // 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 phony.Inbox - pc *iw.PacketConn + pc *iw.PacketConn config *config.NodeConfig // Config secret ed25519.PrivateKey public ed25519.PublicKey links links - proto protoHandler - store keyStore + proto protoHandler + store keyStore log *log.Logger addPeerTimer *time.Timer ctx context.Context @@ -43,13 +44,13 @@ func (c *Core) _init() error { // Init sets up structs // Start launches goroutines that depend on structs being set up // This is pretty much required to completely avoid race conditions + c.config.RLock() + defer c.config.RUnlock() if c.log == nil { c.log = log.New(ioutil.Discard, "", 0) } - c.config.RLock() sigPriv, err := hex.DecodeString(c.config.PrivateKey) - c.config.RUnlock() if err != nil { return err } @@ -65,6 +66,9 @@ func (c *Core) _init() error { c.ctx, c.ctxCancel = context.WithCancel(context.Background()) c.store.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 } @@ -177,20 +181,3 @@ func (c *Core) _stop() { */ 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 -} diff --git a/src/core/keystore.go b/src/core/keystore.go index 4342488..d8a808a 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -17,7 +17,7 @@ const keyStoreTimeout = 2 * time.Minute type keyArray [ed25519.PublicKeySize]byte type keyStore struct { - core *Core + core *Core address address.Address subnet address.Subnet mutex sync.Mutex @@ -26,7 +26,6 @@ type keyStore struct { addrBuffer map[address.Address]*buffer subnetToInfo map[address.Subnet]*keyInfo subnetBuffer map[address.Subnet]*buffer - buf []byte // scratch space to prefix with typeSessionTraffic before sending } type keyInfo struct { @@ -45,7 +44,10 @@ func (k *keyStore) init(core *Core) { k.core = core k.address = *address.AddrForKey(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.addrToInfo = make(map[address.Address]*keyInfo) k.addrBuffer = make(map[address.Address]*buffer) @@ -204,38 +206,39 @@ func (k *keyStore) maxSessionMTU() uint64 { } func (k *keyStore) readPC(p []byte) (int, error) { - for { - bs := p - n, from, err := k.core.pc.ReadFrom(bs) - if err != nil { - return n, err - } - if n == 0 { - continue - } - switch bs[0] { - case typeSessionTraffic: - // This is what we want to handle here - case typeSessionProto: - var key keyArray - copy(key[:], from.(iwt.Addr)) - data := append([]byte(nil), bs[1:n]...) - k.core.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 - } - /* TODO ICMP packet too big + buf := make([]byte, k.core.pc.MTU(), 65535) + for { + bs := buf + n, from, err := k.core.pc.ReadFrom(bs) + if err != nil { + return n, err + } + if n == 0 { + continue + } + switch bs[0] { + case typeSessionTraffic: + // This is what we want to handle here + case typeSessionProto: + var key keyArray + copy(key[:], from.(iwt.Addr)) + data := append([]byte(nil), bs[1:n]...) + k.core.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 + } + /* TODO? ICMP packet too big, for now tuntap sends this when needed if len(bs) > int(tun.MTU()) { ptb := &icmp.PacketTooBig{ MTU: int(tun.mtu), @@ -246,32 +249,32 @@ func (k *keyStore) readPC(p []byte) (int, error) { } 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 dstAddr != k.address && dstSubnet != k.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 + */ + 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 dstAddr != k.address && dstSubnet != k.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 + } } 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 } if len(bs) < 40 { - strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) - return 0, errors.New(strErr) + strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) + return 0, errors.New(strErr) } var srcAddr, dstAddr address.Address var srcSubnet, dstSubnet address.Subnet @@ -280,16 +283,17 @@ func (k *keyStore) writePC(bs []byte) (int, error) { copy(srcSubnet[:], bs[8:]) copy(dstSubnet[:], bs[24:]) 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) - k.buf = append(k.buf, bs...) + buf := make([]byte, 1+len(bs), 65535) + buf[0] = typeSessionTraffic + copy(buf[1:], bs) if dstAddr.IsValid() { - k.sendToAddress(dstAddr, k.buf) + k.sendToAddress(dstAddr, buf) } else if dstSubnet.IsValid() { - k.sendToSubnet(dstSubnet, k.buf) + k.sendToSubnet(dstSubnet, buf) } else { - return 0, errors.New("invalid destination address") + return 0, errors.New("invalid destination address") } return len(bs), nil } diff --git a/src/core/proto.go b/src/core/proto.go index 24d54ca..557ac1d 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -31,7 +31,7 @@ type reqInfo struct { type protoHandler struct { phony.Inbox - core *Core + core *Core nodeinfo nodeinfo sreqs map[keyArray]*reqInfo preqs map[keyArray]*reqInfo diff --git a/src/tuntap/admin.go b/src/tuntap/admin.go index 9c9ceb6..80b2df0 100644 --- a/src/tuntap/admin.go +++ b/src/tuntap/admin.go @@ -34,8 +34,8 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) { } return res, nil }) - _ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) - _ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) - _ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) - _ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) + //_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) + //_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) + //_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) + //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) } diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index cb13690..8642a00 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -1,20 +1,8 @@ package tuntap import ( - "crypto/ed25519" - - "github.com/yggdrasil-network/yggdrasil-go/src/address" "golang.org/x/net/icmp" "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 @@ -34,28 +22,8 @@ func (tun *TunAdapter) read() { begin := TUN_OFFSET_BYTES end := begin + n bs := buf[begin:end] - if bs[0]&0xf0 != 0x60 { - continue // not IPv6 - } - 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) + if _, err := tun.core.Write(bs); err != nil { + tun.log.Errorln("Unable to send packet:", err) } } } @@ -63,63 +31,23 @@ func (tun *TunAdapter) read() { func (tun *TunAdapter) write() { var buf [TUN_OFFSET_BYTES + 65535]byte for { - bs := buf[TUN_OFFSET_BYTES-1:] - n, from, err := tun.core.ReadFrom(bs) + bs := buf[TUN_OFFSET_BYTES:] + n, err := tun.core.Read(bs) if err != nil { + tun.log.Errorln("Exiting tun writer due to core read error:", err) return } - if n == 0 { - 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()) { + if n > int(tun.MTU()) { ptb := &icmp.PacketTooBig{ MTU: int(tun.mtu), Data: bs[:40], } 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 } - 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 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)] + bs = buf[:TUN_OFFSET_BYTES+n] if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil { tun.Act(nil, func() { if !tun.isOpen { diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 7b20bfb..41da007 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -9,7 +9,6 @@ package tuntap // TODO: Don't block in reader on writes that are pending searches import ( - "crypto/ed25519" "errors" "fmt" "net" @@ -34,7 +33,6 @@ type MTU uint16 // calling yggdrasil.Start(). type TunAdapter struct { core *core.Core - store keyStore config *config.NodeConfig log *log.Logger addr address.Address @@ -45,7 +43,6 @@ type TunAdapter struct { //mutex sync.RWMutex // Protects the below isOpen bool 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 @@ -98,18 +95,8 @@ func MaximumMTU() uint64 { // 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 { tun.core = core - tun.store.init(tun) tun.config = config 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 } @@ -132,8 +119,7 @@ func (tun *TunAdapter) _start() error { if tun.config == nil { return errors.New("no configuration available to TUN") } - sk := tun.core.PrivateKey() - pk := sk.Public().(ed25519.PublicKey) + pk := tun.core.PublicKey() tun.addr = *address.AddrForKey(pk) tun.subnet = *address.SubnetForKey(pk) 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 } mtu := tun.config.IfMTU - if tun.maxSessionMTU() < mtu { - mtu = tun.maxSessionMTU() + if tun.core.MaxMTU() < mtu { + mtu = tun.core.MaxMTU() } if err := tun.setup(tun.config.IfName, addr, mtu); err != nil { return err @@ -188,4 +174,3 @@ func (tun *TunAdapter) _stop() error { } return nil } -