diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 64cc6ae9f..7f820db58 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -216,6 +216,9 @@ func main() { options := []admin.SetupOption{ admin.ListenAddress(cfg.AdminListen), } + if cfg.LogLookups { + options = append(options, admin.LogLookups{}) + } if n.admin, err = admin.New(n.core, logger, options...); err != nil { panic(err) } diff --git a/contrib/mobile/mobile.go b/contrib/mobile/mobile.go index 0b52ffa2d..cf026a706 100644 --- a/contrib/mobile/mobile.go +++ b/contrib/mobile/mobile.go @@ -164,10 +164,10 @@ func (m *Yggdrasil) Stop() error { logger.EnableLevel("info") logger.Infof("Stopping the mobile Yggdrasil instance %s", "") if m.multicast != nil { - logger.Infof("Stopping multicast %s", "") - if err := m.multicast.Stop(); err != nil { - return err - } + logger.Infof("Stopping multicast %s", "") + if err := m.multicast.Stop(); err != nil { + return err + } } logger.Infof("Stopping TUN device %s", "") if m.tun != nil { diff --git a/go.mod b/go.mod index 3f2f6b76a..faa0e0d83 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/yggdrasil-network/yggdrasil-go go 1.20 require ( - github.com/Arceliar/ironwood v0.0.0-20230805085300-86206813435f + github.com/Arceliar/ironwood v0.0.0-20231028101932-ceac99571f43 github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d github.com/cheggaaa/pb/v3 v3.1.4 github.com/gologme/log v1.3.0 diff --git a/go.sum b/go.sum index e8bbf5f19..901eabaa7 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Arceliar/ironwood v0.0.0-20230805085300-86206813435f h1:Fz0zG7ZyQQqk+ROnmHuGrIZO250Lx/YHmp9o48XE+Vw= -github.com/Arceliar/ironwood v0.0.0-20230805085300-86206813435f/go.mod h1:5x7fWW0mshe9WQ1lvSMmmHBYC3BeHH9gpwW5tz7cbfw= +github.com/Arceliar/ironwood v0.0.0-20231028101932-ceac99571f43 h1:M4NczBPk7Fy0Uy2YvNoXwSkk3dGoGTOYtUjyqpOC5ko= +github.com/Arceliar/ironwood v0.0.0-20231028101932-ceac99571f43/go.mod h1:5x7fWW0mshe9WQ1lvSMmmHBYC3BeHH9gpwW5tz7cbfw= github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d h1:UK9fsWbWqwIQkMCz1CP+v5pGbsGoWAw6g4AyvMpm1EM= github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d/go.mod h1:BCnxhRf47C/dy/e/D2pmB8NkB3dQVIrkD98b220rx5Q= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= diff --git a/src/admin/options.go b/src/admin/options.go index 4607384ff..b2e273b33 100644 --- a/src/admin/options.go +++ b/src/admin/options.go @@ -1,9 +1,20 @@ package admin +import ( + "encoding/hex" + "encoding/json" + "sync" + "time" + + "github.com/Arceliar/ironwood/network" +) + func (c *AdminSocket) _applyOption(opt SetupOption) { switch v := opt.(type) { case ListenAddress: c.config.listenaddr = v + case LogLookups: + c.logLookups() } } @@ -14,3 +25,46 @@ type SetupOption interface { type ListenAddress string func (a ListenAddress) isSetupOption() {} + +type LogLookups struct{} + +func (l LogLookups) isSetupOption() {} + +func (a *AdminSocket) logLookups() { + type resi struct { + Key string `json:"key"` + Path []uint64 `json:"path"` + Time int64 `json:"time"` + } + type res struct { + Infos []resi `json:"infos"` + } + type info struct { + path []uint64 + time time.Time + } + infos := make(map[string]info) + var m sync.Mutex + a.core.PacketConn.PacketConn.Debug.SetDebugLookupLogger(func(l network.DebugLookupInfo) { + key := hex.EncodeToString(l.Key[:]) + m.Lock() + infos[key] = info{path: l.Path, time: time.Now()} + m.Unlock() + }) + _ = a.AddHandler( + "lookups", "Dump a record of lookups received in the past hour", []string{}, + func(in json.RawMessage) (interface{}, error) { + m.Lock() + rs := make([]resi, 0, len(infos)) + for k, v := range infos { + if time.Since(v.time) > 24*time.Hour { + // TODO? automatic cleanup, so we don't need to call lookups periodically to prevent leaks + delete(infos, k) + } + rs = append(rs, resi{Key: k, Path: v.path, Time: v.time.Unix()}) + } + m.Unlock() + return &res{Infos: rs}, nil + }, + ) +} diff --git a/src/config/config.go b/src/config/config.go index bb94b6740..289b6f920 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -53,6 +53,7 @@ type NodeConfig struct { IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."` NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."` + LogLookups bool `json:",omitempty"` } type MulticastInterfaceConfig struct {