From: Sergey Matveev Date: Sun, 28 Apr 2019 13:47:27 +0000 (+0300) Subject: Merge branch 'develop' X-Git-Tag: 4.0^0 X-Git-Url: http://www.git.cypherpunks.ru/?a=commitdiff_plain;h=5a70eb101538b11bb4e4a87d00a75505c81a1ebc;hp=281445c2346df04cf7cb36a664cc6dd8bfc2117b;p=nncp.git Merge branch 'develop' --- diff --git a/.gitmodules b/.gitmodules index fb795d9..12047c5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,32 +1,32 @@ -[submodule "src/github.com/davecgh/go-xdr"] - path = src/github.com/davecgh/go-xdr +[submodule "src/cypherpunks.ru/nncp/vendor/github.com/davecgh/go-xdr"] + path = src/cypherpunks.ru/nncp/vendor/github.com/davecgh/go-xdr url = https://github.com/davecgh/go-xdr.git -[submodule "src/github.com/dustin/go-humanize"] - path = src/github.com/dustin/go-humanize +[submodule "src/cypherpunks.ru/nncp/vendor/github.com/dustin/go-humanize"] + path = src/cypherpunks.ru/nncp/vendor/github.com/dustin/go-humanize url = https://github.com/dustin/go-humanize.git -[submodule "src/github.com/flynn/noise"] - path = src/github.com/flynn/noise +[submodule "src/cypherpunks.ru/nncp/vendor/github.com/flynn/noise"] + path = src/cypherpunks.ru/nncp/vendor/github.com/flynn/noise url = https://github.com/flynn/noise.git -[submodule "src/gopkg.in/check.v1"] - path = src/gopkg.in/check.v1 +[submodule "src/cypherpunks.ru/nncp/vendor/gopkg.in/check.v1"] + path = src/cypherpunks.ru/nncp/vendor/gopkg.in/check.v1 url = https://github.com/go-check/check.git branch = v1 -[submodule "src/gopkg.in/yaml.v2"] - path = src/gopkg.in/yaml.v2 +[submodule "src/cypherpunks.ru/nncp/vendor/gopkg.in/yaml.v2"] + path = src/cypherpunks.ru/nncp/vendor/gopkg.in/yaml.v2 url = https://github.com/go-yaml/yaml.git branch = v2 -[submodule "src/golang.org/x/crypto"] - path = src/golang.org/x/crypto +[submodule "src/cypherpunks.ru/nncp/vendor/golang.org/x/crypto"] + path = src/cypherpunks.ru/nncp/vendor/golang.org/x/crypto url = https://go.googlesource.com/crypto -[submodule "src/golang.org/x/sys"] - path = src/golang.org/x/sys +[submodule "src/cypherpunks.ru/nncp/vendor/golang.org/x/sys"] + path = src/cypherpunks.ru/nncp/vendor/golang.org/x/sys url = https://go.googlesource.com/sys -[submodule "src/golang.org/x/net"] - path = src/golang.org/x/net +[submodule "src/cypherpunks.ru/nncp/vendor/golang.org/x/net"] + path = src/cypherpunks.ru/nncp/vendor/golang.org/x/net url = https://go.googlesource.com/net -[submodule "src/github.com/gorhill/cronexpr"] - path = src/github.com/gorhill/cronexpr +[submodule "src/cypherpunks.ru/nncp/vendor/github.com/gorhill/cronexpr"] + path = src/cypherpunks.ru/nncp/vendor/github.com/gorhill/cronexpr url = https://github.com/gorhill/cronexpr.git -[submodule "src/cypherpunks.ru/balloon"] - path = src/cypherpunks.ru/balloon +[submodule "src/cypherpunks.ru/nncp/vendor/cypherpunks.ru/balloon"] + path = src/cypherpunks.ru/nncp/vendor/cypherpunks.ru/balloon url = git://git.cypherpunks.ru/balloon.git diff --git a/BSDmakefile b/BSDmakefile index b57abb4..63c724c 100644 --- a/BSDmakefile +++ b/BSDmakefile @@ -1,4 +1,3 @@ -GOPATH != pwd VERSION != cat VERSION include common.mk diff --git a/GNUmakefile b/GNUmakefile index 79efdfc..5af4eb0 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 2f4b607..5186d07 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4 +4.0 diff --git a/common.mk b/common.mk index 145e843..602d754 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 @@ LDFLAGS = \ -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 @@ ALL = \ nncp-toss \ nncp-xfer -all: $(ALL) - -nncp-bundle: - GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-bundle - -nncp-call: - GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-call - -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 +SRC := $(PWD)/src/cypherpunks.ru/nncp +BIN := $(PWD)/bin +GOPATH ?= $(PWD)/gopath -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 +all: $(ALL) -nncp-toss: - GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-toss +$(BIN): + mkdir -p $(BIN) -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 @@ 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 3b2664c..497bc40 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 2f6f386..ac665ac 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -20,8 +20,6 @@ Nearly all commands have the following common options: @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 @@ their integrity. [-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 @@ This command queues file in @ref{Spool, spool} directory immediately 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 @@ Parse @ref{Log, log} file and print out its records in human-readable form. @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 @@ -382,6 +388,8 @@ And with the @option{-dump} option it will give you the actual payload 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 @@ ones. If @option{-seen} option is specified, then delete only @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 @@ successful tossing of @file{XXX} packet. @ref{nncp-xfer}, 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 65bc9f9..0722f04 100644 --- a/doc/download.texi +++ b/doc/download.texi @@ -20,79 +20,82 @@ Tarballs include all necessary required libraries: @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 74e6661..45de886 100644 --- a/doc/eblob.texi +++ b/doc/eblob.texi @@ -32,16 +32,16 @@ winner). 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 @@ Eblob is an @url{https://tools.ietf.org/html/rfc4506, XDR}-encoded structure: 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 e2df9bd..e9f067d 100644 --- a/doc/index.texi +++ b/doc/index.texi @@ -6,7 +6,7 @@ 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 67edc72..c597a0f 100644 --- a/doc/integrity.texi +++ b/doc/integrity.texi @@ -23,7 +23,6 @@ uid NNCP releases % 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 46e6357..a17c2ef 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 16f1d6f..ed1bf08 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -3,6 +3,33 @@ 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 b1c2c38..d216f93 100644 --- a/doc/pkt.texi +++ b/doc/pkt.texi @@ -28,7 +28,7 @@ drive. @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 @@ storages and that are synchronized between TCP daemons. 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 @@ Each encrypted packet has the following header: @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 @@ Each encrypted packet has the following header: 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 @@ After the headers comes an encrypted payload size and MAC of that size. 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 @@ When node A want to send encrypted packet to node B, it: @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 dc94af9..0dec0f2 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 3e3caba..da05881 100644 --- a/doc/usecases.ru.texi +++ b/doc/usecases.ru.texi @@ -8,10 +8,12 @@ * Медленная/дорогая связь для больших объёмов данных, плохой QoS: UsecaseQoSRU. * Экстремальные наземные окружающие условия, нет связи: UsecaseNoLinkRU. * Односторонняя широковещательная связь: UsecaseBroadcastRU. +* Спутниковые каналы связи: UsecaseSatelliteLinksRU. * Частные, изолированные MitM/Sybil-устойчивые сети: UsecaseF2FRU. * Высоко защищённые изолированные компьютеры с воздушным зазором: UsecaseAirgapRU. * Обход сетевой цензуры, здоровье: UsecaseCensorRU. * Разведка, шпионаж, тайная агентура: UsecaseSpyRU. +* Дешёвая ночная связь: UsecaseCallerRU. @end menu @node UsecaseMailRU @@ -104,9 +106,9 @@ NNCP поддерживает @ref{Niceness, приоритезацию траф опцию: @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 @@ NNCP поддерживает @ref{Niceness, приоритезацию траф переотправлять широковещательные рассылки время от времени, повышая шансы на то, что получатель примет их, регулярно слушая рассылку. +@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 @@ neigh: Эти ребята знают насколько небезопасен Интернет, несовместим с понятием приватности. Им необходим быстрый сброс и забор данных. Нет -возможности провести несколько итераций туда-обратно (round trip) -- +возможности провести несколько итераций приёмо-передач (round-trips) -- только сбросить данные, выстрелить и забыть. Опять же, это может быть переносной накопитель и/или @url{https://en.wikipedia.org/wiki/USB_dead_drop, USB тайник} (dead drop), @@ -316,7 +346,7 @@ Bluetooth и WiFi могут быть и довольно быстрыми, по Общение узлов между собой происходит в, так называемой, @ref{Spool, спул} области: директории содержащей только необработанные зашифрованные -пакеты. После передачи пакета вы всё-равно не сможете его прочитать: +пакеты. После передачи пакета вы всё равно не сможете его прочитать: необходимо запустить другую фазу: @ref{nncp-toss, распаковку}, которая использует ваши приватные криптографические ключи. То есть, даже если вы потеряете свой компьютер, устройства хранения и тому прочее -- это не @@ -326,3 +356,47 @@ Bluetooth и WiFi могут быть и довольно быстрыми, по файлов и почтовых сообщений) может и должна бы быть произведена на отдельном компьютере (@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 c276435..1c0a750 100644 --- a/doc/usecases.texi +++ b/doc/usecases.texi @@ -10,10 +10,12 @@ See also this page @ref{Сценарии, on russian}. * 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 8e487d8..7051f07 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 @@ func (ctx *Ctx) CallNode( 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 @@ func (ctx *Ctx) CallNode( 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 75d12a5..bcd547e 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 @@ func NewNode(name string, yml NodeYAML) (*Node, error) { 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 (nodeOur *NodeOur) ToYAML() string { 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 53dd549..c83c80b 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 417e2a0..02b488b 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 86dc099..553a6d1 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 @@ func main() { 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 @@ func main() { 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 d8adc60..7919b6a 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 usage() { 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 @@ func main() { } } + 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 @@ func main() { *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 d960942..1930715 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 @@ func main() { 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 3ad1d69..be009f4 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 @@ func main() { 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 cf1626e..7ddbb04 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 a119e38..274cdad 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 f426fd4..a99bd2f 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 @@ func main() { 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 7705568..3f28972 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 @@ func (ic *InetdConn) SetWriteDeadline(t time.Time) error { } 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 @@ func performSP(ctx *nncp.Ctx, conn nncp.ConnDeadlined, nice uint8) { }, "") } 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 0cf7810..bdcf5a3 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 6e7eaf5..b7f31ab 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 14f2fea..32b62bf 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 c578ec9..aea1d8b 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 ff77eb4..1ccea9e 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 @@ import ( "cypherpunks.ru/nncp" "github.com/davecgh/go-xdr/xdr2" - "golang.org/x/crypto/blake2b" ) func usage() { @@ -44,6 +43,7 @@ func usage() { 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 @@ func main() { 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 @@ func main() { } 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 06549b8..fe068b5 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 @@ func process(ctx *nncp.Ctx, path string, keep, dryRun, stdout, dumpMeta bool) bo } } } - 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 @@ func main() { } 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 @@ func main() { 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 @@ func main() { 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 7ce924f..0298379 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 fcc872f..a4fbfcb 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 bb4a586..a87923c 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 01fe150..e4a8653 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 @@ func main() { } 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 @@ func main() { } 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 @@ func main() { 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 @@ func main() { )); 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 @@ Tx: 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 ab3fc66..fb7246a 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 @@ package nncp import ( "errors" "io/ioutil" + "log" "os" "path/filepath" + + "golang.org/x/sys/unix" ) type Ctx struct { @@ -103,3 +106,11 @@ func CtxFromCmdline(cfgPath, spoolPath, logPath string, quiet, debug bool) (*Ctx 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 b25f5ab..816388d 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 @@ package nncp 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 @@ const ( ) 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 @@ type EBlob struct { PCost uint32 Salt *[32]byte Blob []byte - MAC *[blake2b.Size256]byte } func blake256() hash.Hash { @@ -69,46 +65,31 @@ func NewEBlob(sCost, tCost, pCost int, password, data []byte) ([]byte, 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 - } - 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 { - return nil, err - } - mac, err := blake2b.New256(keyAuth) - if err != nil { - return nil, err - } - chacha20.XORKeyStream(data, data, new([16]byte), keyEnc) - if _, err = mac.Write(data); err != nil { - return nil, err - } - macTag := new([blake2b.Size256]byte) - mac.Sum(macTag[:0]) eblob := EBlob{ - Magic: MagicNNCPBv2, + Magic: MagicNNCPBv3, SCost: uint32(sCost), TCost: uint32(tCost), PCost: uint32(pCost), Salt: salt, - Blob: data, - MAC: macTag, + Blob: nil, } - var eblobRaw bytes.Buffer - if _, err = xdr.Marshal(&eblobRaw, &eblob); err != nil { + var eblobBuf bytes.Buffer + if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil { return nil, err } - return eblobRaw.Bytes(), nil + key := balloon.H(blake256, password, salt[:], sCost, tCost, pCost) + aead, err := chacha20poly1305.New(key) + if err != nil { + return nil, err + } + 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 + } + return eblobBuf.Bytes(), nil } func DeEBlob(eblobRaw, password []byte) ([]byte, error) { @@ -117,7 +98,7 @@ func DeEBlob(eblobRaw, password []byte) ([]byte, 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 @@ func DeEBlob(eblobRaw, password []byte) ([]byte, error) { 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 0000000..59cfe97 --- /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 0000000..cada0a9 --- /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 cea9546..68031d8 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 @@ func (ctx *Ctx) Humanize(s string) string { } if err, exists := sds["err"]; exists { msg += ": " + err + } else { + msg += " " + rem } case "nncp-bundle": switch sds["xx"] { @@ -196,6 +198,29 @@ func (ctx *Ctx) Humanize(s string) string { 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 @@ func (ctx *Ctx) Humanize(s string) string { 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 019fe70..ee7052d 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 @@ along with this program. If not, see . package nncp import ( + "io" "os" "path/filepath" "strconv" @@ -64,11 +65,11 @@ func (ctx *Ctx) Jobs(nodeId *NodeId, xx TRxTx) chan Job { 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 cc94cb6..556e22d 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 55d8844..5ba13e9 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 4902140..32f2eb6 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 VersionGet() string { 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 b6cdcc6..e903567 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 1d1ff34..b2ab591 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 @@ const ( 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 @@ func init() { 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 @@ func init() { panic(err) } pktEnc := PktEnc{ - Magic: MagicNNCPEv3, + Magic: MagicNNCPEv4, Nice: 123, Sender: dummyId, Recipient: dummyId, @@ -132,42 +134,60 @@ func NewPkt(typ PktType, nice uint8, path []byte) (*Pkt, error) { 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 @@ func PktEncWrite( 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 @@ func PktEncWrite( return err } tbs := PktTbs{ - Magic: MagicNNCPEv3, + Magic: MagicNNCPEv4, Nice: nice, Sender: our.Id, Recipient: their.Id, @@ -200,7 +221,7 @@ func PktEncWrite( 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 @@ func PktEncWrite( 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 { + key := make([]byte, chacha20poly1305.KeySize) + if _, err = io.ReadFull(kdf, key); err != nil { return err } - keyAuth := make([]byte, 64) - if _, err = io.ReadFull(kdf, keyAuth); 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 PktEncWrite( 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 @@ func PktEncRead( 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 { - return their, 0, 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 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 { - 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) + sizeBuf, err = aead.Open(sizeBuf[:0], nonce, sizeBuf, nil) if err != nil { return their, 0, err } + size := int64(binary.BigEndian.Uint64(sizeBuf)) - 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 5775e73..43602d7 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 @@ func TestPktEncRead(t *testing.T) { 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 d3ffb9f..f282514 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 @@ func payloadsSplit(payloads [][]byte) [][]byte { } 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 @@ type SPState struct { rxRate int txRate int isDead bool + listOnly bool + onlyPkts map[[32]byte]bool sync.RWMutex } @@ -213,8 +215,8 @@ func (state *SPState) NotAlive() bool { } 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 @@ func (ctx *Ctx) infosOur(nodeId *NodeId, nice uint8, seen *map[[32]byte]uint8) [ 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 @@ func (ctx *Ctx) StartI( 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 @@ func (ctx *Ctx) StartR(conn ConnDeadlined, nice uint8, xxOnly TRxTx) (*SPState, 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 @@ func (state *SPState) StartWorkers( } }() } - 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 @@ func (state *SPState) StartWorkers( } }() - 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 @@ func (state *SPState) StartWorkers( 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 @@ func (state *SPState) StartWorkers( 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 @@ func (state *SPState) StartWorkers( "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 @@ func (state *SPState) StartWorkers( 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 @@ func (state *SPState) StartWorkers( 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 @@ func (state *SPState) StartWorkers( 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 @@ func (state *SPState) StartWorkers( 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) Wait() { } 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", - ) } - replies = append(replies, MarshalSP( - SPTypeFreq, - SPFreq{info.Hash, uint64(offset)}, - )) - case SPTypeFile: - state.ctx.LogD( - "sp-process", - SdsAdd(sds, SDS{"type": "file"}), - "unmarshaling packet", + 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)}, + )) + } + case SPTypeFile: + 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 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) { 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 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) { 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 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) { }() }() 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 @@ func (state *SPState) ProcessSP(payload []byte) ([][]byte, error) { 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 14af6b9..3d73333 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 fa49c16..1f717fa 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 @@ import ( "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 newNotification(fromTo *FromToYAML, subject string) io.Reader { 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 @@ func (ctx *Ctx) Toss( 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 @@ func (ctx *Ctx) Toss( } 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 4d49d21..fb1a29f 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 0692eca..fcf1c83 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 @@ import ( "github.com/davecgh/go-xdr/xdr2" "golang.org/x/crypto/blake2b" + "golang.org/x/crypto/chacha20poly1305" ) func (ctx *Ctx) Tx( @@ -41,7 +42,8 @@ func (ctx *Ctx) Tx( 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 @@ func (ctx *Ctx) Tx( 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 @@ func (ctx *Ctx) Tx( 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 @@ func (ctx *Ctx) Tx( 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 @@ func prepareTxFile(srcPath string) (io.Reader, *os.File, int64, error) { } 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 @@ func (ctx *Ctx) TxFileChunked( 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 @@ func (ctx *Ctx) TxExec( 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 6ea7ef2..4bfccfc 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/vendor/cypherpunks.ru/balloon b/src/cypherpunks.ru/nncp/vendor/cypherpunks.ru/balloon new file mode 160000 index 0000000..0e07700 --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/cypherpunks.ru/balloon @@ -0,0 +1 @@ +Subproject commit 0e07700b027907d44e0060fc3f75c4590478452b diff --git a/src/github.com/davecgh/go-xdr b/src/cypherpunks.ru/nncp/vendor/github.com/davecgh/go-xdr similarity index 100% rename from src/github.com/davecgh/go-xdr rename to src/cypherpunks.ru/nncp/vendor/github.com/davecgh/go-xdr diff --git a/src/cypherpunks.ru/nncp/vendor/github.com/dustin/go-humanize b/src/cypherpunks.ru/nncp/vendor/github.com/dustin/go-humanize new file mode 160000 index 0000000..9f541cc --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/github.com/dustin/go-humanize @@ -0,0 +1 @@ +Subproject commit 9f541cc9db5d55bce703bd99987c9d5cb8eea45e diff --git a/src/github.com/flynn/noise b/src/cypherpunks.ru/nncp/vendor/github.com/flynn/noise similarity index 100% rename from src/github.com/flynn/noise rename to src/cypherpunks.ru/nncp/vendor/github.com/flynn/noise diff --git a/src/github.com/gorhill/cronexpr b/src/cypherpunks.ru/nncp/vendor/github.com/gorhill/cronexpr similarity index 100% rename from src/github.com/gorhill/cronexpr rename to src/cypherpunks.ru/nncp/vendor/github.com/gorhill/cronexpr diff --git a/src/cypherpunks.ru/nncp/vendor/golang.org/x/crypto b/src/cypherpunks.ru/nncp/vendor/golang.org/x/crypto new file mode 160000 index 0000000..a29dc8f --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/golang.org/x/crypto @@ -0,0 +1 @@ +Subproject commit a29dc8fdc73485234dbef99ebedb95d2eced08de diff --git a/src/cypherpunks.ru/nncp/vendor/golang.org/x/net b/src/cypherpunks.ru/nncp/vendor/golang.org/x/net new file mode 160000 index 0000000..4829fb1 --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/golang.org/x/net @@ -0,0 +1 @@ +Subproject commit 4829fb13d2c62012c17688fa7f629f371014946d diff --git a/src/cypherpunks.ru/nncp/vendor/golang.org/x/sys b/src/cypherpunks.ru/nncp/vendor/golang.org/x/sys new file mode 160000 index 0000000..a129542 --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/golang.org/x/sys @@ -0,0 +1 @@ +Subproject commit a129542de9ae0895210abff9c95d67a1f33cb93d diff --git a/src/cypherpunks.ru/nncp/vendor/gopkg.in/check.v1 b/src/cypherpunks.ru/nncp/vendor/gopkg.in/check.v1 new file mode 160000 index 0000000..788fd78 --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/gopkg.in/check.v1 @@ -0,0 +1 @@ +Subproject commit 788fd78401277ebd861206a03c884797c6ec5541 diff --git a/src/cypherpunks.ru/nncp/vendor/gopkg.in/yaml.v2 b/src/cypherpunks.ru/nncp/vendor/gopkg.in/yaml.v2 new file mode 160000 index 0000000..7b8349a --- /dev/null +++ b/src/cypherpunks.ru/nncp/vendor/gopkg.in/yaml.v2 @@ -0,0 +1 @@ +Subproject commit 7b8349ac747c6a24702b762d2c4fd9266cf4f1d6 diff --git a/src/cypherpunks.ru/nncp/via.go b/src/cypherpunks.ru/nncp/via.go index f6f3e98..0868b76 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 diff --git a/src/github.com/dustin/go-humanize b/src/github.com/dustin/go-humanize deleted file mode 160000 index 02af396..0000000 --- a/src/github.com/dustin/go-humanize +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 02af3965c54e8cacf948b97fef38925c4120652c diff --git a/src/golang.org/x/crypto b/src/golang.org/x/crypto deleted file mode 160000 index a49355c..0000000 --- a/src/golang.org/x/crypto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a49355c7e3f8fe157a85be2f77e6e269a0f89602 diff --git a/src/golang.org/x/net b/src/golang.org/x/net deleted file mode 160000 index 32a936f..0000000 --- a/src/golang.org/x/net +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 32a936f46389aa10549d60bd7833e54b01685d09 diff --git a/src/golang.org/x/sys b/src/golang.org/x/sys deleted file mode 160000 index 3c6ecd8..0000000 --- a/src/golang.org/x/sys +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3c6ecd8f22c6f40fbeec94c000a069d7d87c7624 diff --git a/src/gopkg.in/check.v1 b/src/gopkg.in/check.v1 deleted file mode 160000 index 20d25e2..0000000 --- a/src/gopkg.in/check.v1 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 20d25e2804050c1cd24a7eea1e7a6447dd0e74ec diff --git a/src/gopkg.in/yaml.v2 b/src/gopkg.in/yaml.v2 deleted file mode 160000 index 5420a8b..0000000 --- a/src/gopkg.in/yaml.v2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5420a8b6744d3b0345ab293f6fcba19c978f1183