func CfgParse(data []byte) (*Ctx, error) {
var err error
- if bytes.Compare(data[:8], MagicNNCPBv3[:]) == 0 {
+ if bytes.Compare(data[:8], MagicNNCPBv3.B[:]) == 0 {
os.Stderr.WriteString("Passphrase:") // #nosec G104
password, err := term.ReadPassword(0)
if err != nil {
if err != nil {
return nil, err
}
+ } else if bytes.Compare(data[:8], MagicNNCPBv2.B[:]) == 0 {
+ log.Fatalln(MagicNNCPBv2.TooOld())
+ } else if bytes.Compare(data[:8], MagicNNCPBv1.B[:]) == 0 {
+ log.Fatalln(MagicNNCPBv1.TooOld())
}
var cfgGeneral map[string]interface{}
if err = hjson.Unmarshal(data, &cfgGeneral); err != nil {
package nncp
var (
- MagicNNCPMv2 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'M', 0, 0, 2}
-
ChunkedSuffixMeta = ".nncp.meta"
ChunkedSuffixPart = ".nncp.chunk"
)
)
continue
}
- if pktEnc.Magic != nncp.MagicNNCPEv5 {
+ switch pktEnc.Magic {
+ case nncp.MagicNNCPEv1.B:
+ err = nncp.MagicNNCPEv1.TooOld()
+ case nncp.MagicNNCPEv2.B:
+ err = nncp.MagicNNCPEv2.TooOld()
+ case nncp.MagicNNCPEv3.B:
+ err = nncp.MagicNNCPEv3.TooOld()
+ case nncp.MagicNNCPEv4.B:
+ err = nncp.MagicNNCPEv4.TooOld()
+ case nncp.MagicNNCPEv5.B:
+ default:
+ err = errors.New("Bad packet magic number")
+ }
+ if err != nil {
ctx.LogD(
"bundle-rx",
- append(les, nncp.LE{K: "Err", V: "Bad packet magic number"}),
+ append(les, nncp.LE{K: "Err", V: err.Error()}),
logMsg,
)
continue
if _, err := xdr.Unmarshal(bytes.NewReader(data), &eblob); err != nil {
log.Fatalln(err)
}
- if eblob.Magic != nncp.MagicNNCPBv3 {
+ switch eblob.Magic {
+ case nncp.MagicNNCPBv1.B:
+ log.Fatalln(nncp.MagicNNCPBv1.TooOld())
+ case nncp.MagicNNCPBv2.B:
+ log.Fatalln(nncp.MagicNNCPBv2.TooOld())
+ case nncp.MagicNNCPBv3.B:
+ default:
log.Fatalln(errors.New("Unknown eblob type"))
}
fmt.Println("Strengthening function: Balloon with BLAKE2b-256")
fmt.Fprintln(os.Stderr, "Packet is read from stdin.")
}
+func doPlain(pkt nncp.Pkt, dump, decompress bool) {
+ if dump {
+ bufW := bufio.NewWriter(os.Stdout)
+ var r io.Reader
+ r = bufio.NewReader(os.Stdin)
+ if decompress {
+ decompressor, err := zstd.NewReader(r)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ r = decompressor
+ }
+ if _, err := io.Copy(bufW, r); err != nil {
+ log.Fatalln(err)
+ }
+ if err := bufW.Flush(); err != nil {
+ log.Fatalln(err)
+ }
+ return
+ }
+ payloadType := "unknown"
+ switch pkt.Type {
+ case nncp.PktTypeFile:
+ payloadType = "file"
+ case nncp.PktTypeFreq:
+ payloadType = "file request"
+ case nncp.PktTypeExec:
+ payloadType = "exec compressed"
+ case nncp.PktTypeExecFat:
+ payloadType = "exec uncompressed"
+ case nncp.PktTypeTrns:
+ payloadType = "transitional"
+ }
+ var path string
+ switch pkt.Type {
+ case nncp.PktTypeExec, nncp.PktTypeExecFat:
+ path = string(bytes.Replace(
+ pkt.Path[:pkt.PathLen],
+ []byte{0},
+ []byte(" "),
+ -1,
+ ))
+ case nncp.PktTypeTrns:
+ path = nncp.Base32Codec.EncodeToString(pkt.Path[:pkt.PathLen])
+ default:
+ path = string(pkt.Path[:pkt.PathLen])
+ }
+ fmt.Printf(
+ "Packet type: plain\nPayload type: %s\nNiceness: %s (%d)\nPath: %s\n",
+ payloadType, nncp.NicenessFmt(pkt.Nice), pkt.Nice, path,
+ )
+ return
+}
+
+func doEncrypted(pktEnc nncp.PktEnc, dump bool, cfgPath string, beginning []byte) {
+ if !dump {
+ fmt.Printf(
+ "Packet type: encrypted\nNiceness: %s (%d)\nSender: %s\nRecipient: %s\n",
+ nncp.NicenessFmt(pktEnc.Nice), pktEnc.Nice, pktEnc.Sender, pktEnc.Recipient,
+ )
+ return
+ }
+ ctx, err := nncp.CtxFromCmdline(cfgPath, "", "", false, false, false, false)
+ if err != nil {
+ log.Fatalln("Error during initialization:", err)
+ }
+ if ctx.Self == nil {
+ log.Fatalln("Config lacks private keys")
+ }
+ bufW := bufio.NewWriter(os.Stdout)
+ if _, _, err = nncp.PktEncRead(
+ ctx.Self,
+ ctx.Neigh,
+ io.MultiReader(
+ bytes.NewReader(beginning),
+ bufio.NewReader(os.Stdin),
+ ),
+ bufW,
+ ); err != nil {
+ log.Fatalln(err)
+ }
+ if err = bufW.Flush(); err != nil {
+ log.Fatalln(err)
+ }
+}
+
func main() {
var (
overheads = flag.Bool("overheads", false, "Print packet overheads")
return
}
- var err error
beginning := make([]byte, nncp.PktOverhead)
- if _, err = io.ReadFull(os.Stdin, beginning); err != nil {
+ if _, err := io.ReadFull(os.Stdin, beginning); err != nil {
log.Fatalln("Not enough data to read")
}
var pkt nncp.Pkt
- _, err = xdr.Unmarshal(bytes.NewReader(beginning), &pkt)
- if err == nil && pkt.Magic == nncp.MagicNNCPPv3 {
- if *dump {
- bufW := bufio.NewWriter(os.Stdout)
- var r io.Reader
- r = bufio.NewReader(os.Stdin)
- if *decompress {
- decompressor, err := zstd.NewReader(r)
- if err != nil {
- log.Fatalln(err)
- }
- r = decompressor
- }
- if _, err = io.Copy(bufW, r); err != nil {
- log.Fatalln(err)
- }
- if err = bufW.Flush(); err != nil {
- log.Fatalln(err)
- }
+ if _, err := xdr.Unmarshal(bytes.NewReader(beginning), &pkt); err == nil {
+ switch pkt.Magic {
+ case nncp.MagicNNCPPv1.B:
+ log.Fatalln(nncp.MagicNNCPPv1.TooOld())
+ case nncp.MagicNNCPPv2.B:
+ log.Fatalln(nncp.MagicNNCPPv2.TooOld())
+ case nncp.MagicNNCPPv3.B:
+ doPlain(pkt, *dump, *decompress)
return
}
- payloadType := "unknown"
- switch pkt.Type {
- case nncp.PktTypeFile:
- payloadType = "file"
- case nncp.PktTypeFreq:
- payloadType = "file request"
- case nncp.PktTypeExec:
- payloadType = "exec"
- case nncp.PktTypeExecFat:
- payloadType = "exec uncompressed"
- case nncp.PktTypeTrns:
- payloadType = "transitional"
- }
- var path string
- switch pkt.Type {
- case nncp.PktTypeExec, nncp.PktTypeExecFat:
- path = string(bytes.Replace(
- pkt.Path[:pkt.PathLen],
- []byte{0},
- []byte(" "),
- -1,
- ))
- case nncp.PktTypeTrns:
- path = nncp.Base32Codec.EncodeToString(pkt.Path[:pkt.PathLen])
- default:
- path = string(pkt.Path[:pkt.PathLen])
- }
- fmt.Printf(
- "Packet type: plain\nPayload type: %s\nNiceness: %s (%d)\nPath: %s\n",
- payloadType, nncp.NicenessFmt(pkt.Nice), pkt.Nice, path,
- )
- return
}
var pktEnc nncp.PktEnc
- _, err = xdr.Unmarshal(bytes.NewReader(beginning), &pktEnc)
- if err == nil && pktEnc.Magic == nncp.MagicNNCPEv5 {
- if *dump {
- ctx, err := nncp.CtxFromCmdline(*cfgPath, "", "", false, false, false, false)
- if err != nil {
- log.Fatalln("Error during initialization:", err)
- }
- if ctx.Self == nil {
- log.Fatalln("Config lacks private keys")
- }
- bufW := bufio.NewWriter(os.Stdout)
- if _, _, err = nncp.PktEncRead(
- ctx.Self,
- ctx.Neigh,
- io.MultiReader(
- bytes.NewReader(beginning),
- bufio.NewReader(os.Stdin),
- ),
- bufW,
- ); err != nil {
- log.Fatalln(err)
- }
- if err = bufW.Flush(); err != nil {
- log.Fatalln(err)
- }
+ if _, err := xdr.Unmarshal(bytes.NewReader(beginning), &pktEnc); err == nil {
+ switch pkt.Magic {
+ case nncp.MagicNNCPEv1.B:
+ log.Fatalln(nncp.MagicNNCPEv1.TooOld())
+ case nncp.MagicNNCPEv2.B:
+ log.Fatalln(nncp.MagicNNCPEv2.TooOld())
+ case nncp.MagicNNCPEv3.B:
+ log.Fatalln(nncp.MagicNNCPEv3.TooOld())
+ case nncp.MagicNNCPEv4.B:
+ log.Fatalln(nncp.MagicNNCPEv4.TooOld())
+ case nncp.MagicNNCPEv5.B:
+ doEncrypted(pktEnc, *dump, *cfgPath, beginning)
return
}
- fmt.Printf(
- "Packet type: encrypted\nNiceness: %s (%d)\nSender: %s\nRecipient: %s\n",
- nncp.NicenessFmt(pktEnc.Nice), pktEnc.Nice, pktEnc.Sender, pktEnc.Recipient,
- )
- return
}
log.Fatalln("Unable to determine packet type")
}
return false
}
fd.Close() // #nosec G104
- if metaPkt.Magic != nncp.MagicNNCPMv2 {
+ if metaPkt.Magic == nncp.MagicNNCPMv1.B {
+ ctx.LogE("reass", les, nncp.MagicNNCPMv1.TooOld(), logMsg)
+ return false
+ }
+ if metaPkt.Magic != nncp.MagicNNCPMv2.B {
ctx.LogE("reass", les, nncp.BadMagic, logMsg)
return false
}
continue
}
pktEnc, pktEncRaw, err := ctx.HdrRead(fd)
- if err != nil || pktEnc.Magic != nncp.MagicNNCPEv5 {
- ctx.LogD("xfer-rx-not-packet", les, func(les nncp.LEs) string {
- return logMsg(les) + ": is not a packet"
- })
+ if err != nil {
+ switch pktEnc.Magic {
+ case nncp.MagicNNCPEv1.B:
+ err = nncp.MagicNNCPEv1.TooOld()
+ case nncp.MagicNNCPEv2.B:
+ err = nncp.MagicNNCPEv2.TooOld()
+ case nncp.MagicNNCPEv3.B:
+ err = nncp.MagicNNCPEv3.TooOld()
+ case nncp.MagicNNCPEv4.B:
+ err = nncp.MagicNNCPEv4.TooOld()
+ case nncp.MagicNNCPEv5.B:
+ default:
+ err = errors.New("is not an encrypted packet")
+ }
+ }
+ if err != nil {
+ ctx.LogD(
+ "xfer-rx-not-packet",
+ append(les, nncp.LE{K: "Err", V: err}),
+ func(les nncp.LEs) string {
+ return logMsg(les) + ": not valid packet: " + err.Error()
+ },
+ )
fd.Close() // #nosec G104
continue
}
DefaultP = 2
)
-var (
- MagicNNCPBv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 3}
-)
-
type EBlob struct {
Magic [8]byte
SCost uint32
return nil, err
}
eblob := EBlob{
- Magic: MagicNNCPBv3,
+ Magic: MagicNNCPBv3.B,
SCost: uint32(sCost),
TCost: uint32(tCost),
PCost: uint32(pCost),
if _, err = xdr.Unmarshal(bytes.NewReader(eblobRaw), &eblob); err != nil {
return nil, err
}
- if eblob.Magic != MagicNNCPBv3 {
- return nil, BadMagic
+ switch eblob.Magic {
+ case MagicNNCPBv1.B:
+ err = MagicNNCPBv1.TooOld()
+ case MagicNNCPBv2.B:
+ err = MagicNNCPBv1.TooOld()
+ case MagicNNCPBv3.B:
+ default:
+ err = BadMagic
+ }
+ if err != nil {
+ return nil, err
}
key := balloon.H(
blake256,
}
pktEnc, pktEncRaw, err := ctx.HdrRead(fd)
fd.Close()
- if err != nil || pktEnc.Magic != MagicNNCPEv5 {
+ if err != nil || pktEnc.Magic != MagicNNCPEv5.B {
continue
}
ctx.LogD("job", LEs{
--- /dev/null
+/*
+NNCP -- Node to Node copy, utilities for store-and-forward data exchange
+Copyright (C) 2016-2021 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 "fmt"
+
+type Magic struct {
+ B [8]byte
+ Name string
+ Till string
+}
+
+var (
+ MagicNNCPBv1 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 1},
+ Name: "NNCPBv1 (EBlob v1)", Till: "1.0",
+ }
+ MagicNNCPBv2 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 2},
+ Name: "NNCPBv2 (EBlob v2)", Till: "3.4",
+ }
+ MagicNNCPBv3 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 3},
+ Name: "NNCPBv3 (EBlob v3)", Till: "now",
+ }
+ MagicNNCPDv1 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'D', 0, 0, 1},
+ Name: "NNCPDv1 (multicast discovery v1)", Till: "now",
+ }
+ MagicNNCPEv1 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 1},
+ Name: "NNCPEv1 (encrypted packet v1)", Till: "0.12",
+ }
+ MagicNNCPEv2 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 2},
+ Name: "NNCPEv2 (encrypted packet v2)", Till: "1.0",
+ }
+ MagicNNCPEv3 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 3},
+ Name: "NNCPEv3 (encrypted packet v3)", Till: "3.4",
+ }
+ MagicNNCPEv4 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 4},
+ Name: "NNCPEv4 (encrypted packet v4)", Till: "6.6.0",
+ }
+ MagicNNCPEv5 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 5},
+ Name: "NNCPEv5 (encrypted packet v5)", Till: "now",
+ }
+ MagicNNCPSv1 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'S', 0, 0, 1},
+ Name: "NNCPSv1 (sync protocol v1)", Till: "now",
+ }
+ MagicNNCPMv1 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'M', 0, 0, 1},
+ Name: "NNCPMv1 (chunked .meta v1)", Till: "6.6.0",
+ }
+ MagicNNCPMv2 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'M', 0, 0, 2},
+ Name: "NNCPMv2 (chunked .meta v2)", Till: "now",
+ }
+ MagicNNCPPv1 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 1},
+ Name: "NNCPPv1 (plain packet v1)", Till: "2.0",
+ }
+ MagicNNCPPv2 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 2},
+ Name: "NNCPPv2 (plain packet v2)", Till: "4.1",
+ }
+ MagicNNCPPv3 = Magic{
+ B: [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 3},
+ Name: "NNCPPv3 (plain packet v3)", Till: "now",
+ }
+)
+
+func (m *Magic) TooOld() error {
+ return fmt.Errorf("%s format is unsupported (used till %s)", m.Name, m.Till)
+}
}
var (
- MagicNNCPDv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'D', 0, 0, 1}
-
mcdIP = net.ParseIP("ff02::4e4e:4350")
mcdAddrLifetime = 2 * time.Minute
})
continue
}
- if mcd.Magic != MagicNNCPDv1 {
+ if mcd.Magic != MagicNNCPDv1.B {
ctx.LogD("mcd", les, func(les LEs) string {
return fmt.Sprintf(
"MCD Rx %s/%d: unexpected magic: %s",
return err
}
var buf bytes.Buffer
- mcd := MCD{Magic: MagicNNCPDv1, Sender: ctx.Self.Id}
+ mcd := MCD{Magic: MagicNNCPDv1.B, Sender: ctx.Self.Id}
if _, err := xdr.Marshal(&buf, mcd); err != nil {
panic(err)
}
)
var (
- MagicNNCPPv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 3}
- MagicNNCPEv5 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 5}
- BadMagic error = errors.New("Unknown magic number")
- BadPktType error = errors.New("Unknown packet type")
+ BadMagic error = errors.New("Unknown magic number")
+ BadPktType error = errors.New("Unknown packet type")
PktOverhead int64
PktEncOverhead int64
panic(err)
}
pktEnc := PktEnc{
- Magic: MagicNNCPEv5,
+ Magic: MagicNNCPEv5.B,
Sender: dummyId,
Recipient: dummyId,
}
return nil, errors.New("Too long path")
}
pkt := Pkt{
- Magic: MagicNNCPPv3,
+ Magic: MagicNNCPPv3.B,
Type: typ,
Nice: nice,
PathLen: uint8(len(path)),
return nil, err
}
tbs := PktTbs{
- Magic: MagicNNCPEv5,
+ Magic: MagicNNCPEv5.B,
Nice: nice,
Sender: our.Id,
Recipient: their.Id,
signature := new([ed25519.SignatureSize]byte)
copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes()))
pktEnc := PktEnc{
- Magic: MagicNNCPEv5,
+ Magic: MagicNNCPEv5.B,
Nice: nice,
Sender: our.Id,
Recipient: their.Id,
curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub)
key := make([]byte, chacha20poly1305.KeySize)
- blake3.DeriveKey(key, string(MagicNNCPEv5[:]), sharedKey[:])
+ blake3.DeriveKey(key, string(MagicNNCPEv5.B[:]), sharedKey[:])
aead, err := chacha20poly1305.New(key)
if err != nil {
return nil, err
return nil, io.ErrUnexpectedEOF
}
if padSize > 0 {
- blake3.DeriveKey(key, string(MagicNNCPEv5[:])+" PAD", sharedKey[:])
+ blake3.DeriveKey(key, string(MagicNNCPEv5.B[:])+" PAD", sharedKey[:])
xof := blake3.New(32, key).XOF()
if _, err = io.CopyN(out, xof, padSize); err != nil {
return nil, err
func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) ([]byte, bool, error) {
tbs := PktTbs{
- Magic: MagicNNCPEv5,
+ Magic: MagicNNCPEv5.B,
Nice: pktEnc.Nice,
Sender: their.Id,
Recipient: our.Id,
if err != nil {
return nil, 0, err
}
- if pktEnc.Magic != MagicNNCPEv5 {
- return nil, 0, BadMagic
+ switch pktEnc.Magic {
+ case MagicNNCPEv1.B:
+ err = MagicNNCPEv1.TooOld()
+ case MagicNNCPEv2.B:
+ err = MagicNNCPEv2.TooOld()
+ case MagicNNCPEv3.B:
+ err = MagicNNCPEv3.TooOld()
+ case MagicNNCPEv4.B:
+ err = MagicNNCPEv4.TooOld()
+ case MagicNNCPEv5.B:
+ default:
+ err = BadMagic
+ }
+ if err != nil {
+ return nil, 0, err
}
their, known := nodes[*pktEnc.Sender]
if !known {
curve25519.ScalarMult(sharedKey, our.ExchPrv, &pktEnc.ExchPub)
key := make([]byte, chacha20poly1305.KeySize)
- blake3.DeriveKey(key, string(MagicNNCPEv5[:]), sharedKey[:])
+ blake3.DeriveKey(key, string(MagicNNCPEv5.B[:]), sharedKey[:])
aead, err := chacha20poly1305.New(key)
if err != nil {
return their, 0, err
}
var (
- MagicNNCPLv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'S', 0, 0, 1}
-
SPInfoOverhead int
SPFreqOverhead int
SPFileOverhead int
func (state *SPState) WriteSP(dst io.Writer, payload []byte, ping bool) error {
state.writeSPBuf.Reset()
n, err := xdr.Marshal(&state.writeSPBuf, SPRaw{
- Magic: MagicNNCPLv1,
+ Magic: MagicNNCPSv1.B,
Payload: payload,
})
if err != nil {
}
state.RxLastSeen = time.Now()
state.RxBytes += int64(n)
- if sp.Magic != MagicNNCPLv1 {
+ if sp.Magic != MagicNNCPSv1.B {
return nil, BadMagic
}
return sp.Payload, nil
os.MkdirAll(txPath, os.FileMode(0700))
for _, data := range datum {
pktTrans := Pkt{
- Magic: MagicNNCPPv3,
+ Magic: MagicNNCPPv3.B,
Type: PktTypeTrns,
PathLen: MTHSize,
}
leftSize := fileSize
metaPkt := ChunkedMeta{
- Magic: MagicNNCPMv2,
+ Magic: MagicNNCPMv2.B,
FileSize: uint64(fileSize),
ChunkSize: uint64(chunkSize),
Checksums: make([][MTHSize]byte, 0, (fileSize/chunkSize)+1),