import (
"bytes"
+ "encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/gorhill/cronexpr"
"github.com/hjson/hjson-go/v4"
- "golang.org/x/crypto/ed25519"
+ "golang.org/x/crypto/blake2b"
"golang.org/x/term"
)
CfgSpoolEnv = "NNCPSPOOL"
CfgLogEnv = "NNCPLOG"
CfgNoSync = "NNCPNOSYNC"
+ CfgKeysEnv = "NNCPKEYS"
)
var (
DefaultSendmailPath string = "/usr/sbin/sendmail"
DefaultSpoolPath string = "/var/spool/nncp"
DefaultLogPath string = "/var/spool/nncp/log"
+ DefaultKeysPath string = "/usr/local/etc/nncp.keys"
)
type NodeJSON struct {
Id string `json:"id"`
- ExchPub string `json:"exchpub"`
- SignPub string `json:"signpub"`
+ KeyId string `json:"keyid"`
NoisePub *string `json:"noisepub,omitempty"`
Incoming *string `json:"incoming,omitempty"`
Exec map[string][]string `json:"exec,omitempty"`
type NodeOurJSON struct {
Id string `json:"id"`
- ExchPub string `json:"exchpub"`
- ExchPrv string `json:"exchprv"`
- SignPub string `json:"signpub"`
- SignPrv string `json:"signprv"`
+ KeyId string `json:"keyid"`
NoisePub string `json:"noisepub"`
NoisePrv string `json:"noiseprv"`
}
return nil, err
}
- exchPub, err := Base32Codec.DecodeString(cfg.ExchPub)
+ keyId, err := hex.DecodeString(cfg.KeyId)
if err != nil {
return nil, err
}
- if len(exchPub) != 32 {
- return nil, errors.New("Invalid exchPub size")
- }
-
- signPub, err := Base32Codec.DecodeString(cfg.SignPub)
- if err != nil {
- return nil, err
- }
- if len(signPub) != ed25519.PublicKeySize {
- return nil, errors.New("Invalid signPub size")
+ if len(keyId) != 32 {
+ return nil, errors.New("Invalid keyid size")
}
var noisePub []byte
node := Node{
Name: name,
Id: nodeId,
- ExchPub: new([32]byte),
- SignPub: ed25519.PublicKey(signPub),
Exec: cfg.Exec,
Incoming: incoming,
FreqPath: freqPath,
OnlineDeadline: defOnlineDeadline,
MaxOnlineTime: defMaxOnlineTime,
}
- copy(node.ExchPub[:], exchPub)
+ copy(node.KeyId[:], keyId)
if len(noisePub) > 0 {
node.NoisePub = new([32]byte)
copy(node.NoisePub[:], noisePub)
return nil, err
}
- exchPub, err := Base32Codec.DecodeString(cfg.ExchPub)
- if err != nil {
- return nil, err
- }
- if len(exchPub) != 32 {
- return nil, errors.New("Invalid exchPub size")
- }
-
- exchPrv, err := Base32Codec.DecodeString(cfg.ExchPrv)
- if err != nil {
- return nil, err
- }
- if len(exchPrv) != 32 {
- return nil, errors.New("Invalid exchPrv size")
- }
-
- signPub, err := Base32Codec.DecodeString(cfg.SignPub)
- if err != nil {
- return nil, err
- }
- if len(signPub) != ed25519.PublicKeySize {
- return nil, errors.New("Invalid signPub size")
- }
-
- signPrv, err := Base32Codec.DecodeString(cfg.SignPrv)
+ keyId, err := hex.DecodeString(cfg.KeyId)
if err != nil {
return nil, err
}
- if len(signPrv) != ed25519.PrivateKeySize {
- return nil, errors.New("Invalid signPrv size")
+ if len(keyId) != 32 {
+ return nil, errors.New("Invalid keyid size")
}
noisePub, err := Base32Codec.DecodeString(cfg.NoisePub)
node := NodeOur{
Id: id,
- ExchPub: new([32]byte),
- ExchPrv: new([32]byte),
- SignPub: ed25519.PublicKey(signPub),
- SignPrv: ed25519.PrivateKey(signPrv),
+ KeyId: new([blake2b.Size256]byte),
NoisePub: new([32]byte),
NoisePrv: new([32]byte),
}
- copy(node.ExchPub[:], exchPub)
- copy(node.ExchPrv[:], exchPrv)
+ copy(node.KeyId[:], keyId)
copy(node.NoisePub[:], noisePub)
copy(node.NoisePrv[:], noisePrv)
return &node, nil
+++ /dev/null
-// NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-// Copyright (C) 2016-2025 Sergey Matveev <stargrave@stargrave.org>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 3 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package nncp
-
-import (
- "errors"
- "fmt"
- "io/fs"
- "os"
- "path/filepath"
- "sort"
- "strconv"
- "strings"
-)
-
-func cfgDirMkdir(dst ...string) error {
- return os.MkdirAll(filepath.Join(dst...), os.FileMode(0777))
-}
-
-func cfgDirSave(v interface{}, dst ...string) error {
- var r string
- switch v := v.(type) {
- case *string:
- if v == nil {
- return nil
- }
- r = *v
- case string:
- r = v
- case *int:
- if v == nil {
- return nil
- }
- r = strconv.Itoa(*v)
- case *uint:
- if v == nil {
- return nil
- }
- r = strconv.Itoa(int(*v))
- case *uint64:
- if v == nil {
- return nil
- }
- r = strconv.FormatUint(*v, 10)
- case int:
- r = strconv.Itoa(v)
- default:
- panic("unsupported value type")
- }
- mode := os.FileMode(0666)
- if strings.HasSuffix(dst[len(dst)-1], "prv") {
- mode = os.FileMode(0600)
- }
- return os.WriteFile(filepath.Join(dst...), []byte(r+"\n"), mode)
-}
-
-func cfgDirTouch(dst ...string) error {
- if fd, err := os.Create(filepath.Join(dst...)); err == nil {
- fd.Close()
- } else {
- return err
- }
- return nil
-}
-
-func CfgToDir(dst string, cfg *CfgJSON) (err error) {
- if err = cfgDirMkdir(dst); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Spool, dst, "spool"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Log, dst, "log"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Umask, dst, "umask"); err != nil {
- return
- }
- if cfg.OmitPrgrs {
- if err = cfgDirTouch(dst, "noprogress"); err != nil {
- return
- }
- }
- if cfg.NoHdr {
- if err = cfgDirTouch(dst, "nohdr"); err != nil {
- return
- }
- }
-
- if len(cfg.MCDRxIfis) > 0 {
- if err = cfgDirSave(
- strings.Join(cfg.MCDRxIfis, "\n"),
- dst, "mcd-listen",
- ); err != nil {
- return
- }
- }
- if len(cfg.MCDTxIfis) > 0 {
- if err = cfgDirMkdir(dst, "mcd-send"); err != nil {
- return
- }
- for ifi, t := range cfg.MCDTxIfis {
- if err = cfgDirSave(t, dst, "mcd-send", ifi); err != nil {
- return
- }
- }
- }
-
- if cfg.Notify != nil {
- if cfg.Notify.File != nil {
- if err = cfgDirMkdir(dst, "notify", "file"); err != nil {
- return
- }
- if err = cfgDirSave(
- cfg.Notify.File.From,
- dst, "notify", "file", "from",
- ); err != nil {
- return
- }
- if err = cfgDirSave(
- cfg.Notify.File.To,
- dst, "notify", "file", "to",
- ); err != nil {
- return
- }
- }
- if cfg.Notify.Freq != nil {
- if err = cfgDirMkdir(dst, "notify", "freq"); err != nil {
- return
- }
- if err = cfgDirSave(
- cfg.Notify.Freq.From,
- dst, "notify", "freq", "from",
- ); err != nil {
- return
- }
- if err = cfgDirSave(
- cfg.Notify.Freq.To,
- dst, "notify", "freq", "to",
- ); err != nil {
- return
- }
- }
- for k, v := range cfg.Notify.Exec {
- if err = cfgDirMkdir(dst, "notify", "exec", k); err != nil {
- return
- }
- if err = cfgDirSave(v.From, dst, "notify", "exec", k, "from"); err != nil {
- return
- }
- if err = cfgDirSave(v.To, dst, "notify", "exec", k, "to"); err != nil {
- return
- }
- }
- }
-
- if cfg.Self != nil {
- if err = cfgDirMkdir(dst, "self"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.Id, dst, "self", "id"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.ExchPub, dst, "self", "exchpub"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.ExchPrv, dst, "self", "exchprv"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.SignPub, dst, "self", "signpub"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.SignPrv, dst, "self", "signprv"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.NoisePub, dst, "self", "noisepub"); err != nil {
- return
- }
- if err = cfgDirSave(cfg.Self.NoisePrv, dst, "self", "noiseprv"); err != nil {
- return
- }
- }
-
- for name, n := range cfg.Neigh {
- if err = cfgDirMkdir(dst, "neigh", name); err != nil {
- return
- }
- if err = cfgDirSave(n.Id, dst, "neigh", name, "id"); err != nil {
- return
- }
- if err = cfgDirSave(n.ExchPub, dst, "neigh", name, "exchpub"); err != nil {
- return
- }
- if err = cfgDirSave(n.SignPub, dst, "neigh", name, "signpub"); err != nil {
- return
- }
- if err = cfgDirSave(n.NoisePub, dst, "neigh", name, "noisepub"); err != nil {
- return
- }
- if err = cfgDirSave(n.Incoming, dst, "neigh", name, "incoming"); err != nil {
- return
- }
-
- if len(n.Exec) > 0 {
- if err = cfgDirMkdir(dst, "neigh", name, "exec"); err != nil {
- return
- }
- for k, v := range n.Exec {
- if err = cfgDirSave(
- strings.Join(v, "\n"),
- dst, "neigh", name, "exec", k,
- ); err != nil {
- return
- }
- }
- }
-
- if n.Freq != nil {
- if err = cfgDirMkdir(dst, "neigh", name, "freq"); err != nil {
- return
- }
- if err = cfgDirSave(
- n.Freq.Path,
- dst, "neigh", name, "freq", "path",
- ); err != nil {
- return
- }
- if err = cfgDirSave(
- n.Freq.Chunked,
- dst, "neigh", name, "freq", "chunked",
- ); err != nil {
- return
- }
- if err = cfgDirSave(
- n.Freq.MinSize,
- dst, "neigh", name, "freq", "minsize",
- ); err != nil {
- return
- }
- if err = cfgDirSave(
- n.Freq.MaxSize,
- dst, "neigh", name, "freq", "maxsize",
- ); err != nil {
- return
- }
- }
-
- if n.ACK != nil {
- if err = cfgDirMkdir(dst, "neigh", name, "ack"); err != nil {
- return
- }
- if err = cfgDirSave(
- n.ACK.MinSize,
- dst, "neigh", name, "ack", "minsize",
- ); err != nil {
- return
- }
- if err = cfgDirSave(
- n.ACK.Nice,
- dst, "neigh", name, "ack", "nice",
- ); err != nil {
- return
- }
- }
-
- if len(n.Via) > 0 {
- if err = cfgDirSave(
- strings.Join(n.Via, "\n"),
- dst, "neigh", name, "via",
- ); err != nil {
- return
- }
- }
-
- if len(n.Addrs) > 0 {
- if err = cfgDirMkdir(dst, "neigh", name, "addrs"); err != nil {
- return
- }
- for k, v := range n.Addrs {
- if err = cfgDirSave(v, dst, "neigh", name, "addrs", k); err != nil {
- return
- }
- }
- }
-
- if err = cfgDirSave(n.RxRate, dst, "neigh", name, "rxrate"); err != nil {
- return
- }
- if err = cfgDirSave(n.TxRate, dst, "neigh", name, "txrate"); err != nil {
- return
- }
- if err = cfgDirSave(n.OnlineDeadline, dst, "neigh", name, "onlinedeadline"); err != nil {
- return
- }
- if err = cfgDirSave(n.MaxOnlineTime, dst, "neigh", name, "maxonlinetime"); err != nil {
- return
- }
-
- for i, call := range n.Calls {
- is := strconv.Itoa(i)
- if err = cfgDirMkdir(dst, "neigh", name, "calls", is); err != nil {
- return
- }
- if err = cfgDirSave(call.Cron, dst, "neigh", name, "calls", is, "cron"); err != nil {
- return
- }
- if err = cfgDirSave(call.Nice, dst, "neigh", name, "calls", is, "nice"); err != nil {
- return
- }
- if err = cfgDirSave(call.Xx, dst, "neigh", name, "calls", is, "xx"); err != nil {
- return
- }
- if err = cfgDirSave(call.RxRate, dst, "neigh", name, "calls", is, "rxrate"); err != nil {
- return
- }
- if err = cfgDirSave(call.TxRate, dst, "neigh", name, "calls", is, "txrate"); err != nil {
- return
- }
- if err = cfgDirSave(call.Addr, dst, "neigh", name, "calls", is, "addr"); err != nil {
- return
- }
- if err = cfgDirSave(call.OnlineDeadline, dst, "neigh", name, "calls", is, "onlinedeadline"); err != nil {
- return
- }
- if err = cfgDirSave(call.MaxOnlineTime, dst, "neigh", name, "calls", is, "maxonlinetime"); err != nil {
- return
- }
- if call.WhenTxExists {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "when-tx-exists"); err != nil {
- return
- }
- }
- if call.NoCK {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "nock"); err != nil {
- return
- }
- }
- if call.MCDIgnore {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "mcd-ignore"); err != nil {
- return
- }
- }
- if call.AutoToss {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss"); err != nil {
- return
- }
- }
- if call.AutoTossDoSeen {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-doseen"); err != nil {
- return
- }
- }
- if call.AutoTossNoFile {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-nofile"); err != nil {
- return
- }
- }
- if call.AutoTossNoFreq {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-nofreq"); err != nil {
- return
- }
- }
- if call.AutoTossNoExec {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-noexec"); err != nil {
- return
- }
- }
- if call.AutoTossNoTrns {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-notrns"); err != nil {
- return
- }
- }
- if call.AutoTossNoArea {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-noarea"); err != nil {
- return
- }
- }
- if call.AutoTossNoACK {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-noack"); err != nil {
- return
- }
- }
- if call.AutoTossGenACK {
- if err = cfgDirTouch(dst, "neigh", name, "calls", is, "autotoss-gen-ack"); err != nil {
- return
- }
- }
- }
- }
-
- for name, a := range cfg.Areas {
- if err = cfgDirMkdir(dst, "areas", name); err != nil {
- return
- }
- if err = cfgDirSave(a.Id, dst, "areas", name, "id"); err != nil {
- return
- }
- if err = cfgDirSave(a.Pub, dst, "areas", name, "pub"); err != nil {
- return
- }
- if err = cfgDirSave(a.Prv, dst, "areas", name, "prv"); err != nil {
- return
- }
- if err = cfgDirSave(a.Incoming, dst, "areas", name, "incoming"); err != nil {
- return
- }
- if a.AllowUnknown {
- if err = cfgDirTouch(dst, "areas", name, "allow-unknown"); err != nil {
- return
- }
- }
- if len(a.Exec) > 0 {
- if err = cfgDirMkdir(dst, "areas", name, "exec"); err != nil {
- return
- }
- for k, v := range a.Exec {
- if err = cfgDirSave(
- strings.Join(v, "\n"),
- dst, "areas", name, "exec", k,
- ); err != nil {
- return
- }
- }
- }
- if len(a.Subs) > 0 {
- if err = cfgDirSave(
- strings.Join(a.Subs, "\n"),
- dst, "areas", name, "subs",
- ); err != nil {
- return
- }
- }
- }
-
- if len(cfg.YggdrasilAliases) > 0 {
- if err = cfgDirMkdir(dst, "yggdrasil-aliases"); err != nil {
- return
- }
- for alias, v := range cfg.YggdrasilAliases {
- if err = cfgDirSave(v, dst, "yggdrasil-aliases", alias); err != nil {
- return
- }
- }
- }
-
- return
-}
-
-func cfgDirLoad(src ...string) (v string, exists bool, err error) {
- b, err := os.ReadFile(filepath.Join(src...))
- if err != nil {
- if errors.Is(err, fs.ErrNotExist) {
- return "", false, nil
- }
- return "", false, err
- }
- return strings.TrimSuffix(string(b), "\n"), true, nil
-}
-
-func cfgDirLoadMust(src ...string) (v string, err error) {
- s, exists, err := cfgDirLoad(src...)
- if err != nil {
- return "", err
- }
- if !exists {
- return "", fmt.Errorf("required \"%s\" does not exist", src[len(src)-1])
- }
- return s, nil
-}
-
-func cfgDirLoadOpt(src ...string) (v *string, err error) {
- s, exists, err := cfgDirLoad(src...)
- if err != nil {
- return nil, err
- }
- if !exists {
- return nil, nil
- }
- return &s, nil
-}
-
-func cfgDirLoadIntOpt(src ...string) (i64 *int64, err error) {
- s, err := cfgDirLoadOpt(src...)
- if err != nil {
- return nil, err
- }
- if s == nil {
- return nil, nil
- }
- i, err := strconv.ParseInt(*s, 10, 64)
- if err != nil {
- return nil, err
- }
- return &i, nil
-}
-
-func cfgDirExists(src ...string) bool {
- if _, err := os.Stat(filepath.Join(src...)); err == nil {
- return true
- }
- return false
-}
-
-func cfgDirReadFromTo(src ...string) (*FromToJSON, error) {
- fromTo := FromToJSON{}
-
- var err error
- fromTo.From, err = cfgDirLoadMust(append(src, "from")...)
- if err != nil {
- return nil, err
- }
-
- fromTo.To, err = cfgDirLoadMust(append(src, "to")...)
- if err != nil {
- return nil, err
- }
-
- return &fromTo, nil
-}
-
-func DirToCfg(src string) (*CfgJSON, error) {
- cfg := CfgJSON{}
- var err error
-
- cfg.Spool, err = cfgDirLoadMust(src, "spool")
- if err != nil {
- return nil, err
- }
- cfg.Log, err = cfgDirLoadMust(src, "log")
- if err != nil {
- return nil, err
- }
-
- if cfg.Umask, err = cfgDirLoadOpt(src, "umask"); err != nil {
- return nil, err
- }
- cfg.OmitPrgrs = cfgDirExists(src, "noprogress")
- cfg.NoHdr = cfgDirExists(src, "nohdr")
-
- sp, err := cfgDirLoadOpt(src, "mcd-listen")
- if err != nil {
- return nil, err
- }
- if sp != nil {
- cfg.MCDRxIfis = strings.Split(*sp, "\n")
- }
-
- fis, err := os.ReadDir(filepath.Join(src, "mcd-send"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- if len(fis) > 0 {
- cfg.MCDTxIfis = make(map[string]int, len(fis))
- }
- for _, fi := range fis {
- n := fi.Name()
- if n[0] == '.' {
- continue
- }
- b, err := os.ReadFile(filepath.Join(src, "mcd-send", fi.Name()))
- if err != nil {
- return nil, err
- }
- i, err := strconv.Atoi(strings.TrimSuffix(string(b), "\n"))
- if err != nil {
- return nil, err
- }
- cfg.MCDTxIfis[n] = i
- }
-
- notify := NotifyJSON{Exec: make(map[string]*FromToJSON)}
- if cfgDirExists(src, "notify", "file") {
- if notify.File, err = cfgDirReadFromTo(src, "notify", "file"); err != nil {
- return nil, err
- }
- }
- if cfgDirExists(src, "notify", "freq") {
- if notify.Freq, err = cfgDirReadFromTo(src, "notify", "freq"); err != nil {
- return nil, err
- }
- }
- fis, err = os.ReadDir(filepath.Join(src, "notify", "exec"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- for _, fi := range fis {
- n := fi.Name()
- if n[0] == '.' || !fi.IsDir() {
- continue
- }
- if notify.Exec[fi.Name()], err = cfgDirReadFromTo(src, "notify", "exec", n); err != nil {
- return nil, err
- }
- }
- if notify.File != nil || notify.Freq != nil || len(notify.Exec) > 0 {
- cfg.Notify = ¬ify
- }
-
- if _, err = os.ReadDir(filepath.Join(src, "self")); err == nil {
- self := NodeOurJSON{}
- if self.Id, err = cfgDirLoadMust(src, "self", "id"); err != nil {
- return nil, err
- }
- if self.ExchPub, err = cfgDirLoadMust(src, "self", "exchpub"); err != nil {
- return nil, err
- }
- if self.ExchPrv, err = cfgDirLoadMust(src, "self", "exchprv"); err != nil {
- return nil, err
- }
- if self.SignPub, err = cfgDirLoadMust(src, "self", "signpub"); err != nil {
- return nil, err
- }
- if self.SignPrv, err = cfgDirLoadMust(src, "self", "signprv"); err != nil {
- return nil, err
- }
- if self.NoisePub, err = cfgDirLoadMust(src, "self", "noisepub"); err != nil {
- return nil, err
- }
- if self.NoisePrv, err = cfgDirLoadMust(src, "self", "noiseprv"); err != nil {
- return nil, err
- }
- cfg.Self = &self
- } else if !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
-
- cfg.Neigh = make(map[string]NodeJSON)
- fis, err = os.ReadDir(filepath.Join(src, "neigh"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- for _, fi := range fis {
- n := fi.Name()
- if n[0] == '.' {
- continue
- }
- node := NodeJSON{}
- if node.Id, err = cfgDirLoadMust(src, "neigh", n, "id"); err != nil {
- return nil, err
- }
- if node.ExchPub, err = cfgDirLoadMust(src, "neigh", n, "exchpub"); err != nil {
- return nil, err
- }
- if node.SignPub, err = cfgDirLoadMust(src, "neigh", n, "signpub"); err != nil {
- return nil, err
- }
- if node.NoisePub, err = cfgDirLoadOpt(src, "neigh", n, "noisepub"); err != nil {
- return nil, err
- }
- if node.Incoming, err = cfgDirLoadOpt(src, "neigh", n, "incoming"); err != nil {
- return nil, err
- }
-
- node.Exec = make(map[string][]string)
- fis2, err := os.ReadDir(filepath.Join(src, "neigh", n, "exec"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- for _, fi2 := range fis2 {
- n2 := fi2.Name()
- if n2[0] == '.' {
- continue
- }
- s, err := cfgDirLoadMust(src, "neigh", n, "exec", n2)
- if err != nil {
- return nil, err
- }
- node.Exec[n2] = strings.Split(s, "\n")
- }
-
- if cfgDirExists(src, "neigh", n, "freq") {
- node.Freq = &NodeFreqJSON{}
- if node.Freq.Path, err = cfgDirLoadOpt(src, "neigh", n, "freq", "path"); err != nil {
- return nil, err
- }
-
- i64, err := cfgDirLoadIntOpt(src, "neigh", n, "freq", "chunked")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint64(*i64)
- node.Freq.Chunked = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "freq", "minsize")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint64(*i64)
- node.Freq.MinSize = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "freq", "maxsize")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint64(*i64)
- node.Freq.MaxSize = &i
- }
- }
-
- if cfgDirExists(src, "neigh", n, "ack") {
- node.ACK = &NodeACKJSON{}
- i64, err := cfgDirLoadIntOpt(src, "neigh", n, "ack", "minsize")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint64(*i64)
- node.ACK.MinSize = &i
- }
- if node.ACK.Nice, err = cfgDirLoadOpt(
- src, "neigh", n, "ack", "nice",
- ); err != nil {
- return nil, err
- }
- }
-
- via, err := cfgDirLoadOpt(src, "neigh", n, "via")
- if err != nil {
- return nil, err
- }
- if via != nil {
- node.Via = strings.Split(*via, "\n")
- }
-
- node.Addrs = make(map[string]string)
- fis2, err = os.ReadDir(filepath.Join(src, "neigh", n, "addrs"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- for _, fi2 := range fis2 {
- n2 := fi2.Name()
- if n2[0] == '.' {
- continue
- }
- if node.Addrs[n2], err = cfgDirLoadMust(src, "neigh", n, "addrs", n2); err != nil {
- return nil, err
- }
- }
-
- i64, err := cfgDirLoadIntOpt(src, "neigh", n, "rxrate")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := int(*i64)
- node.RxRate = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "txrate")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := int(*i64)
- node.TxRate = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "onlinedeadline")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint(*i64)
- node.OnlineDeadline = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "maxonlinetime")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint(*i64)
- node.MaxOnlineTime = &i
- }
-
- fis2, err = os.ReadDir(filepath.Join(src, "neigh", n, "calls"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- callsIdx := make([]int, 0, len(fis2))
- for _, fi2 := range fis2 {
- n2 := fi2.Name()
- if !fi2.IsDir() {
- continue
- }
- i, err := strconv.Atoi(n2)
- if err != nil {
- continue
- }
- callsIdx = append(callsIdx, i)
- }
- sort.Ints(callsIdx)
- for _, i := range callsIdx {
- call := CallJSON{}
- is := strconv.Itoa(i)
- if call.Cron, err = cfgDirLoadMust(
- src, "neigh", n, "calls", is, "cron",
- ); err != nil {
- return nil, err
- }
- if call.Nice, err = cfgDirLoadOpt(
- src, "neigh", n, "calls", is, "nice",
- ); err != nil {
- return nil, err
- }
- if call.Xx, err = cfgDirLoadOpt(
- src, "neigh", n, "calls", is, "xx",
- ); err != nil {
- return nil, err
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "rxrate")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := int(*i64)
- call.RxRate = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "txrate")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := int(*i64)
- call.TxRate = &i
- }
-
- if call.Addr, err = cfgDirLoadOpt(
- src, "neigh", n, "calls", is, "addr",
- ); err != nil {
- return nil, err
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "onlinedeadline")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint(*i64)
- call.OnlineDeadline = &i
- }
-
- i64, err = cfgDirLoadIntOpt(src, "neigh", n, "calls", is, "maxonlinetime")
- if err != nil {
- return nil, err
- }
- if i64 != nil {
- i := uint(*i64)
- call.MaxOnlineTime = &i
- }
-
- if cfgDirExists(src, "neigh", n, "calls", is, "when-tx-exists") {
- call.WhenTxExists = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "nock") {
- call.NoCK = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "mcd-ignore") {
- call.MCDIgnore = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss") {
- call.AutoToss = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-doseen") {
- call.AutoTossDoSeen = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-nofile") {
- call.AutoTossNoFile = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-nofreq") {
- call.AutoTossNoFreq = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noexec") {
- call.AutoTossNoExec = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-notrns") {
- call.AutoTossNoTrns = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noarea") {
- call.AutoTossNoArea = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-noack") {
- call.AutoTossNoACK = true
- }
- if cfgDirExists(src, "neigh", n, "calls", is, "autotoss-gen-ack") {
- call.AutoTossGenACK = true
- }
- node.Calls = append(node.Calls, call)
- }
- cfg.Neigh[n] = node
- }
-
- cfg.Areas = make(map[string]AreaJSON)
- fis, err = os.ReadDir(filepath.Join(src, "areas"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- for _, fi := range fis {
- n := fi.Name()
- if n[0] == '.' {
- continue
- }
- area := AreaJSON{}
- if area.Id, err = cfgDirLoadMust(src, "areas", n, "id"); err != nil {
- return nil, err
- }
- if area.Pub, err = cfgDirLoadOpt(src, "areas", n, "pub"); err != nil {
- return nil, err
- }
- if area.Prv, err = cfgDirLoadOpt(src, "areas", n, "prv"); err != nil {
- return nil, err
- }
-
- subs, err := cfgDirLoadOpt(src, "areas", n, "subs")
- if err != nil {
- return nil, err
- }
- if subs != nil {
- area.Subs = strings.Split(*subs, "\n")
- }
-
- area.Exec = make(map[string][]string)
- fis2, err := os.ReadDir(filepath.Join(src, "areas", n, "exec"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- for _, fi2 := range fis2 {
- n2 := fi2.Name()
- if n2[0] == '.' {
- continue
- }
- s, err := cfgDirLoadMust(src, "areas", n, "exec", n2)
- if err != nil {
- return nil, err
- }
- area.Exec[n2] = strings.Split(s, "\n")
- }
-
- if area.Incoming, err = cfgDirLoadOpt(src, "areas", n, "incoming"); err != nil {
- return nil, err
- }
-
- if cfgDirExists(src, "areas", n, "allow-unknown") {
- area.AllowUnknown = true
- }
- cfg.Areas[n] = area
- }
-
- fis, err = os.ReadDir(filepath.Join(src, "yggdrasil-aliases"))
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return nil, err
- }
- if len(fis) > 0 {
- cfg.YggdrasilAliases = make(map[string]string, len(fis))
- }
- for _, fi := range fis {
- n := fi.Name()
- if n[0] == '.' {
- continue
- }
- b, err := os.ReadFile(filepath.Join(src, "yggdrasil-aliases", fi.Name()))
- if err != nil {
- return nil, err
- }
- cfg.YggdrasilAliases[n] = strings.TrimSuffix(string(b), "\n")
- }
-
- return &cfg, nil
-}
ctx.Self,
ctx.Neigh,
bufio.NewReaderSize(fd, nncp.MTHBlockSize),
- pipeW, true, nil,
+ pipeW,
)
var pkt nncp.Pkt
_, err = xdr.Unmarshal(pipeR, &pkt)
case nncp.MagicNNCPEv5.B:
err = nncp.MagicNNCPEv5.TooOld()
case nncp.MagicNNCPEv6.B:
+ err = nncp.MagicNNCPEv6.TooOld()
+ case nncp.MagicNNCPEv7.B:
default:
err = errors.New("Bad packet magic number")
}
+++ /dev/null
-// NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-// Copyright (C) 2016-2025 Sergey Matveev <stargrave@stargrave.org>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 3 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-// Convert NNCP Hjson configuration file to the directory layout.
-package main
-
-import (
- "flag"
- "fmt"
- "log"
- "os"
-
- "github.com/hjson/hjson-go/v4"
- "go.cypherpunks.su/nncp/v8"
-)
-
-func usageCfgDir() {
- fmt.Fprint(os.Stderr, "nncp-cfgdir -- Convert configuration file to the directory layout.\n\n")
- fmt.Fprintf(os.Stderr, "Usage: %s [options] [-cfg ...] -dump /path/to/dir\n", os.Args[0])
- fmt.Fprintf(os.Stderr, " %s [options] -load /path/to/dir >cfg.hjson\nOptions:\n", os.Args[0])
- flag.PrintDefaults()
-}
-
-func mainCfgDir() {
- var (
- doDump = flag.Bool("dump", false, "Dump configuration file to the directory")
- doLoad = flag.Bool("load", false, "Load directory to create configuration file")
- cfgPath = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
- version = flag.Bool("version", false, "Print version information")
- warranty = flag.Bool("warranty", false, "Print warranty information")
- )
- log.SetFlags(log.Lshortfile)
- flag.Usage = usageCfgDir
- flag.Parse()
- if *warranty {
- fmt.Println(nncp.Warranty)
- return
- }
- if *version {
- fmt.Println(nncp.VersionGet())
- return
- }
-
- if (!*doDump && !*doLoad) || flag.NArg() != 1 {
- usageCfgDir()
- os.Exit(1)
- }
-
- if *doDump {
- cfgRaw, err := os.ReadFile(*cfgPath)
- if err != nil {
- log.Fatalln(err)
- }
- cfg, err := nncp.CfgParse(cfgRaw)
- if err != nil {
- log.Fatalln(err)
- }
- if err = nncp.CfgToDir(flag.Arg(0), cfg); err != nil {
- log.Fatalln(err)
- }
- }
- if *doLoad {
- cfg, err := nncp.DirToCfg(flag.Arg(0))
- if err != nil {
- log.Fatalln(err)
- }
- if _, err = nncp.Cfg2Ctx(cfg); err != nil {
- log.Fatalln(err)
- }
- marshaled, err := hjson.MarshalWithOptions(cfg, hjson.EncoderOptions{
- Eol: "\n",
- BracesSameLine: true,
- QuoteAlways: false,
- IndentBy: " ",
- })
- if err != nil {
- log.Fatalln(err)
- }
- os.Stdout.Write(marshaled)
- os.Stdout.WriteString("\n")
- }
-}
}
cfg.Neigh[node.Name] = nncp.NodeJSON{
Id: node.Id.String(),
- ExchPub: nncp.Base32Codec.EncodeToString(node.ExchPub[:]),
- SignPub: nncp.Base32Codec.EncodeToString(node.SignPub[:]),
+ KeyId: nncp.HexEncode(node.KeyId[:]),
NoisePub: noisePub,
}
}
areaName = flag.String("area", "", "Generate area's keypairs")
yggdrasil = flag.Bool("yggdrasil", false, "Generate Yggdrasil keypair")
noComments = flag.Bool("nocomments", false, "Do not include descriptive comments")
+ name = flag.String("name", "anon", "Name in public key")
version = flag.Bool("version", false, "Print version information")
warranty = flag.Bool("warranty", false, "Print warranty information")
)
return
}
- nodeOur, err := nncp.NewNodeGenerate()
+ nodeOur, err := nncp.NewNodeGenerate(*name)
if err != nil {
log.Fatalln(err)
}
self: {
# DO NOT show anyone your private keys!!!
id: %s
- exchpub: %s
- exchprv: %s
- signpub: %s
- signprv: %s
+ keyid: %s
noiseprv: %s
noisepub: %s
}
neigh: {
self: {
id: %s
- exchpub: %s
- signpub: %s
+ keyid: %s
noisepub: %s
exec: {sendmail: ["%s"]}
}
nncp.DefaultSpoolPath,
nncp.DefaultLogPath,
nodeOur.Id.String(),
- nncp.Base32Codec.EncodeToString(nodeOur.ExchPub[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.ExchPrv[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.SignPub[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.SignPrv[:]),
+ nncp.HexEncode(nodeOur.KeyId[:]),
nncp.Base32Codec.EncodeToString(nodeOur.NoisePrv[:]),
nncp.Base32Codec.EncodeToString(nodeOur.NoisePub[:]),
nodeOur.Id.String(),
- nncp.Base32Codec.EncodeToString(nodeOur.ExchPub[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.SignPub[:]),
+ nncp.HexEncode(nodeOur.KeyId[:]),
nncp.Base32Codec.EncodeToString(nodeOur.NoisePub[:]),
nncp.DefaultSendmailPath,
)
self: {
# DO NOT show anyone your private keys!!!
id: %s
- exchpub: %s
- exchprv: %s
- signpub: %s
- signprv: %s
+ keyid: %s
noiseprv: %s
noisepub: %s
}
self: {
# You should give public keys below to your neighbours
id: %s
- exchpub: %s
- signpub: %s
+ keyid: %s
noisepub: %s
exec: {
nncp.DefaultSpoolPath,
nncp.DefaultLogPath,
nodeOur.Id.String(),
- nncp.Base32Codec.EncodeToString(nodeOur.ExchPub[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.ExchPrv[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.SignPub[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.SignPrv[:]),
+ nncp.HexEncode(nodeOur.KeyId[:]),
nncp.Base32Codec.EncodeToString(nodeOur.NoisePrv[:]),
nncp.Base32Codec.EncodeToString(nodeOur.NoisePub[:]),
nodeOur.Id.String(),
- nncp.Base32Codec.EncodeToString(nodeOur.ExchPub[:]),
- nncp.Base32Codec.EncodeToString(nodeOur.SignPub[:]),
+ nncp.HexEncode(nodeOur.KeyId[:]),
nncp.Base32Codec.EncodeToString(nodeOur.NoisePub[:]),
nncp.DefaultSendmailPath,
nncp.DefaultSendmailPath,
CmdNameBundle = "nncp-bundle"
CmdNameCall = "nncp-call"
CmdNameCaller = "nncp-caller"
- CmdNameCfgDir = "nncp-cfgdir"
CmdNameCfgEnc = "nncp-cfgenc"
CmdNameCfgMin = "nncp-cfgmin"
CmdNameCfgNew = "nncp-cfgnew"
mainCall()
case CmdNameCaller:
mainCaller()
- case CmdNameCfgDir:
- mainCfgDir()
case CmdNameCfgEnc:
mainCfgEnc()
case CmdNameCfgMin:
bufW := bufio.NewWriter(os.Stdout)
var err error
if area == nil {
- _, _, _, err = nncp.PktEncRead(
+ _, _, err = nncp.PktEncRead(
ctx.Self, ctx.Neigh,
io.MultiReader(bytes.NewReader(beginning), bufio.NewReader(os.Stdin)),
- bufW, senderNode != nil, nil,
+ bufW,
)
} else {
- areaNode := nncp.NodeOur{Id: new(nncp.NodeId), ExchPrv: new([32]byte)}
- copy(areaNode.Id[:], area.Id[:])
- copy(areaNode.ExchPrv[:], area.Prv[:])
- _, _, _, err = nncp.PktEncRead(
- &areaNode, ctx.Neigh,
- io.MultiReader(bytes.NewReader(beginning), bufio.NewReader(os.Stdin)),
- bufW, senderNode != nil, nil,
- )
+ panic("no area yet")
}
if err != nil {
log.Fatalln(err)
if *overheads {
fmt.Printf(
- "Plain: %d\nEncrypted: %d\nSize: %d\n",
+ "Plain: %d\nEncrypted: %d\n",
nncp.PktOverhead,
nncp.PktEncOverhead,
- nncp.PktSizeOverhead,
)
return
}
case nncp.MagicNNCPEv5.B:
log.Fatalln(nncp.MagicNNCPEv5.TooOld())
case nncp.MagicNNCPEv6.B:
+ log.Fatalln(nncp.MagicNNCPEv6.TooOld())
+ case nncp.MagicNNCPEv7.B:
doEncrypted(ctx, pktEnc, *dump, beginning[:nncp.PktEncOverhead])
return
}
case nncp.MagicNNCPEv5.B:
err = nncp.MagicNNCPEv5.TooOld()
case nncp.MagicNNCPEv6.B:
+ err = nncp.MagicNNCPEv6.TooOld()
+ case nncp.MagicNNCPEv7.B:
default:
err = errors.New("is not an encrypted packet")
}
if env != "" {
cfgPath = env
}
+ env = os.Getenv(CfgKeysEnv)
+ if env != "" {
+ DefaultKeysPath = env
+ }
if showPrgrs && omitPrgrs {
return nil, errors.New("simultaneous -progress and -noprogress")
}
return nil, err
}
if fi.IsDir() {
- cfg, err = DirToCfg(cfgPath)
- if err != nil {
- return nil, err
- }
+ panic("cfg is dir")
} else {
cfgRaw, err := os.ReadFile(cfgPath)
if err != nil {
case MagicNNCPEv5.B:
err = MagicNNCPEv5.TooOld()
case MagicNNCPEv6.B:
+ err = MagicNNCPEv6.TooOld()
+ case MagicNNCPEv7.B:
default:
err = BadMagic
}
}
MagicNNCPEv6 = Magic{
B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 6},
- Name: "NNCPEv6 (encrypted packet v6)", Till: "now",
+ Name: "NNCPEv6 (encrypted packet v6)", Till: "8.13.0",
+ }
+ MagicNNCPEv7 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 7},
+ Name: "NNCPEv7 (encrypted packet v7)", Till: "now",
}
MagicNNCPSv1 = Magic{
B: [8]byte{'N', 'N', 'C', 'P', 'S', 0, 0, 1},
)
var (
- Version string = "8.13.0"
+ Version string = "dev"
Base32Codec *base32.Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
)
package nncp
import (
+ "bytes"
"crypto/rand"
+ "encoding/hex"
"errors"
"fmt"
+ "io"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
"sync"
"time"
"github.com/flynn/noise"
"golang.org/x/crypto/blake2b"
- "golang.org/x/crypto/ed25519"
- "golang.org/x/crypto/nacl/box"
)
const DummyB32Id = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
return Base32Codec.EncodeToString(id[:])
}
+func HexEncode(b []byte) string {
+ return strings.ToUpper(hex.EncodeToString(b))
+}
+
type Node struct {
Name string
Id *NodeId
- ExchPub *[32]byte
- SignPub ed25519.PublicKey
+ KeyId [32]byte
NoisePub *[32]byte
Exec map[string][]string
Incoming *string
type NodeOur struct {
Id *NodeId
- ExchPub *[32]byte
- ExchPrv *[32]byte
- SignPub ed25519.PublicKey
- SignPrv ed25519.PrivateKey
+ KeyId *[32]byte
NoisePub *[32]byte
NoisePrv *[32]byte
}
-func NewNodeGenerate() (*NodeOur, error) {
- exchPub, exchPrv, err := box.GenerateKey(rand.Reader)
+func NewNodeGenerate(name string) (*NodeOur, error) {
+ prv, err := os.CreateTemp(DefaultKeysPath, "prv*")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(prv.Name())
+ pub, err := os.CreateTemp(DefaultKeysPath, "pub*")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(pub.Name())
+ cmd := exec.Command("cmkeytool",
+ "-sub", "N="+name,
+ "-algo", "mceliece6960119-x25519",
+ "-ku", "kem", "-ku", "nncp")
+ cmd.ExtraFiles = []*os.File{nil, nil, pub, nil, nil, nil, prv}
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return nil, fmt.Errorf("%s: %s", err, string(out))
+ }
+ _, err = prv.Seek(0, io.SeekStart)
if err != nil {
return nil, err
}
- signPub, signPrv, err := ed25519.GenerateKey(rand.Reader)
+ cmd = exec.Command("kekspp", "-v", "-p", "/pub-id")
+ cmd.Stdin = prv
+ out, err = cmd.Output()
+ if err != nil {
+ return nil, err
+ }
+ out = bytes.TrimRight(out, "\n")
+ keyId, err := hex.DecodeString(string(out))
+ if err != nil {
+ return nil, err
+ }
+ if len(keyId) != blake2b.Size256 {
+ panic("unexpected pub-id len")
+ }
+ err = os.Rename(prv.Name(), filepath.Join(DefaultKeysPath, string(out)+".prv"))
+ if err != nil {
+ return nil, err
+ }
+ err = os.Rename(pub.Name(), filepath.Join(DefaultKeysPath, string(out)+".pub"))
+ if err != nil {
+ return nil, err
+ }
+ err = os.Symlink(
+ "../"+string(out)+".prv",
+ filepath.Join(DefaultKeysPath, "prvs", string(out)),
+ )
+ if err != nil {
+ return nil, err
+ }
+ err = os.Symlink(
+ "../"+string(out)+".pub",
+ filepath.Join(DefaultKeysPath, "pubs", string(out)),
+ )
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
- noisePub := new([32]byte)
- noisePrv := new([32]byte)
- copy(noisePrv[:], noiseKey.Private)
- copy(noisePub[:], noiseKey.Public)
-
- id := NodeId(blake2b.Sum256([]byte(signPub)))
+ id := NodeId(keyId)
node := NodeOur{
Id: &id,
- ExchPub: exchPub,
- ExchPrv: exchPrv,
- SignPub: signPub,
- SignPrv: signPrv,
- NoisePub: noisePub,
- NoisePrv: noisePrv,
+ KeyId: new([blake2b.Size256]byte),
+ NoisePub: new([32]byte),
+ NoisePrv: new([32]byte),
}
+ copy(node.KeyId[:], keyId)
+ copy(node.NoisePub[:], noiseKey.Public)
+ copy(node.NoisePrv[:], noiseKey.Private)
return &node, nil
}
return &Node{
Name: "self",
Id: nodeOur.Id,
- ExchPub: nodeOur.ExchPub,
- SignPub: nodeOur.SignPub,
+ KeyId: *nodeOur.KeyId,
FreqChunked: MaxFileSize,
FreqMaxSize: MaxFileSize,
}
import (
"bytes"
- "crypto/cipher"
- "crypto/rand"
"errors"
"io"
+ "os"
+ "os/exec"
+ "path/filepath"
xdr "github.com/davecgh/go-xdr/xdr2"
- "golang.org/x/crypto/chacha20poly1305"
- "golang.org/x/crypto/curve25519"
- "golang.org/x/crypto/ed25519"
- "golang.org/x/crypto/nacl/box"
- "golang.org/x/crypto/poly1305"
- "lukechampine.com/blake3"
)
type PktType uint8
var (
BadPktType error = errors.New("Unknown packet type")
- DeriveKeyFullCtx = string(MagicNNCPEv6.B[:]) + " FULL"
- DeriveKeySizeCtx = string(MagicNNCPEv6.B[:]) + " SIZE"
- DeriveKeyPadCtx = string(MagicNNCPEv6.B[:]) + " PAD"
-
- PktOverhead int64
- PktEncOverhead int64
- PktSizeOverhead int64
+ PktOverhead int64
+ PktEncOverhead int64
TooBig = errors.New("Too big than allowed")
)
Nice uint8
Sender *NodeId
Recipient *NodeId
- ExchPub [32]byte
- Sign [ed25519.SignatureSize]byte
-}
-
-type PktSize struct {
- Payload uint64
- Pad uint64
}
func NewPkt(typ PktType, nice uint8, path []byte) (*Pkt, error) {
}
PktEncOverhead = int64(n)
buf.Reset()
-
- size := PktSize{}
- n, err = xdr.Marshal(&buf, size)
- if err != nil {
- panic(err)
- }
- PktSizeOverhead = int64(n)
-}
-
-func ctrIncr(b []byte) {
- for i := len(b) - 1; i >= 0; i-- {
- b[i]++
- if b[i] != 0 {
- return
- }
- }
- panic("counter overflow")
-}
-
-func TbsPrepare(our *NodeOur, their *Node, pktEnc *PktEnc) []byte {
- tbs := PktTbs{
- Magic: MagicNNCPEv6.B,
- Nice: pktEnc.Nice,
- Sender: their.Id,
- Recipient: our.Id,
- ExchPub: pktEnc.ExchPub,
- }
- var tbsBuf bytes.Buffer
- if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil {
- panic(err)
- }
- return tbsBuf.Bytes()
-}
-
-func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) ([]byte, bool, error) {
- tbs := TbsPrepare(our, their, pktEnc)
- return tbs, ed25519.Verify(their.SignPub, tbs, pktEnc.Sign[:]), nil
-}
-
-func sizeWithTags(size int64) (fullSize int64) {
- size += PktSizeOverhead
- fullSize = size + (size/EncBlkSize)*poly1305.TagSize
- if size%EncBlkSize != 0 {
- fullSize += poly1305.TagSize
- }
- return
-}
-
-func sizePadCalc(sizePayload, minSize int64, wrappers int) (sizePad int64) {
- expectedSize := sizePayload - PktOverhead
- for i := 0; i < wrappers; i++ {
- expectedSize = PktEncOverhead + sizeWithTags(PktOverhead+expectedSize)
- }
- sizePad = minSize - expectedSize
- if sizePad < 0 {
- sizePad = 0
- }
- return
}
func PktEncWrite(
minSize, maxSize int64, wrappers int,
r io.Reader, w io.Writer,
) (pktEncRaw []byte, size int64, err error) {
- pub, prv, err := box.GenerateKey(rand.Reader)
- if err != nil {
- return nil, 0, err
- }
-
- var buf bytes.Buffer
- _, err = xdr.Marshal(&buf, pkt)
- if err != nil {
- return
- }
- pktRaw := make([]byte, buf.Len())
- copy(pktRaw, buf.Bytes())
- buf.Reset()
-
- tbs := PktTbs{
- Magic: MagicNNCPEv6.B,
- Nice: nice,
- Sender: our.Id,
- Recipient: their.Id,
- ExchPub: *pub,
- }
- _, err = xdr.Marshal(&buf, &tbs)
- if err != nil {
- return
- }
- signature := new([ed25519.SignatureSize]byte)
- copy(signature[:], ed25519.Sign(our.SignPrv, buf.Bytes()))
- ad := blake3.Sum256(buf.Bytes())
- buf.Reset()
-
- pktEnc := PktEnc{
- Magic: MagicNNCPEv6.B,
- Nice: nice,
- Sender: our.Id,
- Recipient: their.Id,
- ExchPub: *pub,
- Sign: *signature,
- }
- _, err = xdr.Marshal(&buf, &pktEnc)
- if err != nil {
- return
- }
- pktEncRaw = make([]byte, buf.Len())
- copy(pktEncRaw, buf.Bytes())
- buf.Reset()
- _, err = w.Write(pktEncRaw)
- if err != nil {
- return
- }
-
- sharedKey, err := curve25519.X25519(prv[:], their.ExchPub[:])
- if err != nil {
- return
- }
- keyFull := make([]byte, chacha20poly1305.KeySize)
- keySize := make([]byte, chacha20poly1305.KeySize)
- blake3.DeriveKey(keyFull, DeriveKeyFullCtx, sharedKey)
- blake3.DeriveKey(keySize, DeriveKeySizeCtx, sharedKey)
- aeadFull, err := chacha20poly1305.New(keyFull)
- if err != nil {
- return
- }
- aeadSize, err := chacha20poly1305.New(keySize)
- if err != nil {
- return
- }
- nonce := make([]byte, aeadFull.NonceSize())
-
- data := make([]byte, EncBlkSize, EncBlkSize+aeadFull.Overhead())
- mr := io.MultiReader(bytes.NewReader(pktRaw), r)
- var sizePayload int64
- var n int
- var ct []byte
- for {
- n, err = io.ReadFull(mr, data)
- sizePayload += int64(n)
- if sizePayload > maxSize {
- err = TooBig
+ {
+ var buf bytes.Buffer
+ pktEnc := PktEnc{
+ Magic: MagicNNCPEv7.B,
+ Nice: nice,
+ Sender: our.Id,
+ Recipient: their.Id,
+ }
+ _, err = xdr.Marshal(&buf, &pktEnc)
+ if err != nil {
return
}
- if err == nil {
- ct = aeadFull.Seal(data[:0], nonce, data[:n], ad[:])
- _, err = w.Write(ct)
- if err != nil {
- return
- }
- ctrIncr(nonce)
- continue
- }
- if !(err == io.EOF || err == io.ErrUnexpectedEOF) {
+ pktEncRaw = buf.Bytes()
+ }
+ cmd := exec.Command("cmenctool", "-no-to", "-no-from", "-no-id", "-from",
+ filepath.Join(DefaultKeysPath, "pubs", HexEncode(our.KeyId[:])),
+ filepath.Join(DefaultKeysPath, "pubs", HexEncode(their.KeyId[:])),
+ )
+ cmd.Env = append(cmd.Env, "CM_PRVS="+filepath.Join(DefaultKeysPath, "prvs"))
+ cmd.Env = append(cmd.Env, "CM_PUBS="+filepath.Join(DefaultKeysPath, "pubs"))
+ {
+ var buf bytes.Buffer
+ _, err = xdr.Marshal(&buf, &pkt)
+ if err != nil {
return
}
- break
+ cmd.Stdin = io.MultiReader(&buf, r)
}
-
- sizePad := sizePadCalc(sizePayload, minSize, wrappers)
- _, err = xdr.Marshal(&buf, &PktSize{uint64(sizePayload), uint64(sizePad)})
+ cmd.Stderr = os.Stderr
+ encrypted, err := cmd.StdoutPipe()
if err != nil {
return
}
-
- var aeadLast cipher.AEAD
- if n+int(PktSizeOverhead) > EncBlkSize {
- left := make([]byte, (n+int(PktSizeOverhead))-EncBlkSize)
- copy(left, data[n-len(left):])
- copy(data[PktSizeOverhead:], data[:n-len(left)])
- copy(data[:PktSizeOverhead], buf.Bytes())
- ct = aeadSize.Seal(data[:0], nonce, data[:EncBlkSize], ad[:])
- _, err = w.Write(ct)
- if err != nil {
- return
- }
- ctrIncr(nonce)
- copy(data, left)
- n = len(left)
- aeadLast = aeadFull
- } else {
- copy(data[PktSizeOverhead:], data[:n])
- copy(data[:PktSizeOverhead], buf.Bytes())
- n += int(PktSizeOverhead)
- aeadLast = aeadSize
- }
-
- var sizeBlockPadded int
- var sizePadLeft int64
- if sizePad > EncBlkSize-int64(n) {
- sizeBlockPadded = EncBlkSize
- sizePadLeft = sizePad - (EncBlkSize - int64(n))
- } else {
- sizeBlockPadded = n + int(sizePad)
- sizePadLeft = 0
- }
- for i := n; i < sizeBlockPadded; i++ {
- data[i] = 0
+ err = cmd.Start()
+ if err != nil {
+ return
}
- ct = aeadLast.Seal(data[:0], nonce, data[:sizeBlockPadded], ad[:])
- _, err = w.Write(ct)
+ size, err = io.Copy(w, io.MultiReader(bytes.NewReader(pktEncRaw), encrypted))
if err != nil {
return
}
-
- size = sizePayload
- if sizePadLeft > 0 {
- keyPad := make([]byte, chacha20poly1305.KeySize)
- blake3.DeriveKey(keyPad, DeriveKeyPadCtx, sharedKey[:])
- _, err = io.CopyN(w, blake3.New(32, keyPad).XOF(), sizePadLeft)
+ err = cmd.Wait()
+ if err != nil {
+ return
}
return
}
func PktEncRead(
our *NodeOur, nodes map[NodeId]*Node,
r io.Reader, w io.Writer,
- signatureVerify bool,
- sharedKeyCached []byte,
-) (sharedKey []byte, their *Node, size int64, err error) {
+) (their *Node, size int64, err error) {
var pktEnc PktEnc
_, err = xdr.Unmarshal(r, &pktEnc)
if err != nil {
case MagicNNCPEv5.B:
err = MagicNNCPEv5.TooOld()
case MagicNNCPEv6.B:
+ err = MagicNNCPEv6.TooOld()
+ case MagicNNCPEv7.B:
default:
err = BadMagic
}
err = errors.New("Invalid recipient")
return
}
-
- var tbsRaw []byte
- if signatureVerify {
- their = nodes[*pktEnc.Sender]
- if their == nil {
- err = errors.New("Unknown sender")
- return
- }
- var verified bool
- tbsRaw, verified, err = TbsVerify(our, their, &pktEnc)
- if err != nil {
- return
- }
- if !verified {
- err = errors.New("Invalid signature")
- return
- }
- } else {
- tbsRaw = TbsPrepare(our, &Node{Id: pktEnc.Sender}, &pktEnc)
- }
- ad := blake3.Sum256(tbsRaw)
- if sharedKeyCached == nil {
- var key []byte
- key, err = curve25519.X25519(our.ExchPrv[:], pktEnc.ExchPub[:])
- if err != nil {
- return
- }
- sharedKey = key[:]
- } else {
- sharedKey = sharedKeyCached
- }
-
- keyFull := make([]byte, chacha20poly1305.KeySize)
- keySize := make([]byte, chacha20poly1305.KeySize)
- blake3.DeriveKey(keyFull, DeriveKeyFullCtx, sharedKey[:])
- blake3.DeriveKey(keySize, DeriveKeySizeCtx, sharedKey[:])
- aeadFull, err := chacha20poly1305.New(keyFull)
- if err != nil {
- return
- }
- aeadSize, err := chacha20poly1305.New(keySize)
+ cmd := exec.Command("cmenctool", "-d",
+ "-assume-to", HexEncode(pktEnc.Recipient[:]),
+ "-assume-from", HexEncode(pktEnc.Sender[:]))
+ cmd.Env = append(cmd.Env, "CM_PRVS="+filepath.Join(DefaultKeysPath, "prvs"))
+ cmd.Env = append(cmd.Env, "CM_PUBS="+filepath.Join(DefaultKeysPath, "pubs"))
+ cmd.Stdin = r
+ decrypted, err := cmd.StdoutPipe()
if err != nil {
return
}
- nonce := make([]byte, aeadFull.NonceSize())
-
- ct := make([]byte, EncBlkSize+aeadFull.Overhead())
- pt := make([]byte, EncBlkSize)
- var n int
-FullRead:
- for {
- n, err = io.ReadFull(r, ct)
- switch err {
- case nil:
- pt, err = aeadFull.Open(pt[:0], nonce, ct, ad[:])
- if err != nil {
- break FullRead
- }
- size += EncBlkSize
- _, err = w.Write(pt)
- if err != nil {
- return
- }
- ctrIncr(nonce)
- continue
- case io.ErrUnexpectedEOF:
- break FullRead
- default:
- return
- }
- }
-
- pt, err = aeadSize.Open(pt[:0], nonce, ct[:n], ad[:])
+ err = cmd.Start()
if err != nil {
return
}
- var pktSize PktSize
- _, err = xdr.Unmarshal(bytes.NewReader(pt), &pktSize)
+ size, err = io.Copy(w, decrypted)
if err != nil {
return
}
- pt = pt[PktSizeOverhead:]
-
- left := int64(pktSize.Payload) - size
- for left > int64(len(pt)) {
- size += int64(len(pt))
- left -= int64(len(pt))
- _, err = w.Write(pt)
- if err != nil {
- return
- }
- n, err = io.ReadFull(r, ct)
- if err != nil && err != io.ErrUnexpectedEOF {
- return
- }
- ctrIncr(nonce)
- pt, err = aeadFull.Open(pt[:0], nonce, ct[:n], ad[:])
- if err != nil {
- return
- }
- }
- size += left
- _, err = w.Write(pt[:left])
+ err = cmd.Wait()
if err != nil {
return
}
- pt = pt[left:]
-
- if pktSize.Pad < uint64(len(pt)) {
- err = errors.New("unexpected pad")
- return
- }
- for i := 0; i < len(pt); i++ {
- if pt[i] != 0 {
- err = errors.New("non-zero pad byte")
- return
- }
- }
- sizePad := int64(pktSize.Pad) - int64(len(pt))
- if sizePad == 0 {
- return
- }
-
- keyPad := make([]byte, chacha20poly1305.KeySize)
- blake3.DeriveKey(keyPad, DeriveKeyPadCtx, sharedKey[:])
- xof := blake3.New(32, keyPad).XOF()
- pt = make([]byte, len(ct))
- for sizePad > 0 {
- n, err = io.ReadFull(r, ct)
- if err != nil && err != io.ErrUnexpectedEOF {
- return
- }
- _, err = io.ReadFull(xof, pt[:n])
- if err != nil {
- panic(err)
- }
- if !bytes.Equal(ct[:n], pt[:n]) {
- err = errors.New("wrong pad value")
- return
- }
- sizePad -= int64(n)
- }
- if sizePad < 0 {
- err = errors.New("excess pad")
- }
return
}
xdr "github.com/davecgh/go-xdr/xdr2"
"github.com/dustin/go-humanize"
"github.com/klauspost/compress/zstd"
- "golang.org/x/crypto/blake2b"
- "golang.org/x/crypto/poly1305"
)
const (
return strings.NewReader(strings.Join(lines, "\n"))
}
-func pktSizeWithoutEnc(pktSize int64) int64 {
- pktSize = pktSize - PktEncOverhead - PktOverhead - PktSizeOverhead
- pktSizeBlocks := pktSize / (EncBlkSize + poly1305.TagSize)
- if pktSize%(EncBlkSize+poly1305.TagSize) != 0 {
- pktSize -= poly1305.TagSize
- }
- pktSize -= pktSizeBlocks * poly1305.TagSize
- return pktSize
-}
-
var JobRepeatProcess = errors.New("needs processing repeat")
func jobProcess(
} else {
via := node.Via[:len(node.Via)-1]
node = ctx.Neigh[*node.Via[len(node.Via)-1]]
- node = &Node{Id: node.Id, Via: via, ExchPub: node.ExchPub}
+ node = &Node{Id: node.Id, Via: via, KeyId: node.KeyId}
pktTrns, err := NewPkt(PktTypeTrns, 0, nodeId[:])
if err != nil {
panic(err)
}
}
- case PktTypeArea:
- if opts.NoArea {
- return nil
- }
- areaId := new(AreaId)
- copy(areaId[:], pkt.Path[:int(pkt.PathLen)])
- les := append(les, LE{"Type", "area"}, LE{"Area", areaId})
- logMsg := func(les LEs) string {
- return fmt.Sprintf(
- "Tossing %s/%s (%s): area %s",
- sender.Name, pktName,
- humanize.IBytes(pktSize),
- ctx.AreaName(areaId),
- )
- }
- area := ctx.AreaId2Area[*areaId]
- if area == nil {
- err = errors.New("unknown area")
- ctx.LogE("rx-area-unknown", les, err, logMsg)
- return err
- }
- pktEnc, pktEncRaw, err := ctx.HdrRead(pipeR)
- fullPipeR := io.MultiReader(bytes.NewReader(pktEncRaw), pipeR)
- if err != nil {
- ctx.LogE("rx-area-pkt-enc-read", les, err, logMsg)
- return err
- }
- msgHashRaw := blake2b.Sum256(pktEncRaw)
- msgHash := Base32Codec.EncodeToString(msgHashRaw[:])
- les = append(les, LE{"AreaMsg", msgHash})
- ctx.LogD("rx-area", les, logMsg)
-
- if opts.DryRun {
- for _, nodeId := range area.Subs {
- node := ctx.Neigh[*nodeId]
- lesEcho := append(les, LE{"Echo", nodeId})
- seenDir := filepath.Join(
- ctx.Spool, nodeId.String(), AreaDir, area.Id.String(),
- )
- seenPath := filepath.Join(seenDir, msgHash)
- logMsgNode := func(les LEs) string {
- return fmt.Sprintf(
- "%s: echoing to: %s", logMsg(les), node.Name,
- )
- }
- if _, err := os.Stat(seenPath); err == nil {
- ctx.LogD("rx-area-echo-seen", lesEcho, func(les LEs) string {
- return logMsgNode(les) + ": already sent"
- })
- continue
- }
- ctx.LogI("rx-area-echo", lesEcho, logMsgNode)
- }
- } else {
- for _, nodeId := range area.Subs {
- node := ctx.Neigh[*nodeId]
- lesEcho := append(les, LE{"Echo", nodeId})
- seenDir := filepath.Join(
- ctx.Spool, nodeId.String(), AreaDir, area.Id.String(),
- )
- seenPath := filepath.Join(seenDir, msgHash)
- logMsgNode := func(les LEs) string {
- return fmt.Sprintf("%s: echo to: %s", logMsg(les), node.Name)
- }
- if _, err := os.Stat(seenPath); err == nil {
- ctx.LogD("rx-area-echo-seen", lesEcho, func(les LEs) string {
- return logMsgNode(les) + ": already sent"
- })
- continue
- }
- if nodeId != sender.Id && nodeId != pktEnc.Sender {
- ctx.LogI("rx-area-echo", lesEcho, logMsgNode)
- if _, _, _, err = ctx.Tx(
- node,
- &pkt,
- nice,
- int64(pktSize), 0, MaxFileSize,
- fullPipeR,
- pktName,
- nil,
- ); err != nil {
- ctx.LogE("rx-area", lesEcho, err, logMsgNode)
- return err
- }
- }
- if err = os.MkdirAll(seenDir, os.FileMode(0777)); err != nil {
- ctx.LogE("rx-area-mkdir", lesEcho, err, logMsgNode)
- return err
- }
- if fd, err := os.Create(seenPath); err == nil {
- fd.Close()
- if err = DirSync(seenDir); err != nil {
- ctx.LogE("rx-area-dirsync", les, err, logMsgNode)
- return err
- }
- } else {
- ctx.LogE("rx-area-touch", lesEcho, err, logMsgNode)
- return err
- }
- return JobRepeatProcess
- }
- }
-
- seenDir := filepath.Join(
- ctx.Spool, ctx.SelfId.String(), AreaDir, area.Id.String(),
- )
- seenPath := filepath.Join(seenDir, msgHash)
- if _, err := os.Stat(seenPath); err == nil {
- ctx.LogD("rx-area-seen", les, func(les LEs) string {
- return logMsg(les) + ": already seen"
- })
- if !opts.DryRun && jobPath != "" {
- if err = os.Remove(jobPath); err != nil {
- ctx.LogE("rx-area-remove", les, err, func(les LEs) string {
- return fmt.Sprintf(
- "Tossing area %s/%s (%s): %s: removing",
- sender.Name, pktName,
- humanize.IBytes(pktSize),
- msgHash,
- )
- })
- return err
- } else if ctx.HdrUsage {
- os.Remove(JobPath2Hdr(jobPath))
- }
- }
- return nil
- }
-
- if area.Prv == nil {
- ctx.LogD("rx-area-no-prv", les, func(les LEs) string {
- return logMsg(les) + ": no private key for decoding"
- })
- } else {
- signatureVerify := true
- if _, senderKnown := ctx.Neigh[*pktEnc.Sender]; !senderKnown {
- if !area.AllowUnknown {
- err = errors.New("unknown sender")
- ctx.LogE(
- "rx-area-unknown",
- append(les, LE{"Sender", pktEnc.Sender}),
- err,
- func(les LEs) string {
- return logMsg(les) + ": sender: " + pktEnc.Sender.String()
- },
- )
- return err
- }
- signatureVerify = false
- }
- areaNodeOur := NodeOur{Id: new(NodeId), ExchPrv: new([32]byte)}
- copy(areaNodeOur.Id[:], area.Id[:])
- copy(areaNodeOur.ExchPrv[:], area.Prv[:])
- areaNode := Node{
- Id: new(NodeId),
- Name: area.Name,
- Incoming: area.Incoming,
- Exec: area.Exec,
- Origin: pktEnc.Sender,
- }
- copy(areaNode.Id[:], area.Id[:])
- pktName := fmt.Sprintf(
- "area/%s/%s",
- Base32Codec.EncodeToString(areaId[:]), msgHash,
- )
-
- pipeR, pipeW := io.Pipe()
- errs := make(chan error, 1)
- go func() {
- errs <- jobProcess(
- ctx,
- pipeR,
- pktName,
- les,
- &areaNode,
- nice,
- uint64(pktSizeWithoutEnc(int64(pktSize))),
- "",
- decompressor,
- opts,
- )
- }()
- _, _, _, err = PktEncRead(
- &areaNodeOur,
- ctx.Neigh,
- fullPipeR,
- pipeW,
- signatureVerify,
- nil,
- )
- if err != nil {
- ctx.LogE("rx-area-pkt-enc-read2", les, err, logMsg)
- pipeW.CloseWithError(err)
- <-errs
- return err
- }
- pipeW.Close()
- if err = <-errs; err != nil {
- return err
- }
- }
-
- if !opts.DryRun && jobPath != "" {
- if err = os.MkdirAll(seenDir, os.FileMode(0777)); err != nil {
- ctx.LogE("rx-area-mkdir", les, err, logMsg)
- return err
- }
- if fd, err := os.Create(seenPath); err == nil {
- fd.Close()
- if err = DirSync(seenDir); err != nil {
- ctx.LogE("rx-area-dirsync", les, err, logMsg)
- return err
- }
- }
- if err = os.Remove(jobPath); err != nil {
- ctx.LogE("rx", les, err, func(les LEs) string {
- return fmt.Sprintf(
- "Tossing area %s/%s (%s): %s: removing",
- sender.Name, pktName,
- humanize.IBytes(pktSize),
- msgHash,
- )
- })
- return err
- } else if ctx.HdrUsage {
- os.Remove(JobPath2Hdr(jobPath))
- }
- }
-
case PktTypeACK:
if opts.NoACK {
return nil
continue
}
errs := make(chan error, 1)
- var sharedKey []byte
Retry:
pipeR, pipeW := io.Pipe()
go func() {
les,
sender,
job.PktEnc.Nice,
- uint64(pktSizeWithoutEnc(job.Size)),
+ uint64(job.Size),
job.Path,
decompressor,
opts,
)
}()
pipeWB := bufio.NewWriter(pipeW)
- sharedKey, _, _, err = PktEncRead(
+ _, _, err = PktEncRead(
ctx.Self,
ctx.Neigh,
bufio.NewReaderSize(fd, MTHBlockSize),
pipeWB,
- sharedKey == nil,
- sharedKey,
)
if err != nil {
pipeW.CloseWithError(err)
if area != nil {
wrappers++
}
- var expectedSize int64
- if srcSize > 0 {
- expectedSize = srcSize + PktOverhead
- expectedSize += sizePadCalc(expectedSize, minSize, wrappers)
- expectedSize = PktEncOverhead + sizeWithTags(expectedSize)
- if maxSize != 0 && expectedSize > maxSize {
- return nil, 0, "", TooBig
- }
- if !ctx.IsEnoughSpace(expectedSize) {
- return nil, 0, "", errors.New("is not enough space")
- }
- }
+ expectedSize := srcSize + PktOverhead + PktEncOverhead
tmp, err := ctx.NewTmpFileWHash()
if err != nil {
return nil, 0, "", err
dst.Close()
}(src, pipeW)
} else {
- go func(src io.Reader, dst io.WriteCloser) {
- ctx.LogD("tx", LEs{
- {"Area", area.Id},
- {"Nice", int(nice)},
- {"Size", expectedSize},
- }, func(les LEs) string {
- return fmt.Sprintf(
- "Tx area packet to %s (source %s) nice: %s",
- ctx.AreaName(areaId),
- humanize.IBytes(uint64(expectedSize)),
- NicenessFmt(nice),
- )
- })
- areaNode := Node{Id: new(NodeId), ExchPub: new([32]byte)}
- copy(areaNode.Id[:], area.Id[:])
- copy(areaNode.ExchPub[:], area.Pub[:])
- pktEncRaw, size, err := PktEncWrite(
- ctx.Self, &areaNode, pkt, nice, 0, maxSize, 0, src, dst,
- )
- results <- PktEncWriteResult{pktEncRaw, size, err}
- dst.Close()
- }(src, pipeW)
- pipeRPrev = pipeR
- pipeR, pipeW = io.Pipe()
- go func(src io.Reader, dst io.WriteCloser) {
- pktArea, err := NewPkt(PktTypeArea, 0, area.Id[:])
- if err != nil {
- panic(err)
- }
- ctx.LogD("tx", LEs{
- {"Node", hops[0].Id},
- {"Nice", int(nice)},
- {"Size", expectedSize},
- }, func(les LEs) string {
- return fmt.Sprintf(
- "Tx packet to %s (source %s) nice: %s",
- ctx.NodeName(hops[0].Id),
- humanize.IBytes(uint64(expectedSize)),
- NicenessFmt(nice),
- )
- })
- pktEncRaw, size, err := PktEncWrite(
- ctx.Self, hops[0], pktArea, nice, minSize, maxSize, wrappers, src, dst,
- )
- results <- PktEncWriteResult{pktEncRaw, size, err}
- dst.Close()
- }(pipeRPrev, pipeW)
+ panic("no area yet")
}
for i := 1; i < len(hops); i++ {
pktTrns, err := NewPkt(PktTypeTrns, 0, hops[i-1].Id[:])