mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-23 18:15:24 +00:00
(broken state) WIP on tuntap
This commit is contained in:
parent
f1c37f8440
commit
0cff56fcc1
@ -112,3 +112,35 @@ func SubnetForKey(publicKey ed25519.PublicKey) *Subnet {
|
|||||||
snet[len(prefix)-1] |= 0x01
|
snet[len(prefix)-1] |= 0x01
|
||||||
return &snet
|
return &snet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetKet returns the partial ed25519.PublicKey for the Address.
|
||||||
|
// This is used for key lookup.
|
||||||
|
func (a *Address) GetKey() ed25519.PublicKey {
|
||||||
|
var key [ed25519.PublicKeySize]byte
|
||||||
|
prefix := GetPrefix()
|
||||||
|
ones := int(a[len(prefix)])
|
||||||
|
for idx := 0; idx < ones; idx++ {
|
||||||
|
key[idx/8] |= 0x80 >> byte(idx%8)
|
||||||
|
}
|
||||||
|
keyOffset := ones + 1
|
||||||
|
addrOffset := 8*len(prefix) + 8
|
||||||
|
for idx := addrOffset; idx < 8*len(a); idx++ {
|
||||||
|
bits := a[idx/8] & (0x80 >> byte(idx%8))
|
||||||
|
bits <<= byte(idx % 8)
|
||||||
|
keyIdx := keyOffset + (idx - addrOffset)
|
||||||
|
bits >>= byte(keyIdx % 8)
|
||||||
|
key[keyIdx/8] |= bits
|
||||||
|
}
|
||||||
|
for idx := range key {
|
||||||
|
key[idx] = ^key[idx]
|
||||||
|
}
|
||||||
|
return ed25519.PublicKey(key[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKet returns the partial ed25519.PublicKey for the Subnet.
|
||||||
|
// This is used for key lookup.
|
||||||
|
func (s *Subnet) GetKey() ed25519.PublicKey {
|
||||||
|
var addr Address
|
||||||
|
copy(addr[:], s[:])
|
||||||
|
return addr.GetKey()
|
||||||
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
//"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
//"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
|
|
||||||
"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"
|
||||||
"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"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
//"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -82,13 +82,14 @@ func (a *AdminSocket) UpdateConfig(config *config.NodeConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AdminSocket) SetupAdminHandlers(na *AdminSocket) {
|
func (a *AdminSocket) SetupAdminHandlers(na *AdminSocket) {
|
||||||
|
/* TODO
|
||||||
a.AddHandler("getSelf", []string{}, func(in Info) (Info, error) {
|
a.AddHandler("getSelf", []string{}, func(in Info) (Info, error) {
|
||||||
ip := a.core.Address().String()
|
ip := a.core.Address().String()
|
||||||
subnet := a.core.Subnet()
|
subnet := a.core.Subnet()
|
||||||
return Info{
|
return Info{
|
||||||
"self": Info{
|
"self": Info{
|
||||||
ip: Info{
|
ip: Info{
|
||||||
"box_pub_key": a.core.EncryptionPublicKey(),
|
// TODO"box_pub_key": a.core.EncryptionPublicKey(),
|
||||||
"build_name": version.BuildName(),
|
"build_name": version.BuildName(),
|
||||||
"build_version": version.BuildVersion(),
|
"build_version": version.BuildVersion(),
|
||||||
"coords": fmt.Sprintf("%v", a.core.Coords()),
|
"coords": fmt.Sprintf("%v", a.core.Coords()),
|
||||||
@ -140,203 +141,205 @@ func (a *AdminSocket) SetupAdminHandlers(na *AdminSocket) {
|
|||||||
return Info{"switchqueues": queues.asMap()}, nil
|
return Info{"switchqueues": queues.asMap()}, nil
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
a.AddHandler("getDHT", []string{}, func(in Info) (Info, error) {
|
/*
|
||||||
dht := make(Info)
|
a.AddHandler("getDHT", []string{}, func(in Info) (Info, error) {
|
||||||
for _, d := range a.core.GetDHT() {
|
dht := make(Info)
|
||||||
panic("TODO")
|
for _, d := range a.core.GetDHT() {
|
||||||
addr := new(address.Address) // TODO *address.AddrForNodeID(crypto.GetNodeID(&d.PublicKey))
|
panic("TODO")
|
||||||
so := net.IP(addr[:]).String()
|
addr := new(address.Address) // TODO *address.AddrForNodeID(crypto.GetNodeID(&d.PublicKey))
|
||||||
dht[so] = Info{
|
so := net.IP(addr[:]).String()
|
||||||
"coords": fmt.Sprintf("%v", d.Coords),
|
dht[so] = Info{
|
||||||
"last_seen": d.LastSeen.Seconds(),
|
"coords": fmt.Sprintf("%v", d.Coords),
|
||||||
"box_pub_key": hex.EncodeToString(d.PublicKey[:]),
|
"last_seen": d.LastSeen.Seconds(),
|
||||||
|
"box_pub_key": hex.EncodeToString(d.PublicKey[:]),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return Info{"dht": dht}, nil
|
||||||
return Info{"dht": dht}, nil
|
})
|
||||||
})
|
a.AddHandler("getSessions", []string{}, func(in Info) (Info, error) {
|
||||||
a.AddHandler("getSessions", []string{}, func(in Info) (Info, error) {
|
sessions := make(Info)
|
||||||
sessions := make(Info)
|
for _, s := range a.core.GetSessions() {
|
||||||
for _, s := range a.core.GetSessions() {
|
panic("TODO")
|
||||||
panic("TODO")
|
addr := new(address.Address) //*address.AddrForNodeID(crypto.GetNodeID(&s.PublicKey))
|
||||||
addr := new(address.Address) //*address.AddrForNodeID(crypto.GetNodeID(&s.PublicKey))
|
so := net.IP(addr[:]).String()
|
||||||
so := net.IP(addr[:]).String()
|
sessions[so] = Info{
|
||||||
sessions[so] = Info{
|
"coords": fmt.Sprintf("%v", s.Coords),
|
||||||
"coords": fmt.Sprintf("%v", s.Coords),
|
"bytes_sent": s.BytesSent,
|
||||||
"bytes_sent": s.BytesSent,
|
"bytes_recvd": s.BytesRecvd,
|
||||||
"bytes_recvd": s.BytesRecvd,
|
"mtu": s.MTU,
|
||||||
"mtu": s.MTU,
|
"uptime": s.Uptime.Seconds(),
|
||||||
"uptime": s.Uptime.Seconds(),
|
"was_mtu_fixed": s.WasMTUFixed,
|
||||||
"was_mtu_fixed": s.WasMTUFixed,
|
"box_pub_key": hex.EncodeToString(s.PublicKey[:]),
|
||||||
"box_pub_key": hex.EncodeToString(s.PublicKey[:]),
|
}
|
||||||
|
}
|
||||||
|
return Info{"sessions": sessions}, nil
|
||||||
|
})
|
||||||
|
a.AddHandler("addPeer", []string{"uri", "[interface]"}, func(in Info) (Info, error) {
|
||||||
|
// Set sane defaults
|
||||||
|
intf := ""
|
||||||
|
// Has interface been specified?
|
||||||
|
if itf, ok := in["interface"]; ok {
|
||||||
|
intf = itf.(string)
|
||||||
|
}
|
||||||
|
if a.core.AddPeer(in["uri"].(string), intf) == nil {
|
||||||
|
return Info{
|
||||||
|
"added": []string{
|
||||||
|
in["uri"].(string),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Info{"sessions": sessions}, nil
|
|
||||||
})
|
|
||||||
a.AddHandler("addPeer", []string{"uri", "[interface]"}, func(in Info) (Info, error) {
|
|
||||||
// Set sane defaults
|
|
||||||
intf := ""
|
|
||||||
// Has interface been specified?
|
|
||||||
if itf, ok := in["interface"]; ok {
|
|
||||||
intf = itf.(string)
|
|
||||||
}
|
|
||||||
if a.core.AddPeer(in["uri"].(string), intf) == nil {
|
|
||||||
return Info{
|
return Info{
|
||||||
"added": []string{
|
"not_added": []string{
|
||||||
in["uri"].(string),
|
in["uri"].(string),
|
||||||
},
|
},
|
||||||
}, nil
|
}, errors.New("Failed to add peer")
|
||||||
}
|
})
|
||||||
return Info{
|
a.AddHandler("disconnectPeer", []string{"port"}, func(in Info) (Info, error) {
|
||||||
"not_added": []string{
|
port, err := strconv.ParseInt(fmt.Sprint(in["port"]), 10, 64)
|
||||||
in["uri"].(string),
|
if err != nil {
|
||||||
},
|
return Info{}, err
|
||||||
}, errors.New("Failed to add peer")
|
}
|
||||||
})
|
if a.core.DisconnectPeer(uint64(port)) == nil {
|
||||||
a.AddHandler("disconnectPeer", []string{"port"}, func(in Info) (Info, error) {
|
return Info{
|
||||||
port, err := strconv.ParseInt(fmt.Sprint(in["port"]), 10, 64)
|
"disconnected": []string{
|
||||||
if err != nil {
|
fmt.Sprint(port),
|
||||||
return Info{}, err
|
},
|
||||||
}
|
}, nil
|
||||||
if a.core.DisconnectPeer(uint64(port)) == nil {
|
} else {
|
||||||
return Info{
|
return Info{
|
||||||
"disconnected": []string{
|
"not_disconnected": []string{
|
||||||
fmt.Sprint(port),
|
fmt.Sprint(port),
|
||||||
},
|
},
|
||||||
}, nil
|
}, errors.New("Failed to disconnect peer")
|
||||||
} else {
|
}
|
||||||
return Info{
|
})
|
||||||
"not_disconnected": []string{
|
a.AddHandler("removePeer", []string{"uri", "[interface]"}, func(in Info) (Info, error) {
|
||||||
fmt.Sprint(port),
|
// Set sane defaults
|
||||||
},
|
intf := ""
|
||||||
}, errors.New("Failed to disconnect peer")
|
// Has interface been specified?
|
||||||
}
|
if itf, ok := in["interface"]; ok {
|
||||||
})
|
intf = itf.(string)
|
||||||
a.AddHandler("removePeer", []string{"uri", "[interface]"}, func(in Info) (Info, error) {
|
}
|
||||||
// Set sane defaults
|
if a.core.RemovePeer(in["uri"].(string), intf) == nil {
|
||||||
intf := ""
|
return Info{
|
||||||
// Has interface been specified?
|
"removed": []string{
|
||||||
if itf, ok := in["interface"]; ok {
|
in["uri"].(string),
|
||||||
intf = itf.(string)
|
},
|
||||||
}
|
}, nil
|
||||||
if a.core.RemovePeer(in["uri"].(string), intf) == nil {
|
} else {
|
||||||
return Info{
|
return Info{
|
||||||
"removed": []string{
|
"not_removed": []string{
|
||||||
in["uri"].(string),
|
in["uri"].(string),
|
||||||
},
|
},
|
||||||
}, nil
|
}, errors.New("Failed to remove peer")
|
||||||
} else {
|
}
|
||||||
return Info{
|
return Info{
|
||||||
"not_removed": []string{
|
"not_removed": []string{
|
||||||
in["uri"].(string),
|
in["uri"].(string),
|
||||||
},
|
},
|
||||||
}, errors.New("Failed to remove peer")
|
}, errors.New("Failed to remove peer")
|
||||||
}
|
})
|
||||||
return Info{
|
a.AddHandler("getAllowedEncryptionPublicKeys", []string{}, func(in Info) (Info, error) {
|
||||||
"not_removed": []string{
|
return Info{"allowed_box_pubs": a.core.GetAllowedEncryptionPublicKeys()}, nil
|
||||||
in["uri"].(string),
|
})
|
||||||
},
|
a.AddHandler("addAllowedEncryptionPublicKey", []string{"box_pub_key"}, func(in Info) (Info, error) {
|
||||||
}, errors.New("Failed to remove peer")
|
if a.core.AddAllowedEncryptionPublicKey(in["box_pub_key"].(string)) == nil {
|
||||||
})
|
return Info{
|
||||||
a.AddHandler("getAllowedEncryptionPublicKeys", []string{}, func(in Info) (Info, error) {
|
"added": []string{
|
||||||
return Info{"allowed_box_pubs": a.core.GetAllowedEncryptionPublicKeys()}, nil
|
in["box_pub_key"].(string),
|
||||||
})
|
},
|
||||||
a.AddHandler("addAllowedEncryptionPublicKey", []string{"box_pub_key"}, func(in Info) (Info, error) {
|
}, nil
|
||||||
if a.core.AddAllowedEncryptionPublicKey(in["box_pub_key"].(string)) == nil {
|
}
|
||||||
return Info{
|
return Info{
|
||||||
"added": []string{
|
"not_added": []string{
|
||||||
in["box_pub_key"].(string),
|
in["box_pub_key"].(string),
|
||||||
},
|
},
|
||||||
}, nil
|
}, errors.New("Failed to add allowed key")
|
||||||
}
|
})
|
||||||
return Info{
|
a.AddHandler("removeAllowedEncryptionPublicKey", []string{"box_pub_key"}, func(in Info) (Info, error) {
|
||||||
"not_added": []string{
|
if a.core.RemoveAllowedEncryptionPublicKey(in["box_pub_key"].(string)) == nil {
|
||||||
in["box_pub_key"].(string),
|
return Info{
|
||||||
},
|
"removed": []string{
|
||||||
}, errors.New("Failed to add allowed key")
|
in["box_pub_key"].(string),
|
||||||
})
|
},
|
||||||
a.AddHandler("removeAllowedEncryptionPublicKey", []string{"box_pub_key"}, func(in Info) (Info, error) {
|
}, nil
|
||||||
if a.core.RemoveAllowedEncryptionPublicKey(in["box_pub_key"].(string)) == nil {
|
}
|
||||||
return Info{
|
return Info{
|
||||||
"removed": []string{
|
"not_removed": []string{
|
||||||
in["box_pub_key"].(string),
|
in["box_pub_key"].(string),
|
||||||
},
|
},
|
||||||
}, nil
|
}, errors.New("Failed to remove allowed key")
|
||||||
}
|
})
|
||||||
return Info{
|
a.AddHandler("dhtPing", []string{"box_pub_key", "coords", "[target]"}, func(in Info) (Info, error) {
|
||||||
"not_removed": []string{
|
var reserr error
|
||||||
in["box_pub_key"].(string),
|
var result yggdrasil.DHTRes
|
||||||
},
|
if in["target"] == nil {
|
||||||
}, errors.New("Failed to remove allowed key")
|
in["target"] = "none"
|
||||||
})
|
|
||||||
a.AddHandler("dhtPing", []string{"box_pub_key", "coords", "[target]"}, func(in Info) (Info, error) {
|
|
||||||
var reserr error
|
|
||||||
var result yggdrasil.DHTRes
|
|
||||||
if in["target"] == nil {
|
|
||||||
in["target"] = "none"
|
|
||||||
}
|
|
||||||
coords := util.DecodeCoordString(in["coords"].(string))
|
|
||||||
var boxPubKey crypto.BoxPubKey
|
|
||||||
if b, err := hex.DecodeString(in["box_pub_key"].(string)); err == nil {
|
|
||||||
copy(boxPubKey[:], b)
|
|
||||||
if n, err := hex.DecodeString(in["target"].(string)); err == nil {
|
|
||||||
var targetNodeID crypto.NodeID
|
|
||||||
copy(targetNodeID[:], n)
|
|
||||||
result, reserr = a.core.DHTPing(boxPubKey, coords, &targetNodeID)
|
|
||||||
} else {
|
|
||||||
result, reserr = a.core.DHTPing(boxPubKey, coords, nil)
|
|
||||||
}
|
}
|
||||||
} else {
|
coords := util.DecodeCoordString(in["coords"].(string))
|
||||||
return Info{}, err
|
var boxPubKey crypto.BoxPubKey
|
||||||
}
|
|
||||||
if reserr != nil {
|
|
||||||
return Info{}, reserr
|
|
||||||
}
|
|
||||||
infos := make(map[string]map[string]string, len(result.Infos))
|
|
||||||
for _, dinfo := range result.Infos {
|
|
||||||
info := map[string]string{
|
|
||||||
"box_pub_key": hex.EncodeToString(dinfo.PublicKey[:]),
|
|
||||||
"coords": fmt.Sprintf("%v", dinfo.Coords),
|
|
||||||
}
|
|
||||||
panic("TODO")
|
|
||||||
addr := "" //net.IP(address.AddrForNodeID(crypto.GetNodeID(&dinfo.PublicKey))[:]).String()
|
|
||||||
infos[addr] = info
|
|
||||||
}
|
|
||||||
return Info{"nodes": infos}, nil
|
|
||||||
})
|
|
||||||
a.AddHandler("getNodeInfo", []string{"[box_pub_key]", "[coords]", "[nocache]"}, func(in Info) (Info, error) {
|
|
||||||
var nocache bool
|
|
||||||
if in["nocache"] != nil {
|
|
||||||
nocache = in["nocache"].(string) == "true"
|
|
||||||
}
|
|
||||||
var boxPubKey crypto.BoxPubKey
|
|
||||||
var coords []uint64
|
|
||||||
if in["box_pub_key"] == nil && in["coords"] == nil {
|
|
||||||
nodeinfo := a.core.MyNodeInfo()
|
|
||||||
var jsoninfo interface{}
|
|
||||||
if err := json.Unmarshal(nodeinfo, &jsoninfo); err != nil {
|
|
||||||
return Info{}, err
|
|
||||||
}
|
|
||||||
return Info{"nodeinfo": jsoninfo}, nil
|
|
||||||
} else if in["box_pub_key"] == nil || in["coords"] == nil {
|
|
||||||
return Info{}, errors.New("Expecting both box_pub_key and coords")
|
|
||||||
} else {
|
|
||||||
if b, err := hex.DecodeString(in["box_pub_key"].(string)); err == nil {
|
if b, err := hex.DecodeString(in["box_pub_key"].(string)); err == nil {
|
||||||
copy(boxPubKey[:], b)
|
copy(boxPubKey[:], b)
|
||||||
|
if n, err := hex.DecodeString(in["target"].(string)); err == nil {
|
||||||
|
var targetNodeID crypto.NodeID
|
||||||
|
copy(targetNodeID[:], n)
|
||||||
|
result, reserr = a.core.DHTPing(boxPubKey, coords, &targetNodeID)
|
||||||
|
} else {
|
||||||
|
result, reserr = a.core.DHTPing(boxPubKey, coords, nil)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Info{}, err
|
return Info{}, err
|
||||||
}
|
}
|
||||||
coords = util.DecodeCoordString(in["coords"].(string))
|
if reserr != nil {
|
||||||
}
|
return Info{}, reserr
|
||||||
result, err := a.core.GetNodeInfo(boxPubKey, coords, nocache)
|
}
|
||||||
if err == nil {
|
infos := make(map[string]map[string]string, len(result.Infos))
|
||||||
var m map[string]interface{}
|
for _, dinfo := range result.Infos {
|
||||||
if err = json.Unmarshal(result, &m); err == nil {
|
info := map[string]string{
|
||||||
return Info{"nodeinfo": m}, nil
|
"box_pub_key": hex.EncodeToString(dinfo.PublicKey[:]),
|
||||||
|
"coords": fmt.Sprintf("%v", dinfo.Coords),
|
||||||
|
}
|
||||||
|
panic("TODO")
|
||||||
|
addr := "" //net.IP(address.AddrForNodeID(crypto.GetNodeID(&dinfo.PublicKey))[:]).String()
|
||||||
|
infos[addr] = info
|
||||||
|
}
|
||||||
|
return Info{"nodes": infos}, nil
|
||||||
|
})
|
||||||
|
a.AddHandler("getNodeInfo", []string{"[box_pub_key]", "[coords]", "[nocache]"}, func(in Info) (Info, error) {
|
||||||
|
var nocache bool
|
||||||
|
if in["nocache"] != nil {
|
||||||
|
nocache = in["nocache"].(string) == "true"
|
||||||
|
}
|
||||||
|
var boxPubKey crypto.BoxPubKey
|
||||||
|
var coords []uint64
|
||||||
|
if in["box_pub_key"] == nil && in["coords"] == nil {
|
||||||
|
nodeinfo := a.core.MyNodeInfo()
|
||||||
|
var jsoninfo interface{}
|
||||||
|
if err := json.Unmarshal(nodeinfo, &jsoninfo); err != nil {
|
||||||
|
return Info{}, err
|
||||||
|
}
|
||||||
|
return Info{"nodeinfo": jsoninfo}, nil
|
||||||
|
} else if in["box_pub_key"] == nil || in["coords"] == nil {
|
||||||
|
return Info{}, errors.New("Expecting both box_pub_key and coords")
|
||||||
|
} else {
|
||||||
|
if b, err := hex.DecodeString(in["box_pub_key"].(string)); err == nil {
|
||||||
|
copy(boxPubKey[:], b)
|
||||||
|
} else {
|
||||||
|
return Info{}, err
|
||||||
|
}
|
||||||
|
coords = util.DecodeCoordString(in["coords"].(string))
|
||||||
|
}
|
||||||
|
result, err := a.core.GetNodeInfo(boxPubKey, coords, nocache)
|
||||||
|
if err == nil {
|
||||||
|
var m map[string]interface{}
|
||||||
|
if err = json.Unmarshal(result, &m); err == nil {
|
||||||
|
return Info{"nodeinfo": m}, nil
|
||||||
|
}
|
||||||
|
return Info{}, err
|
||||||
}
|
}
|
||||||
return Info{}, err
|
return Info{}, err
|
||||||
}
|
})
|
||||||
return Info{}, err
|
*/
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start runs the admin API socket to listen for / respond to admin API calls.
|
// Start runs the admin API socket to listen for / respond to admin API calls.
|
||||||
|
@ -1,227 +0,0 @@
|
|||||||
package tuntap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Arceliar/phony"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
|
||||||
"golang.org/x/net/icmp"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
)
|
|
||||||
|
|
||||||
const tunConnTimeout = 2 * time.Minute
|
|
||||||
|
|
||||||
type tunConn struct {
|
|
||||||
phony.Inbox
|
|
||||||
tun *TunAdapter
|
|
||||||
conn *yggdrasil.Conn
|
|
||||||
addr address.Address
|
|
||||||
snet address.Subnet
|
|
||||||
stop chan struct{}
|
|
||||||
alive *time.Timer // From calling time.AfterFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tunConn) close() {
|
|
||||||
s.tun.Act(s, s._close_from_tun)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tunConn) _close_from_tun() {
|
|
||||||
go s.conn.Close() // Just in case it blocks on actor operations
|
|
||||||
delete(s.tun.addrToConn, s.addr)
|
|
||||||
delete(s.tun.subnetToConn, s.snet)
|
|
||||||
func() {
|
|
||||||
defer func() { recover() }()
|
|
||||||
close(s.stop) // Closes reader/writer goroutines
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tunConn) _read(bs []byte) (err error) {
|
|
||||||
select {
|
|
||||||
case <-s.stop:
|
|
||||||
err = errors.New("session was already closed")
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
if len(bs) == 0 {
|
|
||||||
err = errors.New("read packet with 0 size")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ipv4 := len(bs) > 20 && bs[0]&0xf0 == 0x40
|
|
||||||
ipv6 := len(bs) > 40 && bs[0]&0xf0 == 0x60
|
|
||||||
isCGA := true
|
|
||||||
// Check source addresses
|
|
||||||
switch {
|
|
||||||
case ipv6 && bs[8] == 0x02 && bytes.Equal(s.addr[:16], bs[8:24]): // source
|
|
||||||
case ipv6 && bs[8] == 0x03 && bytes.Equal(s.snet[:8], bs[8:16]): // source
|
|
||||||
default:
|
|
||||||
isCGA = false
|
|
||||||
}
|
|
||||||
// Check destination addresses
|
|
||||||
switch {
|
|
||||||
case ipv6 && bs[24] == 0x02 && bytes.Equal(s.tun.addr[:16], bs[24:40]): // destination
|
|
||||||
case ipv6 && bs[24] == 0x03 && bytes.Equal(s.tun.subnet[:8], bs[24:32]): // destination
|
|
||||||
default:
|
|
||||||
isCGA = false
|
|
||||||
}
|
|
||||||
// Decide how to handle the packet
|
|
||||||
var skip bool
|
|
||||||
switch {
|
|
||||||
case isCGA: // Allowed
|
|
||||||
case s.tun.ckr.isEnabled() && (ipv4 || ipv6):
|
|
||||||
var srcAddr address.Address
|
|
||||||
var dstAddr address.Address
|
|
||||||
var addrlen int
|
|
||||||
if ipv4 {
|
|
||||||
copy(srcAddr[:], bs[12:16])
|
|
||||||
copy(dstAddr[:], bs[16:20])
|
|
||||||
addrlen = 4
|
|
||||||
}
|
|
||||||
if ipv6 {
|
|
||||||
copy(srcAddr[:], bs[8:24])
|
|
||||||
copy(dstAddr[:], bs[24:40])
|
|
||||||
addrlen = 16
|
|
||||||
}
|
|
||||||
if !s.tun.ckr.isValidLocalAddress(dstAddr, addrlen) {
|
|
||||||
// The destination address isn't in our CKR allowed range
|
|
||||||
skip = true
|
|
||||||
} else if key, err := s.tun.ckr.getPublicKeyForAddress(srcAddr, addrlen); err == nil {
|
|
||||||
if *s.conn.RemoteAddr().(*crypto.BoxPubKey) == key {
|
|
||||||
// This is the one allowed CKR case, where source and destination addresses are both good
|
|
||||||
} else {
|
|
||||||
// The CKR key associated with this address doesn't match the sender's NodeID
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We have no CKR route for this source address
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
if skip {
|
|
||||||
err = errors.New("address not allowed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.tun.writer.writeFrom(s, bs)
|
|
||||||
s.stillAlive()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tunConn) writeFrom(from phony.Actor, bs []byte) {
|
|
||||||
s.Act(from, func() {
|
|
||||||
s._write(bs)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tunConn) _write(bs []byte) (err error) {
|
|
||||||
select {
|
|
||||||
case <-s.stop:
|
|
||||||
err = errors.New("session was already closed")
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
v4 := len(bs) > 20 && bs[0]&0xf0 == 0x40
|
|
||||||
v6 := len(bs) > 40 && bs[0]&0xf0 == 0x60
|
|
||||||
isCGA := true
|
|
||||||
// Check source addresses
|
|
||||||
switch {
|
|
||||||
case v6 && bs[8] == 0x02 && bytes.Equal(s.tun.addr[:16], bs[8:24]): // source
|
|
||||||
case v6 && bs[8] == 0x03 && bytes.Equal(s.tun.subnet[:8], bs[8:16]): // source
|
|
||||||
default:
|
|
||||||
isCGA = false
|
|
||||||
}
|
|
||||||
// Check destiantion addresses
|
|
||||||
switch {
|
|
||||||
case v6 && bs[24] == 0x02 && bytes.Equal(s.addr[:16], bs[24:40]): // destination
|
|
||||||
case v6 && bs[24] == 0x03 && bytes.Equal(s.snet[:8], bs[24:32]): // destination
|
|
||||||
default:
|
|
||||||
isCGA = false
|
|
||||||
}
|
|
||||||
// Decide how to handle the packet
|
|
||||||
var skip bool
|
|
||||||
switch {
|
|
||||||
case isCGA: // Allowed
|
|
||||||
case s.tun.ckr.isEnabled() && (v4 || v6):
|
|
||||||
var srcAddr address.Address
|
|
||||||
var dstAddr address.Address
|
|
||||||
var addrlen int
|
|
||||||
if v4 {
|
|
||||||
copy(srcAddr[:], bs[12:16])
|
|
||||||
copy(dstAddr[:], bs[16:20])
|
|
||||||
addrlen = 4
|
|
||||||
}
|
|
||||||
if v6 {
|
|
||||||
copy(srcAddr[:], bs[8:24])
|
|
||||||
copy(dstAddr[:], bs[24:40])
|
|
||||||
addrlen = 16
|
|
||||||
}
|
|
||||||
if !s.tun.ckr.isValidLocalAddress(srcAddr, addrlen) {
|
|
||||||
// The source address isn't in our CKR allowed range
|
|
||||||
skip = true
|
|
||||||
} else if key, err := s.tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
|
|
||||||
if *s.conn.RemoteAddr().(*crypto.BoxPubKey) == key {
|
|
||||||
// This is the one allowed CKR case, where source and destination addresses are both good
|
|
||||||
} else {
|
|
||||||
// The CKR key associated with this address doesn't match the sender's NodeID
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We have no CKR route for this destination address... why do we have the packet in the first place?
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
if skip {
|
|
||||||
err = errors.New("address not allowed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msg := yggdrasil.FlowKeyMessage{
|
|
||||||
FlowKey: util.GetFlowKey(bs),
|
|
||||||
Message: bs,
|
|
||||||
}
|
|
||||||
s.conn.WriteFrom(s, msg, func(err error) {
|
|
||||||
if err == nil {
|
|
||||||
// No point in wasting resources to send back an error if there was none
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Act(s.conn, func() {
|
|
||||||
if e, eok := err.(yggdrasil.ConnError); !eok {
|
|
||||||
if e.Closed() {
|
|
||||||
s.tun.log.Debugln(s.conn.String(), "TUN/TAP generic write debug:", err)
|
|
||||||
} else {
|
|
||||||
s.tun.log.Errorln(s.conn.String(), "TUN/TAP generic write error:", err)
|
|
||||||
}
|
|
||||||
} else if e.PacketTooBig() {
|
|
||||||
// TODO: This currently isn't aware of IPv4 for CKR
|
|
||||||
ptb := &icmp.PacketTooBig{
|
|
||||||
MTU: int(e.PacketMaximumSize()),
|
|
||||||
Data: bs[:900],
|
|
||||||
}
|
|
||||||
if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil {
|
|
||||||
s.tun.writer.writeFrom(s, packet)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if e.Closed() {
|
|
||||||
s.tun.log.Debugln(s.conn.String(), "TUN/TAP conn write debug:", err)
|
|
||||||
} else {
|
|
||||||
s.tun.log.Errorln(s.conn.String(), "TUN/TAP conn write error:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
s.stillAlive()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *tunConn) stillAlive() {
|
|
||||||
if s.alive != nil {
|
|
||||||
s.alive.Stop()
|
|
||||||
}
|
|
||||||
s.alive = time.AfterFunc(tunConnTimeout, s.close)
|
|
||||||
}
|
|
@ -1,12 +1,12 @@
|
|||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/yggdrasil"
|
//"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
|
|
||||||
"golang.org/x/net/icmp"
|
//"golang.org/x/net/icmp"
|
||||||
"golang.org/x/net/ipv6"
|
//"golang.org/x/net/ipv6"
|
||||||
|
|
||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
)
|
)
|
||||||
@ -84,139 +84,142 @@ 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 {
|
panic("TODO")
|
||||||
tun.log.Errorln("TUN iface read error:", err)
|
/*
|
||||||
return
|
if err != nil {
|
||||||
}
|
tun.log.Errorln("TUN iface read error:", err)
|
||||||
// Offset the buffer from now on so that we can ignore ethernet frames if
|
|
||||||
// they are present
|
|
||||||
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 iface read undersized unknown packet, length:", len(bs))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
var dstAddr address.Address
|
|
||||||
var dstSnet address.Subnet
|
|
||||||
var addrlen int
|
|
||||||
n := len(bs)
|
|
||||||
// Check the IP protocol - if it doesn't match then we drop the packet and
|
|
||||||
// do nothing with it
|
|
||||||
if bs[0]&0xf0 == 0x60 {
|
|
||||||
// Check if we have a fully-sized IPv6 header
|
|
||||||
if len(bs) < 40 {
|
|
||||||
tun.log.Traceln("TUN iface read undersized ipv6 packet, length:", len(bs))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check the packet size
|
// Offset the buffer from now on so that we can ignore ethernet frames if
|
||||||
if n-tun_IPv6_HEADER_LENGTH != 256*int(bs[4])+int(bs[5]) {
|
// they are present
|
||||||
|
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 iface read undersized unknown packet, length:", len(bs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// IPv6 address
|
// From the IP header, work out what our source and destination addresses
|
||||||
addrlen = 16
|
// and node IDs are. We will need these in order to work out where to send
|
||||||
copy(dstAddr[:addrlen], bs[24:])
|
// the packet
|
||||||
copy(dstSnet[:addrlen/2], bs[24:])
|
var dstAddr address.Address
|
||||||
} else if bs[0]&0xf0 == 0x40 {
|
var dstSnet address.Subnet
|
||||||
// Check if we have a fully-sized IPv4 header
|
var addrlen int
|
||||||
if len(bs) < 20 {
|
n := len(bs)
|
||||||
tun.log.Traceln("TUN iface read undersized ipv4 packet, length:", len(bs))
|
// Check the IP protocol - if it doesn't match then we drop the packet and
|
||||||
|
// do nothing with it
|
||||||
|
if bs[0]&0xf0 == 0x60 {
|
||||||
|
// Check if we have a fully-sized IPv6 header
|
||||||
|
if len(bs) < 40 {
|
||||||
|
tun.log.Traceln("TUN iface read undersized ipv6 packet, length:", len(bs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Check the packet size
|
||||||
|
if n-tun_IPv6_HEADER_LENGTH != 256*int(bs[4])+int(bs[5]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// IPv6 address
|
||||||
|
addrlen = 16
|
||||||
|
copy(dstAddr[:addrlen], bs[24:])
|
||||||
|
copy(dstSnet[:addrlen/2], bs[24:])
|
||||||
|
} else if bs[0]&0xf0 == 0x40 {
|
||||||
|
// Check if we have a fully-sized IPv4 header
|
||||||
|
if len(bs) < 20 {
|
||||||
|
tun.log.Traceln("TUN iface read undersized ipv4 packet, length:", len(bs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Check the packet size
|
||||||
|
if n != 256*int(bs[2])+int(bs[3]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// IPv4 address
|
||||||
|
addrlen = 4
|
||||||
|
copy(dstAddr[:addrlen], bs[16:])
|
||||||
|
} else {
|
||||||
|
// Unknown address length or protocol, so drop the packet and ignore it
|
||||||
|
tun.log.Traceln("Unknown packet type, dropping")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check the packet size
|
if tun.ckr.isEnabled() {
|
||||||
if n != 256*int(bs[2])+int(bs[3]) {
|
if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) {
|
||||||
return
|
if key, err := tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
|
||||||
|
// A public key was found, get the node ID for the search
|
||||||
|
panic("TODO")
|
||||||
|
//dstNodeID := crypto.GetNodeID(&key)
|
||||||
|
//dstAddr = *address.AddrForNodeID(dstNodeID)
|
||||||
|
//dstSnet = *address.SubnetForNodeID(dstNodeID)
|
||||||
|
addrlen = 16
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// IPv4 address
|
|
||||||
addrlen = 4
|
|
||||||
copy(dstAddr[:addrlen], bs[16:])
|
|
||||||
} else {
|
|
||||||
// Unknown address length or protocol, so drop the packet and ignore it
|
|
||||||
tun.log.Traceln("Unknown packet type, dropping")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if tun.ckr.isEnabled() {
|
|
||||||
if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) {
|
if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) {
|
||||||
if /*key*/ _, err := tun.ckr.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
|
// Couldn't find this node's ygg IP
|
||||||
// A public key was found, get the node ID for the search
|
dlen := len(bs)
|
||||||
panic("TODO")
|
if dlen > 900 {
|
||||||
//dstNodeID := crypto.GetNodeID(&key)
|
dlen = 900
|
||||||
//dstAddr = *address.AddrForNodeID(dstNodeID)
|
|
||||||
//dstSnet = *address.SubnetForNodeID(dstNodeID)
|
|
||||||
addrlen = 16
|
|
||||||
}
|
}
|
||||||
|
ptb := &icmp.DstUnreach{
|
||||||
|
Data: bs[:dlen],
|
||||||
|
}
|
||||||
|
if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypeDestinationUnreachable, 0, ptb); err == nil {
|
||||||
|
tun.writer.writeFrom(nil, packet)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
// Do we have an active connection for this node address?
|
||||||
if addrlen != 16 || (!dstAddr.IsValid() && !dstSnet.IsValid()) {
|
var dstString string
|
||||||
// Couldn't find this node's ygg IP
|
session, isIn := tun.addrToConn[dstAddr]
|
||||||
dlen := len(bs)
|
|
||||||
if dlen > 900 {
|
|
||||||
dlen = 900
|
|
||||||
}
|
|
||||||
ptb := &icmp.DstUnreach{
|
|
||||||
Data: bs[:dlen],
|
|
||||||
}
|
|
||||||
if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypeDestinationUnreachable, 0, ptb); err == nil {
|
|
||||||
tun.writer.writeFrom(nil, packet)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Do we have an active connection for this node address?
|
|
||||||
var dstString string
|
|
||||||
session, isIn := tun.addrToConn[dstAddr]
|
|
||||||
if !isIn || session == nil {
|
|
||||||
session, isIn = tun.subnetToConn[dstSnet]
|
|
||||||
if !isIn || session == nil {
|
if !isIn || session == nil {
|
||||||
// Neither an address nor a subnet mapping matched, therefore populate
|
session, isIn = tun.subnetToConn[dstSnet]
|
||||||
// the node ID and mask to commence a search
|
if !isIn || session == nil {
|
||||||
panic("TODO")
|
// Neither an address nor a subnet mapping matched, therefore populate
|
||||||
if dstAddr.IsValid() {
|
// the node ID and mask to commence a search
|
||||||
//dstString = dstAddr.GetNodeIDLengthString()
|
panic("TODO")
|
||||||
} else {
|
if dstAddr.IsValid() {
|
||||||
//dstString = dstSnet.GetNodeIDLengthString()
|
//dstString = dstAddr.GetNodeIDLengthString()
|
||||||
|
} else {
|
||||||
|
//dstString = dstSnet.GetNodeIDLengthString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// If we don't have a connection then we should open one
|
||||||
// If we don't have a connection then we should open one
|
if !isIn || session == nil {
|
||||||
if !isIn || session == nil {
|
// Check we haven't been given empty node ID, really this shouldn't ever
|
||||||
// Check we haven't been given empty node ID, really this shouldn't ever
|
// happen but just to be sure...
|
||||||
// happen but just to be sure...
|
if dstString == "" {
|
||||||
if dstString == "" {
|
panic("Given empty dstString - this shouldn't happen")
|
||||||
panic("Given empty dstString - this shouldn't happen")
|
}
|
||||||
|
_, known := tun.dials[dstString]
|
||||||
|
tun.dials[dstString] = append(tun.dials[dstString], bs)
|
||||||
|
for len(tun.dials[dstString]) > 32 {
|
||||||
|
tun.dials[dstString] = tun.dials[dstString][1:]
|
||||||
|
}
|
||||||
|
if !known {
|
||||||
|
go func() {
|
||||||
|
conn, err := tun.dialer.Dial("nodeid", dstString)
|
||||||
|
tun.Act(nil, func() {
|
||||||
|
packets := tun.dials[dstString]
|
||||||
|
delete(tun.dials, dstString)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// We've been given a connection so prepare the session wrapper
|
||||||
|
var tc *tunConn
|
||||||
|
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 iface wrap:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, packet := range packets {
|
||||||
|
tc.writeFrom(nil, packet)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_, known := tun.dials[dstString]
|
// If we have a connection now, try writing to it
|
||||||
tun.dials[dstString] = append(tun.dials[dstString], bs)
|
if isIn && session != nil {
|
||||||
for len(tun.dials[dstString]) > 32 {
|
session.writeFrom(tun, bs)
|
||||||
tun.dials[dstString] = tun.dials[dstString][1:]
|
|
||||||
}
|
}
|
||||||
if !known {
|
*/
|
||||||
go func() {
|
|
||||||
conn, err := tun.dialer.Dial("nodeid", dstString)
|
|
||||||
tun.Act(nil, func() {
|
|
||||||
packets := tun.dials[dstString]
|
|
||||||
delete(tun.dials, dstString)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// We've been given a connection so prepare the session wrapper
|
|
||||||
var tc *tunConn
|
|
||||||
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 iface wrap:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, packet := range packets {
|
|
||||||
tc.writeFrom(nil, packet)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we have a connection now, try writing to it
|
|
||||||
if isIn && session != nil {
|
|
||||||
session.writeFrom(tun, bs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
152
src/tuntap/keystore.go
Normal file
152
src/tuntap/keystore.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package tuntap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ed25519"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
iwt "github.com/Arceliar/ironwood/types"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
|
)
|
||||||
|
|
||||||
|
const keyStoreTimeout = 2 * time.Minute
|
||||||
|
|
||||||
|
type keyStore struct {
|
||||||
|
tun *TunAdapter
|
||||||
|
mutex sync.Mutex
|
||||||
|
keyToInfo map[keyArray]*keyInfo
|
||||||
|
addrToInfo map[address.Address]*keyInfo
|
||||||
|
addrBuffer map[address.Address]*buffer
|
||||||
|
subnetToInfo map[address.Subnet]*keyInfo
|
||||||
|
subnetBuffer map[address.Subnet]*buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyArray [ed25519.PublicKeySize]byte
|
||||||
|
|
||||||
|
type keyInfo struct {
|
||||||
|
key keyArray
|
||||||
|
address address.Address
|
||||||
|
subnet address.Subnet
|
||||||
|
mtu MTU // TODO use this
|
||||||
|
timeout *time.Timer // From calling a time.AfterFunc to do cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
type buffer struct {
|
||||||
|
packets [][]byte
|
||||||
|
timeout *time.Timer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyStore) init(tun *TunAdapter) {
|
||||||
|
k.tun = tun
|
||||||
|
k.keyToInfo = make(map[keyArray]*keyInfo)
|
||||||
|
k.addrToInfo = make(map[address.Address]*keyInfo)
|
||||||
|
k.addrBuffer = make(map[address.Address]*buffer)
|
||||||
|
k.subnetToInfo = make(map[address.Subnet]*keyInfo)
|
||||||
|
k.subnetBuffer = make(map[address.Subnet]*buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyStore) sendToAddress(addr address.Address, bs []byte) {
|
||||||
|
k.mutex.Lock()
|
||||||
|
defer k.mutex.Unlock()
|
||||||
|
if info := k.addrToInfo[addr]; info != nil {
|
||||||
|
k.tun.core.WriteTo(bs, iwt.Addr(info.key[:]))
|
||||||
|
k.resetTimeout(info)
|
||||||
|
} else {
|
||||||
|
var buf *buffer
|
||||||
|
if buf = k.addrBuffer[addr]; buf == nil {
|
||||||
|
buf = new(buffer)
|
||||||
|
k.addrBuffer[addr] = buf
|
||||||
|
}
|
||||||
|
msg := append([]byte(nil), bs...)
|
||||||
|
buf.packets = append(buf.packets, msg)
|
||||||
|
if buf.timeout != nil {
|
||||||
|
buf.timeout.Stop()
|
||||||
|
}
|
||||||
|
buf.timeout = time.AfterFunc(keyStoreTimeout, func() {
|
||||||
|
k.mutex.Lock()
|
||||||
|
defer k.mutex.Unlock()
|
||||||
|
if nbuf := k.addrBuffer[addr]; nbuf == buf {
|
||||||
|
delete(k.addrBuffer, addr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) {
|
||||||
|
k.mutex.Lock()
|
||||||
|
defer k.mutex.Unlock()
|
||||||
|
if info := k.subnetToInfo[subnet]; info != nil {
|
||||||
|
k.tun.core.WriteTo(bs, iwt.Addr(info.key[:]))
|
||||||
|
k.resetTimeout(info)
|
||||||
|
} else {
|
||||||
|
var buf *buffer
|
||||||
|
if buf = k.subnetBuffer[subnet]; buf == nil {
|
||||||
|
buf = new(buffer)
|
||||||
|
k.subnetBuffer[subnet] = buf
|
||||||
|
}
|
||||||
|
msg := append([]byte(nil), bs...)
|
||||||
|
buf.packets = append(buf.packets, msg)
|
||||||
|
if buf.timeout != nil {
|
||||||
|
buf.timeout.Stop()
|
||||||
|
}
|
||||||
|
buf.timeout = time.AfterFunc(keyStoreTimeout, func() {
|
||||||
|
k.mutex.Lock()
|
||||||
|
defer k.mutex.Unlock()
|
||||||
|
if nbuf := k.subnetBuffer[subnet]; nbuf == buf {
|
||||||
|
delete(k.subnetBuffer, subnet)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyStore) update(key ed25519.PublicKey) {
|
||||||
|
k.mutex.Lock()
|
||||||
|
defer k.mutex.Unlock()
|
||||||
|
var kArray keyArray
|
||||||
|
copy(kArray[:], key)
|
||||||
|
var info *keyInfo
|
||||||
|
if info = k.keyToInfo[kArray]; info == nil {
|
||||||
|
info = new(keyInfo)
|
||||||
|
info.key = kArray
|
||||||
|
info.address = *address.AddrForKey(ed25519.PublicKey(info.key[:]))
|
||||||
|
info.subnet = *address.SubnetForKey(ed25519.PublicKey(info.key[:]))
|
||||||
|
info.mtu = MTU(^uint16(0)) // TODO
|
||||||
|
k.keyToInfo[info.key] = info
|
||||||
|
k.addrToInfo[info.address] = info
|
||||||
|
k.subnetToInfo[info.subnet] = info
|
||||||
|
k.resetTimeout(info)
|
||||||
|
if buf := k.addrBuffer[info.address]; buf != nil {
|
||||||
|
for _, bs := range buf.packets {
|
||||||
|
k.tun.core.WriteTo(bs, iwt.Addr(info.key[:]))
|
||||||
|
}
|
||||||
|
delete(k.addrBuffer, info.address)
|
||||||
|
}
|
||||||
|
if buf := k.subnetBuffer[info.subnet]; buf != nil {
|
||||||
|
for _, bs := range buf.packets {
|
||||||
|
k.tun.core.WriteTo(bs, iwt.Addr(info.key[:]))
|
||||||
|
}
|
||||||
|
delete(k.subnetBuffer, info.subnet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k.resetTimeout(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyStore) resetTimeout(info *keyInfo) {
|
||||||
|
if info.timeout != nil {
|
||||||
|
info.timeout.Stop()
|
||||||
|
}
|
||||||
|
info.timeout = time.AfterFunc(keyStoreTimeout, func() {
|
||||||
|
k.mutex.Lock()
|
||||||
|
defer k.mutex.Unlock()
|
||||||
|
if nfo := k.keyToInfo[info.key]; nfo == info {
|
||||||
|
delete(k.keyToInfo, info.key)
|
||||||
|
}
|
||||||
|
if nfo := k.addrToInfo[info.address]; nfo == info {
|
||||||
|
delete(k.addrToInfo, info.address)
|
||||||
|
}
|
||||||
|
if nfo := k.subnetToInfo[info.subnet]; nfo == info {
|
||||||
|
delete(k.subnetToInfo, info.subnet)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -9,6 +9,7 @@ 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"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -38,13 +39,12 @@ const tun_IPv6_HEADER_LENGTH = 40
|
|||||||
// calling yggdrasil.Start().
|
// calling yggdrasil.Start().
|
||||||
type TunAdapter struct {
|
type TunAdapter struct {
|
||||||
core *yggdrasil.Core
|
core *yggdrasil.Core
|
||||||
|
store keyStore
|
||||||
writer tunWriter
|
writer tunWriter
|
||||||
reader tunReader
|
reader tunReader
|
||||||
config *config.NodeState
|
config *config.NodeState
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
listener *yggdrasil.Listener
|
|
||||||
dialer *yggdrasil.Dialer
|
|
||||||
addr address.Address
|
addr address.Address
|
||||||
subnet address.Subnet
|
subnet address.Subnet
|
||||||
ckr cryptokey
|
ckr cryptokey
|
||||||
@ -53,15 +53,12 @@ type TunAdapter struct {
|
|||||||
iface tun.Device
|
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
|
isOpen bool
|
||||||
subnetToConn map[address.Subnet]*tunConn
|
|
||||||
dials map[string][][]byte // Buffer of packets to send after dialing finishes
|
|
||||||
isOpen bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TunOptions struct {
|
type TunOptions struct {
|
||||||
Listener *yggdrasil.Listener
|
//Listener *yggdrasil.Listener
|
||||||
Dialer *yggdrasil.Dialer
|
//Dialer *yggdrasil.Dialer
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -113,20 +110,20 @@ func MaximumMTU() MTU {
|
|||||||
// Init initialises the TUN 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 {
|
||||||
|
/* TODO
|
||||||
tunoptions, ok := options.(TunOptions)
|
tunoptions, ok := options.(TunOptions)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid options supplied to TunAdapter module")
|
return fmt.Errorf("invalid options supplied to TunAdapter module")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
tun.core = core
|
tun.core = core
|
||||||
|
tun.store.init(tun)
|
||||||
tun.config = config
|
tun.config = config
|
||||||
tun.log = log
|
tun.log = log
|
||||||
tun.listener = tunoptions.Listener
|
|
||||||
tun.dialer = tunoptions.Dialer
|
|
||||||
tun.addrToConn = make(map[address.Address]*tunConn)
|
|
||||||
tun.subnetToConn = make(map[address.Subnet]*tunConn)
|
|
||||||
tun.dials = make(map[string][][]byte)
|
|
||||||
tun.writer.tun = tun
|
tun.writer.tun = tun
|
||||||
tun.reader.tun = tun
|
tun.reader.tun = tun
|
||||||
|
tun.core.SetOutOfBandHandler(tun.oobHandler)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +142,7 @@ func (tun *TunAdapter) _start() error {
|
|||||||
return errors.New("TUN 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 {
|
||||||
return errors.New("no configuration available to TUN")
|
return errors.New("no configuration available to TUN")
|
||||||
}
|
}
|
||||||
var boxPub crypto.BoxPubKey
|
var boxPub crypto.BoxPubKey
|
||||||
@ -169,9 +166,9 @@ func (tun *TunAdapter) _start() error {
|
|||||||
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.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", current.IfMTU, tun.MTU(), MaximumMTU())
|
||||||
}
|
}
|
||||||
tun.core.SetMaximumSessionMTU(tun.MTU())
|
// TODO tun.core.SetMaximumSessionMTU(tun.MTU())
|
||||||
tun.isOpen = true
|
tun.isOpen = true
|
||||||
go tun.handler()
|
// TODO go tun.handler()
|
||||||
tun.reader.Act(nil, tun.reader._read) // Start the reader
|
tun.reader.Act(nil, tun.reader._read) // Start the reader
|
||||||
tun.ckr.init(tun)
|
tun.ckr.init(tun)
|
||||||
return nil
|
return nil
|
||||||
@ -225,6 +222,7 @@ func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) {
|
|||||||
tun.Act(nil, tun.ckr.configure)
|
tun.Act(nil, tun.ckr.configure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (tun *TunAdapter) handler() error {
|
func (tun *TunAdapter) handler() error {
|
||||||
for {
|
for {
|
||||||
// Accept the incoming connection
|
// Accept the incoming connection
|
||||||
@ -283,3 +281,19 @@ func (tun *TunAdapter) _wrap(conn *yggdrasil.Conn) (c *tunConn, err error) {
|
|||||||
// Return
|
// Return
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (tun *TunAdapter) oobHandler(fromKey, toKey ed25519.PublicKey, data []byte) {
|
||||||
|
panic("TODO")
|
||||||
|
// parse packet
|
||||||
|
// If it's a lookup then send a response
|
||||||
|
// If it's a response then (maybe) update the keystore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tun *TunAdapter) sendKeyLookup(partial ed25519.PublicKey) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tun *TunAdapter) sendKeyResponse(dest ed25519.PublicKey) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user