Merge pull request #474 from neilalexander/gomobile

Various API changes and simplifications to fix mobile builds
This commit is contained in:
Neil Alexander 2019-07-28 19:34:06 +01:00 committed by GitHub
commit 7c4c1558ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 87 additions and 659 deletions

View file

@ -59,7 +59,7 @@ type DHTRes struct {
}
// NodeInfoPayload represents a RequestNodeInfo response, in bytes.
type NodeInfoPayload nodeinfoPayload
type NodeInfoPayload []byte
// SwitchQueues represents information from the switch related to link
// congestion and a list of switch queues created in response to congestion on a
@ -261,7 +261,7 @@ func BuildVersion() string {
return buildVersion
}
// ListenConn returns a listener for Yggdrasil session connections.
// ConnListen returns a listener for Yggdrasil session connections.
func (c *Core) ConnListen() (*Listener, error) {
c.sessions.listenerMutex.Lock()
defer c.sessions.listenerMutex.Unlock()
@ -290,18 +290,6 @@ func (c *Core) ListenTCP(uri string) (*TcpListener, error) {
return c.link.tcp.listen(uri)
}
// NewEncryptionKeys generates a new encryption keypair. The encryption keys are
// used to encrypt traffic and to derive the IPv6 address/subnet of the node.
func (c *Core) NewEncryptionKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) {
return crypto.NewBoxKeys()
}
// NewSigningKeys generates a new signing keypair. The signing keys are used to
// derive the structure of the spanning tree.
func (c *Core) NewSigningKeys() (*crypto.SigPubKey, *crypto.SigPrivKey) {
return crypto.NewSigKeys()
}
// NodeID gets the node ID.
func (c *Core) NodeID() *crypto.NodeID {
return crypto.GetNodeID(&c.boxPub)
@ -312,13 +300,13 @@ func (c *Core) TreeID() *crypto.TreeID {
return crypto.GetTreeID(&c.sigPub)
}
// SigPubKey gets the node's signing public key.
func (c *Core) SigPubKey() string {
// SigningPublicKey gets the node's signing public key.
func (c *Core) SigningPublicKey() string {
return hex.EncodeToString(c.sigPub[:])
}
// BoxPubKey gets the node's encryption public key.
func (c *Core) BoxPubKey() string {
// EncryptionPublicKey gets the node's encryption public key.
func (c *Core) EncryptionPublicKey() string {
return hex.EncodeToString(c.boxPub[:])
}
@ -330,27 +318,21 @@ func (c *Core) Coords() []byte {
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
// address.
func (c *Core) Address() *net.IP {
func (c *Core) Address() net.IP {
address := net.IP(address.AddrForNodeID(c.NodeID())[:])
return &address
return address
}
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
// /64 subnet.
func (c *Core) Subnet() *net.IPNet {
func (c *Core) Subnet() net.IPNet {
subnet := address.SubnetForNodeID(c.NodeID())[:]
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
return net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
}
// RouterAddresses returns the raw address and subnet types as used by the
// router
func (c *Core) RouterAddresses() (address.Address, address.Subnet) {
return c.router.addr, c.router.subnet
}
// NodeInfo gets the currently configured nodeinfo.
func (c *Core) MyNodeInfo() nodeinfoPayload {
// MyNodeInfo gets the currently configured nodeinfo.
func (c *Core) MyNodeInfo() NodeInfoPayload {
return c.router.nodeinfo.getNodeInfo()
}
@ -373,7 +355,7 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
}
if !nocache {
if response, err := c.router.nodeinfo.getCachedNodeInfo(key); err == nil {
return NodeInfoPayload(response), nil
return response, nil
}
}
var coords []byte
@ -388,9 +370,9 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
coords = append(coords, uint8(u64))
}
}
response := make(chan *nodeinfoPayload, 1)
response := make(chan *NodeInfoPayload, 1)
sendNodeInfoRequest := func() {
c.router.nodeinfo.addCallback(key, func(nodeinfo *nodeinfoPayload) {
c.router.nodeinfo.addCallback(key, func(nodeinfo *NodeInfoPayload) {
defer func() { recover() }()
select {
case response <- nodeinfo:
@ -405,9 +387,9 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
close(response)
}()
for res := range response {
return NodeInfoPayload(*res), nil
return *res, nil
}
return NodeInfoPayload{}, errors.New(fmt.Sprintf("getNodeInfo timeout: %s", keyString))
return NodeInfoPayload{}, fmt.Errorf("getNodeInfo timeout: %s", keyString)
}
// SetSessionGatekeeper allows you to configure a handler function for deciding
@ -493,7 +475,8 @@ func (c *Core) RemoveAllowedEncryptionPublicKey(bstr string) (err error) {
return nil
}
// Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID.
// DHTPing sends a DHT ping to the node with the provided key and coords,
// optionally looking up the specified target NodeID.
func (c *Core) DHTPing(keyString, coordString, targetString string) (DHTRes, error) {
var key crypto.BoxPubKey
if keyBytes, err := hex.DecodeString(keyString); err != nil {
@ -553,5 +536,5 @@ func (c *Core) DHTPing(keyString, coordString, targetString string) (DHTRes, err
}
return r, nil
}
return DHTRes{}, errors.New(fmt.Sprintf("DHT ping timeout: %s", keyString))
return DHTRes{}, fmt.Errorf("DHT ping timeout: %s", keyString)
}

View file

@ -35,8 +35,17 @@ func (e *ConnError) Temporary() bool {
// PacketTooBig returns in response to sending a packet that is too large, and
// if so, the maximum supported packet size that should be used for the
// connection.
func (e *ConnError) PacketTooBig() (bool, int) {
return e.maxsize > 0, e.maxsize
func (e *ConnError) PacketTooBig() bool {
return e.maxsize > 0
}
// PacketMaximumSize returns the maximum supported packet size. This will only
// return a non-zero value if ConnError.PacketTooBig() returns true.
func (e *ConnError) PacketMaximumSize() int {
if !e.PacketTooBig() {
return 0
}
return e.maxsize
}
// Closed returns if the session is already closed and is now unusable.

View file

@ -45,7 +45,7 @@ func (c *Core) init() error {
c.log = log.New(ioutil.Discard, "", 0)
}
current, _ := c.config.Get()
current := c.config.GetCurrent()
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
if err != nil {
@ -94,7 +94,7 @@ func (c *Core) init() error {
func (c *Core) addPeerLoop() {
for {
// the peers from the config - these could change!
current, _ := c.config.Get()
current := c.config.GetCurrent()
// Add peers from the Peers section
for _, peer := range current.Peers {

View file

@ -13,7 +13,7 @@ import (
type nodeinfo struct {
core *Core
myNodeInfo nodeinfoPayload
myNodeInfo NodeInfoPayload
myNodeInfoMutex sync.RWMutex
callbacks map[crypto.BoxPubKey]nodeinfoCallback
callbacksMutex sync.Mutex
@ -21,15 +21,13 @@ type nodeinfo struct {
cacheMutex sync.RWMutex
}
type nodeinfoPayload []byte
type nodeinfoCached struct {
payload nodeinfoPayload
payload NodeInfoPayload
created time.Time
}
type nodeinfoCallback struct {
call func(nodeinfo *nodeinfoPayload)
call func(nodeinfo *NodeInfoPayload)
created time.Time
}
@ -38,7 +36,7 @@ type nodeinfoReqRes struct {
SendPermPub crypto.BoxPubKey // Sender's permanent key
SendCoords []byte // Sender's coords
IsResponse bool
NodeInfo nodeinfoPayload
NodeInfo NodeInfoPayload
}
// Initialises the nodeinfo cache/callback maps, and starts a goroutine to keep
@ -70,7 +68,7 @@ func (m *nodeinfo) init(core *Core) {
}
// Add a callback for a nodeinfo lookup
func (m *nodeinfo) addCallback(sender crypto.BoxPubKey, call func(nodeinfo *nodeinfoPayload)) {
func (m *nodeinfo) addCallback(sender crypto.BoxPubKey, call func(nodeinfo *NodeInfoPayload)) {
m.callbacksMutex.Lock()
defer m.callbacksMutex.Unlock()
m.callbacks[sender] = nodeinfoCallback{
@ -80,7 +78,7 @@ func (m *nodeinfo) addCallback(sender crypto.BoxPubKey, call func(nodeinfo *node
}
// Handles the callback, if there is one
func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo nodeinfoPayload) {
func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo NodeInfoPayload) {
m.callbacksMutex.Lock()
defer m.callbacksMutex.Unlock()
if callback, ok := m.callbacks[sender]; ok {
@ -90,7 +88,7 @@ func (m *nodeinfo) callback(sender crypto.BoxPubKey, nodeinfo nodeinfoPayload) {
}
// Get the current node's nodeinfo
func (m *nodeinfo) getNodeInfo() nodeinfoPayload {
func (m *nodeinfo) getNodeInfo() NodeInfoPayload {
m.myNodeInfoMutex.RLock()
defer m.myNodeInfoMutex.RUnlock()
return m.myNodeInfo
@ -135,7 +133,7 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error {
}
// Add nodeinfo into the cache for a node
func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload nodeinfoPayload) {
func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload NodeInfoPayload) {
m.cacheMutex.Lock()
defer m.cacheMutex.Unlock()
m.cache[key] = nodeinfoCached{
@ -145,13 +143,13 @@ func (m *nodeinfo) addCachedNodeInfo(key crypto.BoxPubKey, payload nodeinfoPaylo
}
// Get a nodeinfo entry from the cache
func (m *nodeinfo) getCachedNodeInfo(key crypto.BoxPubKey) (nodeinfoPayload, error) {
func (m *nodeinfo) getCachedNodeInfo(key crypto.BoxPubKey) (NodeInfoPayload, error) {
m.cacheMutex.RLock()
defer m.cacheMutex.RUnlock()
if nodeinfo, ok := m.cache[key]; ok {
return nodeinfo.payload, nil
}
return nodeinfoPayload{}, errors.New("No cache entry found")
return NodeInfoPayload{}, errors.New("No cache entry found")
}
// Handles a nodeinfo request/response - called from the router

View file

@ -132,187 +132,12 @@ func (r *router) mainLoop() {
case f := <-r.admin:
f()
case e := <-r.reconfigure:
current, _ := r.core.config.Get()
current := r.core.config.GetCurrent()
e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
}
}
}
/*
// Checks a packet's to/from address to make sure it's in the allowed range.
// If a session to the destination exists, gets the session and passes the packet to it.
// If no session exists, it triggers (or continues) a search.
// If the session hasn't responded recently, it triggers a ping or search to keep things alive or deal with broken coords *relatively* quickly.
// It also deals with oversized packets if there are MTU issues by calling into icmpv6.go to spoof PacketTooBig traffic, or DestinationUnreachable if the other side has their adapter disabled.
func (r *router) sendPacket(bs []byte) {
var sourceAddr address.Address
var destAddr address.Address
var destSnet address.Subnet
var destPubKey *crypto.BoxPubKey
var destNodeID *crypto.NodeID
var addrlen int
if bs[0]&0xf0 == 0x60 {
// Check if we have a fully-sized header
if len(bs) < 40 {
panic("Tried to send a packet shorter than an IPv6 header...")
}
// IPv6 address
addrlen = 16
copy(sourceAddr[:addrlen], bs[8:])
copy(destAddr[:addrlen], bs[24:])
copy(destSnet[:addrlen/2], bs[24:])
} else if bs[0]&0xf0 == 0x40 {
// Check if we have a fully-sized header
if len(bs) < 20 {
panic("Tried to send a packet shorter than an IPv4 header...")
}
// IPv4 address
addrlen = 4
copy(sourceAddr[:addrlen], bs[12:])
copy(destAddr[:addrlen], bs[16:])
} else {
// Unknown address length
return
}
if !r.cryptokey.isValidSource(sourceAddr, addrlen) {
// The packet had a source address that doesn't belong to us or our
// configured crypto-key routing source subnets
return
}
if !destAddr.IsValid() && !destSnet.IsValid() {
// The addresses didn't match valid Yggdrasil node addresses so let's see
// whether it matches a crypto-key routing range instead
if key, err := r.cryptokey.getPublicKeyForAddress(destAddr, addrlen); err == nil {
// A public key was found, get the node ID for the search
destPubKey = &key
destNodeID = crypto.GetNodeID(destPubKey)
// Do a quick check to ensure that the node ID refers to a vaild Yggdrasil
// address or subnet - this might be superfluous
addr := *address.AddrForNodeID(destNodeID)
copy(destAddr[:], addr[:])
copy(destSnet[:], addr[:])
if !destAddr.IsValid() && !destSnet.IsValid() {
return
}
} else {
// No public key was found in the CKR table so we've exhausted our options
return
}
}
searchCompleted := func(sinfo *sessionInfo, err error) {
if err != nil {
r.core.log.Debugln("DHT search failed:", err)
return
}
}
doSearch := func(packet []byte) {
var nodeID, mask *crypto.NodeID
switch {
case destNodeID != nil:
// We already know the full node ID, probably because it's from a CKR
// route in which the public key is known ahead of time
nodeID = destNodeID
var m crypto.NodeID
for i := range m {
m[i] = 0xFF
}
mask = &m
case destAddr.IsValid():
// We don't know the full node ID - try and use the address to generate
// a truncated node ID
nodeID, mask = destAddr.GetNodeIDandMask()
case destSnet.IsValid():
// We don't know the full node ID - try and use the subnet to generate
// a truncated node ID
nodeID, mask = destSnet.GetNodeIDandMask()
default:
return
}
sinfo, isIn := r.core.searches.searches[*nodeID]
if !isIn {
sinfo = r.core.searches.newIterSearch(nodeID, mask, searchCompleted)
}
if packet != nil {
sinfo.packet = packet
}
r.core.searches.continueSearch(sinfo)
}
var sinfo *sessionInfo
var isIn bool
if destAddr.IsValid() {
sinfo, isIn = r.core.sessions.getByTheirAddr(&destAddr)
}
if destSnet.IsValid() {
sinfo, isIn = r.core.sessions.getByTheirSubnet(&destSnet)
}
sTime := sinfo.time.Load().(time.Time)
pingTime := sinfo.pingTime.Load().(time.Time)
pingSend := sinfo.pingSend.Load().(time.Time)
switch {
case !isIn || !sinfo.init.Load().(bool):
// No or unintiialized session, so we need to search first
doSearch(bs)
case time.Since(sTime) > 6*time.Second:
if sTime.Before(pingTime) && time.Since(pingTime) > 6*time.Second {
// We haven't heard from the dest in a while
// We tried pinging but didn't get a response
// They may have changed coords
// Try searching to discover new coords
// Note that search spam is throttled internally
doSearch(nil)
} else {
// We haven't heard about the dest in a while
now := time.Now()
if !sTime.Before(pingTime) {
// Update pingTime to start the clock for searches (above)
sinfo.pingTime.Store(now)
}
if time.Since(pingSend) > time.Second {
// Send at most 1 ping per second
sinfo.pingSend.Store(now)
r.core.sessions.sendPingPong(sinfo, false)
}
}
fallthrough // Also send the packet
default:
// If we know the public key ahead of time (i.e. a CKR route) then check
// if the session perm pub key matches before we send the packet to it
if destPubKey != nil {
if !bytes.Equal((*destPubKey)[:], sinfo.theirPermPub[:]) {
return
}
}
// Drop packets if the session MTU is 0 - this means that one or other
// side probably has their TUN adapter disabled
if sinfo.getMTU() == 0 {
// Don't continue - drop the packet
return
}
// Generate an ICMPv6 Packet Too Big for packets larger than session MTU
if len(bs) > int(sinfo.getMTU()) {
// Get the size of the oversized payload, up to a max of 900 bytes
window := 900
if int(sinfo.getMTU()) < window {
window = int(sinfo.getMTU())
}
// Send the error back to the adapter
r.reject <- RejectedPacket{
Reason: PacketTooBig,
Packet: bs[:window],
Detail: int(sinfo.getMTU()),
}
// Don't continue - drop the packet
return
}
sinfo.send <- bs
}
}
*/
// Checks incoming traffic type and passes it to the appropriate handler.
func (r *router) handleIn(packet []byte) {
pType, pTypeLen := wire_decode_uint64(packet)

View file

@ -394,7 +394,7 @@ func (p *nodeinfoReqRes) decode(bs []byte) bool {
if len(bs) == 0 {
return false
}
p.NodeInfo = make(nodeinfoPayload, len(bs))
p.NodeInfo = make(NodeInfoPayload, len(bs))
if !wire_chop_slice(p.NodeInfo[:], &bs) {
return false
}