2021-05-23 19:42:26 +00:00
|
|
|
package core
|
2019-05-18 16:21:02 +00:00
|
|
|
|
|
|
|
import (
|
2021-05-15 19:50:56 +00:00
|
|
|
"crypto/ed25519"
|
2021-06-13 10:43:03 +00:00
|
|
|
"encoding/json"
|
2022-10-02 12:20:39 +00:00
|
|
|
"fmt"
|
2019-05-18 16:21:02 +00:00
|
|
|
"net"
|
2021-05-24 01:34:13 +00:00
|
|
|
"net/url"
|
2022-10-02 12:20:39 +00:00
|
|
|
"sync/atomic"
|
|
|
|
"time"
|
2019-05-18 16:21:02 +00:00
|
|
|
|
2022-09-17 19:07:00 +00:00
|
|
|
"github.com/Arceliar/phony"
|
2021-05-08 13:35:58 +00:00
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
2019-05-18 16:21:02 +00:00
|
|
|
)
|
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
type SelfInfo struct {
|
2023-03-19 10:33:07 +00:00
|
|
|
Key ed25519.PublicKey
|
|
|
|
RoutingEntries uint64
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
type PeerInfo struct {
|
2022-10-26 08:24:24 +00:00
|
|
|
Key ed25519.PublicKey
|
|
|
|
Root ed25519.PublicKey
|
|
|
|
Coords []uint64
|
|
|
|
Port uint64
|
|
|
|
Priority uint8
|
|
|
|
Remote string
|
|
|
|
RXBytes uint64
|
|
|
|
TXBytes uint64
|
|
|
|
Uptime time.Duration
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
type DHTEntryInfo struct {
|
2023-03-26 21:49:40 +00:00
|
|
|
Key ed25519.PublicKey
|
|
|
|
Parent ed25519.PublicKey
|
|
|
|
Sequence uint64
|
|
|
|
//Port uint64
|
|
|
|
//Rest uint64
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2023-03-26 21:49:40 +00:00
|
|
|
/*
|
2022-08-06 14:05:12 +00:00
|
|
|
type PathEntryInfo struct {
|
2023-03-19 10:33:07 +00:00
|
|
|
Key ed25519.PublicKey
|
|
|
|
Sequence uint64
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
2023-03-26 21:49:40 +00:00
|
|
|
*/
|
2019-05-20 18:51:44 +00:00
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
type SessionInfo struct {
|
2022-09-03 15:55:57 +00:00
|
|
|
Key ed25519.PublicKey
|
|
|
|
RXBytes uint64
|
|
|
|
TXBytes uint64
|
|
|
|
Uptime time.Duration
|
2019-05-19 15:29:04 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
func (c *Core) GetSelf() SelfInfo {
|
|
|
|
var self SelfInfo
|
2021-07-05 18:14:12 +00:00
|
|
|
s := c.PacketConn.PacketConn.Debug.GetSelf()
|
2021-05-15 19:50:56 +00:00
|
|
|
self.Key = s.Key
|
2023-03-19 10:33:07 +00:00
|
|
|
self.RoutingEntries = s.RoutingEntries
|
2021-05-15 19:50:56 +00:00
|
|
|
return self
|
2019-05-19 15:29:04 +00:00
|
|
|
}
|
2019-05-18 16:21:02 +00:00
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
func (c *Core) GetPeers() []PeerInfo {
|
2023-03-19 10:33:07 +00:00
|
|
|
peers := []PeerInfo{}
|
2021-06-13 14:25:08 +00:00
|
|
|
names := make(map[net.Conn]string)
|
2022-09-17 19:07:00 +00:00
|
|
|
phony.Block(&c.links, func() {
|
|
|
|
for _, info := range c.links._links {
|
2022-10-25 17:58:52 +00:00
|
|
|
if info == nil {
|
|
|
|
continue
|
|
|
|
}
|
2022-09-17 19:07:00 +00:00
|
|
|
names[info.conn] = info.lname
|
|
|
|
}
|
|
|
|
})
|
2021-07-05 18:14:12 +00:00
|
|
|
ps := c.PacketConn.PacketConn.Debug.GetPeers()
|
2021-05-15 19:50:56 +00:00
|
|
|
for _, p := range ps {
|
2022-08-06 14:05:12 +00:00
|
|
|
var info PeerInfo
|
2021-05-15 19:50:56 +00:00
|
|
|
info.Key = p.Key
|
|
|
|
info.Root = p.Root
|
|
|
|
info.Port = p.Port
|
2022-10-26 08:24:24 +00:00
|
|
|
info.Priority = p.Priority
|
2023-03-19 10:33:07 +00:00
|
|
|
if p.Conn != nil {
|
|
|
|
info.Remote = p.Conn.RemoteAddr().String()
|
|
|
|
if linkconn, ok := p.Conn.(*linkConn); ok {
|
|
|
|
info.RXBytes = atomic.LoadUint64(&linkconn.rx)
|
|
|
|
info.TXBytes = atomic.LoadUint64(&linkconn.tx)
|
|
|
|
info.Uptime = time.Since(linkconn.up)
|
|
|
|
}
|
|
|
|
if name := names[p.Conn]; name != "" {
|
|
|
|
info.Remote = name
|
|
|
|
}
|
2022-02-01 13:37:45 +00:00
|
|
|
}
|
2019-05-18 16:21:02 +00:00
|
|
|
peers = append(peers, info)
|
|
|
|
}
|
|
|
|
return peers
|
|
|
|
}
|
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
func (c *Core) GetDHT() []DHTEntryInfo {
|
|
|
|
var dhts []DHTEntryInfo
|
2021-07-05 18:14:12 +00:00
|
|
|
ds := c.PacketConn.PacketConn.Debug.GetDHT()
|
2021-05-15 19:50:56 +00:00
|
|
|
for _, d := range ds {
|
2022-08-06 14:05:12 +00:00
|
|
|
var info DHTEntryInfo
|
2021-05-15 19:50:56 +00:00
|
|
|
info.Key = d.Key
|
2023-03-26 21:49:40 +00:00
|
|
|
info.Parent = d.Parent
|
|
|
|
info.Sequence = d.Sequence
|
|
|
|
//info.Port = d.Port
|
2023-03-18 12:14:32 +00:00
|
|
|
//info.Rest = d.Rest
|
2021-05-15 19:50:56 +00:00
|
|
|
dhts = append(dhts, info)
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
2021-05-15 19:50:56 +00:00
|
|
|
return dhts
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2023-03-26 21:49:40 +00:00
|
|
|
/*
|
2022-08-06 14:05:12 +00:00
|
|
|
func (c *Core) GetPaths() []PathEntryInfo {
|
|
|
|
var paths []PathEntryInfo
|
2021-07-05 18:14:12 +00:00
|
|
|
ps := c.PacketConn.PacketConn.Debug.GetPaths()
|
2021-05-15 19:50:56 +00:00
|
|
|
for _, p := range ps {
|
2022-08-06 14:05:12 +00:00
|
|
|
var info PathEntryInfo
|
2021-05-15 19:50:56 +00:00
|
|
|
info.Key = p.Key
|
2023-03-19 10:33:07 +00:00
|
|
|
info.Sequence = p.Sequence
|
2023-03-18 12:14:32 +00:00
|
|
|
//info.Path = p.Path
|
2021-05-15 19:50:56 +00:00
|
|
|
paths = append(paths, info)
|
2019-05-19 15:29:04 +00:00
|
|
|
}
|
2021-05-15 19:50:56 +00:00
|
|
|
return paths
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
2023-03-26 21:49:40 +00:00
|
|
|
*/
|
2019-05-18 16:21:02 +00:00
|
|
|
|
2022-08-06 14:05:12 +00:00
|
|
|
func (c *Core) GetSessions() []SessionInfo {
|
|
|
|
var sessions []SessionInfo
|
2021-07-05 18:14:12 +00:00
|
|
|
ss := c.PacketConn.Debug.GetSessions()
|
2021-05-15 19:50:56 +00:00
|
|
|
for _, s := range ss {
|
2022-08-06 14:05:12 +00:00
|
|
|
var info SessionInfo
|
2021-05-15 19:50:56 +00:00
|
|
|
info.Key = s.Key
|
2022-09-03 15:55:57 +00:00
|
|
|
info.RXBytes = s.RX
|
|
|
|
info.TXBytes = s.TX
|
|
|
|
info.Uptime = s.Uptime
|
2021-05-15 19:50:56 +00:00
|
|
|
sessions = append(sessions, info)
|
2019-05-19 15:29:04 +00:00
|
|
|
}
|
|
|
|
return sessions
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2021-05-24 02:51:09 +00:00
|
|
|
// Listen starts a new listener (either TCP or TLS). The input should be a url.URL
|
|
|
|
// parsed from a string of the form e.g. "tcp://a.b.c.d:e". In the case of a
|
|
|
|
// link-local address, the interface should be provided as the second argument.
|
2022-09-17 19:07:00 +00:00
|
|
|
func (c *Core) Listen(u *url.URL, sintf string) (*Listener, error) {
|
|
|
|
switch u.Scheme {
|
|
|
|
case "tcp":
|
|
|
|
return c.links.tcp.listen(u, sintf)
|
|
|
|
case "tls":
|
|
|
|
return c.links.tls.listen(u, sintf)
|
|
|
|
case "unix":
|
|
|
|
return c.links.unix.listen(u, sintf)
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unrecognised scheme %q", u.Scheme)
|
|
|
|
}
|
2021-05-24 02:47:12 +00:00
|
|
|
}
|
|
|
|
|
2019-05-18 16:21:02 +00:00
|
|
|
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
2019-09-01 22:47:47 +00:00
|
|
|
// address. The IPv6 address is only relevant when the node is operating as an
|
|
|
|
// IP router and often is meaningless when embedded into an application, unless
|
|
|
|
// that application also implements either VPN functionality or deals with IP
|
|
|
|
// packets specifically.
|
2019-07-28 10:30:24 +00:00
|
|
|
func (c *Core) Address() net.IP {
|
2021-05-08 13:35:58 +00:00
|
|
|
addr := net.IP(address.AddrForKey(c.public)[:])
|
|
|
|
return addr
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
|
2019-09-01 22:47:47 +00:00
|
|
|
// /64 subnet. The IPv6 subnet is only relevant when the node is operating as an
|
|
|
|
// IP router and often is meaningless when embedded into an application, unless
|
|
|
|
// that application also implements either VPN functionality or deals with IP
|
|
|
|
// packets specifically.
|
2019-07-28 10:30:24 +00:00
|
|
|
func (c *Core) Subnet() net.IPNet {
|
2021-05-08 13:35:58 +00:00
|
|
|
subnet := address.SubnetForKey(c.public)[:]
|
|
|
|
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
|
|
return net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetLogger sets the output logger of the Yggdrasil node after startup. This
|
2019-09-01 22:47:47 +00:00
|
|
|
// may be useful if you want to redirect the output later. Note that this
|
|
|
|
// expects a Logger from the github.com/gologme/log package and not from Go's
|
|
|
|
// built-in log package.
|
2022-10-02 12:20:39 +00:00
|
|
|
func (c *Core) SetLogger(log Logger) {
|
2019-05-18 16:21:02 +00:00
|
|
|
c.log = log
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddPeer adds a peer. This should be specified in the peer URI format, e.g.:
|
2022-10-02 11:35:43 +00:00
|
|
|
//
|
|
|
|
// tcp://a.b.c.d:e
|
|
|
|
// socks://a.b.c.d:e/f.g.h.i:j
|
|
|
|
//
|
2019-05-18 16:21:02 +00:00
|
|
|
// This adds the peer to the peer list, so that they will be called again if the
|
|
|
|
// connection drops.
|
2022-10-02 11:35:43 +00:00
|
|
|
func (c *Core) AddPeer(uri string, sourceInterface string) error {
|
2022-10-02 11:39:18 +00:00
|
|
|
var known bool
|
|
|
|
phony.Block(c, func() {
|
|
|
|
_, known = c.config._peers[Peer{uri, sourceInterface}]
|
|
|
|
})
|
|
|
|
if known {
|
|
|
|
return fmt.Errorf("peer already configured")
|
|
|
|
}
|
2022-10-02 11:35:43 +00:00
|
|
|
u, err := url.Parse(uri)
|
|
|
|
if err != nil {
|
2019-05-18 16:21:02 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-11-12 11:30:03 +00:00
|
|
|
info, err := c.links.call(u, sourceInterface, nil)
|
2022-10-02 11:35:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
2022-10-02 11:35:43 +00:00
|
|
|
phony.Block(c, func() {
|
|
|
|
c.config._peers[Peer{uri, sourceInterface}] = &info
|
|
|
|
})
|
2019-05-18 16:21:02 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-02 11:35:43 +00:00
|
|
|
// RemovePeer removes a peer. The peer should be specified in URI format, see AddPeer.
|
|
|
|
// The peer is not disconnected immediately.
|
|
|
|
func (c *Core) RemovePeer(uri string, sourceInterface string) error {
|
|
|
|
var err error
|
|
|
|
phony.Block(c, func() {
|
|
|
|
peer := Peer{uri, sourceInterface}
|
|
|
|
linkInfo, ok := c.config._peers[peer]
|
|
|
|
if !ok {
|
|
|
|
err = fmt.Errorf("peer not configured")
|
|
|
|
return
|
2020-07-06 13:14:34 +00:00
|
|
|
}
|
2022-10-02 11:35:43 +00:00
|
|
|
if ok && linkInfo != nil {
|
|
|
|
c.links.Act(nil, func() {
|
|
|
|
if link := c.links._links[*linkInfo]; link != nil {
|
|
|
|
_ = link.close()
|
|
|
|
}
|
|
|
|
})
|
2020-07-06 13:14:34 +00:00
|
|
|
}
|
2022-10-02 11:35:43 +00:00
|
|
|
delete(c.config._peers, peer)
|
2020-07-06 13:21:28 +00:00
|
|
|
})
|
2022-10-02 11:35:43 +00:00
|
|
|
return err
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
|
|
|
|
2019-05-18 16:21:02 +00:00
|
|
|
// CallPeer calls a peer once. This should be specified in the peer URI format,
|
|
|
|
// e.g.:
|
2022-09-03 10:42:05 +00:00
|
|
|
//
|
|
|
|
// tcp://a.b.c.d:e
|
|
|
|
// socks://a.b.c.d:e/f.g.h.i:j
|
|
|
|
//
|
2019-05-18 16:21:02 +00:00
|
|
|
// This does not add the peer to the peer list, so if the connection drops, the
|
|
|
|
// peer will not be called again automatically.
|
2021-05-24 02:47:12 +00:00
|
|
|
func (c *Core) CallPeer(u *url.URL, sintf string) error {
|
2022-11-12 11:30:03 +00:00
|
|
|
_, err := c.links.call(u, sintf, nil)
|
2022-10-02 11:35:43 +00:00
|
|
|
return err
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
2021-06-13 09:54:06 +00:00
|
|
|
|
|
|
|
func (c *Core) PublicKey() ed25519.PublicKey {
|
|
|
|
return c.public
|
|
|
|
}
|
|
|
|
|
2021-06-13 10:43:03 +00:00
|
|
|
// Hack to get the admin stuff working, TODO something cleaner
|
|
|
|
|
|
|
|
type AddHandler interface {
|
2022-09-24 11:22:38 +00:00
|
|
|
AddHandler(name, desc string, args []string, handlerfunc AddHandlerFunc) error
|
2021-06-13 10:43:03 +00:00
|
|
|
}
|
|
|
|
|
2021-09-01 01:16:57 +00:00
|
|
|
type AddHandlerFunc func(json.RawMessage) (interface{}, error)
|
|
|
|
|
2021-06-13 10:43:03 +00:00
|
|
|
// SetAdmin must be called after Init and before Start.
|
|
|
|
// It sets the admin handler for NodeInfo and the Debug admin functions.
|
|
|
|
func (c *Core) SetAdmin(a AddHandler) error {
|
2022-09-24 11:22:38 +00:00
|
|
|
if err := a.AddHandler(
|
|
|
|
"getNodeInfo", "Request nodeinfo from a remote node by its public key", []string{"key"},
|
|
|
|
c.proto.nodeinfo.nodeInfoAdminHandler,
|
|
|
|
); err != nil {
|
2021-06-13 10:43:03 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-09-24 11:22:38 +00:00
|
|
|
if err := a.AddHandler(
|
|
|
|
"debug_remoteGetSelf", "Debug use only", []string{"key"},
|
|
|
|
c.proto.getSelfHandler,
|
|
|
|
); err != nil {
|
2021-06-13 10:43:03 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-09-24 11:22:38 +00:00
|
|
|
if err := a.AddHandler(
|
|
|
|
"debug_remoteGetPeers", "Debug use only", []string{"key"},
|
|
|
|
c.proto.getPeersHandler,
|
|
|
|
); err != nil {
|
2021-06-13 10:43:03 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-09-24 11:22:38 +00:00
|
|
|
if err := a.AddHandler(
|
|
|
|
"debug_remoteGetDHT", "Debug use only", []string{"key"},
|
|
|
|
c.proto.getDHTHandler,
|
|
|
|
); err != nil {
|
2021-06-13 10:43:03 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|