BSDmakefile | 1 -
GNUmakefile | 1 -
VERSION | 2 +-
common.mk | 69 +++++++++++------------------------------------------
doc/about.ru.texi | 2 ++
doc/cmds.texi | 41 +++++++++++++++++++++++++----------------
doc/download.texi | 45 ++++++++++++++++++++++++---------------------
doc/eblob.texi | 29 +++++++++++++----------------
doc/index.texi | 2 +-
doc/integrity.texi | 1 -
doc/news.ru.texi | 28 ++++++++++++++++++++++++++++
doc/news.texi | 27 +++++++++++++++++++++++++++
doc/pkt.texi | 47 ++++++++++++++++++++++-------------------------
doc/style.css | 3 ++-
doc/usecases.ru.texi | 84 +++++++++++++++++++++++++++++++++++++++++++++++++----
doc/usecases.texi | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++---
makedist.sh | 65 +++++++++++++++++++++++++++++++----------------------
ports/nncp/Makefile | 2 +-
ports/nncp/pkg-descr | 2 +-
src/cypherpunks.ru/nncp/call.go | 31 ++++++++++++++++++-------------
src/cypherpunks.ru/nncp/cfg.go | 12 ++++++------
src/cypherpunks.ru/nncp/check.go | 2 +-
src/cypherpunks.ru/nncp/chunked.go | 2 +-
src/cypherpunks.ru/nncp/cmd/nncp-bundle/main.go | 10 ++++++----
src/cypherpunks.ru/nncp/cmd/nncp-call/main.go | 47 +++++++++++++++++++++++++++++++++--------------
src/cypherpunks.ru/nncp/cmd/nncp-caller/main.go | 6 ++++--
src/cypherpunks.ru/nncp/cmd/nncp-cfgenc/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-cfgmin/main.go | 2 +-
src/cypherpunks.ru/nncp/cmd/nncp-cfgnew/main.go | 2 +-
src/cypherpunks.ru/nncp/cmd/nncp-check/main.go | 8 +++++---
src/cypherpunks.ru/nncp/cmd/nncp-daemon/main.go | 13 ++++++++-----
src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-file/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-freq/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-log/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go | 20 +++++++++++++++-----
src/cypherpunks.ru/nncp/cmd/nncp-reass/main.go | 26 +++++++++++++++++---------
src/cypherpunks.ru/nncp/cmd/nncp-rm/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-stat/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-toss/main.go | 4 ++--
src/cypherpunks.ru/nncp/cmd/nncp-xfer/main.go | 35 ++++++++++++++++++++++-------------
src/cypherpunks.ru/nncp/ctx.go | 13 ++++++++++++-
src/cypherpunks.ru/nncp/eblob.go | 93 ++++++++++++++++++++---------------------------------
src/cypherpunks.ru/nncp/go.mod | 15 +++++++++++++++
src/cypherpunks.ru/nncp/go.sum | 25 +++++++++++++++++++++++++
src/cypherpunks.ru/nncp/humanizer.go | 29 ++++++++++++++++++++++++++++-
src/cypherpunks.ru/nncp/jobs.go | 7 ++++---
src/cypherpunks.ru/nncp/lockdir.go | 2 +-
src/cypherpunks.ru/nncp/log.go | 2 +-
src/cypherpunks.ru/nncp/nncp.go | 4 ++--
src/cypherpunks.ru/nncp/node.go | 2 +-
src/cypherpunks.ru/nncp/pkt.go | 198 ++++++++++++++++++++++-------------------------------
src/cypherpunks.ru/nncp/pkt_test.go | 4 ++--
src/cypherpunks.ru/nncp/sp.go | 413 ++++++++++++++++++++++++++---------------------------
src/cypherpunks.ru/nncp/tmp.go | 2 +-
src/cypherpunks.ru/nncp/toss.go | 32 +++++++++++++++++++++++++-------
src/cypherpunks.ru/nncp/toss_test.go | 2 +-
src/cypherpunks.ru/nncp/tx.go | 43 +++++++++++++++++++++++++++++++------------
src/cypherpunks.ru/nncp/tx_test.go | 2 +-
src/cypherpunks.ru/nncp/via.go | 2 +-
diff --git a/BSDmakefile b/BSDmakefile
index 148fb82f8f709ad6be51726f7ce6424f6cdd78de884166fd80ee43c752a4cc00..c9cd663e8c3f32f851b25f1b5d9df2abd244b965e99d83b74d4c6129b5728d16 100644
--- a/BSDmakefile
+++ b/BSDmakefile
@@ -1,4 +1,3 @@
-GOPATH != pwd
VERSION != cat VERSION
include common.mk
diff --git a/GNUmakefile b/GNUmakefile
index aa473484fbdce0ba0f0a563adfcf34bbc8883a56f4f1f0a0ef036fb6fe106229..4c73fbf6b76de756957722c0bd77ccd3c74a681ea13fe3c081491614d169bcbb 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,4 +1,3 @@
-GOPATH = $(shell pwd)
VERSION = $(shell cat VERSION)
include common.mk
diff --git a/VERSION b/VERSION
index 201baede28f0e6e68178dea6552eff49010d545c454f0a8100f412f4e5507892..dddd2b6fe8e64351ebd48d13898cd77b3dd21803c72f8a028b265ed6c316055f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.4
+4.0
diff --git a/common.mk b/common.mk
index d78edabb252d4afc25db08db07b4c3cbcddc8e955f1141ad5daaf420e34a1055..32bcbe138dc2fd48c2400a24d01ff3ee6be4ed2d21ce70e68626cc87036c8782 100644
--- a/common.mk
+++ b/common.mk
@@ -1,4 +1,5 @@
PREFIX ?= /usr/local
+GO ?= go
SENDMAIL ?= /usr/sbin/sendmail
CFGPATH ?= $(PREFIX)/etc/nncp.yaml
@@ -15,6 +16,7 @@ -X cypherpunks.ru/nncp.DefaultCfgPath=$(CFGPATH) \
-X cypherpunks.ru/nncp.DefaultSendmailPath=$(SENDMAIL) \
-X cypherpunks.ru/nncp.DefaultSpoolPath=$(SPOOLPATH) \
-X cypherpunks.ru/nncp.DefaultLogPath=$(LOGPATH)
+BUILDMOD ?= -mod=vendor
ALL = \
nncp-bundle \
@@ -36,67 +38,24 @@ nncp-stat \
nncp-toss \
nncp-xfer
-all: $(ALL)
+SRC := $(PWD)/src/cypherpunks.ru/nncp
+BIN := $(PWD)/bin
+GOPATH ?= $(PWD)/gopath
-nncp-bundle:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-bundle
+all: $(ALL)
-nncp-call:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-call
+$(BIN):
+ mkdir -p $(BIN)
-nncp-caller:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-caller
-
-nncp-cfgenc:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-cfgenc
-
-nncp-cfgmin:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-cfgmin
-
-nncp-cfgnew:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-cfgnew
-
-nncp-check:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-check
-
-nncp-daemon:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-daemon
-
-nncp-exec:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-exec
-
-nncp-file:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-file
-
-nncp-freq:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-freq
-
-nncp-log:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-log
-
-nncp-pkt:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-pkt
-
-nncp-reass:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-reass
-
-nncp-rm:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-rm
-
-nncp-stat:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-stat
-
-nncp-toss:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-toss
-
-nncp-xfer:
- GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-xfer
+$(ALL): $(BIN)
+ cd $(SRC) ; GOPATH=$(GOPATH) $(GO) build $(BUILDMOD) -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/$@
+ mv $(SRC)/$@ $(BIN)
test:
- GOPATH=$(GOPATH) go test -failfast cypherpunks.ru/nncp/...
+ cd $(SRC) ; GOPATH=$(GOPATH) $(GO) test $(BUILDMOD) -failfast cypherpunks.ru/nncp/...
clean:
- rm -f $(ALL)
+ rm -rf bin
.PHONY: doc
@@ -105,7 +64,7 @@ $(MAKE) -C doc
install: all doc
mkdir -p $(BINDIR)
- cp -f $(ALL) $(BINDIR)
+ (cd bin ; cp -f $(ALL) $(BINDIR))
for e in $(ALL) ; do chmod 755 $(BINDIR)/$$e ; done
mkdir -p $(INFODIR)
cp -f doc/nncp.info $(INFODIR)
diff --git a/doc/about.ru.texi b/doc/about.ru.texi
index ef87089883323f791c508c45ad00f4675333372449ce45406e8d6b6b38d55b35..a0f8b7089ab5c9fab059716d12828afcee766b1486c1ccfcedf696392b633ddf 100644
--- a/doc/about.ru.texi
+++ b/doc/about.ru.texi
@@ -1,6 +1,8 @@
@node Об утилитах
@section Подробнее об утилитах NNCP
+@verbatiminclude pedro.txt
+
@strong{NNCP} (Node to Node copy) это набор утилит упрощающий безопасный
обмен файлами, почтой и командами в режиме сохранить-и-переслать.
diff --git a/doc/cmds.texi b/doc/cmds.texi
index faab2ef4574c7145a4f3855f229d20089a5ebb3c818f2f43bc784a2caf2b240e..a60938daf1dbb12342ebe18ffdd108f2160cd58d62440c23b8e6b59817a3f17a 100644
--- a/doc/cmds.texi
+++ b/doc/cmds.texi
@@ -20,8 +20,6 @@ Set desired outgoing packet @ref{Niceness, niceness level}.
@item -replynice
Set desired reply packet @ref{Niceness, niceness level}. Only freq
and exec packets look at that niceness level.
-@item -node
- Process only single specified node.
@item -via
Override @ref{CfgVia, via} configuration option for destination node.
Specified nodes must be separated with comma: @verb{|NODE1,NODE2|}.
@@ -97,6 +95,8 @@ % nncp-call [options]
[-onlinedeadline INT]
[-maxonlinetime INT]
[-rx|-tx]
+ [-list]
+ [-pkts PKT,PKT,...]
[-rxrate INT]
[-txrate INT]
NODE[:ADDR] [FORCEADDR]
@@ -115,7 +115,11 @@ only outbound transmission is performed. @option{-onlinedeadline}
overrides @ref{CfgOnlineDeadline, @emph{onlinedeadline}}.
@option{-maxonlinetime} overrides @ref{CfgMaxOnlineTime,
@emph{maxonlinetime}}. @option{-rxrate}/@option{-txrate} override
-@ref{CfgXxRate, rxrate/txrate}.
+@ref{CfgXxRate, rxrate/txrate}. @option{-list} option allows you to list
+packets of remote node, without any transmission.
+
+You can specify what packets your want to download, by specifying
+@option{-pkts} option with comma-separated list of packets identifiers.
@node nncp-caller
@section nncp-caller
@@ -301,12 +305,13 @@
If @file{SRC} equals to @file{-}, then create an encrypted temporary
file and copy everything taken from stdin to it and use for outbound
packet creation. Pay attention that if you want to send 1 GiB of data
-taken from stdin, then you have to have 2 GiB of disk space for that
-temporary file and resulting encrypted packet. You can control where
-temporary file will be stored using @env{TMPDIR} environment variable.
-Encryption is performed with @url{https://cr.yp.to/chacha.html,
-ChaCha20} algorithm. Data is splitted on 128 KiB blocks. Each block is
-encrypted with increasing nonce counter.
+taken from stdin, then you have to have more than 2 GiB of disk space
+for that temporary file and resulting encrypted packet. You can control
+where temporary file will be stored using @env{TMPDIR} environment
+variable. Encryption is performed in AEAD mode with
+@url{https://cr.yp.to/chacha.html, ChaCha20}-@url{https://en.wikipedia.org/wiki/Poly1305, Poly1305}
+algorithms. Data is splitted on 128 KiB blocks. Each block is encrypted
+with increasing nonce counter.
If @option{-chunked} is specified, then source file will be split
@ref{Chunked, on chunks}. @option{INT} is the desired chunk size in
@@ -350,6 +355,7 @@
@verbatim
% nncp-pkt [options] < pkt
% nncp-pkt [options] [-decompress] -dump < pkt > payload
+% nncp-pkt -overheads
@end verbatim
Low level packet parser. Normally it should not be used, but can help in
@@ -381,6 +387,8 @@ And with the @option{-dump} option it will give you the actual payload
(the whole file, mail message, and so on). @option{-decompress} option
tries to zlib-decompress the data from plain packet (useful for mail
packets).
+
+@option{-overheads} options print encrypted, plain and size header overheads.
@node nncp-reass
@section nncp-reass
@@ -475,25 +483,26 @@ @node nncp-stat
@section nncp-stat
@verbatim
-% nncp-stat [options]
+% nncp-stat [options] [-node NODE]
@end verbatim
Print current @ref{Spool, spool} statistics about unsent and unprocessed
-packets. For each node and each niceness level there will be printed how
-many packets (with the total size) are in inbound (Rx) and outbound (Tx)
-queues.
+packets. For each node (unless @option{-node} specified) and each
+niceness level there will be printed how many packets (with the total
+size) are in inbound (Rx) and outbound (Tx) queues.
@node nncp-toss
@section nncp-toss
@verbatim
% nncp-toss [options]
+ [-node NODE]
[-dryrun]
[-cycle INT]
[-seen]
[-nofile]
[-nofreq]
- [-nomail]
+ [-noexec]
[-notrns]
@end verbatim
@@ -515,14 +524,14 @@ @ref{nncp-bundle}, @ref{nncp-daemon} and @ref{nncp-call} commands skip
inbound packets that has been already seen, processed and tossed. This
is helpful to prevent duplicates.
-@option{-nofile}, @option{-nofreq}, @option{-nomail}, @option{-notrns}
+@option{-nofile}, @option{-nofreq}, @option{-noexec}, @option{-notrns}
options allow to disable any kind of packet types processing.
@node nncp-xfer
@section nncp-xfer
@verbatim
-% nncp-xfer [options] [-mkdir] [-keep] [-rx|-tx] DIR
+% nncp-xfer [options] [-node NODE] [-mkdir] [-keep] [-rx|-tx] DIR
@end verbatim
Search for directory in @file{DIR} containing inbound packets for us and
diff --git a/doc/download.texi b/doc/download.texi
index a52d1b4d2d8e1210fa8781f976f3aabd8fed9a5a35d7e462e15d3283f176fca9..715c00e7dca689ef8e9377c31d8668dddf5839145882d5b47c0201a6eee3b079 100644
--- a/doc/download.texi
+++ b/doc/download.texi
@@ -20,79 +20,82 @@ @item @code{golang.org/x/net} @tab BSD 3-Clause
@item @code{golang.org/x/sys} @tab BSD 3-Clause
@end multitable
-@multitable {XXXXX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
-@headitem Version @tab Size @tab Tarball @tab SHA256 checksum
+@multitable {XXXXX} {XXXX-XX-XX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
+@headitem Version @tab Date @tab Size @tab Tarball @tab SHA256 checksum
-@item @ref{Release 3.3, 3.3} @tab 1152 KiB
+@item @ref{Release 3.4, 3.4} @tab 2018-06-10 @tab 1154 KiB
+@tab @url{download/nncp-3.4.tar.xz, link} @url{download/nncp-3.4.tar.xz.sig, sign}
+@tab @code{9796C4CB 7B670FC7 5FEED3CD 467CA556 B230387D 935B09BB 4B19FD57 FD17FFBA}
+
+@item @ref{Release 3.3, 3.3} @tab 2018-06-02 @tab 1152 KiB
@tab @url{download/nncp-3.3.tar.xz, link} @url{download/nncp-3.3.tar.xz.sig, sign}
@tab @code{1F8FA9B4 6125D8A9 0608298B A1ED87E1 12DB2D8B 81C766DE F4DFE191 C7B1BFC2}
-@item @ref{Release 3.2, 3.2} @tab 1147 KiB
+@item @ref{Release 3.2, 3.2} @tab 2018-05-27 @tab 1147 KiB
@tab @url{download/nncp-3.2.tar.xz, link} @url{download/nncp-3.2.tar.xz.sig, sign}
@tab @code{BE76802F 1E273D1D E91F0648 A7CB23C5 989F5390 A36F2D0C FD873046 51B9141E}
-@item @ref{Release 3.1, 3.1} @tab 1145 KiB
+@item @ref{Release 3.1, 3.1} @tab 2018-02-18 @tab 1145 KiB
@tab @url{download/nncp-3.1.tar.xz, link} @url{download/nncp-3.1.tar.xz.sig, sign}
@tab @code{B9344516 4230B58E 8AAADAA2 066F37F2 493CCB71 B025126B BCAD8FAD 6535149F}
-@item @ref{Release 3.0, 3.0} @tab 993 KiB
+@item @ref{Release 3.0, 3.0} @tab 2017-12-30 @tab 993 KiB
@tab @url{download/nncp-3.0.tar.xz, link} @url{download/nncp-3.0.tar.xz.sig, sign}
@tab @code{248B2257 2F576E79 A19672E9 B82EB649 18FC95A9 194408C0 67EA4DD3 0468286D}
-@item @ref{Release 2.0, 2.0} @tab 986 KiB
+@item @ref{Release 2.0, 2.0} @tab 2017-12-02 @tab 986 KiB
@tab @url{download/nncp-2.0.tar.xz, link} @url{download/nncp-2.0.tar.xz.sig, sign}
@tab @code{BEF31B13 FB25381E A511FB77 067798AB 27409238 BDF5600F E2EADB29 E5E78996}
-@item @ref{Release 1.0, 1.0} @tab 987 KiB
+@item @ref{Release 1.0, 1.0} @tab 2017-12-02 @tab 987 KiB
@tab @url{download/nncp-1.0.tar.xz, link} @url{download/nncp-1.0.tar.xz.sig, sign}
@tab @code{68BF7803 CD25F59A 56D9FD6C 695002B5 BFBAF591 8A6583F4 3139FC28 CA1AB4AF}
-@item @ref{Release 0.12, 0.12} @tab 978 KiB
+@item @ref{Release 0.12, 0.12} @tab 2017-10-08 @tab 978 KiB
@tab @url{download/nncp-0.12.tar.xz, link} @url{download/nncp-0.12.tar.xz.sig, sign}
@tab @code{707B4005 97753B29 73A5F3E5 DAB51B92 21CC296D 690EF4BC ADE93E0D 2595A5F2}
-@item @ref{Release 0.11, 0.11} @tab 1031 KiB
+@item @ref{Release 0.11, 0.11} @tab 2017-08-21 @tab 1031 KiB
@tab @url{download/nncp-0.11.tar.xz, link} @url{download/nncp-0.11.tar.xz.sig, sign}
@tab @code{D0F73C3B ADBF6B8B 13641A61 4D34F65F 20AF4C84 90894331 BF1F1609 2D65E719}
-@item @ref{Release 0.10, 0.10} @tab 949 KiB
+@item @ref{Release 0.10, 0.10} @tab 2017-07-04 @tab 949 KiB
@tab @url{download/nncp-0.10.tar.xz, link} @url{download/nncp-0.10.tar.xz.sig, sign}
@tab @code{DCE7C762 2F9281EB 282F1A67 5CA6500E 854F2DEC D60F3264 07872B91 4F4E6FA0}
-@item @ref{Release 0.9, 0.9} @tab 942 KiB
+@item @ref{Release 0.9, 0.9} @tab 2017-05-17 @tab 942 KiB
@tab @url{download/nncp-0.9.tar.xz, link} @url{download/nncp-0.9.tar.xz.sig, sign}
@tab @code{8D0765A5 F9D81086 7E1F5AB4 52A9464D C5035CCB 4E09A29A 9C9A4934 1A72AB2C}
-@item @ref{Release 0.8, 0.8} @tab 932 KiB
+@item @ref{Release 0.8, 0.8} @tab 2017-04-30 @tab 932 KiB
@tab @url{download/nncp-0.8.tar.xz, link} @url{download/nncp-0.8.tar.xz.sig, sign}
@tab @code{9BD607D5 C5551857 B7E9277D 0E857936 1DB7353A E0F1556E EA9B1D91 8305B184}
-@item @ref{Release 0.7, 0.7} @tab 783 KiB
+@item @ref{Release 0.7, 0.7} @tab 2017-04-02 @tab 783 KiB
@tab @url{download/nncp-0.7.tar.xz, link} @url{download/nncp-0.7.tar.xz.sig, sign}
@tab @code{D3407323 F89296DD 743FA764 51964B43 794E61BE 0E1D2DD4 ABD02042 B94FFC4F}
-@item @ref{Release 0.6, 0.6} @tab 746 KiB
+@item @ref{Release 0.6, 0.6} @tab 2017-02-05 @tab 746 KiB
@tab @url{download/nncp-0.6.tar.xz, link} @url{download/nncp-0.6.tar.xz.sig, sign}
@tab @code{DCFEE3F9 F669AC28 563C50DB 67BB8B43 0CFF4AB6 EC770ACE B5378D0B B40C0656}
-@item @ref{Release 0.5, 0.5} @tab 743 KiB
+@item @ref{Release 0.5, 0.5} @tab 2017-01-19 @tab 743 KiB
@tab @url{download/nncp-0.5.tar.xz, link} @url{download/nncp-0.5.tar.xz.sig, sign}
@tab @code{D98F9149 5A6D6726 4C659640 1AD7F400 271A58CE 5D8D4AC5 5D1CF934 59BEDFA6}
-@item @ref{Release 0.4, 0.4} @tab 741 KiB
+@item @ref{Release 0.4, 0.4} @tab 2017-01-17 @tab 741 KiB
@tab @url{download/nncp-0.4.tar.xz, link} @url{download/nncp-0.4.tar.xz.sig, sign}
@tab @code{93577327 B3DEBFE3 A80BEB0D 8325B2E6 0939EC55 4DBB05F3 4CA34B99 229C3722}
-
-@item @ref{Release 0.3, 0.3} @tab 741 KiB
+@item @ref{Release 0.3, 0.3} @tab 2017-01-17 @tab 741 KiB
@tab @url{download/nncp-0.3.tar.xz, link} @url{download/nncp-0.3.tar.xz.sig, sign}
@tab @code{6E76EC5E 6B575C65 BF2D6388 870F2A1C 417D63E4 1628CAA1 BB499D0D 0634473B}
-@item @ref{Release 0.2, 0.2} @tab 740 KiB
+@item @ref{Release 0.2, 0.2} @tab 2017-01-17 @tab 740 KiB
@tab @url{download/nncp-0.2.tar.xz, link} @url{download/nncp-0.2.tar.xz.sig, sign}
@tab @code{00BEAC5A 0C4083B0 42E3152B ACA6FF20 12768B82 CE24D716 8E04279C ECE14DB7}
-@item 0.1 @tab 720 KiB
+@item 0.1 @tab 2017-01-10 @tab 720 KiB
@tab @url{download/nncp-0.1.tar.xz, link} @url{download/nncp-0.1.tar.xz.sig, sign}
@tab @code{8F71D65B 70865EBF FE802CDF A5C14D00 A9FD6559 FD722E60 5D97E82C 5E2412C2}
diff --git a/doc/eblob.texi b/doc/eblob.texi
index 7c4ae400d39b4ea4f17981e6d3cb1a79ff542bc17c2c33af4dc199adbf16f1ea..077e14f4d2376dfe398fcf4ead21a569a73ffcd25352a005597121d46d9d22b8 100644
--- a/doc/eblob.texi
+++ b/doc/eblob.texi
@@ -32,16 +32,16 @@
Eblob is an @url{https://tools.ietf.org/html/rfc4506, XDR}-encoded structure:
@verbatim
-+-------+------------------+------------+
-| MAGIC | S | T | P | SALT | BLOB | MAC |
-+-------+------------------+------------+
++-------+------------------+------+
+| MAGIC | S | T | P | SALT | BLOB |
++-------+------------------+------+
@end verbatim
@multitable @columnfractions 0.2 0.3 0.5
@headitem @tab XDR type @tab Value
@item Magic number @tab
8-byte, fixed length opaque data @tab
- @verb{|N N C P B 0x00 0x00 0x02|}
+ @verb{|N N C P B 0x00 0x00 0x03|}
@item S, T, P @tab
unsigned integer @tab
Space cost, time cost and parallel jobs number
@@ -50,22 +50,19 @@ 32 bytes, fixed length opaque data @tab
Randomly generated salt
@item Blob @tab
variable length opaque data @tab
- Encrypted data itself
-@item MAC @tab
- 32 bytes, fixed length opaque data @tab
- BLAKE2b-256 MAC of encrypted blob
+ Authenticated and Encrypted data itself
@end multitable
@enumerate
@item generate the main key using @code{balloon(BLAKE2b-256, S, T, P,
salt, password)}
@item initialize @url{https://blake2.net/, BLAKE2Xb} XOF with generated
-main key and 96-byte output length
-@item feed @verb{|N N C P B 0x00 0x00 0x02|} magic number to XOF
-@item read 32-bytes of blob encryption key
-@item read 64-bytes of blob authentication key
-@item encrypt the blob using @url{https://cr.yp.to/chacha.html,
-ChaCha20}. Blob is splitted on 128 KiB blocks. Each block is encrypted
-with increasing nonce counter
-@item authenticate ciphertext with MAC
+main key and 32-byte output length
+@item feed @verb{|N N C P B 0x00 0x00 0x03|} magic number to XOF
+@item read 32-bytes of blob AEAD encryption key
+@item encrypt and authenticate blob using
+ @url{https://cr.yp.to/chacha.html, ChaCha20}-@url{https://en.wikipedia.org/wiki/Poly1305, Poly1305}.
+ Blob is splitted on 128 KiB blocks. Each block is encrypted with
+ increasing nonce counter. Eblob packet itself, with empty blob
+ field, is fed as an additional authenticated data
@end enumerate
diff --git a/doc/index.texi b/doc/index.texi
index c0ff5e7a24c85180ea80236ded89c0b4dfae8a6907017a1ba48f0d2b6aaf57e1..a5ba6e1a7a85eb8d4b2fbea63c2ef60555749af7c893f1b6f4b31a25d01573a6 100644
--- a/doc/index.texi
+++ b/doc/index.texi
@@ -6,7 +6,7 @@ @copying
This manual is for NNCP (Node to Node copy) -- collection of utilities
simplifying secure store-and-forward files and mail exchanging.
-Copyright @copyright{} 2016-2018 @email{stargrave@@stargrave.org, Sergey Matveev}
+Copyright @copyright{} 2016-2019 @email{stargrave@@stargrave.org, Sergey Matveev}
@quotation
Permission is granted to copy, distribute and/or modify this document
diff --git a/doc/integrity.texi b/doc/integrity.texi
index 409df9651861c4cc7aed1362fc09698e26b0f995bb22f556b29d95ad3910559f..371677601807eaf0ae233077e21479857b27a6469c1a0f77d5df76835993ef4d 100644
--- a/doc/integrity.texi
+++ b/doc/integrity.texi
@@ -23,7 +23,6 @@ @verbatim
% gpg --keyserver hkp://keys.gnupg.net/ --recv-keys 0x2B25868E75A1A953
% gpg --auto-key-locate dane --locate-keys releases at nncpgo dot org
% gpg --auto-key-locate wkd --locate-keys releases at nncpgo dot org
-% gpg --auto-key-locate pka --locate-keys releases at nncpgo dot org
@end verbatim
@item
diff --git a/doc/news.ru.texi b/doc/news.ru.texi
index 6f820e37fbe6962f5a999c61d538bde400e06f6ad1e5418e7eda35df48c70259..61e6fa17a6970c7e0a72181c567c1601eea00d0865483375bf5a3a2cb3f28119 100644
--- a/doc/news.ru.texi
+++ b/doc/news.ru.texi
@@ -1,6 +1,34 @@
@node Новости
@section Новости
+@node Релиз 4.0
+@subsection Релиз 4.0
+@itemize
+@item
+@strong{Несовместимое} изменение формата зашифрованных и eblob пакетов:
+используется AEAD режим шифрования с 128 КиБ блоками, так как раньше
+@command{nncp-toss} не проверял MAC зашифрованного пакета прежде чем
+отсылать дешифрованные данные внешней команде. Старые версии не
+поддерживаются.
+@item
+Проверка доступного места перед копированием во время работы
+@command{nncp-xfer}, @command{nncp-daemon}, @command{nncp-call(er)}.
+@item
+@command{nncp-call} имеет возможность только показывать список пакетов
+на удалённой машине, без их передачи.
+@item
+@command{nncp-call} имеет возможность передавать только чётко указанные пакеты.
+@item
+Восстановлена работоспособность @option{xxrate} настройки в
+@option{calls} секции конфигурационного файла.
+@item
+Зависимые библиотеки обновлены.
+@item
+Небольшие исправления ошибок.
+@item
+Начало использования @code{go.mod} подсистемы.
+@end itemize
+
@node Релиз 3.4
@subsection Релиз 3.4
@itemize
diff --git a/doc/news.texi b/doc/news.texi
index 925a396dc99cb37c16fca90ff142397f5397e84d1ce00f122c123b07bd1a21f0..0088aa0e00a8b1550849d880c9434b1a24d7ceb4a9917943730050dae96c6c1c 100644
--- a/doc/news.texi
+++ b/doc/news.texi
@@ -3,6 +3,33 @@ @unnumbered News
See also this page @ref{Новости, on russian}.
+@node Release 4.0
+@section Release 4.0
+@itemize
+@item
+@strong{Incompatible} encrypted and eblob packet format change: AEAD
+encryption mode with 128 KiB blocks is used now, because previously
+@command{nncp-toss} did not verify encrypted packet's MAC before feeding
+decrypted data to external command. Older versions are not supported.
+@item
+Available free space checking before copying in @command{nncp-xfer},
+@command{nncp-daemon}, @command{nncp-call(er)}.
+@item
+@command{nncp-call} has ability only to list packets on remote node,
+without their transmission.
+@item
+@command{nncp-call} has ability to transfer only specified packets.
+@item
+Workability of @option{xxrate} preference in @option{calls}
+configuration file section.
+@item
+Dependant libraries are updated.
+@item
+Minor bugfixes.
+@item
+Begin using of @code{go.mod} subsystem.
+@end itemize
+
@node Release 3.4
@section Release 3.4
@itemize
diff --git a/doc/pkt.texi b/doc/pkt.texi
index f269ab8634205703b90496932652fa652d7a2e5fb5d803465004c3d187977ccf..a25082ef8c80556be8a0df29b2cb192b73fe3fa662582d42a374891b3dc55a67 100644
--- a/doc/pkt.texi
+++ b/doc/pkt.texi
@@ -28,7 +28,7 @@ @multitable @columnfractions 0.2 0.3 0.5
@headitem @tab XDR type @tab Value
@item Magic number @tab
8-byte, fixed length opaque data @tab
- @verb{|N N C P P 0x00 0x00 0x01|}
+ @verb{|N N C P P 0x00 0x00 0x02|}
@item Payload type @tab
unsigned integer @tab
0 (file), 1 (freq), 2 (exec), 3 (transition)
@@ -78,11 +78,11 @@
Each encrypted packet has the following header:
@verbatim
- +------------ HEADER --------------------+ +-------- ENCRYPTED --------+
- / \ / \
-+--------------------------------------------+------------+----...-----------+------+
-| MAGIC | NICE | SENDER | RCPT | EPUB | SIGN | SIZE | MAC | CIPHERTEXT | MAC | JUNK |
-+-------------------------------------/------\------------+----...-----------+------+
+ +------------ HEADER --------------------+ +------------- ENCRYPTED -------------+
+ / \ / \
++--------------------------------------------+------+---------+----------...---+------+
+| MAGIC | NICE | SENDER | RCPT | EPUB | SIGN | SIZE | BLOCK 0 | BLOCK 1 ... | JUNK |
++-------------------------------------/------\------+---------+----------...---+------+
/ \
+-------------------------------------+
| MAGIC | NICE | SENDER | RCPT | EPUB |
@@ -93,7 +93,7 @@ @multitable @columnfractions 0.2 0.3 0.5
@headitem @tab XDR type @tab Value
@item Magic number @tab
8-byte, fixed length opaque data @tab
- @verb{|N N C P E 0x00 0x00 0x03|}
+ @verb{|N N C P E 0x00 0x00 0x04|}
@item Niceness @tab
unsigned integer @tab
1-255, packet @ref{Niceness, niceness} level
@@ -113,12 +113,12 @@ @end multitable
Signature is calculated over all previous fields.
-All following encryption is done using @url{https://cr.yp.to/chacha.html,
-ChaCha20} algorithm. Data is splitted on 128 KiB blocks. Each block is
-encrypted with increasing nonce counter. @url{https://blake2.net/,
-BLAKE2b-256} MAC is appended to the ciphertext.
+All following encryption is done in AEAD mode using
+@url{https://cr.yp.to/chacha.html, ChaCha20}-@url{https://en.wikipedia.org/wiki/Poly1305, Poly1305}
+algorithms. Data is splitted on 128 KiB blocks. Each block is encrypted with
+increasing nonce counter.
-After the headers comes an encrypted payload size and MAC of that size.
+Authenticated and encrypted size come after the header:
@multitable @columnfractions 0.2 0.3 0.5
@headitem @tab XDR type @tab Value
@@ -127,7 +127,7 @@ unsigned hyper integer @tab
Payload size.
@end multitable
-Next comes the actual encrypted payload with corresponding MAC.
+Then comes the actual payload.
Each node has static @strong{exchange} and @strong{signature} keypairs.
When node A want to send encrypted packet to node B, it:
@@ -143,18 +143,15 @@ private ephemeral one
@item derive the keys:
@enumerate
@item initialize @url{https://blake2.net/, BLAKE2Xb} XOF with
- derived ephemeral key and 224-byte output length
- @item feed @verb{|N N C P E 0x00 0x00 0x03|} magic number to XOF
- @item read 32-bytes of "size" encryption key (for ChaCha20)
- @item read 64-bytes of "size" authentication key (for BLAKE2b-MAC)
- @item read 32-bytes of payload encryption key
- @item read 64-bytes of payload authentication key
- @item optionally read 32-bytes pad generation key (for ChaCha20)
+ derived ephemeral key and 96-byte output length
+ @item feed @verb{|N N C P E 0x00 0x00 0x04|} magic number to XOF
+ @item read 32-bytes of "size" AEAD encryption key
+ @item read 32-bytes of payload AEAD encryption key
+ @item optionally read 32-bytes pad generation key
@end enumerate
-@item encrypts size, appends its ciphertext to the header
-@item appends MAC tag over that ciphertext
-@item encrypts and appends payload ciphertext
-@item appends MAC tag over that payload ciphertext
+@item encrypts size, appends its authenticated ciphertext to the header
+@item encrypts payload, appends its authenticated ciphertext
@item possibly appends any kind of "junk" noise data to hide real
- payload's size from the adversary
+ payload's size from the adversary (generated using XOF with
+ unlimited output length)
@end enumerate
diff --git a/doc/style.css b/doc/style.css
index 228b076e684e52cfa41bd3d7376be26fa55bf0cba471ad7c589778c876947ddf..7cfb55f8ad0828d46db2d8ab86aec767541141dedbdb0a821ba846b195309e85 100644
--- a/doc/style.css
+++ b/doc/style.css
@@ -1,10 +1,11 @@
diff --git a/doc/usecases.ru.texi b/doc/usecases.ru.texi
index c4797772fad78185aa01545dfe5b64a056f6bf3b382e87903b7e3f69c752c8a3..8bdf213c97c13f7cf76a754c983e595a880b2982b0a33242dd9baa196c9b268e 100644
--- a/doc/usecases.ru.texi
+++ b/doc/usecases.ru.texi
@@ -8,10 +8,12 @@ * Ненадёжный/дорогой канал связи: UsecaseUnreliableRU.
* Медленная/дорогая связь для больших объёмов данных, плохой QoS: UsecaseQoSRU.
* Экстремальные наземные окружающие условия, нет связи: UsecaseNoLinkRU.
* Односторонняя широковещательная связь: UsecaseBroadcastRU.
+* Спутниковые каналы связи: UsecaseSatelliteLinksRU.
* Частные, изолированные MitM/Sybil-устойчивые сети: UsecaseF2FRU.
* Высоко защищённые изолированные компьютеры с воздушным зазором: UsecaseAirgapRU.
* Обход сетевой цензуры, здоровье: UsecaseCensorRU.
* Разведка, шпионаж, тайная агентура: UsecaseSpyRU.
+* Дешёвая ночная связь: UsecaseCallerRU.
@end menu
@node UsecaseMailRU
@@ -104,9 +106,9 @@ раньше или позднее остальных. Почти все команды имеют соответствующую
опцию:
@verbatim
-% nncp-file -nice 32 myfile node:dst
-% nncp-xfer -nice 192 /mnt/shared
-% nncp-call -nice 224 bob
+% nncp-file -nice FLASH myfile node:dst
+% nncp-xfer -nice PRIORITY /mnt/shared
+% nncp-call -nice NORMAL bob
[...]
@end verbatim
@@ -182,6 +184,34 @@ Встроенная возможность определять дубляжи пакетов позволит вам
переотправлять широковещательные рассылки время от времени, повышая
шансы на то, что получатель примет их, регулярно слушая рассылку.
+@node UsecaseSatelliteLinksRU
+@subsection Спутниковые каналы связи
+
+Спутниковые каналы связи имеют @strong{очень} большие задержки вместе с
+высокими пропускными способностями. Вы можете посылать мегабиты данных в
+секунду, но они достигнут удалённой стороны только спустя полсекунды!
+Большинство протоколов обмена файлами, таких как
+@url{https://en.wikipedia.org/wiki/Files_transferred_over_shell_protocol, FISH},
+@url{https://ru.wikipedia.org/wiki/FTP, FTP},
+@url{https://ru.wikipedia.org/wiki/SCP, scp},
+@url{https://en.wikipedia.org/wiki/XMODEM, XMODEM} will perform very
+будут работать очень плохо из-за большого количества приёмо-передач
+(round-trips). Каждая передача файла явно генерирует пакеты запросов и
+подтверждений, посылаемые поверх канала связи. Удалённая сторона ничего
+не будет делать пока она их не получит. Более того, не все протоколы
+позволяют делать дуплексную отправку данных (когда обе стороны посылают
+данные одновременно).
+
+@ref{Sync, Протокол синхронизации} (SP) NNCP пытается решить все эти
+особенности за счёт сокращения количества приёмо-передач, количества
+проходящих пакетов. Все списки файлов, запросов на скачивание файла
+группируются вместе (pipelined) в один огромный пакет. Только запросы на
+остановку передачи и подтверждения успешного приёма файла явно
+посылаются. Можно запросить чтобы SP только принимал или отправлял
+пакеты для нашей ноды. SP может игнорировать файлы с маленьким
+приоритетом. Полные списки файлов отправляются уже на этапе процедуры
+рукопожатия.
+
@node UsecaseF2FRU
@subsection Частные, изолированные MitM/Sybil-устойчивые сети
@@ -297,7 +327,7 @@ @subsection Разведка, шпионаж, тайная агентура
Эти ребята знают насколько небезопасен Интернет, несовместим с
понятием приватности. Им необходим быстрый сброс и забор данных. Нет
-возможности провести несколько итераций туда-обратно (round trip) --
+возможности провести несколько итераций приёмо-передач (round-trips) --
только сбросить данные, выстрелить и забыть. Опять же, это может быть
переносной накопитель и/или
@url{https://en.wikipedia.org/wiki/USB_dead_drop, USB тайник} (dead drop),
@@ -316,7 +346,7 @@ видно.
Общение узлов между собой происходит в, так называемой, @ref{Spool,
спул} области: директории содержащей только необработанные зашифрованные
-пакеты. После передачи пакета вы всё-равно не сможете его прочитать:
+пакеты. После передачи пакета вы всё равно не сможете его прочитать:
необходимо запустить другую фазу: @ref{nncp-toss, распаковку}, которая
использует ваши приватные криптографические ключи. То есть, даже если вы
потеряете свой компьютер, устройства хранения и тому прочее -- это не
@@ -326,3 +356,47 @@ Распаковка (чтение этих зашифрованных пакетов с извлечением переданных
файлов и почтовых сообщений) может и должна бы быть произведена на
отдельном компьютере (@ref{nncp-cfgmin} команда может помочь с созданием
конфигурационного файла без приватных ключей для этой цели).
+
+Если вы действительно хотите взять с собой приватные ключи, то
+@ref{nncp-cfgenc} команда способна зашифровать ваш конфигурационный
+файл. Парольная фраза вами введённая усиливается функцией нагружающей и
+центральный процессор и память.
+
+@node UsecaseCallerRU
+@subsection Дешёвая ночная связь
+
+Стоимость Интернет/телефонного трафика может варьироваться, в
+зависимости от времени дня. Ночные звонки/соединения могут быть дешевле
+в два раза. Вы хотите посылать ваши файлы в это время, но позволять
+изредка проходить высокоприоритетной почте в любое время. А также вы
+хотите проходить любому трафику когда узел доступен через ЛВС (LAN).
+
+Вы легко можете настроить ваши предпочтения в @ref{Call, настройках
+звонков} для @ref{nncp-caller} команды, используемой при online связи.
+
+@verbatim
+neigh:
+ [...]
+ some-node:
+ [...]
+ addrs:
+ lan: "[fe80::be5f:f4ff:fedd:2752%igb0]:5400"
+ wan: "some-node.com:5400"
+ calls:
+ -
+ cron: "*/1 * * * *"
+ addr: lan
+ nice: MAX
+ onlinedeadline: 3600
+ -
+ cron: "*/10 * * * *"
+ addr: wan
+ nice: PRIORITY
+ xx: rx
+ -
+ cron: "*/1 0-7 * * *"
+ addr: wan
+ nice: BULK
+ onlinedeadline: 3600
+ maxonlinetime: 3600
+@end verbatim
diff --git a/doc/usecases.texi b/doc/usecases.texi
index 186240bc1de144d674b5670b801cc676294e5c8d7c6b8c7934b06c11e849809f..39c444cc04b23e821393dc60eb51080bce564a8c40f1166268d5ae4c9dea35d8 100644
--- a/doc/usecases.texi
+++ b/doc/usecases.texi
@@ -10,10 +10,12 @@ * Unreliable/expensive communication link: UsecaseUnreliable.
* Slow/expensive link for high-volume data, bad QoS: UsecaseQoS.
* Extreme terrestrial environments, no link: UsecaseNoLink.
* One-way broadcasting communications: UsecaseBroadcast.
+* Satellite links: UsecaseSatelliteLinks.
* Private, isolated MitM/Sybil-resistant networks: UsecaseF2F.
* Highly secure isolated air-gap computers: UsecaseAirgap.
* Network censorship bypassing, health: UsecaseCensor.
* Reconnaissance, spying, intelligence, covert agents: UsecaseSpy.
+* Cheap night transfers: UsecaseCaller.
@end menu
@node UsecaseMail
@@ -99,9 +101,9 @@ niceness level, that will guarantee that it will be processed earlier or
later than the other ones. Nearly all commands has corresponding option:
@verbatim
-% nncp-file -nice 32 myfile node:dst
-% nncp-xfer -nice 192 /mnt/shared
-% nncp-call -nice 224 bob
+% nncp-file -nice FLASH myfile node:dst
+% nncp-xfer -nice PRIORITY /mnt/shared
+% nncp-call -nice NORMAL bob
[...]
@end verbatim
@@ -172,6 +174,32 @@ With built-in packet duplicates detection ability, you can retransmit
your broadcasts from time to time, to increase chances the recipient
will catch them by regular stream listening.
+@node UsecaseSatelliteLinks
+@section Satellite links
+
+Satellite links have @strong{very} high delays together with high
+bandwidths. You can send several megabits of data per second, but they
+will reach the remote side only after half a second!
+Most file sharing protocols like
+@url{https://en.wikipedia.org/wiki/Files_transferred_over_shell_protocol, FISH},
+@url{https://en.wikipedia.org/wiki/FTP, FTP},
+@url{https://en.wikipedia.org/wiki/Secure_copy, scp},
+@url{https://en.wikipedia.org/wiki/XMODEM, XMODEM}
+will perform very badly because of round-trips quantity. Each file
+transmission explicitly generates request and acknowledgement packets
+that are send over the link. Remote side won't do anything until it
+receives them. Moreover not all protocols allow duplex data
+transmission (when both sides are sending data simultaneously).
+
+NNCP's @ref{Sync, synchronization protocol} (SP) tries to mitigate all
+that issues by reducing number of round-trips, number of packets passing
+through. All file lists, file download requests are grouped together
+(pipelined) in one huge packet. Only transmission halt and successful
+file download acknowledgements are sent explicitly. SP could be asked
+only either to upload or download packets for our node. SP could ignore
+files with low priority. Full files listing is passing even during the
+handshake procedure.
+
@node UsecaseF2F
@section Private, isolated MitM/Sybil-resistant networks
@@ -305,3 +333,47 @@ same device. Tossing (reading those encrypted packets and extracting
transferred files and mail messages) could and should be done on a
separate computer (@ref{nncp-cfgmin} command could help creating
configuration file without private keys for that purpose).
+
+If you really want to carry your private keys, then @ref{nncp-cfgenc}
+command will be able to encrypt your configuration file. Passphrase you
+enter is strengthened with both CPU and memory hard function.
+
+@node UsecaseCaller
+@section Cheap night transfers
+
+Your Internet/telephone traffic price can vary, depending on daytime.
+Night calls/connections could be twice as cheaper. You wish to send your
+files at that time, but keep high priority email infrequently passing
+through in anytime. Also you wish to pass any kind of traffic when the
+node is available through the LAN.
+
+You can easily set your preferences in @ref{Call, call
+configurations} for @ref{nncp-caller} command used in online
+communications.
+
+@verbatim
+neigh:
+ [...]
+ some-node:
+ [...]
+ addrs:
+ lan: "[fe80::be5f:f4ff:fedd:2752%igb0]:5400"
+ wan: "some-node.com:5400"
+ calls:
+ -
+ cron: "*/1 * * * *"
+ addr: lan
+ nice: MAX
+ onlinedeadline: 3600
+ -
+ cron: "*/10 * * * *"
+ addr: wan
+ nice: PRIORITY
+ xx: rx
+ -
+ cron: "*/1 0-7 * * *"
+ addr: wan
+ nice: BULK
+ onlinedeadline: 3600
+ maxonlinetime: 3600
+@end verbatim
diff --git a/makedist.sh b/makedist.sh
index 2989fd3d1b283cc5a441596bda4e5ddbc630c743fda58f1b174a6e89bcd997db..f548b3bb659ed8c2cc8e16821b2e338720e56c2352542bdd6175be33a9f139b0 100755
--- a/makedist.sh
+++ b/makedist.sh
@@ -5,19 +5,23 @@ tmp=$(mktemp -d)
release=$1
[ -n "$release" ]
+vendor=src/cypherpunks.ru/nncp/vendor
+
git clone . $tmp/nncp-$release
repos="
- src/github.com/davecgh/go-xdr
- src/github.com/dustin/go-humanize
- src/github.com/flynn/noise
- src/golang.org/x/crypto
- src/golang.org/x/net
- src/golang.org/x/sys
- src/gopkg.in/check.v1
- src/gopkg.in/yaml.v2
+ cypherpunks.ru/balloon
+ github.com/davecgh/go-xdr
+ github.com/dustin/go-humanize
+ github.com/flynn/noise
+ github.com/gorhill/cronexpr
+ golang.org/x/crypto
+ golang.org/x/net
+ golang.org/x/sys
+ gopkg.in/check.v1
+ gopkg.in/yaml.v2
"
for repo in $repos; do
- git clone $repo $tmp/nncp-$release/$repo
+ git clone $vendor/$repo $tmp/nncp-$release/$vendor/$repo
done
cd $tmp/nncp-$release
git checkout $release
@@ -25,43 +29,48 @@ git submodule update --init
cat > $tmp/includes <
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -42,7 +42,10 @@ addrs []string,
nice uint8,
xxOnly TRxTx,
rxRate, txRate int,
- onlineDeadline, maxOnlineTime uint) (isGood bool) {
+ onlineDeadline, maxOnlineTime uint,
+ listOnly bool,
+ onlyPkts map[[32]byte]bool,
+) (isGood bool) {
for _, addr := range addrs {
sds := SDS{"node": node.Id, "addr": addr}
ctx.LogD("call", sds, "dialing")
@@ -52,17 +55,19 @@ ctx.LogD("call", SdsAdd(sds, SDS{"err": err}), "dialing")
continue
}
ctx.LogD("call", sds, "connected")
- state, err := ctx.StartI(
- conn,
- node.Id,
- nice,
- xxOnly,
- rxRate,
- txRate,
- onlineDeadline,
- maxOnlineTime,
- )
- if err == nil {
+ state := SPState{
+ Ctx: ctx,
+ Node: node,
+ Nice: nice,
+ onlineDeadline: onlineDeadline,
+ maxOnlineTime: maxOnlineTime,
+ xxOnly: xxOnly,
+ rxRate: rxRate,
+ txRate: txRate,
+ listOnly: listOnly,
+ onlyPkts: onlyPkts,
+ }
+ if err = state.StartI(conn); err == nil {
ctx.LogI("call-start", sds, "connected")
state.Wait()
ctx.LogI("call-finish", SDS{
diff --git a/src/cypherpunks.ru/nncp/cfg.go b/src/cypherpunks.ru/nncp/cfg.go
index dd81ceae4caa057e7cd7d1deeeb9652407c7eb8822232d28ba2e96300432cb70..c2005d8f13cc0e1f695f16c95c9c6021e7fb54366975c55e7dcc335921ea98fe 100644
--- a/src/cypherpunks.ru/nncp/cfg.go
+++ b/src/cypherpunks.ru/nncp/cfg.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -214,12 +214,12 @@ default:
return nil, errors.New("xx field must be either \"rx\" or \"tx\"")
}
- rxRate := 0
- if callYml.RxRate != nil && *callYml.RxRate > 0 {
+ rxRate := defRxRate
+ if callYml.RxRate != nil {
rxRate = *callYml.RxRate
}
- txRate := 0
- if callYml.TxRate != nil && *callYml.TxRate > 0 {
+ txRate := defTxRate
+ if callYml.TxRate != nil {
txRate = *callYml.TxRate
}
@@ -371,7 +371,7 @@ }
func CfgParse(data []byte) (*Ctx, error) {
var err error
- if bytes.Compare(data[:8], MagicNNCPBv2[:]) == 0 {
+ if bytes.Compare(data[:8], MagicNNCPBv3[:]) == 0 {
os.Stderr.WriteString("Passphrase:")
password, err := terminal.ReadPassword(0)
if err != nil {
diff --git a/src/cypherpunks.ru/nncp/check.go b/src/cypherpunks.ru/nncp/check.go
index a2d1b6e942a5aebac3a84f5948901e74acbb3697af03626bd7b4ada7bb83a9a2..6eae1d08364aaf7f6f70a4dadc13aa3ff9ead37d50f6eb5f925792e4f033464b 100644
--- a/src/cypherpunks.ru/nncp/check.go
+++ b/src/cypherpunks.ru/nncp/check.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/chunked.go b/src/cypherpunks.ru/nncp/chunked.go
index c6f8190b9d99a922469c102c1fcc06795304c06dd16d36a6309f5fdde9033f51..3f293ec6157c6ec92f6ee0f3e7cc8b47a80e2044db2869c47ae7ec92d6f76aa0 100644
--- a/src/cypherpunks.ru/nncp/chunked.go
+++ b/src/cypherpunks.ru/nncp/chunked.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-bundle/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-bundle/main.go
index 0e524d15619d6b66b4e327e7651f3cba2664a9f5b866d0aee8726debf5705578..dcc86c2bade2d0651f95f2f169cff92001468ae5e3044cb4e88422c92075bce9 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-bundle/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-bundle/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Create/digest stream of NNCP encrypted packets
+// Create/digest stream of NNCP encrypted packets.
package main
import (
@@ -236,7 +236,7 @@ if _, err = xdr.Unmarshal(bytes.NewReader(pktEncBuf), &pktEnc); err != nil {
ctx.LogD("nncp-bundle", sds, "Bad packet structure")
continue
}
- if pktEnc.Magic != nncp.MagicNNCPEv3 {
+ if pktEnc.Magic != nncp.MagicNNCPEv4 {
ctx.LogD("nncp-bundle", sds, "Bad packet magic number")
continue
}
@@ -367,7 +367,9 @@ }
if err = bufTmp.Flush(); err != nil {
log.Fatalln("Error during flushing:", err)
}
- tmp.Sync()
+ if err = tmp.Sync(); err != nil {
+ log.Fatalln("Error during syncing:", err)
+ }
tmp.Close()
if err = os.MkdirAll(selfPath, os.FileMode(0700)); err != nil {
log.Fatalln("Error during mkdir:", err)
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-call/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-call/main.go
index 37524822be7cf60658c46d1ab9c99b76bd207d148cdbf3226b2bc7fa02915e01..af15fae979463e0b6b5bd80a75f9ed70b72f3cf1d87c3f1344b45cc8bb5d1867 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-call/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-call/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Call NNCP TCP daemon
+// Call NNCP TCP daemon.
package main
import (
@@ -39,18 +39,20 @@ }
func main() {
var (
- cfgPath = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
- niceRaw = flag.String("nice", nncp.NicenessFmt(255), "Minimal required niceness")
- rxOnly = flag.Bool("rx", false, "Only receive packets")
- txOnly = flag.Bool("tx", false, "Only transmit packets")
- rxRate = flag.Int("rxrate", 0, "Maximal receive rate, pkts/sec")
- txRate = flag.Int("txrate", 0, "Maximal transmit rate, pkts/sec")
- spoolPath = flag.String("spool", "", "Override path to spool")
- logPath = flag.String("log", "", "Override path to logfile")
- quiet = flag.Bool("quiet", false, "Print only errors")
- debug = flag.Bool("debug", false, "Print debug messages")
- version = flag.Bool("version", false, "Print version information")
- warranty = flag.Bool("warranty", false, "Print warranty information")
+ cfgPath = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
+ niceRaw = flag.String("nice", nncp.NicenessFmt(255), "Minimal required niceness")
+ rxOnly = flag.Bool("rx", false, "Only receive packets")
+ txOnly = flag.Bool("tx", false, "Only transmit packets")
+ listOnly = flag.Bool("list", false, "Only list remote packets")
+ onlyPktsRaw = flag.String("pkts", "", "Recieve only that packets, comma separated")
+ rxRate = flag.Int("rxrate", 0, "Maximal receive rate, pkts/sec")
+ txRate = flag.Int("txrate", 0, "Maximal transmit rate, pkts/sec")
+ spoolPath = flag.String("spool", "", "Override path to spool")
+ logPath = flag.String("log", "", "Override path to logfile")
+ quiet = flag.Bool("quiet", false, "Print only errors")
+ debug = flag.Bool("debug", false, "Print debug messages")
+ version = flag.Bool("version", false, "Print version information")
+ warranty = flag.Bool("warranty", false, "Print warranty information")
onlineDeadline = flag.Uint("onlinedeadline", 0, "Override onlinedeadline option")
maxOnlineTime = flag.Uint("maxonlinetime", 0, "Override maxonlinetime option")
@@ -123,6 +125,21 @@ addrs = append(addrs, addr)
}
}
+ var onlyPkts map[[32]byte]bool
+ if len(*onlyPktsRaw) > 0 {
+ splitted = strings.Split(*onlyPktsRaw, ",")
+ onlyPkts = make(map[[32]byte]bool, len(splitted))
+ for _, pktIdRaw := range splitted {
+ pktId, err := nncp.FromBase32(pktIdRaw)
+ if err != nil {
+ log.Fatalln("Invalid packet specified: ", err)
+ }
+ pktIdArr := new([32]byte)
+ copy(pktIdArr[:], pktId)
+ onlyPkts[*pktIdArr] = true
+ }
+ }
+
if !ctx.CallNode(
node,
addrs,
@@ -132,6 +149,8 @@ *rxRate,
*txRate,
*onlineDeadline,
*maxOnlineTime,
+ *listOnly,
+ onlyPkts,
) {
os.Exit(1)
}
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-caller/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-caller/main.go
index 47a73070666d3789fb41c229c7dc768a0222ccae9a8cdc96847a7d6bc15abd3c..7b5fee13453e13a0e81d9a720f75461530e3795b3d31bff28a4a2732960adc68 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-caller/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-caller/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Croned NNCP TCP daemon caller
+// Croned NNCP TCP daemon caller.
package main
import (
@@ -132,6 +132,8 @@ call.RxRate,
call.TxRate,
call.OnlineDeadline,
call.MaxOnlineTime,
+ false,
+ nil,
)
node.Lock()
node.Busy = false
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-cfgenc/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-cfgenc/main.go
index fa4dacad8f72688c744c519b3087b062d4320068492b2cedcd91167db38fb347..b2813035dce350b9748957487870c644f8aeb8ee1ee75fce92e0c474664189e5 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-cfgenc/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-cfgenc/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -79,7 +79,7 @@ var eblob nncp.EBlob
if _, err := xdr.Unmarshal(bytes.NewReader(data), &eblob); err != nil {
log.Fatalln(err)
}
- if eblob.Magic != nncp.MagicNNCPBv2 {
+ if eblob.Magic != nncp.MagicNNCPBv3 {
log.Fatalln(errors.New("Unknown eblob type"))
}
fmt.Println("Strengthening function: Balloon with BLAKE2b-256")
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-cfgmin/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-cfgmin/main.go
index 845f2218f2c401e37110d4ea8822a05c68f794beeafd17713799ccdd7cde4dd3..ea3fbd6e45716519c27bd9f47f8a940e8214a3825558296eed0e9b2d5dc0af98 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-cfgmin/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-cfgmin/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-cfgnew/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-cfgnew/main.go
index 7db9060f298d504c5a5382264521c5b6b55e3b3f0d3e837f955fd0988337da36..24156f793d5f93967de471b984c9c6351635d175f292912929a93a93fd61ab77 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-cfgnew/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-cfgnew/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-check/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-check/main.go
index 29c1ff4ea74a102236d7a817fd338726bb3554f48818846f93017893e34b2ede..e03f4c339cf16ff7ce96db4266062557fc9dc39a9e0d4eae3acf55c1cf6df308 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-check/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-check/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Verify NNCP Rx/Tx packets checksum
+// Verify NNCP Rx/Tx packets checksum.
package main
import (
@@ -75,7 +75,9 @@ for nodeId, node := range ctx.Neigh {
if nodeOnly != nil && nodeId != *nodeOnly.Id {
continue
}
- isBad = isBad || ctx.Check(node.Id)
+ if !ctx.Check(node.Id) {
+ isBad = true
+ }
}
if isBad {
os.Exit(1)
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-daemon/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-daemon/main.go
index 710fa233dec13b57ceda7b85e711d46bb7109556f46fc83ab7478fcc10219453..fe8068705730bf1d7d5f541dad29834cdd12d4e4ed2a18661a5c55c88123a138 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-daemon/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-daemon/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// NNCP TCP daemon
+// NNCP TCP daemon.
package main
import (
@@ -61,8 +61,11 @@ return ic.w.SetWriteDeadline(t)
}
func performSP(ctx *nncp.Ctx, conn nncp.ConnDeadlined, nice uint8) {
- state, err := ctx.StartR(conn, nice, "")
- if err == nil {
+ state := nncp.SPState{
+ Ctx: ctx,
+ Nice: nice,
+ }
+ if err := state.StartR(conn); err == nil {
ctx.LogI("call-start", nncp.SDS{"node": state.Node.Id}, "connected")
state.Wait()
ctx.LogI("call-finish", nncp.SDS{
@@ -75,7 +78,7 @@ "txspeed": strconv.FormatInt(state.TxSpeed, 10),
}, "")
} else {
nodeId := "unknown"
- if state != nil && state.Node != nil {
+ if state.Node != nil {
nodeId = state.Node.Id.String()
}
ctx.LogE("call-start", nncp.SDS{"node": nodeId, "err": err}, "")
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go
index de1c06bad18f8d576e7fb6fa0d7c67d14aed0fbfa621f9748338dbed63047355..633c190ca7b25f2df4e417895728fe71ba2041f15f287d056d132bc763d03b22 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Send execution command via NNCP
+// Send execution command via NNCP.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-file/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-file/main.go
index b554dd1e35d3041b2b00fd953e7f44bbce3c71aac72e795dcb365f241c0e7e0c..d3ecc69d88bb3494cfb37e5f1c4397e047108341329a16a822e0d3287e06bccb 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-file/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-file/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Send file via NNCP
+// Send file via NNCP.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-freq/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-freq/main.go
index 4d9e64fc46318141363ebd63175670de1db3a76ff543934bb7624202a141921c..ca311ab4f2ead1d2146bc0dade8fc22b7abdabf4778b0b830f95fe78876160f7 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-freq/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-freq/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Send file request via NNCP
+// Send file request via NNCP.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-log/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-log/main.go
index b099be28957182276d7f7966169fe21731e22537e6eb38cd4f4a637ed11210eb..3f73bf778cf3e236dae424a1ac61d1aa442f90a2eae5df111d197721360cdcd3 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-log/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-log/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Read NNCP logs
+// Read NNCP logs.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go
index 3d9a8c89cd60e0a046900d2a8aeadbc6e32e74d7a3b1a462e22125c157316b15..abb04be7c8f374e9e1430cd9f5ea8876d93a25198e1ab5bd946ef4a5dfce2e15 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Parse raw NNCP packet
+// Parse raw NNCP packet.
package main
import (
@@ -31,7 +31,6 @@ "os"
"cypherpunks.ru/nncp"
"github.com/davecgh/go-xdr/xdr2"
- "golang.org/x/crypto/blake2b"
)
func usage() {
@@ -44,6 +43,7 @@ }
func main() {
var (
+ overheads = flag.Bool("overheads", false, "Print packet overheads")
dump = flag.Bool("dump", false, "Write decrypted/parsed payload to stdout")
decompress = flag.Bool("decompress", false, "Try to zlib decompress dumped data")
cfgPath = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
@@ -61,8 +61,18 @@ fmt.Println(nncp.VersionGet())
return
}
+ if *overheads {
+ fmt.Printf(
+ "Plain: %d\nEncrypted: %d\nSize: %d\n",
+ nncp.PktOverhead,
+ nncp.PktEncOverhead,
+ nncp.PktSizeOverhead,
+ )
+ return
+ }
+
var err error
- beginning := make([]byte, nncp.PktOverhead-8-2*blake2b.Size256)
+ beginning := make([]byte, nncp.PktOverhead)
if _, err = io.ReadFull(os.Stdin, beginning); err != nil {
log.Fatalln("Not enough data to read")
}
@@ -121,7 +131,7 @@ return
}
var pktEnc nncp.PktEnc
_, err = xdr.Unmarshal(bytes.NewReader(beginning), &pktEnc)
- if err == nil && pktEnc.Magic == nncp.MagicNNCPEv3 {
+ if err == nil && pktEnc.Magic == nncp.MagicNNCPEv4 {
if *dump {
ctx, err := nncp.CtxFromCmdline(*cfgPath, "", "", false, false)
if err != nil {
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-reass/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-reass/main.go
index a3bdda7e04865333c9a12e17791f58ecaac6b6d8c23b0aa66f0d81558e6ae027..636da54533599055d7262ccc7d8afc816e87904035b3bb1544e1460c3b90274c 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-reass/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-reass/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Send file via NNCP
+// Reassembly chunked file.
package main
import (
@@ -203,9 +203,13 @@ hasErrors = true
}
}
}
- dstW.Flush()
+ if err = dstW.Flush(); err != nil {
+ log.Fatalln("Can not flush:", err)
+ }
if tmp != nil {
- tmp.Sync()
+ if err = tmp.Sync(); err != nil {
+ log.Fatalln("Can not sync:", err)
+ }
tmp.Close()
}
ctx.LogD("nncp-reass", sds, "written")
@@ -316,10 +320,10 @@ os.Exit(1)
}
if flag.NArg() > 0 {
- if !process(ctx, flag.Arg(0), *keep, *dryRun, *stdout, *dumpMeta) {
- os.Exit(1)
+ if process(ctx, flag.Arg(0), *keep, *dryRun, *stdout, *dumpMeta) {
+ return
}
- return
+ os.Exit(1)
}
hasErrors := false
@@ -333,7 +337,9 @@ for _, metaPath := range findMetas(ctx, *node.Incoming) {
if _, seen := seenMetaPaths[metaPath]; seen {
continue
}
- hasErrors = hasErrors || !process(ctx, metaPath, *keep, *dryRun, false, false)
+ if !process(ctx, metaPath, *keep, *dryRun, false, false) {
+ hasErrors = true
+ }
seenMetaPaths[metaPath] = struct{}{}
}
}
@@ -342,7 +348,9 @@ if nodeOnly.Incoming == nil {
log.Fatalln("Specified -node does not allow incoming")
}
for _, metaPath := range findMetas(ctx, *nodeOnly.Incoming) {
- hasErrors = hasErrors || !process(ctx, metaPath, *keep, *dryRun, false, false)
+ if !process(ctx, metaPath, *keep, *dryRun, false, false) {
+ hasErrors = true
+ }
}
}
if hasErrors {
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-rm/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-rm/main.go
index 226613f85aadf10244f4e933c4fca2aa3b07f2bc53c261ca3615458d1cff9262..708f9ca5478e7d922ec1f1bc19ea2b91a6f167bac2d26c58380bf8dbc5a54e85 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-rm/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-rm/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Remove packet from the queue
+// Remove packet from the queue.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-stat/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-stat/main.go
index 89bf5899272e878e1d55c1c5ff3fe91fe26ed3f7ddd9c3303701ac957230c25e..41fd3a100631378d0ece93b2cb8840d6b7f4fe0adbcb142456d451b619038dd9 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-stat/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-stat/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Show queued NNCP Rx/Tx stats
+// Show queued NNCP Rx/Tx stats.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-toss/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-toss/main.go
index c57062ebf4f34615a0114d44b3cef2b54ef8cd20f9f6eacdffb377f199f00a48..33fca24c1e2ffebcfdc023af85120037882df9e60101d245e6c8471975a09252 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-toss/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-toss/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Process inbound NNCP packets
+// Process inbound NNCP packets.
package main
import (
diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-xfer/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-xfer/main.go
index 3b017bb5b768062294164329d14ca4b71536c1f33c284a8f2d00d0d7982e962c..3ee59490dd70875cdd5625d105a01a57fe2ee9bab12157f25f0c04b2bcfa63bc 100644
--- a/src/cypherpunks.ru/nncp/cmd/nncp-xfer/main.go
+++ b/src/cypherpunks.ru/nncp/cmd/nncp-xfer/main.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-// Copy NNCP inbound and outbounds packets
+// Exchange NNCP inbound and outbounds packets with external directory.
package main
import (
@@ -162,6 +162,7 @@ continue
}
filename := filepath.Join(dir.Name(), fiInt.Name())
sds["file"] = filename
+ delete(sds, "size")
fd, err := os.Open(filename)
if err != nil {
ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "open")
@@ -170,7 +171,7 @@ continue
}
var pktEnc nncp.PktEnc
_, err = xdr.Unmarshal(fd, &pktEnc)
- if err != nil || pktEnc.Magic != nncp.MagicNNCPEv3 {
+ if err != nil || pktEnc.Magic != nncp.MagicNNCPEv4 {
ctx.LogD("nncp-xfer", sds, "is not a packet")
fd.Close()
continue
@@ -180,13 +181,18 @@ ctx.LogD("nncp-xfer", sds, "too nice")
fd.Close()
continue
}
+ sds["size"] = strconv.FormatInt(fiInt.Size(), 10)
+ if !ctx.IsEnoughSpace(fiInt.Size()) {
+ ctx.LogE("nncp-xfer", sds, "is not enough space")
+ fd.Close()
+ continue
+ }
fd.Seek(0, 0)
tmp, err := ctx.NewTmpFileWHash()
if err != nil {
log.Fatalln(err)
}
- copied, err := io.Copy(tmp.W, bufio.NewReader(fd))
- if err != nil {
+ if _, err = io.CopyN(tmp.W, bufio.NewReader(fd), fiInt.Size()); err != nil {
ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "copy")
isBad = true
fd.Close()
@@ -201,9 +207,7 @@ string(nncp.TRx),
)); err != nil {
log.Fatalln(err)
}
- ctx.LogI("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{
- "size": strconv.FormatInt(copied, 10),
- }), "")
+ ctx.LogI("nncp-xfer", sds, "")
if !*keep {
if err = os.Remove(filename); err != nil {
ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "remove")
@@ -309,14 +313,19 @@ tmp.Close()
isBad = true
continue
}
- err = bufW.Flush()
- tmp.Sync()
- tmp.Close()
- if err != nil {
- ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "copy")
+ if err = bufW.Flush(); err != nil {
+ tmp.Close()
+ ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "flush")
+ isBad = true
+ continue
+ }
+ if err = tmp.Sync(); err != nil {
+ tmp.Close()
+ ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "sync")
isBad = true
continue
}
+ tmp.Close()
if err = os.Rename(tmp.Name(), filepath.Join(dstPath, pktName)); err != nil {
ctx.LogE("nncp-xfer", nncp.SdsAdd(sds, nncp.SDS{"err": err}), "rename")
isBad = true
diff --git a/src/cypherpunks.ru/nncp/ctx.go b/src/cypherpunks.ru/nncp/ctx.go
index fae4d3f1ead908398593b6e7db1ab133590d395a8ca0d67deb3a513a1597b9a7..0c292545c690e9e6f1d7afdd808990fd62808e4ae23db5b3eba2a1090e32ddbc 100644
--- a/src/cypherpunks.ru/nncp/ctx.go
+++ b/src/cypherpunks.ru/nncp/ctx.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -21,8 +21,11 @@
import (
"errors"
"io/ioutil"
+ "log"
"os"
"path/filepath"
+
+ "golang.org/x/sys/unix"
)
type Ctx struct {
@@ -103,3 +106,11 @@ ctx.Quiet = quiet
ctx.Debug = debug
return ctx, nil
}
+
+func (ctx *Ctx) IsEnoughSpace(want int64) bool {
+ var s unix.Statfs_t
+ if err := unix.Statfs(ctx.Spool, &s); err != nil {
+ log.Fatalln(err)
+ }
+ return s.Bavail*int64(s.Bsize) > want
+}
diff --git a/src/cypherpunks.ru/nncp/eblob.go b/src/cypherpunks.ru/nncp/eblob.go
index 5ba76923636b60d80aa2bcf65506fdcc9ea95bc0c7cfd87f23bdd215b851712c..6b63645804df4a8e1fa4f8dadfa5442f3ce6d179a5ebab16a6341bd92c2e4bf4 100644
--- a/src/cypherpunks.ru/nncp/eblob.go
+++ b/src/cypherpunks.ru/nncp/eblob.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -21,15 +21,12 @@
import (
"bytes"
"crypto/rand"
- "crypto/subtle"
- "errors"
"hash"
- "io"
- "chacha20"
"cypherpunks.ru/balloon"
"github.com/davecgh/go-xdr/xdr2"
"golang.org/x/crypto/blake2b"
+ "golang.org/x/crypto/chacha20poly1305"
)
const (
@@ -39,7 +36,7 @@ DefaultP = 2
)
var (
- MagicNNCPBv2 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 2}
+ MagicNNCPBv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 3}
)
type EBlob struct {
@@ -49,7 +46,6 @@ TCost uint32
PCost uint32
Salt *[32]byte
Blob []byte
- MAC *[blake2b.Size256]byte
}
func blake256() hash.Hash {
@@ -69,46 +65,31 @@ var err error
if _, err = rand.Read(salt[:]); err != nil {
return nil, err
}
- key := balloon.H(blake256, password, salt[:], sCost, tCost, pCost)
- kdf, err := blake2b.NewXOF(32+64, key)
- if err != nil {
- return nil, err
+ eblob := EBlob{
+ Magic: MagicNNCPBv3,
+ SCost: uint32(sCost),
+ TCost: uint32(tCost),
+ PCost: uint32(pCost),
+ Salt: salt,
+ Blob: nil,
}
- if _, err = kdf.Write(MagicNNCPBv2[:]); err != nil {
+ var eblobBuf bytes.Buffer
+ if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
return nil, err
}
- keyEnc := new([32]byte)
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
- return nil, err
- }
- keyAuth := make([]byte, 64)
- if _, err = io.ReadFull(kdf, keyAuth); err != nil {
- return nil, err
- }
- mac, err := blake2b.New256(keyAuth)
+ key := balloon.H(blake256, password, salt[:], sCost, tCost, pCost)
+ aead, err := chacha20poly1305.New(key)
if err != nil {
return nil, err
}
- chacha20.XORKeyStream(data, data, new([16]byte), keyEnc)
- if _, err = mac.Write(data); err != nil {
+ buf := make([]byte, 0, len(data)+aead.Overhead())
+ buf = aead.Seal(buf, make([]byte, aead.NonceSize()), data, eblobBuf.Bytes())
+ eblob.Blob = buf
+ eblobBuf.Reset()
+ if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
return nil, err
}
- macTag := new([blake2b.Size256]byte)
- mac.Sum(macTag[:0])
- eblob := EBlob{
- Magic: MagicNNCPBv2,
- SCost: uint32(sCost),
- TCost: uint32(tCost),
- PCost: uint32(pCost),
- Salt: salt,
- Blob: data,
- MAC: macTag,
- }
- var eblobRaw bytes.Buffer
- if _, err = xdr.Marshal(&eblobRaw, &eblob); err != nil {
- return nil, err
- }
- return eblobRaw.Bytes(), nil
+ return eblobBuf.Bytes(), nil
}
func DeEBlob(eblobRaw, password []byte) ([]byte, error) {
@@ -117,7 +98,7 @@ var err error
if _, err = xdr.Unmarshal(bytes.NewReader(eblobRaw), &eblob); err != nil {
return nil, err
}
- if eblob.Magic != MagicNNCPBv2 {
+ if eblob.Magic != MagicNNCPBv3 {
return nil, BadMagic
}
key := balloon.H(
@@ -128,31 +109,25 @@ int(eblob.SCost),
int(eblob.TCost),
int(eblob.PCost),
)
- kdf, err := blake2b.NewXOF(32+64, key)
+ aead, err := chacha20poly1305.New(key)
if err != nil {
return nil, err
}
- if _, err = kdf.Write(MagicNNCPBv2[:]); err != nil {
- return nil, err
- }
- keyEnc := new([32]byte)
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
- return nil, err
- }
- keyAuth := make([]byte, 64)
- if _, err = io.ReadFull(kdf, keyAuth); err != nil {
+
+ ciphertext := eblob.Blob
+ eblob.Blob = nil
+ var eblobBuf bytes.Buffer
+ if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
return nil, err
}
- mac, err := blake2b.New256(keyAuth)
+ data, err := aead.Open(
+ ciphertext[:0],
+ make([]byte, aead.NonceSize()),
+ ciphertext,
+ eblobBuf.Bytes(),
+ )
if err != nil {
return nil, err
}
- if _, err = mac.Write(eblob.Blob); err != nil {
- return nil, err
- }
- if subtle.ConstantTimeCompare(mac.Sum(nil), eblob.MAC[:]) != 1 {
- return nil, errors.New("Unauthenticated blob")
- }
- chacha20.XORKeyStream(eblob.Blob, eblob.Blob, new([16]byte), keyEnc)
- return eblob.Blob, nil
+ return data, nil
}
diff --git a/src/cypherpunks.ru/nncp/go.mod b/src/cypherpunks.ru/nncp/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c39492e9c56f686e78dced827a11c860fb82381fb1b53e22a6cfcf5098d32cbb
--- /dev/null
+++ b/src/cypherpunks.ru/nncp/go.mod
@@ -0,0 +1,15 @@
+module cypherpunks.ru/nncp
+
+require (
+ cypherpunks.ru/balloon v0.0.0-20190427214838-0e07700b0279
+ github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892
+ github.com/dustin/go-humanize v1.0.0
+ github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6
+ github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75
+ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734
+ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6
+ golang.org/x/sys v0.0.0-20190426135247-a129542de9ae
+ gopkg.in/yaml.v2 v2.2.2
+)
+
+replace cypherpunks.ru/balloon => git.cypherpunks.ru/balloon.git v0.0.0-20190427214838-0e07700b0279
diff --git a/src/cypherpunks.ru/nncp/go.sum b/src/cypherpunks.ru/nncp/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..3cf147169a2e914e6bb192b9698d013a54af600d5d565930627874061402e188
--- /dev/null
+++ b/src/cypherpunks.ru/nncp/go.sum
@@ -0,0 +1,25 @@
+git.cypherpunks.ru/balloon.git v0.0.0-20190427214838-0e07700b0279 h1:UtJj64EdBav9c3gXvDzuVhfKv0dSOUu/8rA709WRyBg=
+git.cypherpunks.ru/balloon.git v0.0.0-20190427214838-0e07700b0279/go.mod h1:MMNkZjNnjCkWMS+luQsSoSp6CCzhQiowH2uvfy5KgG8=
+github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892 h1:qg9VbHo1TlL0KDM0vYvBG9EY0X0Yku5WYIPoFWt8f6o=
+github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=
+github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
+github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=
+github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 h1:FP8hkuE6yUEaJnK7O2eTuejKWwW+Rhfj80dQ2JcKxCU=
+golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA=
+golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/src/cypherpunks.ru/nncp/humanizer.go b/src/cypherpunks.ru/nncp/humanizer.go
index d6f41e3f9a6e6e80ec107f9d52e0723857ffe4685836c8a32e6812bfac87ed86..e78569fdf25ffda78552df33b81dc2aea9b770a3ff9cd0c4cde9ececf27408f2 100644
--- a/src/cypherpunks.ru/nncp/humanizer.go
+++ b/src/cypherpunks.ru/nncp/humanizer.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -149,6 +149,8 @@ msg += fmt.Sprintf(" (%s)", size)
}
if err, exists := sds["err"]; exists {
msg += ": " + err
+ } else {
+ msg += " " + rem
}
case "nncp-bundle":
switch sds["xx"] {
@@ -196,6 +198,29 @@ nodeS,
humanize.IBytes(uint64(rx)), humanize.IBytes(uint64(rxs)),
humanize.IBytes(uint64(tx)), humanize.IBytes(uint64(txs)),
)
+ case "sp-info":
+ nice, err := NicenessParse(sds["nice"])
+ if err != nil {
+ return s
+ }
+ msg = fmt.Sprintf(
+ "Packet %s (%s) (nice %s)",
+ sds["hash"],
+ size,
+ NicenessFmt(nice),
+ )
+ offsetParsed, err := strconv.ParseUint(sds["offset"], 10, 64)
+ if err != nil {
+ return s
+ }
+ sizeParsed, err := strconv.ParseUint(sds["size"], 10, 64)
+ if err != nil {
+ return s
+ }
+ msg += fmt.Sprintf(": %d%%", 100*offsetParsed/sizeParsed)
+ if len(rem) > 0 {
+ msg += ": " + rem
+ }
case "sp-infos":
switch sds["xx"] {
case "rx":
@@ -206,6 +231,8 @@ default:
return s
}
msg += fmt.Sprintf("%s packets, %s", sds["pkts"], size)
+ case "sp-process":
+ msg = fmt.Sprintf("%s has %s (%s): %s", nodeS, sds["hash"], size, rem)
case "sp-file":
switch sds["xx"] {
case "rx":
diff --git a/src/cypherpunks.ru/nncp/jobs.go b/src/cypherpunks.ru/nncp/jobs.go
index 3313bfc7e350fce557d69b7d272ebd6c1891b51f8f729d0db8e0b45f0a4612a1..4d3ddd39b0525841e3bac6901f8cbfdd61c2ed0af2eaf78613fc37e176f56a2c 100644
--- a/src/cypherpunks.ru/nncp/jobs.go
+++ b/src/cypherpunks.ru/nncp/jobs.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -19,6 +19,7 @@
package nncp
import (
+ "io"
"os"
"path/filepath"
"strconv"
@@ -64,11 +65,11 @@ if err != nil {
continue
}
var pktEnc PktEnc
- if _, err = xdr.Unmarshal(fd, &pktEnc); err != nil || pktEnc.Magic != MagicNNCPEv3 {
+ if _, err = xdr.Unmarshal(fd, &pktEnc); err != nil || pktEnc.Magic != MagicNNCPEv4 {
fd.Close()
continue
}
- fd.Seek(0, 0)
+ fd.Seek(0, io.SeekStart)
ctx.LogD("jobs", SDS{
"xx": string(xx),
"node": pktEnc.Sender,
diff --git a/src/cypherpunks.ru/nncp/lockdir.go b/src/cypherpunks.ru/nncp/lockdir.go
index ec21c44ca509a09b52dd1093602da6feb87d1d172e3e190d2853539ad94d056f..7158dfcceba3627b341aecdbcc36daebfcf35c6e648379459683e539143a8bf9 100644
--- a/src/cypherpunks.ru/nncp/lockdir.go
+++ b/src/cypherpunks.ru/nncp/lockdir.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/log.go b/src/cypherpunks.ru/nncp/log.go
index c3b431b216fe0ee1e6ea5790d486cd04ff3c1f7aede29cef8899ada6ec2e93bc..42a2228a7288bff2a432d1a595878d936e46bca4941f8ffcc18e0b99e6e96bd9 100644
--- a/src/cypherpunks.ru/nncp/log.go
+++ b/src/cypherpunks.ru/nncp/log.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/nncp.go b/src/cypherpunks.ru/nncp/nncp.go
index 25e51e3d5a622616c4af1817bd35867709bf46b16b3aedfff522a7a79e7a01b1..1e6edfa286b3ea0de506c99f5034e2c8c30335d648d481486ed8770267c3abf1 100644
--- a/src/cypherpunks.ru/nncp/nncp.go
+++ b/src/cypherpunks.ru/nncp/nncp.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -48,7 +48,7 @@ }
func UsageHeader() string {
return VersionGet() + `
-Copyright (C) 2016-2017 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
diff --git a/src/cypherpunks.ru/nncp/node.go b/src/cypherpunks.ru/nncp/node.go
index 1fa20ab8fdbe0812fb6a1ec23e369ef256a2b7c950730e71ff465b99cc5a671c..5b5417253dd2dc7667bb2abce8aa8f7bb8f484725679915b72b86f97eb43a857 100644
--- a/src/cypherpunks.ru/nncp/node.go
+++ b/src/cypherpunks.ru/nncp/node.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/pkt.go b/src/cypherpunks.ru/nncp/pkt.go
index 7c057ab98fed5d90775b8640c0f2693645b47e6dd8c90a18505a5153c9f24999..4085a5856a8553d0de50834500cee6181c40bd01b26b09a923006e49d30e3868 100644
--- a/src/cypherpunks.ru/nncp/pkt.go
+++ b/src/cypherpunks.ru/nncp/pkt.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -20,25 +20,26 @@ package nncp
import (
"bytes"
+ "crypto/cipher"
"crypto/rand"
- "crypto/subtle"
"encoding/binary"
"errors"
"io"
- "chacha20"
"github.com/davecgh/go-xdr/xdr2"
"golang.org/x/crypto/blake2b"
+ "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"
)
type PktType uint8
const (
EncBlkSize = 128 * (1 << 10)
- KDFXOFSize = 2*(32+64) + 32
+ KDFXOFSize = chacha20poly1305.KeySize * 2
PktTypeFile PktType = iota
PktTypeFreq PktType = iota
@@ -52,12 +53,13 @@ )
var (
MagicNNCPPv2 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 2}
- MagicNNCPEv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 3}
+ MagicNNCPEv4 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 4}
BadMagic error = errors.New("Unknown magic number")
BadPktType error = errors.New("Unknown packet type")
- PktOverhead int64
- PktEncOverhead int64
+ PktOverhead int64
+ PktEncOverhead int64
+ PktSizeOverhead int64 = 8 + poly1305.TagSize
)
type Pkt struct {
@@ -95,7 +97,7 @@ n, err := xdr.Marshal(&buf, pkt)
if err != nil {
panic(err)
}
- PktOverhead = 8 + blake2b.Size256 + int64(n) + blake2b.Size256
+ PktOverhead = int64(n)
buf.Reset()
dummyId, err := NodeIdFromString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
@@ -103,7 +105,7 @@ if err != nil {
panic(err)
}
pktEnc := PktEnc{
- Magic: MagicNNCPEv3,
+ Magic: MagicNNCPEv4,
Nice: 123,
Sender: dummyId,
Recipient: dummyId,
@@ -132,42 +134,60 @@ copy(pkt.Path[:], path)
return &pkt, nil
}
-type DevZero struct{}
-
-func (d DevZero) Read(b []byte) (n int, err error) {
- for n = 0; n < len(b); n++ {
- b[n] = 0
- }
- return
-}
-
-func ae(keyEnc *[32]byte, r io.Reader, w io.Writer) (int, error) {
+func aeadProcess(
+ aead cipher.AEAD,
+ nonce []byte,
+ doEncrypt bool,
+ r io.Reader,
+ w io.Writer,
+) (int, error) {
var blkCtr uint64
- ciphNonce := new([16]byte)
- ciphCtr := ciphNonce[8:]
- buf := make([]byte, EncBlkSize)
+ ciphCtr := nonce[len(nonce)-8:]
+ buf := make([]byte, EncBlkSize+aead.Overhead())
+ var toRead []byte
+ var toWrite []byte
var n int
- var written int
+ var readBytes int
var err error
+ if doEncrypt {
+ toRead = buf[:EncBlkSize]
+ } else {
+ toRead = buf
+ }
for {
- n, err = io.ReadFull(r, buf)
+ n, err = io.ReadFull(r, toRead)
if err != nil {
if err == io.EOF {
break
}
if err != io.ErrUnexpectedEOF {
- return written + n, err
+ return readBytes + n, err
}
}
- written += n
+ readBytes += n
blkCtr++
binary.BigEndian.PutUint64(ciphCtr, blkCtr)
- chacha20.XORKeyStream(buf[:n], buf[:n], ciphNonce, keyEnc)
- if _, err = w.Write(buf[:n]); err != nil {
- return written, err
+ if doEncrypt {
+ toWrite = aead.Seal(buf[:0], nonce, buf[:n], nil)
+ } else {
+ toWrite, err = aead.Open(buf[:0], nonce, buf[:n], nil)
+ if err != nil {
+ return readBytes, err
+ }
+ }
+ if _, err = w.Write(toWrite); err != nil {
+ return readBytes, err
}
}
- return written, nil
+ return readBytes, nil
+}
+
+func sizeWithTags(size int64) (fullSize int64) {
+ fullSize = size + (size/EncBlkSize)*poly1305.TagSize
+ if size%EncBlkSize != 0 {
+ fullSize += poly1305.TagSize
+ }
+ return
}
func PktEncWrite(
@@ -177,7 +197,8 @@ pkt *Pkt,
nice uint8,
size, padSize int64,
data io.Reader,
- out io.Writer) error {
+ out io.Writer,
+) error {
pubEph, prvEph, err := box.GenerateKey(rand.Reader)
if err != nil {
return err
@@ -187,7 +208,7 @@ if _, err := xdr.Marshal(&pktBuf, pkt); err != nil {
return err
}
tbs := PktTbs{
- Magic: MagicNNCPEv3,
+ Magic: MagicNNCPEv4,
Nice: nice,
Sender: our.Id,
Recipient: their.Id,
@@ -200,7 +221,7 @@ }
signature := new([ed25519.SignatureSize]byte)
copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes()))
pktEnc := PktEnc{
- Magic: MagicNNCPEv3,
+ Magic: MagicNNCPEv4,
Nice: nice,
Sender: our.Id,
Recipient: their.Id,
@@ -216,71 +237,46 @@ kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:])
if err != nil {
return err
}
- if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil {
+ if _, err = kdf.Write(MagicNNCPEv4[:]); err != nil {
return err
}
- keyEnc := new([32]byte)
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
- return err
- }
- keyAuth := make([]byte, 64)
- if _, err = io.ReadFull(kdf, keyAuth); err != nil {
+ key := make([]byte, chacha20poly1305.KeySize)
+ if _, err = io.ReadFull(kdf, key); err != nil {
return err
}
- mac, err := blake2b.New256(keyAuth)
+ aead, err := chacha20poly1305.New(key)
if err != nil {
return err
}
+ nonce := make([]byte, aead.NonceSize())
- sizeBuf := make([]byte, 8)
- binary.BigEndian.PutUint64(sizeBuf, uint64(size))
- chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc)
- if _, err = out.Write(sizeBuf); err != nil {
- return err
- }
- if _, err = mac.Write(sizeBuf); err != nil {
- return err
- }
- if _, err = out.Write(mac.Sum(nil)); err != nil {
+ fullSize := pktBuf.Len() + int(size)
+ sizeBuf := make([]byte, 8+aead.Overhead())
+ binary.BigEndian.PutUint64(sizeBuf, uint64(sizeWithTags(int64(fullSize))))
+ if _, err = out.Write(aead.Seal(sizeBuf[:0], nonce, sizeBuf[:8], nil)); err != nil {
return err
}
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
- return err
- }
- if _, err = io.ReadFull(kdf, keyAuth); err != nil {
- return err
- }
- mac, err = blake2b.New256(keyAuth)
- if err != nil {
- return err
- }
lr := io.LimitedReader{R: data, N: size}
mr := io.MultiReader(&pktBuf, &lr)
- mw := io.MultiWriter(out, mac)
- fullSize := pktBuf.Len() + int(size)
- written, err := ae(keyEnc, mr, mw)
+ written, err := aeadProcess(aead, nonce, true, mr, out)
if err != nil {
return err
}
if written != fullSize {
return io.ErrUnexpectedEOF
- }
- if _, err = out.Write(mac.Sum(nil)); err != nil {
- return err
}
if padSize > 0 {
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
+ if _, err = io.ReadFull(kdf, key); err != nil {
return err
}
- lr = io.LimitedReader{R: DevZero{}, N: padSize}
- written, err = ae(keyEnc, &lr, out)
+ kdf, err = blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
if err != nil {
return err
}
- if written != int(padSize) {
- return io.ErrUnexpectedEOF
+ if _, err = io.CopyN(out, kdf, padSize); err != nil {
+ return err
}
}
return nil
@@ -288,7 +284,7 @@ }
func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) {
tbs := PktTbs{
- Magic: MagicNNCPEv3,
+ Magic: MagicNNCPEv4,
Nice: pktEnc.Nice,
Sender: their.Id,
Recipient: our.Id,
@@ -305,13 +301,14 @@ func PktEncRead(
our *NodeOur,
nodes map[NodeId]*Node,
data io.Reader,
- out io.Writer) (*Node, int64, error) {
+ out io.Writer,
+) (*Node, int64, error) {
var pktEnc PktEnc
_, err := xdr.Unmarshal(data, &pktEnc)
if err != nil {
return nil, 0, err
}
- if pktEnc.Magic != MagicNNCPEv3 {
+ if pktEnc.Magic != MagicNNCPEv4 {
return nil, 0, BadMagic
}
their, known := nodes[*pktEnc.Sender]
@@ -334,66 +331,37 @@ kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:])
if err != nil {
return their, 0, err
}
- if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil {
+ if _, err = kdf.Write(MagicNNCPEv4[:]); err != nil {
return their, 0, err
}
- keyEnc := new([32]byte)
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
+ key := make([]byte, chacha20poly1305.KeySize)
+ if _, err = io.ReadFull(kdf, key); err != nil {
return their, 0, err
}
- keyAuth := make([]byte, 64)
- if _, err = io.ReadFull(kdf, keyAuth); err != nil {
- return their, 0, err
- }
- mac, err := blake2b.New256(keyAuth)
+ aead, err := chacha20poly1305.New(key)
if err != nil {
return their, 0, err
}
+ nonce := make([]byte, aead.NonceSize())
- sizeBuf := make([]byte, 8)
+ sizeBuf := make([]byte, 8+aead.Overhead())
if _, err = io.ReadFull(data, sizeBuf); err != nil {
return their, 0, err
}
- if _, err = mac.Write(sizeBuf); err != nil {
- return their, 0, err
- }
- tag := make([]byte, blake2b.Size256)
- if _, err = io.ReadFull(data, tag); err != nil {
+ sizeBuf, err = aead.Open(sizeBuf[:0], nonce, sizeBuf, nil)
+ if err != nil {
return their, 0, err
}
- if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
- return their, 0, errors.New("Unauthenticated size")
- }
- chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc)
size := int64(binary.BigEndian.Uint64(sizeBuf))
- if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
- return their, size, err
- }
- if _, err = io.ReadFull(kdf, keyAuth); err != nil {
- return their, size, err
- }
- mac, err = blake2b.New256(keyAuth)
- if err != nil {
- return their, 0, err
- }
-
- fullSize := PktOverhead + size - 8 - 2*blake2b.Size256
- lr := io.LimitedReader{R: data, N: fullSize}
- tr := io.TeeReader(&lr, mac)
- written, err := ae(keyEnc, tr, out)
+ lr := io.LimitedReader{R: data, N: size}
+ written, err := aeadProcess(aead, nonce, false, &lr, out)
if err != nil {
return their, int64(written), err
}
- if written != int(fullSize) {
+ if written != int(size) {
return their, int64(written), io.ErrUnexpectedEOF
- }
- if _, err = io.ReadFull(data, tag); err != nil {
- return their, size, err
- }
- if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
- return their, size, errors.New("Unauthenticated payload")
}
return their, size, nil
}
diff --git a/src/cypherpunks.ru/nncp/pkt_test.go b/src/cypherpunks.ru/nncp/pkt_test.go
index aedb7d10b117f01654e127a6f45558b09da1398b05cafdf8fedc65d48664d5a9..f006b07f6f72e9594f264c34c91c28d036edb6e4af63d0bc94a787a012d60161 100644
--- a/src/cypherpunks.ru/nncp/pkt_test.go
+++ b/src/cypherpunks.ru/nncp/pkt_test.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -120,7 +120,7 @@ }
if *node.Id != *node1.Id {
return false
}
- if sizeGot != int64(size) {
+ if sizeGot != sizeWithTags(PktOverhead+int64(size)) {
return false
}
var pktBuf bytes.Buffer
diff --git a/src/cypherpunks.ru/nncp/sp.go b/src/cypherpunks.ru/nncp/sp.go
index d92302b2875b2641f3ee5dd5ef6bb10712a485e9c9704015657d23fd54b8ff16..43941c7678b24832d081168625933eb07c1ab6e13bdb1e497bbe5f5eb0a58a21 100644
--- a/src/cypherpunks.ru/nncp/sp.go
+++ b/src/cypherpunks.ru/nncp/sp.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -170,11 +170,11 @@ return outbounds
}
type SPState struct {
- ctx *Ctx
+ Ctx *Ctx
Node *Node
+ Nice uint8
onlineDeadline uint
maxOnlineTime uint
- nice uint8
hs *noise.HandshakeState
csOur *noise.CipherState
csTheir *noise.CipherState
@@ -197,6 +197,8 @@ xxOnly TRxTx
rxRate int
txRate int
isDead bool
+ listOnly bool
+ onlyPkts map[[32]byte]bool
sync.RWMutex
}
@@ -213,8 +215,8 @@ uint(now.Sub(state.TxLastSeen).Seconds()) >= state.onlineDeadline
}
func (state *SPState) dirUnlock() {
- state.ctx.UnlockDir(state.rxLock)
- state.ctx.UnlockDir(state.txLock)
+ state.Ctx.UnlockDir(state.rxLock)
+ state.Ctx.UnlockDir(state.txLock)
}
func (state *SPState) WriteSP(dst io.Writer, payload []byte) error {
@@ -280,68 +282,52 @@ }
return payloadsSplit(payloads)
}
-func (ctx *Ctx) StartI(
- conn ConnDeadlined,
- nodeId *NodeId,
- nice uint8,
- xxOnly TRxTx,
- rxRate, txRate int,
- onlineDeadline, maxOnlineTime uint) (*SPState, error) {
- err := ctx.ensureRxDir(nodeId)
+func (state *SPState) StartI(conn ConnDeadlined) error {
+ nodeId := state.Node.Id
+ err := state.Ctx.ensureRxDir(nodeId)
if err != nil {
- return nil, err
+ return err
}
var rxLock *os.File
- if xxOnly == "" || xxOnly == TRx {
- rxLock, err = ctx.LockDir(nodeId, TRx)
+ if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TRx) {
+ rxLock, err = state.Ctx.LockDir(nodeId, TRx)
if err != nil {
- return nil, err
+ return err
}
}
var txLock *os.File
- if xxOnly == "" || xxOnly == TTx {
- txLock, err = ctx.LockDir(nodeId, TTx)
+ if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TTx) {
+ txLock, err = state.Ctx.LockDir(nodeId, TTx)
if err != nil {
- return nil, err
+ return err
}
}
started := time.Now()
- node := ctx.Neigh[*nodeId]
conf := noise.Config{
CipherSuite: NoiseCipherSuite,
Pattern: noise.HandshakeIK,
Initiator: true,
StaticKeypair: noise.DHKey{
- Private: ctx.Self.NoisePrv[:],
- Public: ctx.Self.NoisePub[:],
+ Private: state.Ctx.Self.NoisePrv[:],
+ Public: state.Ctx.Self.NoisePub[:],
},
- PeerStatic: node.NoisePub[:],
+ PeerStatic: state.Node.NoisePub[:],
}
hs, err := noise.NewHandshakeState(conf)
if err != nil {
- return nil, err
- }
- state := SPState{
- ctx: ctx,
- hs: hs,
- Node: node,
- onlineDeadline: onlineDeadline,
- maxOnlineTime: maxOnlineTime,
- nice: nice,
- payloads: make(chan []byte),
- infosTheir: make(map[[32]byte]*SPInfo),
- infosOurSeen: make(map[[32]byte]uint8),
- started: started,
- rxLock: rxLock,
- txLock: txLock,
- xxOnly: xxOnly,
- rxRate: rxRate,
- txRate: txRate,
+ return err
}
+ state.hs = hs
+ state.payloads = make(chan []byte)
+ state.infosTheir = make(map[[32]byte]*SPInfo)
+ state.infosOurSeen = make(map[[32]byte]uint8)
+ state.started = started
+ state.rxLock = rxLock
+ state.txLock = txLock
var infosPayloads [][]byte
- if xxOnly == "" || xxOnly == TTx {
- infosPayloads = ctx.infosOur(nodeId, nice, &state.infosOurSeen)
+ if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TTx) {
+ infosPayloads = state.Ctx.infosOur(nodeId, state.Nice, &state.infosOurSeen)
}
var firstPayload []byte
if len(infosPayloads) > 0 {
@@ -357,122 +343,119 @@ var payload []byte
buf, _, _, err = state.hs.WriteMessage(nil, firstPayload)
if err != nil {
state.dirUnlock()
- return nil, err
+ return err
}
- sds := SDS{"node": nodeId, "nice": strconv.Itoa(int(nice))}
- ctx.LogD("sp-start", sds, "sending first message")
+ sds := SDS{"node": nodeId, "nice": strconv.Itoa(int(state.Nice))}
+ state.Ctx.LogD("sp-start", sds, "sending first message")
conn.SetWriteDeadline(time.Now().Add(DefaultDeadline * time.Second))
if err = state.WriteSP(conn, buf); err != nil {
- ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
state.dirUnlock()
- return nil, err
+ return err
}
- ctx.LogD("sp-start", sds, "waiting for first message")
+ state.Ctx.LogD("sp-start", sds, "waiting for first message")
conn.SetReadDeadline(time.Now().Add(DefaultDeadline * time.Second))
if buf, err = state.ReadSP(conn); err != nil {
- ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
state.dirUnlock()
- return nil, err
+ return err
}
payload, state.csOur, state.csTheir, err = state.hs.ReadMessage(nil, buf)
if err != nil {
- ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
state.dirUnlock()
- return nil, err
+ return err
}
- ctx.LogD("sp-start", sds, "starting workers")
+ state.Ctx.LogD("sp-start", sds, "starting workers")
err = state.StartWorkers(conn, infosPayloads, payload)
if err != nil {
- ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
state.dirUnlock()
- return nil, err
+ return err
}
- return &state, err
+ return err
}
-func (ctx *Ctx) StartR(conn ConnDeadlined, nice uint8, xxOnly TRxTx) (*SPState, error) {
+func (state *SPState) StartR(conn ConnDeadlined) error {
started := time.Now()
conf := noise.Config{
CipherSuite: NoiseCipherSuite,
Pattern: noise.HandshakeIK,
Initiator: false,
StaticKeypair: noise.DHKey{
- Private: ctx.Self.NoisePrv[:],
- Public: ctx.Self.NoisePub[:],
+ Private: state.Ctx.Self.NoisePrv[:],
+ Public: state.Ctx.Self.NoisePub[:],
},
}
hs, err := noise.NewHandshakeState(conf)
if err != nil {
- return nil, err
- }
- state := SPState{
- ctx: ctx,
- hs: hs,
- nice: nice,
- payloads: make(chan []byte),
- infosOurSeen: make(map[[32]byte]uint8),
- infosTheir: make(map[[32]byte]*SPInfo),
- started: started,
- xxOnly: xxOnly,
+ return err
}
+ xxOnly := TRxTx("")
+ state.hs = hs
+ state.payloads = make(chan []byte)
+ state.infosOurSeen = make(map[[32]byte]uint8)
+ state.infosTheir = make(map[[32]byte]*SPInfo)
+ state.started = started
+ state.xxOnly = xxOnly
var buf []byte
var payload []byte
- ctx.LogD(
+ state.Ctx.LogD(
"sp-start",
- SDS{"nice": strconv.Itoa(int(nice))},
+ SDS{"nice": strconv.Itoa(int(state.Nice))},
"waiting for first message",
)
conn.SetReadDeadline(time.Now().Add(DefaultDeadline * time.Second))
if buf, err = state.ReadSP(conn); err != nil {
- ctx.LogE("sp-start", SDS{"err": err}, "")
- return nil, err
+ state.Ctx.LogE("sp-start", SDS{"err": err}, "")
+ return err
}
if payload, _, _, err = state.hs.ReadMessage(nil, buf); err != nil {
- ctx.LogE("sp-start", SDS{"err": err}, "")
- return nil, err
+ state.Ctx.LogE("sp-start", SDS{"err": err}, "")
+ return err
}
var node *Node
- for _, node = range ctx.Neigh {
+ for _, node = range state.Ctx.Neigh {
if subtle.ConstantTimeCompare(state.hs.PeerStatic(), node.NoisePub[:]) == 1 {
break
}
}
if node == nil {
peerId := ToBase32(state.hs.PeerStatic())
- ctx.LogE("sp-start", SDS{"peer": peerId}, "unknown")
- return nil, errors.New("Unknown peer: " + peerId)
+ state.Ctx.LogE("sp-start", SDS{"peer": peerId}, "unknown")
+ return errors.New("Unknown peer: " + peerId)
}
state.Node = node
state.rxRate = node.RxRate
state.txRate = node.TxRate
state.onlineDeadline = node.OnlineDeadline
state.maxOnlineTime = node.MaxOnlineTime
- sds := SDS{"node": node.Id, "nice": strconv.Itoa(int(nice))}
+ sds := SDS{"node": node.Id, "nice": strconv.Itoa(int(state.Nice))}
- if ctx.ensureRxDir(node.Id); err != nil {
- return nil, err
+ if state.Ctx.ensureRxDir(node.Id); err != nil {
+ return err
}
var rxLock *os.File
if xxOnly == "" || xxOnly == TRx {
- rxLock, err = ctx.LockDir(node.Id, TRx)
+ rxLock, err = state.Ctx.LockDir(node.Id, TRx)
if err != nil {
- return nil, err
+ return err
}
}
state.rxLock = rxLock
var txLock *os.File
if xxOnly == "" || xxOnly == TTx {
- txLock, err = ctx.LockDir(node.Id, TTx)
+ txLock, err = state.Ctx.LockDir(node.Id, TTx)
if err != nil {
- return nil, err
+ return err
}
}
state.txLock = txLock
var infosPayloads [][]byte
if xxOnly == "" || xxOnly == TTx {
- infosPayloads = ctx.infosOur(node.Id, nice, &state.infosOurSeen)
+ infosPayloads = state.Ctx.infosOur(node.Id, state.Nice, &state.infosOurSeen)
}
var firstPayload []byte
if len(infosPayloads) > 0 {
@@ -483,36 +466,36 @@ for i := 0; i < (MaxSPSize-len(firstPayload))/SPHeadOverhead; i++ {
firstPayload = append(firstPayload, SPHaltMarshalized...)
}
- ctx.LogD("sp-start", sds, "sending first message")
+ state.Ctx.LogD("sp-start", sds, "sending first message")
buf, state.csTheir, state.csOur, err = state.hs.WriteMessage(nil, firstPayload)
if err != nil {
state.dirUnlock()
- return nil, err
+ return err
}
conn.SetWriteDeadline(time.Now().Add(DefaultDeadline * time.Second))
if err = state.WriteSP(conn, buf); err != nil {
- ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-start", SdsAdd(sds, SDS{"err": err}), "")
state.dirUnlock()
- return nil, err
+ return err
}
- ctx.LogD("sp-start", sds, "starting workers")
+ state.Ctx.LogD("sp-start", sds, "starting workers")
err = state.StartWorkers(conn, infosPayloads, payload)
if err != nil {
state.dirUnlock()
- return nil, err
+ return err
}
- return &state, err
+ return err
}
func (state *SPState) StartWorkers(
conn ConnDeadlined,
infosPayloads [][]byte,
payload []byte) error {
- sds := SDS{"node": state.Node.Id, "nice": strconv.Itoa(int(state.nice))}
+ sds := SDS{"node": state.Node.Id, "nice": strconv.Itoa(int(state.Nice))}
if len(infosPayloads) > 1 {
go func() {
for _, payload := range infosPayloads[1:] {
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-work",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"queuing remaining payload",
@@ -521,20 +504,20 @@ state.payloads <- payload
}
}()
}
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-work",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"processing first payload",
)
replies, err := state.ProcessSP(payload)
if err != nil {
- state.ctx.LogE("sp-work", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-work", SdsAdd(sds, SDS{"err": err}), "")
return err
}
go func() {
for _, reply := range replies {
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-work",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(reply))}),
"queuing reply",
@@ -543,15 +526,18 @@ state.payloads <- reply
}
}()
- if state.xxOnly == "" || state.xxOnly == TTx {
+ if !state.listOnly && (state.xxOnly == "" || state.xxOnly == TTx) {
go func() {
for range time.Tick(time.Second) {
- for _, payload := range state.ctx.infosOur(
+ if state.NotAlive() {
+ return
+ }
+ for _, payload := range state.Ctx.infosOur(
state.Node.Id,
- state.nice,
+ state.Nice,
&state.infosOurSeen,
) {
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-work",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"queuing new info",
@@ -575,7 +561,7 @@ }
var payload []byte
select {
case payload = <-state.payloads:
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-xmit",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"got payload",
@@ -585,7 +571,7 @@ }
if payload == nil {
state.RLock()
if len(state.queueTheir) == 0 {
- state.ctx.LogD("sp-xmit", sds, "file queue is empty")
+ state.Ctx.LogD("sp-xmit", sds, "file queue is empty")
state.RUnlock()
time.Sleep(100 * time.Millisecond)
continue
@@ -602,38 +588,38 @@ "xx": string(TTx),
"hash": ToBase32(freq.Hash[:]),
"size": strconv.FormatInt(int64(freq.Offset), 10),
})
- state.ctx.LogD("sp-file", sdsp, "queueing")
+ state.Ctx.LogD("sp-file", sdsp, "queueing")
fd, err := os.Open(filepath.Join(
- state.ctx.Spool,
+ state.Ctx.Spool,
state.Node.Id.String(),
string(TTx),
ToBase32(freq.Hash[:]),
))
if err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
break
}
fi, err := fd.Stat()
if err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
break
}
fullSize := uint64(fi.Size())
var buf []byte
if freq.Offset < fullSize {
- state.ctx.LogD("sp-file", sdsp, "seeking")
- if _, err = fd.Seek(int64(freq.Offset), 0); err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogD("sp-file", sdsp, "seeking")
+ if _, err = fd.Seek(int64(freq.Offset), io.SeekStart); err != nil {
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
break
}
buf = make([]byte, MaxSPSize-SPHeadOverhead-SPFileOverhead)
n, err := fd.Read(buf)
if err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
break
}
buf = buf[:n]
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-file",
SdsAdd(sdsp, SDS{"size": strconv.Itoa(n)}),
"read",
@@ -648,11 +634,11 @@ })
ourSize := freq.Offset + uint64(len(buf))
sdsp["size"] = strconv.FormatInt(int64(ourSize), 10)
sdsp["fullsize"] = strconv.FormatInt(int64(fullSize), 10)
- state.ctx.LogP("sp-file", sdsp, "")
+ state.Ctx.LogP("sp-file", sdsp, "")
state.Lock()
if len(state.queueTheir) > 0 && *state.queueTheir[0].freq.Hash == *freq.Hash {
if ourSize == fullSize {
- state.ctx.LogD("sp-file", sdsp, "finished")
+ state.Ctx.LogD("sp-file", sdsp, "finished")
if len(state.queueTheir) > 1 {
state.queueTheir = state.queueTheir[1:]
} else {
@@ -662,18 +648,18 @@ } else {
state.queueTheir[0].freq.Offset += uint64(len(buf))
}
} else {
- state.ctx.LogD("sp-file", sdsp, "queue disappeared")
+ state.Ctx.LogD("sp-file", sdsp, "queue disappeared")
}
state.Unlock()
}
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-xmit",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"sending",
)
conn.SetWriteDeadline(time.Now().Add(DefaultDeadline * time.Second))
if err := state.WriteSP(conn, state.csOur.Encrypt(nil, nil, payload)); err != nil {
- state.ctx.LogE("sp-xmit", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-xmit", SdsAdd(sds, SDS{"err": err}), "")
break
}
}
@@ -689,7 +675,7 @@ for {
if state.NotAlive() {
return
}
- state.ctx.LogD("sp-recv", sds, "waiting for payload")
+ state.Ctx.LogD("sp-recv", sds, "waiting for payload")
conn.SetReadDeadline(time.Now().Add(DefaultDeadline * time.Second))
payload, err := state.ReadSP(conn)
if err != nil {
@@ -701,32 +687,32 @@ }
if unmarshalErr.ErrorCode == xdr.ErrIO {
break
}
- state.ctx.LogE("sp-recv", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-recv", SdsAdd(sds, SDS{"err": err}), "")
break
}
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-recv",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"got payload",
)
payload, err = state.csTheir.Decrypt(nil, nil, payload)
if err != nil {
- state.ctx.LogE("sp-recv", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-recv", SdsAdd(sds, SDS{"err": err}), "")
break
}
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-recv",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(payload))}),
"processing",
)
replies, err := state.ProcessSP(payload)
if err != nil {
- state.ctx.LogE("sp-recv", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-recv", SdsAdd(sds, SDS{"err": err}), "")
break
}
go func() {
for _, reply := range replies {
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-recv",
SdsAdd(sds, SDS{"size": strconv.Itoa(len(reply))}),
"queuing reply",
@@ -760,123 +746,129 @@ }
}
func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) {
- sds := SDS{"node": state.Node.Id, "nice": strconv.Itoa(int(state.nice))}
+ sds := SDS{"node": state.Node.Id, "nice": strconv.Itoa(int(state.Nice))}
r := bytes.NewReader(payload)
var err error
var replies [][]byte
var infosGot bool
for r.Len() > 0 {
- state.ctx.LogD("sp-process", sds, "unmarshaling header")
+ state.Ctx.LogD("sp-process", sds, "unmarshaling header")
var head SPHead
if _, err = xdr.Unmarshal(r, &head); err != nil {
- state.ctx.LogE("sp-process", SdsAdd(sds, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-process", SdsAdd(sds, SDS{"err": err}), "")
return nil, err
}
switch head.Type {
case SPTypeInfo:
infosGot = true
sdsp := SdsAdd(sds, SDS{"type": "info"})
- state.ctx.LogD("sp-process", sdsp, "unmarshaling packet")
+ state.Ctx.LogD("sp-process", sdsp, "unmarshaling packet")
var info SPInfo
if _, err = xdr.Unmarshal(r, &info); err != nil {
- state.ctx.LogE("sp-process", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-process", SdsAdd(sdsp, SDS{"err": err}), "")
return nil, err
}
sdsp = SdsAdd(sds, SDS{
"hash": ToBase32(info.Hash[:]),
"size": strconv.FormatInt(int64(info.Size), 10),
+ "nice": strconv.Itoa(int(info.Nice)),
})
- if info.Nice > state.nice {
- state.ctx.LogD("sp-process", sdsp, "too nice")
+ if !state.listOnly && info.Nice > state.Nice {
+ state.Ctx.LogD("sp-process", sdsp, "too nice")
continue
}
- state.ctx.LogD("sp-process", sdsp, "received")
- if state.xxOnly == TTx {
+ state.Ctx.LogD("sp-process", sdsp, "received")
+ if !state.listOnly && state.xxOnly == TTx {
continue
}
state.Lock()
state.infosTheir[*info.Hash] = &info
state.Unlock()
- state.ctx.LogD("sp-process", sdsp, "stating part")
+ state.Ctx.LogD("sp-process", sdsp, "stating part")
pktPath := filepath.Join(
- state.ctx.Spool,
+ state.Ctx.Spool,
state.Node.Id.String(),
string(TRx),
ToBase32(info.Hash[:]),
)
if _, err = os.Stat(pktPath); err == nil {
- state.ctx.LogD("sp-process", sdsp, "already done")
- replies = append(replies, MarshalSP(SPTypeDone, SPDone{info.Hash}))
+ state.Ctx.LogI("sp-info", sdsp, "already done")
+ if !state.listOnly {
+ replies = append(replies, MarshalSP(SPTypeDone, SPDone{info.Hash}))
+ }
continue
}
if _, err = os.Stat(pktPath + SeenSuffix); err == nil {
- state.ctx.LogD("sp-process", sdsp, "already seen")
- replies = append(replies, MarshalSP(SPTypeDone, SPDone{info.Hash}))
+ state.Ctx.LogI("sp-info", sdsp, "already seen")
+ if !state.listOnly {
+ replies = append(replies, MarshalSP(SPTypeDone, SPDone{info.Hash}))
+ }
continue
}
fi, err := os.Stat(pktPath + PartSuffix)
var offset int64
if err == nil {
offset = fi.Size()
- state.ctx.LogD(
- "sp-process",
- SdsAdd(sdsp, SDS{"offset": strconv.FormatInt(offset, 10)}),
- "part exists",
- )
+ }
+ if !state.Ctx.IsEnoughSpace(int64(info.Size) - offset) {
+ state.Ctx.LogI("sp-info", sdsp, "not enough space")
+ continue
+ }
+ state.Ctx.LogI(
+ "sp-info",
+ SdsAdd(sdsp, SDS{"offset": strconv.FormatInt(offset, 10)}),
+ "",
+ )
+ if !state.listOnly && (state.onlyPkts == nil || state.onlyPkts[*info.Hash]) {
+ replies = append(replies, MarshalSP(
+ SPTypeFreq,
+ SPFreq{info.Hash, uint64(offset)},
+ ))
}
- replies = append(replies, MarshalSP(
- SPTypeFreq,
- SPFreq{info.Hash, uint64(offset)},
- ))
case SPTypeFile:
- state.ctx.LogD(
- "sp-process",
- SdsAdd(sds, SDS{"type": "file"}),
- "unmarshaling packet",
- )
+ sdsp := SdsAdd(sds, SDS{"type": "file"})
+ state.Ctx.LogD("sp-process", sdsp, "unmarshaling packet")
var file SPFile
if _, err = xdr.Unmarshal(r, &file); err != nil {
- state.ctx.LogE("sp-process", SdsAdd(sds, SDS{
+ state.Ctx.LogE("sp-process", SdsAdd(sds, SDS{
"err": err,
"type": "file",
}), "")
return nil, err
}
- sdsp := SdsAdd(sds, SDS{
- "xx": string(TRx),
- "hash": ToBase32(file.Hash[:]),
- "size": strconv.Itoa(len(file.Payload)),
- })
+ sdsp["xx"] = string(TRx)
+ sdsp["hash"] = ToBase32(file.Hash[:])
+ sdsp["size"] = strconv.Itoa(len(file.Payload))
filePath := filepath.Join(
- state.ctx.Spool,
+ state.Ctx.Spool,
state.Node.Id.String(),
string(TRx),
ToBase32(file.Hash[:]),
)
- state.ctx.LogD("sp-file", sdsp, "opening part")
+ state.Ctx.LogD("sp-file", sdsp, "opening part")
fd, err := os.OpenFile(
filePath+PartSuffix,
os.O_RDWR|os.O_CREATE,
os.FileMode(0600),
)
if err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
return nil, err
}
- state.ctx.LogD(
+ state.Ctx.LogD(
"sp-file",
SdsAdd(sdsp, SDS{"offset": strconv.FormatInt(int64(file.Offset), 10)}),
"seeking",
)
- if _, err = fd.Seek(int64(file.Offset), 0); err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ if _, err = fd.Seek(int64(file.Offset), io.SeekStart); err != nil {
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
fd.Close()
return nil, err
}
- state.ctx.LogD("sp-file", sdsp, "writing")
+ state.Ctx.LogD("sp-file", sdsp, "writing")
_, err = fd.Write(file.Payload)
if err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "")
fd.Close()
return nil, err
}
@@ -884,7 +876,7 @@ ourSize := uint64(file.Offset) + uint64(len(file.Payload))
state.RLock()
sdsp["fullsize"] = strconv.FormatInt(int64(state.infosTheir[*file.Hash].Size), 10)
sdsp["size"] = strconv.FormatInt(int64(ourSize), 10)
- state.ctx.LogP("sp-file", sdsp, "")
+ state.Ctx.LogP("sp-file", sdsp, "")
if state.infosTheir[*file.Hash].Size != ourSize {
state.RUnlock()
fd.Close()
@@ -895,21 +887,21 @@ spWorkersGroup.Wait()
spWorkersGroup.Add(1)
go func() {
if err := fd.Sync(); err != nil {
- state.ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "sync")
+ state.Ctx.LogE("sp-file", SdsAdd(sdsp, SDS{"err": err}), "sync")
fd.Close()
return
}
state.wg.Add(1)
defer state.wg.Done()
- fd.Seek(0, 0)
- state.ctx.LogD("sp-file", sdsp, "checking")
+ fd.Seek(0, io.SeekStart)
+ state.Ctx.LogD("sp-file", sdsp, "checking")
gut, err := Check(fd, file.Hash[:])
fd.Close()
if err != nil || !gut {
- state.ctx.LogE("sp-file", sdsp, "checksum mismatch")
+ state.Ctx.LogE("sp-file", sdsp, "checksum mismatch")
return
}
- state.ctx.LogI("sp-done", SdsAdd(sdsp, SDS{"xx": string(TRx)}), "")
+ state.Ctx.LogI("sp-done", SdsAdd(sdsp, SDS{"xx": string(TRx)}), "")
os.Rename(filePath+PartSuffix, filePath)
state.Lock()
delete(state.infosTheir, *file.Hash)
@@ -920,72 +912,69 @@ state.payloads <- MarshalSP(SPTypeDone, SPDone{file.Hash})
}()
}()
case SPTypeDone:
- state.ctx.LogD(
- "sp-process",
- SdsAdd(sds, SDS{"type": "done"}),
- "unmarshaling packet",
- )
+ sdsp := SdsAdd(sds, SDS{"type": "done"})
+ state.Ctx.LogD("sp-process", sdsp, "unmarshaling packet")
var done SPDone
if _, err = xdr.Unmarshal(r, &done); err != nil {
- state.ctx.LogE("sp-process", SdsAdd(sds, SDS{
+ state.Ctx.LogE("sp-process", SdsAdd(sds, SDS{
"type": "done",
"err": err,
}), "")
return nil, err
}
- sdsp := SdsAdd(sds, SDS{"hash": ToBase32(done.Hash[:])})
- state.ctx.LogD("sp-done", sdsp, "removing")
+ sdsp["hash"] = ToBase32(done.Hash[:])
+ state.Ctx.LogD("sp-done", sdsp, "removing")
err := os.Remove(filepath.Join(
- state.ctx.Spool,
+ state.Ctx.Spool,
state.Node.Id.String(),
string(TTx),
ToBase32(done.Hash[:]),
))
+ sdsp["xx"] = string(TTx)
if err == nil {
- state.ctx.LogI("sp-done", SdsAdd(sdsp, SDS{"xx": string(TTx)}), "")
+ state.Ctx.LogI("sp-done", sdsp, "")
} else {
- state.ctx.LogE("sp-done", SdsAdd(sdsp, SDS{"xx": string(TTx)}), "")
+ state.Ctx.LogE("sp-done", sdsp, "")
}
case SPTypeFreq:
sdsp := SdsAdd(sds, SDS{"type": "freq"})
- state.ctx.LogD("sp-process", sdsp, "unmarshaling packet")
+ state.Ctx.LogD("sp-process", sdsp, "unmarshaling packet")
var freq SPFreq
if _, err = xdr.Unmarshal(r, &freq); err != nil {
- state.ctx.LogE("sp-process", SdsAdd(sdsp, SDS{"err": err}), "")
+ state.Ctx.LogE("sp-process", SdsAdd(sdsp, SDS{"err": err}), "")
return nil, err
}
- state.ctx.LogD("sp-process", SdsAdd(sdsp, SDS{
- "hash": ToBase32(freq.Hash[:]),
- "offset": strconv.FormatInt(int64(freq.Offset), 10),
- }), "queueing")
+ sdsp["hash"] = ToBase32(freq.Hash[:])
+ sdsp["offset"] = strconv.FormatInt(int64(freq.Offset), 10)
+ state.Ctx.LogD("sp-process", sdsp, "queueing")
nice, exists := state.infosOurSeen[*freq.Hash]
if exists {
- state.Lock()
- insertIdx := 0
- var freqWithNice *FreqWithNice
- for insertIdx, freqWithNice = range state.queueTheir {
- if freqWithNice.nice > nice {
- break
+ if state.onlyPkts == nil || !state.onlyPkts[*freq.Hash] {
+ state.Lock()
+ insertIdx := 0
+ var freqWithNice *FreqWithNice
+ for insertIdx, freqWithNice = range state.queueTheir {
+ if freqWithNice.nice > nice {
+ break
+ }
}
+ state.queueTheir = append(state.queueTheir, nil)
+ copy(state.queueTheir[insertIdx+1:], state.queueTheir[insertIdx:])
+ state.queueTheir[insertIdx] = &FreqWithNice{&freq, nice}
+ state.Unlock()
+ } else {
+ state.Ctx.LogD("sp-process", sdsp, "skipping")
}
- state.queueTheir = append(state.queueTheir, nil)
- copy(state.queueTheir[insertIdx+1:], state.queueTheir[insertIdx:])
- state.queueTheir[insertIdx] = &FreqWithNice{&freq, nice}
- state.Unlock()
} else {
- state.ctx.LogD("sp-process", SdsAdd(sdsp, SDS{
- "hash": ToBase32(freq.Hash[:]),
- "offset": strconv.FormatInt(int64(freq.Offset), 10),
- }), "unknown")
+ state.Ctx.LogD("sp-process", sdsp, "unknown")
}
case SPTypeHalt:
- sdsp := SdsAdd(sds, SDS{"type": "halt"})
- state.ctx.LogD("sp-process", sdsp, "")
+ state.Ctx.LogD("sp-process", SdsAdd(sds, SDS{"type": "halt"}), "")
state.Lock()
state.queueTheir = nil
state.Unlock()
default:
- state.ctx.LogE(
+ state.Ctx.LogE(
"sp-process",
SdsAdd(sds, SDS{"type": head.Type}),
"unknown",
@@ -1002,7 +991,7 @@ pkts++
size += info.Size
}
state.RUnlock()
- state.ctx.LogI("sp-infos", SDS{
+ state.Ctx.LogI("sp-infos", SDS{
"xx": string(TRx),
"node": state.Node.Id,
"pkts": strconv.Itoa(pkts),
diff --git a/src/cypherpunks.ru/nncp/tmp.go b/src/cypherpunks.ru/nncp/tmp.go
index 4d6f0623603b85cdf955ba1666bc40bf437edc7a22bad46db66f22ee483983e6..14325c1d01b283166af762161479e39528e27287b967f69efcc931f396316714 100644
--- a/src/cypherpunks.ru/nncp/tmp.go
+++ b/src/cypherpunks.ru/nncp/tmp.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/toss.go b/src/cypherpunks.ru/nncp/toss.go
index 0465c1ec56f55857a6f9be5d32e2ed529e183d64a11f5933a4602b41c0ed65e5..a8664d437621f851a69b6d5032e7907490d26455a533cd723e1451e711b82265 100644
--- a/src/cypherpunks.ru/nncp/toss.go
+++ b/src/cypherpunks.ru/nncp/toss.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -37,6 +37,7 @@
"github.com/davecgh/go-xdr/xdr2"
"github.com/dustin/go-humanize"
"golang.org/x/crypto/blake2b"
+ "golang.org/x/crypto/poly1305"
)
const (
@@ -55,7 +56,8 @@
func (ctx *Ctx) Toss(
nodeId *NodeId,
nice uint8,
- dryRun, doSeen, noFile, noFreq, noExec, noTrns bool) bool {
+ dryRun, doSeen, noFile, noFreq, noExec, noTrns bool,
+) bool {
isBad := false
for job := range ctx.Jobs(nodeId, TRx) {
pktName := filepath.Base(job.Fd.Name())
@@ -87,12 +89,18 @@ }(job)
var pkt Pkt
var err error
var pktSize int64
+ var pktSizeBlocks int64
if _, err = xdr.Unmarshal(pipeR, &pkt); err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "unmarshal")
isBad = true
goto Closing
}
- pktSize = job.Size - PktEncOverhead - PktOverhead
+ pktSize = job.Size - PktEncOverhead - PktOverhead - PktSizeOverhead
+ pktSizeBlocks = pktSize / (EncBlkSize + poly1305.TagSize)
+ if pktSize%(EncBlkSize+poly1305.TagSize) != 0 {
+ pktSize -= poly1305.TagSize
+ }
+ pktSize -= pktSizeBlocks * poly1305.TagSize
sds["size"] = strconv.FormatInt(pktSize, 10)
ctx.LogD("rx", sds, "taken")
switch pkt.Type {
@@ -176,21 +184,31 @@ goto Closing
}
if !dryRun {
tmp, err := ioutil.TempFile(dir, "nncp-file")
- sds["tmp"] = tmp.Name()
- ctx.LogD("rx", sds, "created")
if err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "mktemp")
isBad = true
goto Closing
}
+ sds["tmp"] = tmp.Name()
+ ctx.LogD("rx", sds, "created")
bufW := bufio.NewWriter(tmp)
if _, err = io.Copy(bufW, pipeR); err != nil {
ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "copy")
isBad = true
goto Closing
}
- bufW.Flush()
- tmp.Sync()
+ if err = bufW.Flush(); err != nil {
+ tmp.Close()
+ ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "copy")
+ isBad = true
+ goto Closing
+ }
+ if err = tmp.Sync(); err != nil {
+ tmp.Close()
+ ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "copy")
+ isBad = true
+ goto Closing
+ }
tmp.Close()
dstPathOrig := filepath.Join(*incoming, dst)
dstPath := dstPathOrig
diff --git a/src/cypherpunks.ru/nncp/toss_test.go b/src/cypherpunks.ru/nncp/toss_test.go
index cb763838a67fd4bbc6cde49f2ec73e06fb606fb5299ad204de4020d6a60c53ff..5a64475c4f0e9eae9154f0275d73981bd313e5d8dd7b365113a1163004c3526b 100644
--- a/src/cypherpunks.ru/nncp/toss_test.go
+++ b/src/cypherpunks.ru/nncp/toss_test.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/tx.go b/src/cypherpunks.ru/nncp/tx.go
index d3535b296e0a79498e0e8e5059832829314c741b1d5d1a4ba22a797345d3af23..9296a40a0cd64175c93e58ffca64c513388a08850b1bd66673ccd79f1f2f7c1b 100644
--- a/src/cypherpunks.ru/nncp/tx.go
+++ b/src/cypherpunks.ru/nncp/tx.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
@@ -34,6 +34,7 @@ "strings"
"github.com/davecgh/go-xdr/xdr2"
"golang.org/x/crypto/blake2b"
+ "golang.org/x/crypto/chacha20poly1305"
)
func (ctx *Ctx) Tx(
@@ -41,7 +42,8 @@ node *Node,
pkt *Pkt,
nice uint8,
size, minSize int64,
- src io.Reader) (*Node, error) {
+ src io.Reader,
+) (*Node, error) {
tmp, err := ctx.NewTmpFileWHash()
if err != nil {
return nil, err
@@ -53,7 +55,11 @@ for i := len(node.Via); i > 0; i-- {
lastNode = ctx.Neigh[*node.Via[i-1]]
hops = append(hops, lastNode)
}
- padSize := minSize - size - int64(len(hops))*(PktOverhead+PktEncOverhead)
+ expectedSize := size
+ for i := 0; i < len(hops); i++ {
+ expectedSize = PktEncOverhead + PktSizeOverhead + sizeWithTags(PktOverhead+expectedSize)
+ }
+ padSize := minSize - expectedSize
if padSize < 0 {
padSize = 0
}
@@ -69,12 +75,11 @@ }, "wrote")
errs <- PktEncWrite(ctx.Self, hops[0], pkt, nice, size, padSize, src, dst)
dst.Close()
}(curSize, src, pipeW)
- curSize += padSize
+ curSize = PktEncOverhead + PktSizeOverhead + sizeWithTags(PktOverhead+curSize) + padSize
var pipeRPrev io.Reader
for i := 1; i < len(hops); i++ {
pktTrns, _ := NewPkt(PktTypeTrns, 0, hops[i-1].Id[:])
- curSize += PktOverhead + PktEncOverhead
pipeRPrev = pipeR
pipeR, pipeW = io.Pipe()
go func(node *Node, pkt *Pkt, size int64, src io.Reader, dst io.WriteCloser) {
@@ -86,6 +91,7 @@ }, "trns wrote")
errs <- PktEncWrite(ctx.Self, node, pkt, nice, size, 0, src, dst)
dst.Close()
}(hops[i], pktTrns, curSize, pipeRPrev, pipeW)
+ curSize = PktEncOverhead + PktSizeOverhead + sizeWithTags(PktOverhead+curSize)
}
go func() {
_, err := io.Copy(tmp.W, pipeR)
@@ -116,19 +122,30 @@ return nil, nil, 0, err
}
os.Remove(src.Name())
tmpW := bufio.NewWriter(src)
- tmpKey := new([32]byte)
+ tmpKey := make([]byte, chacha20poly1305.KeySize)
if _, err = rand.Read(tmpKey[:]); err != nil {
return nil, nil, 0, err
}
- written, err := ae(tmpKey, bufio.NewReader(os.Stdin), tmpW)
+ aead, err := chacha20poly1305.New(tmpKey)
+ if err != nil {
+ return nil, nil, 0, err
+ }
+ nonce := make([]byte, aead.NonceSize())
+ written, err := aeadProcess(aead, nonce, true, bufio.NewReader(os.Stdin), tmpW)
if err != nil {
return nil, nil, 0, err
}
fileSize = int64(written)
- tmpW.Flush()
- src.Seek(0, 0)
+ if err = tmpW.Flush(); err != nil {
+ return nil, nil, 0, err
+ }
+ src.Seek(0, io.SeekStart)
r, w := io.Pipe()
- go ae(tmpKey, bufio.NewReader(src), w)
+ go func() {
+ if _, err := aeadProcess(aead, nonce, false, bufio.NewReader(src), w); err != nil {
+ panic(err)
+ }
+ }()
reader = r
} else {
src, err = os.Open(srcPath)
@@ -190,7 +207,8 @@ node *Node,
nice uint8,
srcPath, dstPath string,
minSize int64,
- chunkSize int64) error {
+ chunkSize int64,
+) error {
if dstPath == "" {
if srcPath == "-" {
return errors.New("Must provide destination filename")
@@ -365,7 +383,8 @@ nice, replyNice uint8,
handle string,
args []string,
body []byte,
- minSize int64) error {
+ minSize int64,
+) error {
path := make([][]byte, 0, 1+len(args))
path = append(path, []byte(handle))
for _, arg := range args {
diff --git a/src/cypherpunks.ru/nncp/tx_test.go b/src/cypherpunks.ru/nncp/tx_test.go
index 55e7a4eba6cc1498d87924ca6b3b1ee0be601a3cf627953bd83785216d390c97..035838f903707994fbe5a74d7ad0213100ae65363c503cf84c04a55f0e328d72 100644
--- a/src/cypherpunks.ru/nncp/tx_test.go
+++ b/src/cypherpunks.ru/nncp/tx_test.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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
diff --git a/src/cypherpunks.ru/nncp/via.go b/src/cypherpunks.ru/nncp/via.go
index cae9e32a767fddee26b070fb363827bbf7d22663898536f4be674785629ecf55..ca80c96bbbb1151c1df566f5a0594d596287583ac1e8558237a75a9cf17d939a 100644
--- a/src/cypherpunks.ru/nncp/via.go
+++ b/src/cypherpunks.ru/nncp/via.go
@@ -1,6 +1,6 @@
/*
NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2018 Sergey Matveev
+Copyright (C) 2016-2019 Sergey Matveev
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