MarshalPEMPrivateKey

This commit is contained in:
HappyHakunaMatata 2024-07-26 23:26:21 +02:00
parent 24198d353a
commit 4f412a2b6d
10 changed files with 1137 additions and 140 deletions

View file

@ -5,7 +5,6 @@ import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"net"
"os"
@ -18,11 +17,13 @@ import (
gsyslog "github.com/hashicorp/go-syslog"
"github.com/hjson/hjson-go/v4"
"github.com/kardianos/minwinsvc"
"github.com/spf13/cobra"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc"
monitoring "github.com/yggdrasil-network/yggdrasil-go/src/monitoring"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
@ -37,32 +38,245 @@ type node struct {
admin *admin.AdminSocket
}
var (
cfg *config.NodeConfig
logger *log.Logger
ctx context.Context
cancel context.CancelFunc
rootCmd = &cobra.Command{
Use: "yggdrasil",
Short: "Yggdrasil managment",
}
genconfCmd = &cobra.Command{
Use: "genconf",
Short: "Print a new config to stdout",
RunE: cmdGenconf,
Annotations: map[string]string{"type": "setup"},
}
versionCmd = &cobra.Command{
Use: "version",
Short: "Prints the version of this build",
Run: cmdVersion,
Annotations: map[string]string{"type": "setup"},
}
useconffileCmd = &cobra.Command{
Use: "useconffile <path>",
Args: cobra.ExactArgs(1),
Short: "Read HJSON/JSON config from specified file path",
RunE: cmdUseconffile,
Annotations: map[string]string{"type": "setup"},
}
addressCmd = &cobra.Command{
Use: "address <path>",
Args: cobra.ExactArgs(1),
Short: "Outputs your IPv6 address",
RunE: cmdAddress,
Annotations: map[string]string{"type": "setup"},
}
snetCmd = &cobra.Command{
Use: "subnet <path>",
Args: cobra.ExactArgs(1),
Short: "Outputs your IPv6 subnet",
RunE: cmdSnet,
Annotations: map[string]string{"type": "setup"},
}
pkeyCmd = &cobra.Command{
Use: "publickey <path>",
Args: cobra.ExactArgs(1),
Short: "Outputs your public key",
RunE: cmdPkey,
Annotations: map[string]string{"type": "setup"},
}
exportKeyCmd = &cobra.Command{
Use: "exportkey <path>",
Args: cobra.ExactArgs(1),
Short: "Outputs your private key in PEM format",
RunE: cmdExportKey,
Annotations: map[string]string{"type": "setup"},
}
logtoCmd = &cobra.Command{
Use: "logto <path>",
Args: cobra.ExactArgs(1),
Short: "File path to log to, \"syslog\" or \"stdout\"",
Run: cmdLogto,
Annotations: map[string]string{"type": "setup"},
}
autoconfCmd = &cobra.Command{
Use: "autoconf",
Short: "Automatic mode (dynamic IP, peer with IPv6 neighbors)",
RunE: cmdAutoconf,
Annotations: map[string]string{"type": "setup"},
}
useconfCmd = &cobra.Command{
Use: "useconf",
Short: "Read HJSON/JSON config from stdin",
RunE: cmdUseconf,
Annotations: map[string]string{"type": "setup"},
}
normaliseconfCmd = &cobra.Command{
Use: "normaliseconf <path>",
Args: cobra.ExactArgs(1),
Short: "Outputs your configuration normalised",
RunE: cmdNormaliseconf,
Annotations: map[string]string{"type": "setup"},
}
)
// The main function is responsible for configuring and starting Yggdrasil.
func init() {
cfg = config.GenerateConfig()
genconfCmd.Flags().BoolP("json", "j", false, "print configuration as JSON instead of HJSON")
normaliseconfCmd.Flags().BoolP("json", "j", false, "print configuration as JSON instead of HJSON")
autoconfCmd.AddCommand(logtoCmd)
useconffileCmd.AddCommand(logtoCmd)
useconfCmd.AddCommand(logtoCmd)
rootCmd.AddCommand(genconfCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(useconffileCmd)
rootCmd.AddCommand(addressCmd)
rootCmd.AddCommand(snetCmd)
rootCmd.AddCommand(pkeyCmd)
rootCmd.AddCommand(exportKeyCmd)
rootCmd.AddCommand(autoconfCmd)
rootCmd.AddCommand(useconfCmd)
rootCmd.AddCommand(normaliseconfCmd)
}
func main() {
genconf := flag.Bool("genconf", false, "print a new config to stdout")
useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin")
useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path")
normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
exportkey := flag.Bool("exportkey", false, "use in combination with either -useconf or -useconffile, outputs your private key in PEM format")
confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON")
autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
ver := flag.Bool("version", false, "prints the version of this build")
logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"")
getaddr := flag.Bool("address", false, "use in combination with either -useconf or -useconffile, outputs your IPv6 address")
getsnet := flag.Bool("subnet", false, "use in combination with either -useconf or -useconffile, outputs your IPv6 subnet")
getpkey := flag.Bool("publickey", false, "use in combination with either -useconf or -useconffile, outputs your public key")
loglevel := flag.String("loglevel", "info", "loglevel to enable")
flag.Parse()
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// Catch interrupts from the operating system to exit gracefully.
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
func cmdGenconf(cmd *cobra.Command, args []string) (err error) {
confjson, err := cmd.Flags().GetBool("json")
if err != nil {
return err
}
cfg.AdminListen = ""
var bs []byte
if confjson {
bs, err = json.MarshalIndent(cfg, "", " ")
} else {
bs, err = hjson.Marshal(cfg)
}
if err != nil {
return err
}
fmt.Println(string(bs))
return nil
}
// Capture the service being stopped on Windows.
minwinsvc.SetOnExit(cancel)
func cmdVersion(cmd *cobra.Command, args []string) {
fmt.Println("Build name:", version.BuildName())
fmt.Println("Build version:", version.BuildVersion())
}
// Create a new logger that logs output to stdout.
var logger *log.Logger
switch *logto {
func cmdUseconffile(cmd *cobra.Command, args []string) (err error) {
useconffile := args[0]
err = ReadConfigFile(useconffile)
if err != nil {
return err
}
err = run()
if err != nil {
return err
}
return nil
}
func cmdAutoconf(cmd *cobra.Command, args []string) (err error) {
err = run()
if err != nil {
return err
}
return nil
}
func cmdUseconf(cmd *cobra.Command, args []string) (err error) {
if _, err := cfg.ReadFrom(os.Stdin); err != nil {
return err
}
err = run()
if err != nil {
return err
}
return nil
}
func cmdAddress(cmd *cobra.Command, args []string) (err error) {
useconffile := args[0]
err = ReadConfigFile(useconffile)
if err != nil {
return err
}
privateKey := ed25519.PrivateKey(cfg.PrivateKey)
publicKey := privateKey.Public().(ed25519.PublicKey)
addr := address.AddrForKey(publicKey)
ip := net.IP(addr[:])
fmt.Println(ip.String())
return nil
}
func cmdSnet(cmd *cobra.Command, args []string) (err error) {
useconffile := args[0]
err = ReadConfigFile(useconffile)
if err != nil {
return err
}
privateKey := ed25519.PrivateKey(cfg.PrivateKey)
publicKey := privateKey.Public().(ed25519.PublicKey)
snet := address.SubnetForKey(publicKey)
ipnet := net.IPNet{
IP: append(snet[:], 0, 0, 0, 0, 0, 0, 0, 0),
Mask: net.CIDRMask(len(snet)*8, 128),
}
fmt.Println(ipnet.String())
return nil
}
func cmdPkey(cmd *cobra.Command, args []string) (err error) {
useconffile := args[0]
err = ReadConfigFile(useconffile)
if err != nil {
return err
}
privateKey := ed25519.PrivateKey(cfg.PrivateKey)
publicKey := privateKey.Public().(ed25519.PublicKey)
fmt.Println(hex.EncodeToString(publicKey))
return nil
}
func cmdExportKey(cmd *cobra.Command, args []string) (err error) {
useconffile := args[0]
err = ReadConfigFile(useconffile)
if err != nil {
return err
}
pem, err := cfg.MarshalPEMPrivateKey()
if err != nil {
panic(err)
}
fmt.Println(string(pem))
return nil
}
func cmdLogto(cmd *cobra.Command, args []string) {
logto := args[0]
switch logto {
case "stdout":
logger = log.New(os.Stdout, "", log.Flags())
@ -72,120 +286,49 @@ func main() {
}
default:
if logfd, err := os.OpenFile(*logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
if logfd, err := os.OpenFile(logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
logger = log.New(logfd, "", log.Flags())
}
}
if logger == nil {
logger = log.New(os.Stdout, "", log.Flags())
logger.Warnln("Logging defaulting to stdout")
}
if *normaliseconf {
setLogLevel("error", logger)
} else {
setLogLevel(*loglevel, logger)
}
cfg := config.GenerateConfig()
var err error
switch {
case *ver:
fmt.Println("Build name:", version.BuildName())
fmt.Println("Build version:", version.BuildVersion())
return
case *autoconf:
// Use an autoconf-generated config, this will give us random keys and
// port numbers, and will use an automatically selected TUN interface.
case *useconf:
if _, err := cfg.ReadFrom(os.Stdin); err != nil {
panic(err)
}
case *useconffile != "":
f, err := os.Open(*useconffile)
func cmdNormaliseconf(cmd *cobra.Command, args []string) (err error) {
confjson, err := cmd.Flags().GetBool("json")
if err != nil {
panic(err)
}
if _, err := cfg.ReadFrom(f); err != nil {
panic(err)
}
_ = f.Close()
case *genconf:
cfg.AdminListen = ""
var bs []byte
if *confjson {
bs, err = json.MarshalIndent(cfg, "", " ")
} else {
bs, err = hjson.Marshal(cfg)
return err
}
useconffile := args[0]
err = ReadConfigFile(useconffile)
if err != nil {
panic(err)
return err
}
fmt.Println(string(bs))
return
default:
fmt.Println("Usage:")
flag.PrintDefaults()
if *getaddr || *getsnet {
fmt.Println("\nError: You need to specify some config data using -useconf or -useconffile.")
}
return
}
privateKey := ed25519.PrivateKey(cfg.PrivateKey)
publicKey := privateKey.Public().(ed25519.PublicKey)
switch {
case *getaddr:
addr := address.AddrForKey(publicKey)
ip := net.IP(addr[:])
fmt.Println(ip.String())
return
case *getsnet:
snet := address.SubnetForKey(publicKey)
ipnet := net.IPNet{
IP: append(snet[:], 0, 0, 0, 0, 0, 0, 0, 0),
Mask: net.CIDRMask(len(snet)*8, 128),
}
fmt.Println(ipnet.String())
return
case *getpkey:
fmt.Println(hex.EncodeToString(publicKey))
return
case *normaliseconf:
cfg.AdminListen = ""
if cfg.PrivateKeyPath != "" {
cfg.PrivateKey = nil
}
var bs []byte
if *confjson {
if confjson {
bs, err = json.MarshalIndent(cfg, "", " ")
} else {
bs, err = hjson.Marshal(cfg)
}
if err != nil {
panic(err)
return err
}
fmt.Println(string(bs))
return
case *exportkey:
pem, err := cfg.MarshalPEMPrivateKey()
if err != nil {
panic(err)
}
fmt.Println(string(pem))
return
return nil
}
func run() (err error) {
ctx, cancel = signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
// Capture the service being stopped on Windows.
minwinsvc.SetOnExit(cancel)
if logger == nil {
logger = log.New(os.Stdout, "", log.Flags())
logger.Warnln("Logging defaulting to stdout")
}
setLogLevel("info", logger)
n := &node{}
// Set up the Yggdrasil node itself.
@ -272,14 +415,18 @@ func main() {
}
}
m, _ := monitoring.New(n.core, logger)
// Block until we are told to shut down.
<-ctx.Done()
// Shut down the node.
_ = m.Stop()
_ = n.admin.Stop()
_ = n.multicast.Stop()
_ = n.tun.Stop()
n.core.Stop()
return nil
}
func setLogLevel(loglevel string, logger *log.Logger) {
@ -307,3 +454,15 @@ func setLogLevel(loglevel string, logger *log.Logger) {
}
}
}
func ReadConfigFile(filepath string) error {
f, err := os.Open(filepath)
if err != nil {
return err
}
if _, err := cfg.ReadFrom(f); err != nil {
return err
}
_ = f.Close()
return nil
}

BIN
contrib/.DS_Store vendored

Binary file not shown.

13
go.mod
View file

@ -11,6 +11,7 @@ require (
github.com/hjson/hjson-go/v4 v4.4.0
github.com/kardianos/minwinsvc v1.0.2
github.com/quic-go/quic-go v0.44.0
github.com/stretchr/testify v1.8.2
github.com/vishvananda/netlink v1.1.0
golang.org/x/crypto v0.23.0
golang.org/x/mobile v0.0.0-20240520174638-fa72addaaa1b
@ -24,24 +25,34 @@ require (
require (
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/bits-and-blooms/bloom/v3 v3.7.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/google/pprof v0.0.0-20221103000818-d260c55eee4c // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/tools v0.21.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.22
github.com/olekukonko/tablewriter v0.0.5
github.com/spf13/cobra v1.8.0
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
)

47
go.sum
View file

@ -2,6 +2,8 @@ github.com/Arceliar/ironwood v0.0.0-20240529054413-b8e59574e2b2 h1:SBdYBKeXYUUFe
github.com/Arceliar/ironwood v0.0.0-20240529054413-b8e59574e2b2/go.mod h1:6WP4799FX0OuWdENGQAh+0RXp9FLh0y7NZ7tM9cJyXk=
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/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
@ -11,9 +13,8 @@ github.com/bits-and-blooms/bloom/v3 v3.7.0 h1:VfknkqV4xI+PsaDIsoHueyxVDZrfvMn56j
github.com/bits-and-blooms/bloom/v3 v3.7.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -23,21 +24,29 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
github.com/gologme/log v1.3.0/go.mod h1:yKT+DvIPdDdDoPtqFrFxheooyVmoqi0BAsw+erN3wA4=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20221103000818-d260c55eee4c h1:lvddKcYTQ545ADhBujtIJmqQrZBDsGo7XIMbAQe/sNY=
github.com/google/pprof v0.0.0-20221103000818-d260c55eee4c/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kardianos/minwinsvc v1.0.2 h1:JmZKFJQrmTGa/WiW+vkJXKmfzdjabuEW4Tirj5lLdR0=
github.com/kardianos/minwinsvc v1.0.2/go.mod h1:LUZNYhNmxujx2tR7FbdxqYJ9XDDoCd3MQcl1o//FWl4=
github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -46,21 +55,36 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg=
github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
@ -99,7 +123,6 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -135,15 +158,19 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 h1:/J/RVnr7ng4fWPRH3xa4WtBJ1Jp+Auu4YNLmGiPv5QU=
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675/go.mod h1:whfbyDBt09xhCYQWtO2+3UVjlaq6/9hDZrjg2ZE6SyA=
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -1,8 +1,11 @@
package core
import (
"bytes"
"crypto/ed25519"
"encoding/binary"
"encoding/json"
"fmt"
"net"
"net/url"
"sync/atomic"
@ -250,3 +253,29 @@ func (c *Core) SetAdmin(a AddHandler) error {
}
return nil
}
func (peerinfo PeerInfo) GetCoordinates() *[]byte {
var coordsBlob []byte
if peerinfo.Coords != nil {
coordsBlob = make([]byte, len(peerinfo.Coords)*8)
for i, coord := range peerinfo.Coords {
binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord)
}
}
return &coordsBlob
}
func (peerinfo PeerInfo) SetCoordinates(coords *[]byte) error {
if len(*coords)%8 != 0 {
return fmt.Errorf("length of byte slice must be a multiple of 8")
}
numUint64 := len(*coords) / 8
buf := bytes.NewReader(*coords)
for i := 0; i < numUint64; i++ {
err := binary.Read(buf, binary.LittleEndian, &peerinfo.Coords[i])
if err != nil {
return err
}
}
return nil
}

View file

@ -0,0 +1,211 @@
package peerinfodb
import (
"crypto/ed25519"
"crypto/x509"
"encoding/binary"
"fmt"
"os"
"path/filepath"
_ "github.com/mattn/go-sqlite3"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
"github.com/yggdrasil-network/yggdrasil-go/src/db"
)
type PeerInfoDBConfig struct {
DbConfig *db.DbConfig
name string
}
var Name = "PeerInfo"
func New() (*PeerInfoDBConfig, error) {
dir, _ := os.Getwd()
fileName := fmt.Sprintf("%s.db", Name)
filePath := filepath.Join(dir, fileName)
schemas := []string{
`CREATE TABLE IF NOT EXISTS peer_infos (
uri TEXT,
up BOOLEAN,
inbound BOOLEAN,
last_error VARCHAR,
last_error_time TIMESTAMP,
key VARCHAR,
root VARCHAR,
coords VARCHAR,
port INT,
priority TINYINT,
Rxbytes BIGINT,
Txbytes BIGINT,
uptime BIGINT,
latency SMALLINT
);`}
dbcfg, err := db.New("sqlite3", &schemas, filePath)
if err != nil {
return nil, err
}
cfg := &PeerInfoDBConfig{
name: Name,
DbConfig: dbcfg,
}
return cfg, nil
}
func (cfg *PeerInfoDBConfig) AddPeer(peer core.PeerInfo) (err error) {
var key, root []byte
if peer.Key != nil {
key, err = x509.MarshalPKIXPublicKey(peer.Key)
if err != nil {
return err
}
}
if peer.Root != nil {
root, err = x509.MarshalPKIXPublicKey(peer.Root)
if err != nil {
return err
}
}
var peerErr interface{}
if peer.LastError != nil {
peerErr = peer.LastError.Error()
} else {
peerErr = nil
}
var coordsBlob []byte
if peer.Coords != nil {
coordsBlob = make([]byte, len(peer.Coords)*8)
for i, coord := range peer.Coords {
binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord)
}
}
if !cfg.DbConfig.DBIsOpened() {
return nil
}
_, err = cfg.DbConfig.DB.Exec(`
INSERT OR REPLACE INTO peer_infos
(
uri,
up,
inbound,
last_error,
last_error_time,
key,
root,
coords,
port,
priority,
Rxbytes,
Txbytes,
uptime,
latency
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
peer.URI, peer.Up, peer.Inbound, peerErr, peer.LastErrorTime, key, root, coordsBlob, peer.Port, peer.Priority, peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency)
if err != nil {
return err
}
return nil
}
func (cfg *PeerInfoDBConfig) RemovePeer(peer core.PeerInfo) (err error) {
key, err := x509.MarshalPKIXPublicKey(peer.Key)
if err != nil {
return err
}
root, err := x509.MarshalPKIXPublicKey(peer.Root)
if err != nil {
return err
}
_, err = cfg.DbConfig.DB.Exec("DELETE FROM peer_infos WHERE uri = ? AND key = ? AND root = ?",
peer.URI, key, root)
if err != nil {
return err
}
return nil
}
func (cfg *PeerInfoDBConfig) GetPeer(peer *core.PeerInfo) (err error) {
key, err := x509.MarshalPKIXPublicKey(peer.Key)
if err != nil {
return err
}
root, err := x509.MarshalPKIXPublicKey(peer.Root)
if err != nil {
return err
}
row := cfg.DbConfig.DB.QueryRow("SELECT * FROM peer_infos WHERE uri = ? AND key = ? AND root = ?",
peer.URI, key, root)
var coord []byte
var peerErr interface{}
err = row.Scan(&peer.URI, &peer.Up, &peer.Inbound, &peerErr, &peer.LastErrorTime, &key, &root, &coord, &peer.Port, &peer.Priority, &peer.RXBytes, &peer.TXBytes, &peer.Uptime, &peer.Latency)
if err != nil {
return err
}
parsedKey, err := x509.ParsePKCS8PrivateKey(key)
if err != nil {
return err
}
ParsedRoot, err := x509.ParsePKCS8PrivateKey(root)
if err != nil {
return err
}
peer.Key = parsedKey.(ed25519.PublicKey)
peer.Root = ParsedRoot.(ed25519.PublicKey)
return nil
}
func (cfg *PeerInfoDBConfig) UpdatePeer(peer core.PeerInfo) (err error) {
key, err := x509.MarshalPKIXPublicKey(peer.Key)
if err != nil {
return err
}
root, err := x509.MarshalPKIXPublicKey(peer.Root)
if err != nil {
return err
}
var peerErr interface{}
if peer.LastError != nil {
peerErr = peer.LastError.Error()
} else {
peerErr = nil
}
var coordsBlob []byte
if peer.Coords != nil {
coordsBlob = make([]byte, len(peer.Coords)*8)
for i, coord := range peer.Coords {
binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord)
}
}
_, err = cfg.DbConfig.DB.Exec(`UPDATE peer_infos
SET
up = ?,
inbound = ?,
last_error = ?,
last_error_time = ?,
coords = ?,
port = ?,
priority = ?,
RXBytes = RXBytes + ?,
TXBytes = TXBytes + ?,
uptime = ?,
latency = ?
WHERE
uri = ? AND key = ? AND root = ?`,
peer.Up, peer.Inbound, peerErr, peer.LastErrorTime, coordsBlob, peer.Port, peer.Priority,
peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency, peer.URI, key, root)
if err != nil {
return err
}
return nil
}
func (cfg *PeerInfoDBConfig) Count() (int, error) {
var count int
err := cfg.DbConfig.DB.QueryRow("SELECT COUNT(*) FROM peer_infos").Scan(&count)
if err != nil {
return 0, err
}
return count, nil
}

90
src/db/db.go Normal file
View file

@ -0,0 +1,90 @@
package db
import (
"database/sql"
"os"
"path"
)
type DbConfig struct {
Uri string
DB *sql.DB
Name string
Driver string
}
var IsOpened = false
func New(driver string, schemas *[]string, uri string) (*DbConfig, error) {
name := path.Base(uri)
db, err := initDB(driver, schemas, uri)
if err != nil {
return nil, err
}
cfg := &DbConfig{
DB: db,
Uri: uri,
Name: name,
Driver: driver,
}
return cfg, nil
}
func initDB(driver string, schemas *[]string, uri string) (*sql.DB, error) {
database, err := sql.Open(driver, uri)
if err != nil {
return nil, err
}
defer database.Close()
tx, err := database.Begin()
if err != nil {
return nil, err
}
for _, schema := range *schemas {
_, err := tx.Exec(schema)
if err != nil {
tx.Rollback()
return nil, err
}
}
tx.Commit()
return database, nil
}
func (cfg *DbConfig) DeleteDb() error {
err := os.Remove(cfg.Uri)
if err != nil {
return err
}
return nil
}
func (cfg *DbConfig) OpenDb() error {
db, err := sql.Open(cfg.Driver, cfg.Uri)
if err != nil {
return err
}
cfg.DB = db
IsOpened = true
return nil
}
func (cfg *DbConfig) CloseDb() error {
if IsOpened {
err := cfg.DB.Close()
if err != nil {
return err
}
IsOpened = false
}
return nil
}
func (cfg *DbConfig) DBIsOpened() bool {
return IsOpened
}
func (cfg *DbConfig) DBIsExist() bool {
_, err := os.Stat(cfg.Uri)
return !os.IsNotExist(err)
}

BIN
src/db/test/PeerInfo.db Normal file

Binary file not shown.

396
src/db/test/db_test.go Normal file
View file

@ -0,0 +1,396 @@
package db_test
import (
"bytes"
"crypto/ed25519"
"crypto/rand"
"crypto/x509"
"encoding/binary"
"fmt"
"reflect"
"strconv"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
peerinfodb "github.com/yggdrasil-network/yggdrasil-go/src/db/PeerInfoDB"
)
func TestPeerGetCoords(t *testing.T) {
peer := core.PeerInfo{
Coords: []uint64{1, 2, 3, 4},
}
target := []byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0}
var coordinates = peer.GetCoordinates()
if reflect.DeepEqual(target, coordinates) {
t.Error(fmt.Errorf("Not equal"))
}
}
func TestPeerSetCoords(t *testing.T) {
peer := core.PeerInfo{
Coords: []uint64{1, 2, 3, 4},
}
target := []byte{4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}
var coordinates = peer.SetCoordinates(&target)
if reflect.DeepEqual(target, coordinates) {
t.Error(fmt.Errorf("Not equal"))
}
fmt.Print(peer.Coords)
}
func TestAddPeer(t *testing.T) {
mockDB, mock, err := sqlmock.New()
require.NoError(t, err)
defer mockDB.Close()
cfg, err := peerinfodb.New()
require.NoError(t, err)
cfg.DbConfig.DB = mockDB
pubkey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
rootPubKey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
peer := core.PeerInfo{
URI: "test.test",
Up: true,
Inbound: true,
LastError: nil,
LastErrorTime: time.Now(),
Key: pubkey,
Root: rootPubKey,
Coords: []uint64{0, 0, 0, 0},
Port: 8080,
Priority: 1,
RXBytes: 1024,
TXBytes: 2048,
Uptime: 3600,
Latency: 50.0,
}
pKey, err := x509.MarshalPKIXPublicKey(peer.Key)
require.NoError(t, err)
pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root)
require.NoError(t, err)
var coordsBlob []byte
if peer.Coords != nil {
coordsBlob = make([]byte, len(peer.Coords)*8)
for i, coord := range peer.Coords {
binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord)
}
}
mock.ExpectExec("INSERT OR REPLACE INTO peer_infos").
WithArgs(
peer.URI,
peer.Up,
peer.Inbound,
nil,
peer.LastErrorTime,
pKey,
pKeyRoot,
coordsBlob,
peer.Port,
peer.Priority,
peer.RXBytes,
peer.TXBytes,
peer.Uptime,
peer.Latency,
).
WillReturnResult(sqlmock.NewResult(1, 1))
err = cfg.AddPeer(peer)
require.NoError(t, err)
err = mock.ExpectationsWereMet()
require.NoError(t, err)
}
func TestRemovePeer(t *testing.T) {
mockDB, mock, err := sqlmock.New()
require.NoError(t, err)
defer mockDB.Close()
cfg, err := peerinfodb.New()
require.NoError(t, err)
cfg.DbConfig.DB = mockDB
pubkey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
rootPubKey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
peer := core.PeerInfo{
URI: "test.test",
Up: true,
Inbound: true,
LastError: nil,
LastErrorTime: time.Now(),
Key: pubkey,
Root: rootPubKey,
Coords: []uint64{0, 0, 0, 0},
Port: 8080,
Priority: 1,
RXBytes: 1024,
TXBytes: 2048,
Uptime: 3600,
Latency: 50.0,
}
pKey, err := x509.MarshalPKIXPublicKey(peer.Key)
require.NoError(t, err)
pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root)
require.NoError(t, err)
mock.ExpectExec("DELETE FROM peer_infos WHERE uri = \\? AND key = \\? AND root = \\?").
WithArgs(peer.URI, pKey, pKeyRoot).
WillReturnResult(sqlmock.NewResult(1, 1))
err = cfg.RemovePeer(peer)
require.NoError(t, err)
err = mock.ExpectationsWereMet()
require.NoError(t, err)
}
func TestGetPeer(t *testing.T) {
mockDB, mock, err := sqlmock.New()
require.NoError(t, err)
defer mockDB.Close()
cfg, err := peerinfodb.New()
require.NoError(t, err)
cfg.DbConfig.DB = mockDB
pubkey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
rootPubKey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
peer := core.PeerInfo{
URI: "test.test",
Up: true,
Inbound: true,
LastError: nil,
LastErrorTime: time.Now(),
Key: pubkey,
Root: rootPubKey,
Coords: []uint64{0, 0, 0, 0},
Port: 8080,
Priority: 1,
RXBytes: 1024,
TXBytes: 2048,
Uptime: 3600,
Latency: 50.0,
}
pKey, err := x509.MarshalPKIXPublicKey(peer.Key)
require.NoError(t, err)
pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root)
require.NoError(t, err)
var coords []byte
rows := sqlmock.NewRows([]string{"uri", "up", "Inbound", "LastError", "LastErrorTime", "Key", "Root", "Coords", "Port", "Priority", "Rxbytes", "Txbytes", "Uptime", "Latency"}).
AddRow(peer.URI, peer.Up, peer.Inbound, peer.LastError, peer.LastErrorTime, peer.Key, peer.Root, coords, peer.Port, peer.Priority, peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency)
mock.ExpectQuery("SELECT * FROM peer_infos WHERE uri = ? AND key = ? AND root = ?").
WithArgs(peer.URI, pKey, pKeyRoot).
WillReturnRows(rows)
err = cfg.GetPeer(&peer)
require.NoError(t, err)
err = mock.ExpectationsWereMet()
require.NoError(t, err)
}
func TestUpdatePeer(t *testing.T) {
mockDB, mock, err := sqlmock.New()
require.NoError(t, err)
defer mockDB.Close()
cfg, err := peerinfodb.New()
require.NoError(t, err)
cfg.DbConfig.DB = mockDB
pubkey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
rootPubKey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
peer := core.PeerInfo{
URI: "test.test",
Up: true,
Inbound: true,
LastError: nil,
LastErrorTime: time.Now(),
Key: pubkey,
Root: rootPubKey,
Coords: []uint64{0, 0, 0, 0},
Port: 8080,
Priority: 1,
RXBytes: 1024,
TXBytes: 2048,
Uptime: 3600,
Latency: 50.0,
}
pKey, err := x509.MarshalPKIXPublicKey(peer.Key)
require.NoError(t, err)
pKeyRoot, err := x509.MarshalPKIXPublicKey(peer.Root)
var coordsBlob []byte
if peer.Coords != nil {
coordsBlob = make([]byte, len(peer.Coords)*8)
for i, coord := range peer.Coords {
binary.LittleEndian.PutUint64(coordsBlob[i*8:], coord)
}
}
require.NoError(t, err)
mock.ExpectExec(`UPDATE peer_infos
SET
up = \?,
inbound = \?,
last_error = \?,
last_error_time = \?,
coords = \?,
port = \?,
priority = \?,
RXBytes = RXBytes \+ \?,
TXBytes = TXBytes \+ \?,
uptime = \?,
latency = \?
WHERE
uri = \? AND key = \? AND root = \?`).
WithArgs(
peer.Up, peer.Inbound, peer.LastError, peer.LastErrorTime, coordsBlob, peer.Port, peer.Priority,
peer.RXBytes, peer.TXBytes, peer.Uptime, peer.Latency, peer.URI, pKey, pKeyRoot).
WillReturnResult(sqlmock.NewResult(1, 1))
err = cfg.UpdatePeer(peer)
require.NoError(t, err)
err = mock.ExpectationsWereMet()
require.NoError(t, err)
}
// One more test here
func TestMain(t *testing.T) {
peerinfodb.Name = fmt.Sprintf(
"%s.%s",
peerinfodb.Name,
strconv.Itoa(int(time.Now().Unix())),
)
peerdb, err := peerinfodb.New()
require.NoError(t, err)
peerdb.DbConfig.OpenDb()
isOpened := peerdb.DbConfig.DBIsOpened()
condition := func() bool {
return isOpened
}
require.Condition(t, condition, "Expected db is opened", isOpened)
pubkey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
rootPubKey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
peer := core.PeerInfo{
URI: "test.test",
Up: true,
Inbound: true,
LastError: nil,
LastErrorTime: time.Now(),
Key: pubkey,
Root: rootPubKey,
Coords: []uint64{0, 0, 0, 0},
Port: 8080,
Priority: 1,
RXBytes: 1024,
TXBytes: 2048,
Uptime: 3600,
Latency: 50.0,
}
root2PubKey, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
peer2 := core.PeerInfo{
URI: "new.test",
Up: true,
Inbound: true,
LastError: nil,
LastErrorTime: time.Now(),
Key: pubkey,
Root: root2PubKey,
Coords: []uint64{0, 0, 0, 0},
Port: 8080,
Priority: 1,
RXBytes: 1024,
TXBytes: 2048,
Uptime: 3600,
Latency: 50.0,
}
peerdb.AddPeer(peer)
peerdb.AddPeer(peer2)
count, err := peerdb.Count()
require.NoError(t, err)
condition = func() bool {
return count == 2
}
require.Condition(t, condition, "Expected count to be 2", count)
peerdb.RemovePeer(peer)
count, err = peerdb.Count()
require.NoError(t, err)
condition = func() bool {
return count == 1
}
require.Condition(t, condition, "Expected count to be 1", count)
peer2.Latency = 10
peer2.RXBytes = 1024
peer2.TXBytes = 1024
peer2.Port = 80
peerdb.UpdatePeer(peer2)
peerdb.GetPeer(&peer2)
condition = func() bool {
return peer2.Latency == 10 &&
peer2.RXBytes == 2048 &&
peer2.TXBytes == 3072 &&
peer2.Port == 80 && peer2.URI == "new.test" && bytes.Equal(peer.Key, pubkey)
}
require.Condition(t, condition, "Inner exception")
peerdb.RemovePeer(peer2)
count, err = peerdb.Count()
require.NoError(t, err)
condition = func() bool {
return count == 0
}
require.Condition(t, condition, "Expected count to be 0", count)
err = peerdb.DbConfig.CloseDb()
isOpened = peerdb.DbConfig.DBIsOpened()
condition = func() bool {
return !isOpened
}
require.Condition(t, condition, "Expected db is not opened", isOpened)
require.NoError(t, err)
err = peerdb.DbConfig.DeleteDb()
require.NoError(t, err)
isExist := peerdb.DbConfig.DBIsExist()
condition = func() bool {
return !isExist
}
require.Condition(t, condition, "Expected db is not exist", isExist)
}

View file

@ -0,0 +1,74 @@
package monitoring
import (
"net"
"sync"
_ "github.com/mattn/go-sqlite3"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
)
type Monitoring struct {
core *core.Core
done chan struct{}
log core.Logger
once sync.Once
}
func New(c *core.Core, log core.Logger) (*Monitoring, error) {
m := &Monitoring{
core: c,
log: log,
}
m.done = make(chan struct{})
go m.Monitoring(func(peer core.PeerInfo) {
log.Printf("Peers: %s", peer.URI)
}, func(session core.SessionInfo) {
addr := address.AddrForKey(session.Key)
addrStr := net.IP(addr[:]).String()
log.Printf("Session: %s", addrStr)
})
return m, nil
}
func (m *Monitoring) Stop() error {
if m == nil {
return nil
}
m.once.Do(func() {
close(m.done)
})
return nil
}
type PeerMonitoring func(peer core.PeerInfo)
type SessionMonitoring func(peer core.SessionInfo)
func (m *Monitoring) Monitoring(PeerMonitoringCallBack PeerMonitoring, SessionMonitoringCallBack SessionMonitoring) {
peers := make(map[string]struct{})
sessions := make(map[string]struct{})
for {
APIpeers := m.core.GetPeers()
for _, peer := range APIpeers {
if _, exist := peers[peer.URI]; !exist {
PeerMonitoringCallBack(peer)
peers[peer.URI] = struct{}{}
}
}
APIsessions := m.core.GetSessions()
for _, session := range APIsessions {
addr := address.AddrForKey(session.Key)
addrStr := net.IP(addr[:]).String()
if _, exist := sessions[addrStr]; !exist {
SessionMonitoringCallBack(session)
sessions[addrStr] = struct{}{}
}
}
select {
case <-m.done:
return
default:
}
}
}