]> Cypherpunks.ru repositories - nncp.git/commitdiff
Remote command execution
authorSergey Matveev <stargrave@stargrave.org>
Sat, 17 Feb 2018 10:38:50 +0000 (13:38 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 17 Feb 2018 20:47:03 +0000 (23:47 +0300)
34 files changed:
README
README.RU
common.mk
doc/about.ru.texi
doc/about.texi
doc/cfg.texi
doc/cmds.texi
doc/comparison.ru.texi
doc/comparison.texi
doc/integration.texi
doc/news.ru.texi
doc/news.texi
doc/niceness.texi
doc/pkt.texi
doc/usecases.ru.texi
doc/usecases.texi
doc/workflow.texi
makedist.sh
ports/nncp/Makefile
ports/nncp/pkg-descr
ports/nncp/pkg-plist
src/cypherpunks.ru/nncp/cfg.go
src/cypherpunks.ru/nncp/cmd/nncp-cfgnew/main.go
src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go [moved from src/cypherpunks.ru/nncp/cmd/nncp-mail/main.go with 61% similarity]
src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go
src/cypherpunks.ru/nncp/cmd/nncp-toss/main.go
src/cypherpunks.ru/nncp/humanizer.go
src/cypherpunks.ru/nncp/node.go
src/cypherpunks.ru/nncp/pkt.go
src/cypherpunks.ru/nncp/pkt_test.go
src/cypherpunks.ru/nncp/toss.go
src/cypherpunks.ru/nncp/toss_test.go
src/cypherpunks.ru/nncp/tx.go
src/cypherpunks.ru/nncp/tx_test.go

diff --git a/README b/README
index dab1ca8fb45b7576e91d88b58c9e649dcc020231..58db3ed563e76b28d8ba89dd946fe5c692d206f9 100644 (file)
--- a/README
+++ b/README
@@ -1,13 +1,14 @@
 NNCP (Node to Node copy) is a collection of utilities simplifying
-secure store-and-forward files and mail exchanging.
+secure store-and-forward files, mail and commands exchanging.
 
 This utilities are intended to help build up small size (dozens of
-nodes) ad-hoc friend-to-friend (F2F) statically routed darknet networks
-for fire-and-forget secure reliable files, file requests and Internet
-mail transmission. All packets are integrity checked, end-to-end
-encrypted (E2EE), explicitly authenticated by known participants public
-keys. Onion encryption is applied to relayed packets. Each node acts
-both as a client and server, can use push and poll behaviour model.
+nodes) ad-hoc friend-to-friend (F2F) statically routed darknet
+delay-tolerant networks for fire-and-forget secure reliable files, file
+requests, Internet mail and commands transmission. All packets are
+integrity checked, end-to-end encrypted (E2EE), explicitly authenticated
+by known participants public keys. Onion encryption is applied to
+relayed packets. Each node acts both as a client and server, can use
+push and poll behaviour model.
 
 Out-of-box offline sneakernet/floppynet, dead drops, sequential and
 append-only CD-ROM/tape storages, air-gapped computers support. But
index eccba53fffa5a08560a3c5d81f4b70a79f3d8309..ba9829c499d86fe6c3dff9e2ddd3c25b86d551b1 100644 (file)
--- a/README.RU
+++ b/README.RU
@@ -1,10 +1,10 @@
 NNCP (Node to Node copy) это набор утилит упрощающий безопасный обмен
 файлами и почтой в режиме сохранить-и-переслать.
 
-ЭÑ\82и Ñ\83Ñ\82илиÑ\82Ñ\8b Ð¿Ñ\80едназнаÑ\87енÑ\8b Ð¿Ð¾Ð¼Ð¾Ñ\87Ñ\8c Ñ\81 Ð¿Ð¾Ñ\81Ñ\82Ñ\80оением Ð¾Ð´Ð½Ð¾Ñ\80анговÑ\8bÑ\85 Ñ\81еÑ\82ей
-небольшого размера (дюжины узлов), в режиме друг-к-другу (F2F) со
-статической маршрутизацией для безопасной надёжной передачи файлов,
-запросов на передачу файлов и Интернет почты по принципу
+ЭÑ\82и Ñ\83Ñ\82илиÑ\82Ñ\8b Ð¿Ñ\80едназнаÑ\87енÑ\8b Ð¿Ð¾Ð¼Ð¾Ñ\87Ñ\8c Ñ\81 Ð¿Ð¾Ñ\81Ñ\82Ñ\80оением Ð¾Ð´Ð½Ð¾Ñ\80анговÑ\8bÑ\85 Ñ\83Ñ\81Ñ\82ойÑ\87ивÑ\8bÑ\85 Ðº
+разрывам сетей небольшого размера (дюжины узлов), в режиме друг-к-другу
+(F2F) со статической маршрутизацией для безопасной надёжной передачи
+файлов, запросов на передачу файлов, Интернет почты и команд по принципу
 выстрелил-и-забыл. Все пакеты проверяются на целостность, шифруются по
 принципу точка-точка (E2EE), аутентифицируются известными публичными
 ключами участников. Луковичное (onion) шифрование применяется ко всем
index 34ee30d35ca1cc6fc1f6dee67d762a2501af37f5..145e84397c3edbb4a656913382eda6dcc950d392 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -25,10 +25,10 @@ ALL = \
        nncp-cfgnew \
        nncp-check \
        nncp-daemon \
+       nncp-exec \
        nncp-file \
        nncp-freq \
        nncp-log \
-       nncp-mail \
        nncp-pkt \
        nncp-reass \
        nncp-rm \
@@ -62,6 +62,9 @@ nncp-check:
 nncp-daemon:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-daemon
 
+nncp-exec:
+       GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-exec
+
 nncp-file:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-file
 
@@ -71,9 +74,6 @@ nncp-freq:
 nncp-log:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-log
 
-nncp-mail:
-       GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-mail
-
 nncp-pkt:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-pkt
 
index 727402c4a3512a6847107263550f1dd21965f4e6..526d37fa62d3786c522652a1312ef7ac32f3f790 100644 (file)
@@ -4,11 +4,12 @@
 NNCP (Node to Node copy) это набор утилит упрощающий безопасный обмен
 файлами и почтой в режиме сохранить-и-переслать.
 
-Эти утилиты предназначены помочь с построением однораговых сетей
+Эти утилиты предназначены помочь с построением однораговых
+@url{https://ru.wikipedia.org/wiki/DTN, устойчивых к разрывам} сетей
 небольшого размера (дюжины узлов), в режиме
 @url{https://ru.wikipedia.org/wiki/Friend-to-friend, друг-к-другу} (F2F)
 со статической маршрутизацией для безопасной надёжной передачи файлов,
-запросов на передачу файлов и Интернет почты по принципу
+запросов на передачу файлов, Интернет почты и команд по принципу
 выстрелил-и-забыл. Все пакеты проверяются на целостность, шифруются по
 принципу @url{https://en.wikipedia.org/wiki/End-to-end_encryption,
 точка-точка}, аутентифицируются известными публичными ключами
index ffe4be082a5411e57eac6e0598d9670de59782e3..4a7ab0560db6d68dff294dfa254d47b7d71953e2 100644 (file)
@@ -6,14 +6,15 @@ See also this page @ref{Об утилитах, on russian}.
 This utilities are intended to help build up small size (dozens of
 nodes) ad-hoc @url{https://en.wikipedia.org/wiki/Friend-to-friend,
 friend-to-friend} (F2F) statically routed
-@url{https://en.wikipedia.org/wiki/Darknet, darknet} networks for
-fire-and-forget secure reliable files, file requests and Internet mail
-transmission. All packets are integrity checked,
-@url{https://en.wikipedia.org/wiki/End-to-end_encryption, end-to-end}
-encrypted, explicitly authenticated by known participants public keys.
-@url{https://en.wikipedia.org/wiki/Onion_routing, Onion encryption} is
-applied to relayed packets. Each node acts both as a client and server,
-can use push and poll behaviour model.
+@url{https://en.wikipedia.org/wiki/Darknet, darknet}
+@url{https://en.wikipedia.org/wiki/Delay-tolerant_networking, delay-tolerant}
+networks for fire-and-forget secure reliable files, file requests,
+Internet mail and commands transmission. All packets are integrity
+checked, @url{https://en.wikipedia.org/wiki/End-to-end_encryption,
+end-to-end} encrypted, explicitly authenticated by known participants
+public keys. @url{https://en.wikipedia.org/wiki/Onion_routing, Onion
+encryption} is applied to relayed packets. Each node acts both as a
+client and server, can use push and poll behaviour model.
 
 Out-of-box offline @url{https://en.wikipedia.org/wiki/Sneakernet,
 sneakernet/floppynet}, @url{https://en.wikipedia.org/wiki/Dead_drop,
index 3483f11c53fb1eec2b821cc98f3ec7146943136c..5be0382bd69628ff5980d37b1abe971d548a36db 100644 (file)
@@ -27,13 +27,15 @@ neigh:
     exchpub: CYVGQ...PSEWQ
     signpub: 2NMVC...CMH5Q
     noisepub: KIBKK...ESM7Q
-    sendmail: [/usr/sbin/sendmail]
+    exec:
+      sendmail: [/usr/sbin/sendmail]
   alice:
     id: XJZBK...65IJQ
     exchpub: MJACJ...FAI6A
     signpub: T4AFC...N2FRQ
     noisepub: UBM5K...VI42A
-    sendmail: ["/bin/sh", "-c", "false"]
+    exec:
+      flag: ["/usr/bin/touch", "-t"]
     incoming: /home/alice/incoming
     onlinedeadline: 1800
     maxonlinetime: 3600
@@ -47,7 +49,10 @@ neigh:
     id: 2IZNP...UYGYA
     exchpub: WFLMZ...B7NHA
     signpub: GTGXG...IE3OA
-    sendmail: [/usr/sbin/sendmail]
+    exec:
+      sendmail: [/usr/sbin/sendmail]
+      warcer: [/path/to/warcer.sh]
+      wgeter: [/path/to/wgeter.sh]
     freq: /home/bob/pub
     freqchunked: 1024
     freqminsize: 2048
@@ -62,9 +67,9 @@ log} file.
 @strong{notify} section contains notification settings for successfully
 tossed file and freq packets. Corresponding @strong{from} and
 @strong{to} fields will be substituted in notification email message.
-@emph{neigh/self/sendmail} will be used as a local mailer. You can omit
-either of those two @emph{from}/@emph{to} sections to omit corresponding
-notifications, or the whole section at once.
+@emph{neigh/self/exec/sendmail} will be used as a local mailer. You can
+omit either of those two @emph{from}/@emph{to} sections to omit
+corresponding notifications, or the whole section at once.
 
 @strong{self} section contains our node's private keypairs.
 @strong{exch*} and @strong{sign*} are used during @ref{Encrypted,
@@ -85,13 +90,25 @@ node has the following fields:
 If present, then node can be online called using @ref{Sync,
 synchronization protocol}. Contains authentication public key.
 
-@anchor{CfgSendmail}
-@item sendmail
-An array containing path to executable and its command line arguments
-that is called for mail sending. If it is empty, then no mail processing
-will be performed from that node. Sendmail command
-@command{["/bin/foo", "bar"]} called the following way:
-@command{NNCP_NICE=NICE NNCP_SENDER=NODEID /bin/foo bar RCPT1 RCPT2 ... < MSG}.
+@anchor{CfgExec}
+@item exec
+Dictionary consisting of handles and corresponding command line
+arguments. In example above there are @command{sendmail} handles,
+@command{warcer}, @command{wgeter} and @command{flag} one. Remote node
+can queue some handle execution with providing additional command line
+arguments and the body fed to command's stdin.
+
+@verb{|sendmail: ["/usr/sbin/sendmail", "-t"]|} handle, when called by
+@verb{|echo hello world | nncp-exec OURNODE sendmail ARG0 ARG1 ARG2|}
+command, will execute:
+
+@verbatim
+echo hello world |
+    NNCP_SELF=OURNODE \
+    NNCP_SENDER=REMOTE \
+    NNCP_NICE=64 \
+    /usr/sbin/sendmail -t ARG0 ARG1 ARG2
+@end verbatim
 
 @anchor{CfgIncoming}
 @item incoming
index 49a34c618c3806e62483ce5d90a9268ff68460df..e7090afff73fe4d0d7be71d68bd4937d9602872d 100644 (file)
@@ -18,6 +18,10 @@ Nearly all commands have the following common options:
 @item -nice
     Set desired outgoing packet @ref{Niceness, niceness level}.
     1-255 values are allowed.
+@item -replynice
+    Set desired reply packet @ref{Niceness, niceness level}. Only freq
+    and exec packets look at that niceness level. 1-255 values are
+    allowed.
 @item -node
     Process only single specified node.
 @item -via
@@ -233,6 +237,39 @@ time to time.
 can handle. @option{-bind} option specifies @option{addr:port} it must
 bind to and listen.
 
+@node nncp-exec
+@section nncp-exec
+
+@verbatim
+% nncp-exec [options] NODE HANDLE [ARG0 ARG1 ...]
+@end verbatim
+
+Send execution command to @option{NODE} for specified @option{HANDLE}.
+Body is read from stdin and compressed. After receiving, remote side
+will execute specified @ref{CfgExec, handle} command with @option{ARG*}
+appended and decompressed body fed to command's stdin.
+
+For example, if remote side has following configuration file for your
+node:
+
+@verbatim
+exec:
+  sendmail: [/usr/sbin/sendmail, "-t"]
+  appender: ["/bin/sh", "-c", "cat >> /append"]
+@end verbatim
+
+then executing @verb{|echo My message | nncp-exec -replynice 123 REMOTE
+sendmail root@localhost|} will lead to executing of:
+
+@verbatim
+echo My message |
+    NNCP_SELF=REMOTE \
+    NNCP_SENDER=OurNodeId \
+    NNCP_NICE=123 \
+    /usr/sbin/sendmail -t root@localhost
+@end verbatim
+
+
 @node nncp-file
 @section nncp-file
 
@@ -295,19 +332,6 @@ queuing.
 
 Parse @ref{Log, log} file and print out its records in human-readable form.
 
-@node nncp-mail
-@section nncp-mail
-
-@verbatim
-% nncp-mail [options] NODE USER ...
-@end verbatim
-
-Send mail, that is read from stdin, to @option{NODE} and specified
-@option{USER}s. Mail message will be compressed. After receiving, remote
-side will execute specified @ref{CfgSendmail, sendmail} command with
-@option{USER}s appended as a command line argument and feed decompressed
-mail body to that command's stdin.
-
 @node nncp-pkt
 @section nncp-pkt
 
index 73580ae68279dfd5d79439e2b0de66bc6967e347..5c90671d636f63ea219be645b09b580a579e799b 100644 (file)
@@ -15,7 +15,7 @@
 @item Передача новостей @tab @strong{Да} @tab @strong{Да} @tab Нет @tab Нет
 @item Передача файлов @tab @strong{Да} @tab @strong{Да} @tab @strong{Да} @tab Нет
 @item Разбиение файлов на части @tab Нет @tab @strong{Да} @tab @strong{Да} @tab Нет
-@item Удалённое исполнение команд @tab @strong{Да} @tab Нет @tab Нет @tab Нет
+@item Удалённое исполнение команд @tab @strong{Да} @tab Нет @tab @strong{Да} @tab Нет
 @item Возобновляемое скачивание @tab @strong{Да} @tab @strong{Да} @tab @strong{Да} @tab Нет
 @item Приоритезация пакетов @tab @strong{Да} @tab Нет @tab @strong{Да} @tab Нет
 @item Сжатие почты @tab Нет @tab @strong{Да} @tab @strong{Да} @tab Нет
index e8edddd32e91383cf2fb12f20913d990f662a733..03087c1c73fcf83e81d7a7abc826953d1575a90a 100644 (file)
@@ -14,7 +14,7 @@ FidoNet} Technology Networks) and @url{https://en.wikipedia.org/wiki/SMTP, SMTP}
 @item News transmission @tab @strong{Yes} @tab @strong{Yes} @tab No @tab No
 @item File transmission @tab @strong{Yes} @tab @strong{Yes} @tab @strong{Yes} @tab No
 @item Chunked files @tab No @tab @strong{Yes} @tab @strong{Yes} @tab No
-@item Remote command execution @tab @strong{Yes} @tab No @tab No @tab No
+@item Remote command execution @tab @strong{Yes} @tab No @tab @strong{Yes} @tab No
 @item Resumable downloads @tab @strong{Yes} @tab @strong{Yes} @tab @strong{Yes} @tab No
 @item Packets prioritizing @tab @strong{Yes} @tab No @tab @strong{Yes} @tab No
 @item Mail compression @tab No @tab @strong{Yes} @tab @strong{Yes} @tab No
index 55e154c3b41c454140b9df4ff4d34cf7ec62c8e0..62c0933d84a17cc180af4da182ac5999a82a5b4a 100644 (file)
@@ -9,6 +9,7 @@ making them store-and-forward friendly.
 * Web feeds: Feeds.
 * Web pages: WARCs.
 * BitTorrent and huge files: BitTorrent.
+* Downloading service: DownloadService.
 * Git::
 * Multimedia streaming: Multimedia.
 @end menu
@@ -27,7 +28,7 @@ mail to a LAN that is connected via NNCP.
 
 @itemize
 
-@item You need an @ref{nncp-mail} program that extracts the sender
+@item You need an @ref{nncp-exec} program that extracts the sender
 address from mail that arrives via NNCP, and that feeds the mail into
 the Postfix @command{sendmail} command.
 
@@ -36,13 +37,13 @@ delivery via NNCP:
 @verbatim
 /usr/local/etc/postfix/master.cf:
 nncp      unix  -       n       n       -       -       pipe
-          flags=F user=nncp argv=nncp-mail -quiet $nexthop $recipient
+          flags=F user=nncp argv=nncp-exec -quiet $nexthop sendmail $recipient
 @end verbatim
 
-This runs the @command{nncp-mail} command to place outgoing mail into
+This runs the @command{nncp-exec} command to place outgoing mail into
 the NNCP queue after replacing @var{$nexthop} by the the receiving NNCP
 node and after replacing @var{$recipient} by the recipients. The
-@command{pipe(8)} delivery agent executes the @command{nncp-mail}
+@command{pipe(8)} delivery agent executes the @command{nncp-exec}
 command without assistance from the shell, so there are no problems with
 shell meta characters in command-line parameters.
 
@@ -89,7 +90,7 @@ Here is how to relay mail from a LAN via NNCP to the Internet.
 
 @itemize
 
-@item You need an @ref{nncp-mail} program that extracts the sender
+@item You need an @ref{nncp-exec} program that extracts the sender
 address from mail that arrives via NNCP, and that feeds the mail into
 the Postfix @command{sendmail} command.
 
@@ -115,13 +116,13 @@ mail delivery via NNCP:
 @verbatim
 /usr/local/etc/postfix/master.cf:
 nncp      unix  -       n       n       -       -       pipe
-          flags=F user=nncp argv=nncp-mail -quiet $nexthop $recipient
+          flags=F user=nncp argv=nncp-exec -quiet $nexthop sendmail $recipient
 @end verbatim
 
-This runs the @command{nncp-mail} command to place outgoing mail into
+This runs the @command{nncp-exec} command to place outgoing mail into
 the NNCP queue. It substitutes the hostname (@emph{nncp-gateway}, or
 whatever you specified) and the recipients before executing the command.
-The @command{nncp-mail} command is executed without assistance from the
+The @command{nncp-exec} command is executed without assistance from the
 shell, so there are no problems with shell meta characters.
 
 @item Execute the command @command{postfix reload} to make the changes
@@ -229,59 +230,6 @@ utility, producing usual directory hierarchy:
     --progress
 @end verbatim
 
-Also you can create separate NNCP node those mail receiver will be the
-script downloading website's page and send you its WARC representation
-as a file. You can configure @option{sendmail} option like this:
-
-@verbatim
-% cat /usr/local/etc/nncp.yaml
-[...]
-  stargrave.org:
-    [...]
-    sendmail: ["/bin/sh", "/path/to/warcer.sh"]
-[...]
-@end verbatim
-
-And @file{warcer.sh} contents are:
-
-@verbatim
-#!/bin/sh -ex
-
-user_agent="Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27"
-
-name="$1"
-read cmdline
-
-tmp=$(mktemp -d)
-cd $tmp
-warc_name=$name-$(date '+%Y%M%d%H%m%S')
-wget \
-    --page-requisites \
-    --convert-links \
-    --adjust-extension \
-    --restrict-file-names=ascii \
-    --span-hosts \
-    --random-wait \
-    --execute robots=off \
-    --user-agent "$user_agent" \
-    --reject '*.woff*,*.ttf,*.eot,*.js' \
-    --tries 10 \
-    --warc-file $warc_name \
-    --no-warc-compression \
-    --no-warc-keep-log \
-    $cmdline || :
-xz -9 "$warc_name".warc
-nncp-file "$warc_name".warc.xz $NNCP_SENDER:
-rm -r $tmp
-@end verbatim
-
-Now you can queueu that node to send you some website's page:
-
-@verbatim
-% echo http://www.nncpgo.org/Postfix.html |
-    nncp-mail remote.node nncp-postfix-page
-@end verbatim
-
 @node BitTorrent
 @section BitTorrent and huge files
 
@@ -347,6 +295,85 @@ http://www.nncpgo.org/download/nncp-0.11.tar.xz.sig
 and all that downloaded (@file{nncp.txz}, @file{nncp.txz.sig}) files
 will be sent to @file{remote.node} when finished.
 
+@node DownloadService
+@section Downloading service
+
+Previous sections tell about manual downloading and sending results to
+remote node. But one wish to remotely initiate downloading. That can be
+easily solved with @ref{CfgExec, exec} handles.
+
+@verbatim
+exec:
+  warcer: ["/bin/sh", "/path/to/warcer.sh"]
+  wgeter: ["/bin/sh", "/path/to/wgeter.sh"]
+  aria2c: [
+    "/usr/local/bin/aria2c",
+    "--on-download-complete", "send-downloaded.sh",
+    "--on-bt-download-complete", "send-downloaded.sh"
+  ]
+@end verbatim
+
+@file{warcer.sh} contents:
+
+@verbatim
+#!/bin/sh -ex
+
+user_agent="Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27"
+
+name="$1"
+read cmdline
+
+tmp=$(mktemp -d)
+cd $tmp
+warc_name=$name-$(date '+%Y%M%d%H%m%S')
+wget \
+    --page-requisites \
+    --convert-links \
+    --adjust-extension \
+    --restrict-file-names=ascii \
+    --span-hosts \
+    --random-wait \
+    --execute robots=off \
+    --user-agent "$user_agent" \
+    --reject '*.woff*,*.ttf,*.eot,*.js' \
+    --tries 10 \
+    --warc-file $warc_name \
+    --no-warc-compression \
+    --no-warc-keep-log \
+    $cmdline || :
+xz -9 "$warc_name".warc
+nncp-file -nice $NNCP_NICE "$warc_name".warc.xz $NNCP_SENDER:
+rm -r $tmp
+@end verbatim
+
+@file{wgeter.sh} contents:
+
+@verbatim
+#!/bin/sh -ex
+
+name="$1"
+read cmdline
+tmp=$(mktemp)
+wget --output-document=$tmp $cmdline
+xz -9 $tmp
+nncp-file -nice $NNCP_NICE $tmp.xz $NNCP_SENDER:$name.xz
+rm $tmp.xz
+@end verbatim
+
+Now you can queue that node to send you some website's page, file or
+BitTorrents:
+
+@verbatim
+% echo http://www.nncpgo.org/Postfix.html |
+    nncp-exec remote.node warcer postfix-whole-page
+% echo http://www.nncpgo.org/Postfix.html |
+    nncp-exec remote.node wgeter postfix-html-page
+% echo \
+    http://www.nncpgo.org/download/nncp-0.11.tar.xz
+    http://www.nncpgo.org/download/nncp-0.11.tar.xz.sig |
+    nncp-exec remote.node aria2c
+@end verbatim
+
 @node Git
 @section Integration with Git
 
index 84b15c4b3ddd6064f8637d2873f1f9f908d963e9..ea8606a2476bd1f3cb445491232b77cb6272546d 100644 (file)
@@ -5,18 +5,32 @@
 @subsection Релиз 3.0
 @itemize
 @item
+@strong{Несовместимое} изменение формата простых пакетов. Работа со
+старыми версиями не поддерживается.
+@item
+Добавлена возможность удалённого исполнения команд, путём
+конфигурирования @option{exec} опции конфигурационного файла и
+использования команды @command{nncp-exec}:
+    @itemize
+    @item
+    Команда @command{nncp-mail} заменена более гибкой и широкой
+    @command{nncp-exec}. Вместо вызова @verb{|nncp-mail NODE RECIPIENT|}
+    нужно использовать @verb{|nncp-exec NODE sendmail RECIPIENT|}.
+    @item
+    @option{sendmail} опция конфигурационного файла заменена на более гибкую
+    @option{exec}. @verb{|sendmail: [...]|} нужно заменить на @verb{|exec:
+    sendmail: [...]|}.
+    @end itemize
+@item
 Возможность переопределить @option{via} опцию конфигурации для целевого
 узла через @option{-via} опцию командной строки для следующих команд:
-@command{nncp-file}, @command{nncp-freq}, @command{nncp-mail}.
+@command{nncp-file}, @command{nncp-freq}, @command{nncp-exec}.
 @item
 Chunked файлы, меньшего размера чем указанный chunk, отправляются просто
 в виде одного файла.
 @item
-@strong{Несовместимое} изменение формата простых пакетов. Добавлено поле
-@emph{NICE}. Работа со старыми версиями не поддерживается.
-@item
-Sendmail команда вызывается с дополнительной переменной окружения
-@env{NNCP_NICE} содержащая значение приоритета пакета с сообщением.
+Exec команды вызываются с дополнительными переменными окружения
+@env{NNCP_NICE} и @env{NNCP_SELF}.
 @item
 Отправляемые файлы в ответ на запрос имеют приоритет указанный в запросе.
 Указать их желаемый приоритет во время вызова @command{nncp-freq} можно
@@ -24,7 +38,7 @@ Sendmail команда вызывается с дополнительной п
 @item
 Команде @command{nncp-toss} можно сказать не обрабатывать определённые
 типы пакетов, за счёт опций @option{-nofile}, @option{-nofreq},
-@option{-nomail}, @option{-notrns}.
+@option{-noexec}, @option{-notrns}.
 @item
 По-умолчанию @command{nncp-file} команда для
 @option{-minsize}/@option{-chunked} опций использует
index d1a89b15f4b1b51e4c11ba198c48cf154398e3ee..4d9e7dccdd8a07fed6a787cb9e1c4f2a518c5130 100644 (file)
@@ -7,25 +7,38 @@ See also this page @ref{Новости, on russian}.
 @section Release 3.0
 @itemize
 @item
+@strong{Incompatible} plain packet format changes. Older versions are
+not supported.
+@item
+Ability to queue remote command execution, by configuring @option{exec}
+option in configuration file and using @command{nncp-exec} command:
+    @itemize
+    @item
+    @command{nncp-mail} command is replaced with more flexible
+    @command{nncp-exec}. Instead of @verb{|nncp-mail NODE RECIPIENT|}
+    you must use @verb{|nncp-exec NODE sendmail RECIPIENT|}.
+    @item
+    @option{sendmail} configuration file option is replaced with
+    @option{exec}. @verb{|sendmail: [...]|} must be replaced with
+    @verb{|exec: sendmail: [...]|}.
+    @end itemize
+@item
 Ability to override @option{via} configuration option for destination
 node via @option{-via} command line option for following commands:
-@command{nncp-file}, @command{nncp-freq}, @command{nncp-mail}.
+@command{nncp-file}, @command{nncp-freq}, @command{nncp-exec}.
 @item
 Chunked files, having size less than specified chunk size, will be sent
 as an ordinary single file.
 @item
-@strong{Incompatible} plain packet format changes. @emph{NICE} field is
-added. Older versions are not supported.
-@item
-Sendmail command is invoked with additional @env{NNCP_FILE} environment
-variable containing niceness level from incoming message packet.
+Exec commands are invoked with additional @env{NNCP_NICE} and
+@env{NNCP_SELF} environment variables.
 @item
 Files, that are sent as a reply to freq, have niceness level taken from
 the freq packet. You can set desired niceness during @command{nncp-freq}
 invocation using @option{-replynice} option.
 @item
 @command{nncp-toss} command can ignore specified packet types during
-processing: @option{-nofile}, @option{-nofreq}, @option{-nomail},
+processing: @option{-nofile}, @option{-nofreq}, @option{-noexec},
 @option{-notrns}.
 @item
 @command{nncp-file} command uses
index 50f392b350fc20a67998c70a214566d958c312d6..b0f99e9cc206818526090ba07ada52cc5afaedd6 100644 (file)
@@ -10,6 +10,6 @@ Send big files with higher nicer level! That will guarantee you that
 higher priority packets, like mail messages, will pass first, even when
 lower priority packet was already been partly downloaded.
 
-There are default niceness levels built-in for @ref{nncp-mail},
+There are default niceness levels built-in for @ref{nncp-exec},
 @ref{nncp-file} and @ref{nncp-freq} commands. But pay attention that it
 can give information about underlying payload to the adversary!
index 9c8c32e262da4a90ce1578b469eeec9c46f79f6f..b1c2c38b37cb5d7ad0f2254645d6e8120b94b1e8 100644 (file)
@@ -13,7 +13,7 @@ All packets are
 @section Plain packet
 
 Plain packet contains either the whole file, or file request (freq), or
-transition packet or email message. It is called "plain", because it
+transition packet or exec message. It is called "plain", because it
 contains plaintext, but plain packets would never be stored on your hard
 drive.
 
@@ -31,7 +31,7 @@ drive.
     @verb{|N N C P P 0x00 0x00 0x01|}
 @item Payload type @tab
     unsigned integer @tab
-    0 (file), 1 (freq), 2 (mail), 3 (transition)
+    0 (file), 1 (freq), 2 (exec), 3 (transition)
 @item Niceness @tab
     unsigned integer @tab
     1-255, preferred packet @ref{Niceness, niceness} level
@@ -43,7 +43,7 @@ drive.
     @itemize
     @item UTF-8 encoded destination path for file transfer
     @item UTF-8 encoded source path for file request
-    @item UTF-8 encoded, space separated, email recipients list
+    @item UTF-8 encoded, zero byte separated, exec's arguments
     @item Node's id the transition packet must be relayed on
     @end itemize
 @end multitable
@@ -58,7 +58,7 @@ Depending on the packet's type, payload could store:
 @itemize
 @item File contents
 @item Destination path for freq
-@item @url{http://zlib.net/, zlib} compressed email
+@item @url{http://zlib.net/, zlib} compressed exec body
 @item Whole encrypted packet we need to relay on
 @end itemize
 
@@ -66,8 +66,7 @@ Also depending on packet's type, niceness level means:
 
 @itemize
 @item Preferable niceness level for files sent by freq
-@item @env{NNCP_NICE} variable's value passed during
-    @ref{CfgSendmail} invocation.
+@item @env{NNCP_NICE} variable's value passed during @ref{CfgExec} invocation.
 @end itemize
 
 @node Encrypted
index 1407c8e7e359f52c71117ab46bac23b3e8fe1cd3..3e3caba2dbdd889cb32f761c52ebb3db131401c2 100644 (file)
@@ -35,7 +35,7 @@ Postfix} SMTP сервер подключённый к Интернету. Но
 KISS}!
 
 Просто скажите вашим обоим Postfix-ам (на сервере и ноутбуке) отправлять
-сообщения через NNCP (@ref{nncp-mail}) на заданный узел. Это делается
+сообщения через NNCP (@ref{nncp-exec}) на заданный узел. Это делается
 аналогично тому как с UUCP, и описано в
 @url{http://www.postfix.org/UUCP_README.html, документации Postfix}.
 
@@ -49,7 +49,7 @@ KISS}!
 
 @ref{nncp-daemon} может быть соединён с @ref{nncp-caller} длительное
 время -- он создаёт TCP соединение на многие часы. Когда SMTP сервер
-получает письмо, то вызывает @ref{nncp-mail} для создания исходящего
+получает письмо, то вызывает @ref{nncp-exec} для создания исходящего
 зашифрованного пакета. Демон ежесекундно проверяет исходящую директорию
 и сразу же посылает оповещение о недоставленных пакетах противоположной
 стороне, которая сразу же их может скачать.
@@ -70,7 +70,7 @@ IMAP4, как правило, нет). У вас легковесный, сжа
 проблематично получить. Более того, каждый обрыв может приводить к
 отсылке данных с самого начала, что не всегда по карману.
 
-Просто отправьте вашу @ref{nncp-mail, почту} и @ref{nncp-file, файлы}
+Просто отправьте вашу @ref{nncp-exec, почту} и @ref{nncp-file, файлы}
 через NNCP. Вы сможете использовать или offline методы доставки --
 читайте о них в следующем разделе, либо использовать поставляемый NNCP
 @ref{nncp-daemon, TCP демон}.
index 47307f8d0546bdf08e4eb80570f639de616c2331..c2764350451617e2f310231653adfc99d38b83cb 100644 (file)
@@ -34,7 +34,7 @@ overcomplicated and bloated for the simple task. Not an option.
 @url{https://en.wikipedia.org/wiki/KISS_principle, KISS}!
 
 Just tell both of your Postfixes (on the server and notebook) to drop
-email as a mail via NNCP (@ref{nncp-mail}) to specified node. This is
+email as a mail via NNCP (@ref{nncp-exec}) to specified node. This is
 done similarly as with UUCP and as written in
 @url{http://www.postfix.org/UUCP_README.html, Postfix documentation}.
 
@@ -48,7 +48,7 @@ that happened on the same machine.
 
 @ref{nncp-daemon} can be connected with @ref{nncp-caller} for a long
 time -- it can create TCP connection that lasts for many hours. When
-SMTP server receives mail, it will call @ref{nncp-mail} creating an
+SMTP server receives mail, it will call @ref{nncp-exec} creating an
 outbound encrypted packet. Daemon checks outbound directory each second
 and immediately sends notification about undelivered packets to remote
 side, that also downloads it at once.
@@ -68,7 +68,7 @@ download continuation. SMTP does not support resuming at all and heavy
 messages is problematic to retrieve. Moreover, each disconnect leads to
 the same data retransmission again, that can not be afforded sometimes.
 
-Just send your @ref{nncp-mail, mail} and @ref{nncp-file, files} through
+Just send your @ref{nncp-exec, mail} and @ref{nncp-file, files} through
 NNCP. You can use either offline delivery methods -- read about them in
 the next section, or you can use included NNCP @ref{nncp-daemon, TCP
 daemon}.
index 27a7ea9a1e3432fd6caf1a59bf3044cfaca3545c..def29296ab8bcf4a50f0753159de18d65c54fd64 100644 (file)
@@ -12,9 +12,9 @@ following workflow:
 neighbours. Add their keys to your configuration file and do any other
 required configuration about their reachability, permissions of file or
 freq transmission.
-@item Use @ref{nncp-file}, @ref{nncp-freq}, @ref{nncp-mail}
+@item Use @ref{nncp-file}, @ref{nncp-freq}, @ref{nncp-exec}
 (@ref{Postfix, look how} Postfix SMTP server could be configured)
-commands to queue file, freq and mail transmissions. Repeat as
+commands to queue file, freq and exec transmissions. Repeat as
 many times any time as you wish.
 @item Depending on connection methods, either:
     @itemize
@@ -29,7 +29,7 @@ many times any time as you wish.
     @end itemize
 @item After successful packet exchanging (or just simply from time to
 time), run @ref{nncp-toss} for tossing (decrypting and processing) all
-inbound queues to receive mail messages, files, file requests and relay
+inbound queues to receive exec messages, files, file requests and relay
 transition packets to other nodes.
 @end enumerate
 
index 22b42d6e155fc926d2e08aef67ab6e29fb18602b..a81bdc73e8274457db5ec2a71835670320513fe7 100755 (executable)
@@ -103,12 +103,13 @@ NNCP (Node to Node copy) is a collection of utilities simplifying
 secure store-and-forward files and mail exchanging.
 
 This utilities are intended to help build up small size (dozens of
-nodes) ad-hoc friend-to-friend (F2F) statically routed darknet networks
-for fire-and-forget secure reliable files, file requests and Internet
-mail transmission. All packets are integrity checked, end-to-end
-encrypted (E2EE), explicitly authenticated by known participants public
-keys. Onion encryption is applied to relayed packets. Each node acts
-both as a client and server, can use push and poll behaviour model.
+nodes) ad-hoc friend-to-friend (F2F) statically routed darknet
+delay-tolerant networks for fire-and-forget secure reliable files, file
+requests, Internet mail and commands transmission. All packets are
+integrity checked, end-to-end encrypted (E2EE), explicitly authenticated
+by known participants public keys. Onion encryption is applied to
+relayed packets. Each node acts both as a client and server, can use
+push and poll behaviour model.
 
 Out-of-box offline sneakernet/floppynet, dead drops, sequential and
 append-only CD-ROM/tape storages, air-gapped computers support. But
@@ -147,10 +148,10 @@ Subject: [RU] Состоялся релиз NNCP $release
 NNCP (Node to Node copy) это набор утилит упрощающий безопасный обмен
 файлами и почтой в режиме сохранить-и-переслать.
 
-ЭÑ\82и Ñ\83Ñ\82илиÑ\82Ñ\8b Ð¿Ñ\80едназнаÑ\87енÑ\8b Ð¿Ð¾Ð¼Ð¾Ñ\87Ñ\8c Ñ\81 Ð¿Ð¾Ñ\81Ñ\82Ñ\80оением Ð¾Ð´Ð½Ð¾Ñ\80анговÑ\8bÑ\85 Ñ\81еÑ\82ей
-небольшого размера (дюжины узлов), в режиме друг-к-другу (F2F) со
-статической маршрутизацией для безопасной надёжной передачи файлов,
-запросов на передачу файлов и Интернет почты по принципу
+ЭÑ\82и Ñ\83Ñ\82илиÑ\82Ñ\8b Ð¿Ñ\80едназнаÑ\87енÑ\8b Ð¿Ð¾Ð¼Ð¾Ñ\87Ñ\8c Ñ\81 Ð¿Ð¾Ñ\81Ñ\82Ñ\80оением Ð¾Ð´Ð½Ð¾Ñ\80анговÑ\8bÑ\85 Ñ\83Ñ\81Ñ\82ойÑ\87ивÑ\8bÑ\85 Ðº
+разрывам сетей небольшого размера (дюжины узлов), в режиме друг-к-другу
+(F2F) со статической маршрутизацией для безопасной надёжной передачи
+файлов, запросов на передачу файлов, Интернет почты и команд по принципу
 выстрелил-и-забыл. Все пакеты проверяются на целостность, шифруются по
 принципу точка-точка (E2EE), аутентифицируются известными публичными
 ключами участников. Луковичное (onion) шифрование применяется ко всем
index 4c539183ef4d8faee58b43e5fc9c59e9db1eb368..ce2e217be19c9f5c5fd69006534f3040e65927e6 100644 (file)
@@ -1,12 +1,12 @@
 # $FreeBSD: head/net/nncp/Makefile 460314 2018-01-29 16:17:45Z yuri $
 
 PORTNAME=      nncp
-DISTVERSION=   2.0
+DISTVERSION=   3.0
 CATEGORIES=    net
 MASTER_SITES=  http://www.nncpgo.org/download/
 
 MAINTAINER=    stargrave@stargrave.org
-COMMENT=       Utilities for secure store-and-forward files and mail exchanging
+COMMENT=       Utilities for secure store-and-forward files, mail and command exchanging
 
 LICENSE=       GPLv3+
 LICENSE_FILE=  ${WRKSRC}/COPYING
index 37b709118e5bd1d7c36b1f4aba82b15f103be4e6..ce972a9da8cb0b31df2397fed5d95ce9316f4230 100644 (file)
@@ -2,12 +2,13 @@ NNCP (Node to Node copy) is a collection of utilities simplifying
 secure store-and-forward files and mail exchanging.
 
 This utilities are intended to help build up small size (dozens of
-nodes) ad-hoc friend-to-friend (F2F) statically routed darknet networks
-for fire-and-forget secure reliable files, file requests and Internet
-mail transmission. All packets are integrity checked, end-to-end
-encrypted (E2EE), explicitly authenticated by known participants public
-keys. Onion encryption is applied to relayed packets. Each node acts
-both as a client and server, can use push and poll behaviour model.
+nodes) ad-hoc friend-to-friend (F2F) statically routed darknet
+delay-tolerant networks for fire-and-forget secure reliable files, file
+requests, Internet mail and commands transmission. All packets are
+integrity checked, end-to-end encrypted (E2EE), explicitly authenticated
+by known participants public keys. Onion encryption is applied to
+relayed packets. Each node acts both as a client and server, can use
+push and poll behaviour model.
 
 Out-of-box offline sneakernet/floppynet, dead drops, sequential and
 append-only CD-ROM/tape storages, air-gapped computers support. But
index 5da0b925825e065b4b12d32817010001f483923a..e98d84ea198a7f7ae4ba9f59da91b4f1e297bb3d 100644 (file)
@@ -6,10 +6,10 @@ bin/nncp-cfgmin
 bin/nncp-cfgnew
 bin/nncp-check
 bin/nncp-daemon
+bin/nncp-exec
 bin/nncp-file
 bin/nncp-freq
 bin/nncp-log
-bin/nncp-mail
 bin/nncp-pkt
 bin/nncp-reass
 bin/nncp-rm
index e6605e4ef3002337dc768d18c8c31f56bbf8efe3..b75196175e429b89f7408789fd932077bafd8cfd 100644 (file)
@@ -48,14 +48,14 @@ type NodeYAML struct {
        Id          string
        ExchPub     string
        SignPub     string
-       NoisePub    *string    `noisepub,omitempty`
-       Sendmail    []string   `sendmail,omitempty`
-       Incoming    *string    `incoming,omitempty`
-       Freq        *string    `freq,omitempty`
-       FreqChunked *uint64    `freqchunked,omitempty`
-       FreqMinSize *uint64    `freqminsize,omitempty`
-       Via         []string   `via,omitempty`
-       Calls       []CallYAML `calls,omitempty`
+       NoisePub    *string             `noisepub,omitempty`
+       Exec        map[string][]string `exec,omitempty`
+       Incoming    *string             `incoming,omitempty`
+       Freq        *string             `freq,omitempty`
+       FreqChunked *uint64             `freqchunked,omitempty`
+       FreqMinSize *uint64             `freqminsize,omitempty`
+       Via         []string            `via,omitempty`
+       Calls       []CallYAML          `calls,omitempty`
 
        Addrs map[string]string `addrs,omitempty`
 
@@ -232,7 +232,7 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                Id:             nodeId,
                ExchPub:        new([32]byte),
                SignPub:        ed25519.PublicKey(signPub),
-               Sendmail:       yml.Sendmail,
+               Exec:           yml.Exec,
                Incoming:       incoming,
                Freq:           freq,
                FreqChunked:    freqChunked,
index eb1b9ace5c15f0b8197a0202f1a687300a7cad0f..a119e3830989d73de494f3d9741c53b8e3f28cfc 100644 (file)
@@ -70,7 +70,9 @@ func main() {
                                ExchPub:  nncp.ToBase32(nodeOur.ExchPub[:]),
                                SignPub:  nncp.ToBase32(nodeOur.SignPub[:]),
                                NoisePub: &noisePub,
-                               Sendmail: []string{nncp.DefaultSendmailPath},
+                               Exec: map[string][]string{
+                                       "sendmail": []string{nncp.DefaultSendmailPath},
+                               },
                        },
                },
                Spool: nncp.DefaultSpoolPath,
similarity index 61%
rename from src/cypherpunks.ru/nncp/cmd/nncp-mail/main.go
rename to src/cypherpunks.ru/nncp/cmd/nncp-exec/main.go
index 13830d217dcef7760ec0020e55256482c344dd6d..8e7aec62682a1e3002d2557145ee33144273b044 100644 (file)
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-// Send email via NNCP
+// Send execution command via NNCP
 package main
 
 import (
@@ -33,23 +33,24 @@ import (
 
 func usage() {
        fmt.Fprintf(os.Stderr, nncp.UsageHeader())
-       fmt.Fprintf(os.Stderr, "nncp-mail -- send email\n\n")
-       fmt.Fprintf(os.Stderr, "Usage: %s [options] NODE USER ...\nOptions:\n", os.Args[0])
+       fmt.Fprintf(os.Stderr, "nncp-exec -- send execution command\n\n")
+       fmt.Fprintf(os.Stderr, "Usage: %s [options] NODE HANDLE [ARG0 ARG1 ...]\nOptions:\n", os.Args[0])
        flag.PrintDefaults()
 }
 
 func main() {
        var (
-               cfgPath     = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
-               niceRaw     = flag.Int("nice", nncp.DefaultNiceMail, "Outbound packet niceness")
-               minSize     = flag.Uint64("minsize", 0, "Minimal required resulting packet size, in KiB")
-               viaOverride = flag.String("via", "", "Override Via path to destination node")
-               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.Int("nice", nncp.DefaultNiceExec, "Outbound packet niceness")
+               replyNiceRaw = flag.Int("replynice", nncp.DefaultNiceFile, "Possible reply packet niceness")
+               minSize      = flag.Uint64("minsize", 0, "Minimal required resulting packet size, in KiB")
+               viaOverride  = flag.String("via", "", "Override Via path to destination node")
+               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")
        )
        flag.Usage = usage
        flag.Parse()
@@ -69,6 +70,10 @@ func main() {
                log.Fatalln("-nice must be between 1 and 255")
        }
        nice := uint8(*niceRaw)
+       if *replyNiceRaw < 1 || *replyNiceRaw > 255 {
+               log.Fatalln("-replynice must be between 1 and 255")
+       }
+       replyNice := uint8(*replyNiceRaw)
 
        ctx, err := nncp.CtxFromCmdline(*cfgPath, *spoolPath, *logPath, *quiet, *debug)
        if err != nil {
@@ -97,13 +102,15 @@ func main() {
 
        body, err := ioutil.ReadAll(bufio.NewReader(os.Stdin))
        if err != nil {
-               log.Fatalln("Can not read mail body from stdin:", err)
+               log.Fatalln("Can not read body from stdin:", err)
        }
 
-       if err = ctx.TxMail(
+       if err = ctx.TxExec(
                node,
                nice,
-               strings.Join(flag.Args()[1:], " "),
+               replyNice,
+               flag.Args()[1],
+               flag.Args()[2:],
                body,
                int64(*minSize)*1024,
        ); err != nil {
index d9c79bab344d81125a7b3fa0db88f8b82caa9a0e..f4de406a4b17eab7eb6b22cff66849d476cdc9d8 100644 (file)
@@ -94,13 +94,20 @@ func main() {
                        payloadType = "file"
                case nncp.PktTypeFreq:
                        payloadType = "file request"
-               case nncp.PktTypeMail:
-                       payloadType = "mail"
+               case nncp.PktTypeExec:
+                       payloadType = "exec"
                case nncp.PktTypeTrns:
                        payloadType = "transitional"
                }
                var path string
                switch pkt.Type {
+               case nncp.PktTypeExec:
+                       path = string(bytes.Replace(
+                               pkt.Path[:pkt.PathLen],
+                               []byte{0},
+                               []byte(" "),
+                               -1,
+                       ))
                case nncp.PktTypeTrns:
                        path = nncp.ToBase32(pkt.Path[:pkt.PathLen])
                default:
index 08e82ce6ce71571464348103d1a04d0e8e969043..cc3ca67fb57e6afd6a215d66d634b833e9aee098 100644 (file)
@@ -46,7 +46,7 @@ func main() {
                cycle     = flag.Uint("cycle", 0, "Repeat tossing after N seconds in infinite loop")
                noFile    = flag.Bool("nofile", false, "Do not process packets with type: file")
                noFreq    = flag.Bool("nofreq", false, "Do not process packets with type: freq")
-               noMail    = flag.Bool("nomail", false, "Do not process packets with type: mail")
+               noExec    = flag.Bool("noexec", false, "Do not process packets with type: exec")
                noTrns    = flag.Bool("notrns", false, "Do not process packets with type: transitional")
                spoolPath = flag.String("spool", "", "Override path to spool")
                logPath   = flag.String("log", "", "Override path to logfile")
@@ -99,7 +99,7 @@ Cycle:
                        *doSeen,
                        *noFile,
                        *noFreq,
-                       *noMail,
+                       *noExec,
                        *noTrns,
                )
        }
index 53ce6a061b42d3c6f9f3cfdeaf3f8e9fb4cbf3b2..cea9546b150d619f9022bb415fd686949f3a390b 100644 (file)
@@ -84,10 +84,10 @@ func (ctx *Ctx) Humanize(s string) string {
                                "File request from %s:%s to %s: %s",
                                nodeS, sds["src"], sds["dst"], rem,
                        )
-               case "mail":
+               case "exec":
                        msg = fmt.Sprintf(
-                               "Mail to %s@%s (%s): %s",
-                               nodeS, strings.Replace(sds["dst"], " ", ",", -1), size, rem,
+                               "Exec to %s@%s (%s): %s",
+                               nodeS, sds["dst"], size, rem,
                        )
                case "trns":
                        msg = fmt.Sprintf(
@@ -102,10 +102,10 @@ func (ctx *Ctx) Humanize(s string) string {
                }
        case "rx":
                switch sds["type"] {
-               case "mail":
+               case "exec":
                        msg = fmt.Sprintf(
-                               "Got mail from %s to %s (%s)",
-                               nodeS, strings.Replace(sds["dst"], " ", ",", -1), size,
+                               "Got exec from %s to %s (%s)",
+                               nodeS, sds["dst"], size,
                        )
                case "file":
                        msg = fmt.Sprintf("Got file %s (%s) from %s", sds["dst"], size, nodeS)
index 68e2fd4f70c95c52c143b5f89f352f7d4208a398..9cd4605662b7fb90bdd5a8ad16758afa13b9e647 100644 (file)
@@ -42,7 +42,7 @@ type Node struct {
        ExchPub        *[32]byte
        SignPub        ed25519.PublicKey
        NoisePub       *[32]byte
-       Sendmail       []string
+       Exec           map[string][]string
        Incoming       *string
        Freq           *string
        FreqChunked    int64
index 0e98d4beacb4c7d7483793c293e3b2fd99990134..b1c506a590d4ec816a61ac030781aa2645a7a8ea 100644 (file)
@@ -42,12 +42,12 @@ const (
 
        PktTypeFile PktType = iota
        PktTypeFreq PktType = iota
-       PktTypeMail PktType = iota
+       PktTypeExec PktType = iota
        PktTypeTrns PktType = iota
 
        MaxPathSize = 1<<8 - 1
 
-       DefaultNiceMail = 64
+       DefaultNiceExec = 64
        DefaultNiceFreq = 64
        DefaultNiceFile = 196
 
@@ -121,19 +121,18 @@ func init() {
        PktEncOverhead = int64(n)
 }
 
-func NewPkt(typ PktType, nice uint8, path string) (*Pkt, error) {
-       pb := []byte(path)
-       if len(pb) > MaxPathSize {
+func NewPkt(typ PktType, nice uint8, path []byte) (*Pkt, error) {
+       if len(path) > MaxPathSize {
                return nil, errors.New("Too long path")
        }
        pkt := Pkt{
                Magic:   MagicNNCPPv2,
                Type:    typ,
                Nice:    nice,
-               PathLen: uint8(len(pb)),
+               PathLen: uint8(len(path)),
                Path:    new([MaxPathSize]byte),
        }
-       copy(pkt.Path[:], pb)
+       copy(pkt.Path[:], path)
        return &pkt, nil
 }
 
index 6f8506a10918073fc20124b52ba2d1deb94b01e5..e0765b3a7179c53be091cc421f4d4ff63c58d50a 100644 (file)
@@ -41,7 +41,7 @@ func TestPktEncWrite(t *testing.T) {
                if len(path) > int(pathSize) {
                        path = path[:int(pathSize)]
                }
-               pkt, err := NewPkt(PktTypeFile, 123, path)
+               pkt, err := NewPkt(PktTypeFile, 123, []byte(path))
                if err != nil {
                        panic(err)
                }
@@ -87,7 +87,7 @@ func TestPktEncRead(t *testing.T) {
                if len(path) > int(pathSize) {
                        path = path[:int(pathSize)]
                }
-               pkt, err := NewPkt(PktTypeFile, 123, path)
+               pkt, err := NewPkt(PktTypeFile, 123, []byte(path))
                if err != nil {
                        panic(err)
                }
index a207785c32cf92ad2c5bb8a658f7ee84ea557cc6..86d154b2aa310a36b454e87c36ab989312c80e44 100644 (file)
@@ -52,7 +52,7 @@ func newNotification(fromTo *FromToYAML, subject string) io.Reader {
        ))
 }
 
-func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun, doSeen, noFile, noFreq, noMail, noTrns bool) bool {
+func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun, doSeen, noFile, noFreq, noExec, noTrns bool) bool {
        isBad := false
        for job := range ctx.Jobs(nodeId, TRx) {
                pktName := filepath.Base(job.Fd.Name())
@@ -93,39 +93,45 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun, doSeen, noFile, noFreq,
                sds["size"] = strconv.FormatInt(pktSize, 10)
                ctx.LogD("rx", sds, "taken")
                switch pkt.Type {
-               case PktTypeMail:
-                       if noMail {
+               case PktTypeExec:
+                       if noExec {
                                goto Closing
                        }
-                       recipients := make([]string, 0)
-                       for _, recipient := range bytes.Split(pkt.Path[:int(pkt.PathLen)], []byte{0}) {
-                               recipients = append(recipients, string(recipient))
+                       path := bytes.Split(pkt.Path[:int(pkt.PathLen)], []byte{0})
+                       handle := string(path[0])
+                       args := make([]string, 0, len(path)-1)
+                       for _, p := range path[1:] {
+                               args = append(args, string(p))
                        }
                        sds := SdsAdd(sds, SDS{
-                               "type": "mail",
-                               "dst":  strings.Join(recipients, " "),
+                               "type": "exec",
+                               "dst":  strings.Join(append([]string{handle}, args...), " "),
                        })
                        decompressor, err := zlib.NewReader(pipeR)
                        if err != nil {
                                log.Fatalln(err)
                        }
                        sender := ctx.Neigh[*job.PktEnc.Sender]
-                       sendmail := sender.Sendmail
-                       if len(sendmail) == 0 {
-                               ctx.LogE("rx", SdsAdd(sds, SDS{"err": "No sendmail configured"}), "")
+                       cmdline, exists := sender.Exec[handle]
+                       if !exists || len(cmdline) == 0 {
+                               ctx.LogE("rx", SdsAdd(sds, SDS{"err": "No handle found"}), "")
                                isBad = true
                                goto Closing
                        }
                        if !dryRun {
                                cmd := exec.Command(
-                                       sendmail[0],
-                                       append(sendmail[1:len(sendmail)], recipients...)...,
+                                       cmdline[0],
+                                       append(cmdline[1:len(cmdline)], args...)...,
+                               )
+                               cmd.Env = append(
+                                       cmd.Env,
+                                       "NNCP_SELF="+ctx.Self.Id.String(),
+                                       "NNCP_SENDER="+sender.Id.String(),
+                                       "NNCP_NICE="+strconv.Itoa(int(pkt.Nice)),
                                )
-                               cmd.Env = append(cmd.Env, "NNCP_SENDER="+sender.Id.String())
-                               cmd.Env = append(cmd.Env, "NNCP_NICE="+strconv.Itoa(int(pkt.Nice)))
                                cmd.Stdin = decompressor
                                if err = cmd.Run(); err != nil {
-                                       ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "sendmail")
+                                       ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "handle")
                                        isBad = true
                                        goto Closing
                                }
@@ -215,8 +221,8 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun, doSeen, noFile, noFreq,
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
                                        isBad = true
                                }
-                               sendmail := ctx.Neigh[*ctx.SelfId].Sendmail
-                               if ctx.NotifyFile != nil {
+                               sendmail, exists := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
+                               if exists && len(sendmail) > 0 && ctx.NotifyFile != nil {
                                        cmd := exec.Command(
                                                sendmail[0],
                                                append(sendmail[1:len(sendmail)], ctx.NotifyFile.To)...,
@@ -292,8 +298,8 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun, doSeen, noFile, noFreq,
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
                                        isBad = true
                                }
-                               if ctx.NotifyFreq != nil {
-                                       sendmail := ctx.Neigh[*ctx.SelfId].Sendmail
+                               sendmail, exists := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
+                               if exists && len(sendmail) > 0 && ctx.NotifyFreq != nil {
                                        cmd := exec.Command(
                                                sendmail[0],
                                                append(sendmail[1:len(sendmail)], ctx.NotifyFreq.To)...,
index 037c777321a62752541cd3d46b2bfc3eb31efd5c..7ff216408c1103142dde1ad7356518ec3cab0639 100644 (file)
@@ -51,8 +51,8 @@ func dirFiles(path string) []string {
        return names
 }
 
-func TestTossEmail(t *testing.T) {
-       f := func(recipients [16]uint8) bool {
+func TestTossExec(t *testing.T) {
+       f := func(replyNice uint8, handle string, recipients [16]uint8) bool {
                for i, recipient := range recipients {
                        recipients[i] = recipient % 8
                }
@@ -90,10 +90,12 @@ func TestTossEmail(t *testing.T) {
                        ctx.Neigh[*our.Id] = our.Their()
                }
                for _, recipient := range recipients {
-                       if err := ctx.TxMail(
+                       if err := ctx.TxExec(
                                ctx.Neigh[*privates[recipient].Id],
-                               DefaultNiceMail,
-                               "recipient",
+                               DefaultNiceExec,
+                               replyNice,
+                               handle,
+                               []string{"arg0", "arg1"},
                                []byte{123},
                                1<<15,
                        ); err != nil {
@@ -108,20 +110,25 @@ func TestTossEmail(t *testing.T) {
                        if len(dirFiles(rxPath)) == 0 {
                                continue
                        }
-                       ctx.Toss(ctx.Self.Id, DefaultNiceMail-1, false, false, false, false, false, false)
+                       ctx.Toss(ctx.Self.Id, DefaultNiceExec-1, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
-                       ctx.Neigh[*nodeOur.Id].Sendmail = []string{"/bin/sh", "-c", "false"}
-                       ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false, false, false, false, false)
+                       ctx.Neigh[*nodeOur.Id].Exec = make(map[string][]string)
+                       ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{"/bin/sh", "-c", "false"}
+                       ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) == 0 {
                                return false
                        }
-                       ctx.Neigh[*nodeOur.Id].Sendmail = []string{
+                       ctx.Neigh[*nodeOur.Id].Exec[handle] = []string{
                                "/bin/sh", "-c",
-                               fmt.Sprintf("cat >> %s", filepath.Join(spool, "mbox")),
+                               fmt.Sprintf(
+                                       "echo $NNCP_NICE $@ >> %s ; cat >> %s",
+                                       filepath.Join(spool, "mbox"),
+                                       filepath.Join(spool, "mbox"),
+                               ),
                        }
-                       ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false, false, false, false, false)
+                       ctx.Toss(ctx.Self.Id, DefaultNiceExec, false, false, false, false, false, false)
                        if len(dirFiles(rxPath)) != 0 {
                                return false
                        }
@@ -132,6 +139,10 @@ func TestTossEmail(t *testing.T) {
                }
                expected := make([]byte, 0, 16)
                for i := 0; i < 16; i++ {
+                       expected = append(
+                               expected,
+                               []byte(fmt.Sprintf("%d arg0 arg1\n", replyNice))...,
+                       )
                        expected = append(expected, 123)
                }
                return bytes.Compare(mbox, expected) == 0
@@ -471,7 +482,6 @@ func TestTossTrns(t *testing.T) {
                        for k, data := range datum {
                                if bytes.Compare(dataRead, data) == 0 {
                                        delete(datum, k)
-                                       break
                                }
                        }
                }
index a7e8b15eadb6215f6551b7dcdd59490bae5eb0a7..43198138b6440907abf09668e31c0cff7fc4b649 100644 (file)
@@ -68,13 +68,7 @@ func (ctx *Ctx) Tx(node *Node, pkt *Pkt, nice uint8, size, minSize int64, src io
 
        var pipeRPrev io.Reader
        for i := 1; i < len(hops); i++ {
-               pktTrans := Pkt{
-                       Magic:   MagicNNCPPv2,
-                       Type:    PktTypeTrns,
-                       PathLen: blake2b.Size256,
-                       Path:    new([MaxPathSize]byte),
-               }
-               copy(pktTrans.Path[:], hops[i-1].Id[:])
+               pktTrns, _ := NewPkt(PktTypeTrns, 0, hops[i-1].Id[:])
                curSize += PktOverhead + PktEncOverhead
                pipeRPrev = pipeR
                pipeR, pipeW = io.Pipe()
@@ -86,7 +80,7 @@ func (ctx *Ctx) Tx(node *Node, pkt *Pkt, nice uint8, size, minSize int64, src io
                        }, "trns wrote")
                        errs <- PktEncWrite(ctx.Self, node, pkt, nice, size, 0, src, dst)
                        dst.Close()
-               }(hops[i], &pktTrans, curSize, pipeRPrev, pipeW)
+               }(hops[i], pktTrns, curSize, pipeRPrev, pipeW)
        }
        go func() {
                _, err := io.Copy(tmp.W, pipeR)
@@ -157,7 +151,7 @@ func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize
        if filepath.IsAbs(dstPath) {
                return errors.New("Relative destination path required")
        }
-       pkt, err := NewPkt(PktTypeFile, nice, dstPath)
+       pkt, err := NewPkt(PktTypeFile, nice, []byte(dstPath))
        if err != nil {
                return err
        }
@@ -169,25 +163,19 @@ func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize
                return err
        }
        _, err = ctx.Tx(node, pkt, nice, fileSize, minSize, reader)
+       sds := SDS{
+               "type": "file",
+               "node": node.Id,
+               "nice": strconv.Itoa(int(nice)),
+               "src":  srcPath,
+               "dst":  dstPath,
+               "size": strconv.FormatInt(fileSize, 10),
+       }
        if err == nil {
-               ctx.LogI("tx", SDS{
-                       "type": "file",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "src":  srcPath,
-                       "dst":  dstPath,
-                       "size": strconv.FormatInt(fileSize, 10),
-               }, "sent")
+               ctx.LogI("tx", sds, "sent")
        } else {
-               ctx.LogE("tx", SDS{
-                       "type": "file",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "src":  srcPath,
-                       "dst":  dstPath,
-                       "size": strconv.FormatInt(fileSize, 10),
-                       "err":  err,
-               }, "sent")
+               sds["err"] = err
+               ctx.LogE("tx", sds, "sent")
        }
        return err
 }
@@ -212,30 +200,24 @@ func (ctx *Ctx) TxFileChunked(node *Node, nice uint8, srcPath, dstPath string, m
        }
 
        if fileSize <= chunkSize {
-               pkt, err := NewPkt(PktTypeFile, nice, dstPath)
+               pkt, err := NewPkt(PktTypeFile, nice, []byte(dstPath))
                if err != nil {
                        return err
                }
                _, err = ctx.Tx(node, pkt, nice, fileSize, minSize, reader)
+               sds := SDS{
+                       "type": "file",
+                       "node": node.Id,
+                       "nice": strconv.Itoa(int(nice)),
+                       "src":  srcPath,
+                       "dst":  dstPath,
+                       "size": strconv.FormatInt(fileSize, 10),
+               }
                if err == nil {
-                       ctx.LogI("tx", SDS{
-                               "type": "file",
-                               "node": node.Id,
-                               "nice": strconv.Itoa(int(nice)),
-                               "src":  srcPath,
-                               "dst":  dstPath,
-                               "size": strconv.FormatInt(fileSize, 10),
-                       }, "sent")
+                       ctx.LogI("tx", sds, "sent")
                } else {
-                       ctx.LogE("tx", SDS{
-                               "type": "file",
-                               "node": node.Id,
-                               "nice": strconv.Itoa(int(nice)),
-                               "src":  srcPath,
-                               "dst":  dstPath,
-                               "size": strconv.FormatInt(fileSize, 10),
-                               "err":  err,
-                       }, "sent")
+                       sds["err"] = err
+                       ctx.LogE("tx", sds, "sent")
                }
                return err
        }
@@ -263,7 +245,7 @@ func (ctx *Ctx) TxFileChunked(node *Node, nice uint8, srcPath, dstPath string, m
                        sizeToSend = chunkSize
                }
                path = dstPath + ChunkedSuffixPart + strconv.Itoa(chunkNum)
-               pkt, err = NewPkt(PktTypeFile, nice, path)
+               pkt, err = NewPkt(PktTypeFile, nice, []byte(path))
                if err != nil {
                        return err
                }
@@ -279,25 +261,19 @@ func (ctx *Ctx) TxFileChunked(node *Node, nice uint8, srcPath, dstPath string, m
                        minSize,
                        io.TeeReader(reader, hsh),
                )
+               sds := SDS{
+                       "type": "file",
+                       "node": node.Id,
+                       "nice": strconv.Itoa(int(nice)),
+                       "src":  srcPath,
+                       "dst":  path,
+                       "size": strconv.FormatInt(sizeToSend, 10),
+               }
                if err == nil {
-                       ctx.LogI("tx", SDS{
-                               "type": "file",
-                               "node": node.Id,
-                               "nice": strconv.Itoa(int(nice)),
-                               "src":  srcPath,
-                               "dst":  path,
-                               "size": strconv.FormatInt(sizeToSend, 10),
-                       }, "sent")
+                       ctx.LogI("tx", sds, "sent")
                } else {
-                       ctx.LogE("tx", SDS{
-                               "type": "file",
-                               "node": node.Id,
-                               "nice": strconv.Itoa(int(nice)),
-                               "src":  srcPath,
-                               "dst":  path,
-                               "size": strconv.FormatInt(sizeToSend, 10),
-                               "err":  err,
-                       }, "sent")
+                       sds["err"] = err
+                       ctx.LogE("tx", sds, "sent")
                        return err
                }
                hsh.Sum(metaPkt.Checksums[chunkNum][:0])
@@ -313,31 +289,25 @@ func (ctx *Ctx) TxFileChunked(node *Node, nice uint8, srcPath, dstPath string, m
                return err
        }
        path = dstPath + ChunkedSuffixMeta
-       pkt, err = NewPkt(PktTypeFile, nice, path)
+       pkt, err = NewPkt(PktTypeFile, nice, []byte(path))
        if err != nil {
                return err
        }
        metaPktSize := int64(metaBuf.Len())
        _, err = ctx.Tx(node, pkt, nice, metaPktSize, minSize, &metaBuf)
+       sds := SDS{
+               "type": "file",
+               "node": node.Id,
+               "nice": strconv.Itoa(int(nice)),
+               "src":  srcPath,
+               "dst":  path,
+               "size": strconv.FormatInt(metaPktSize, 10),
+       }
        if err == nil {
-               ctx.LogI("tx", SDS{
-                       "type": "file",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "src":  srcPath,
-                       "dst":  path,
-                       "size": strconv.FormatInt(metaPktSize, 10),
-               }, "sent")
+               ctx.LogI("tx", sds, "sent")
        } else {
-               ctx.LogE("tx", SDS{
-                       "type": "file",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "src":  srcPath,
-                       "dst":  path,
-                       "size": strconv.FormatInt(metaPktSize, 10),
-                       "err":  err,
-               }, "sent")
+               sds["err"] = err
+               ctx.LogE("tx", sds, "sent")
        }
        return err
 }
@@ -351,36 +321,37 @@ func (ctx *Ctx) TxFreq(node *Node, nice, replyNice uint8, srcPath, dstPath strin
        if filepath.IsAbs(srcPath) {
                return errors.New("Relative source path required")
        }
-       pkt, err := NewPkt(PktTypeFreq, replyNice, srcPath)
+       pkt, err := NewPkt(PktTypeFreq, replyNice, []byte(srcPath))
        if err != nil {
                return err
        }
        src := strings.NewReader(dstPath)
        size := int64(src.Len())
        _, err = ctx.Tx(node, pkt, nice, size, minSize, src)
+       sds := SDS{
+               "type":      "freq",
+               "node":      node.Id,
+               "nice":      strconv.Itoa(int(nice)),
+               "replynice": strconv.Itoa(int(replyNice)),
+               "src":       srcPath,
+               "dst":       dstPath,
+       }
        if err == nil {
-               ctx.LogI("tx", SDS{
-                       "type": "freq",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "src":  srcPath,
-                       "dst":  dstPath,
-               }, "sent")
+               ctx.LogI("tx", sds, "sent")
        } else {
-               ctx.LogE("tx", SDS{
-                       "type": "freq",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "src":  srcPath,
-                       "dst":  dstPath,
-                       "err":  err,
-               }, "sent")
+               sds["err"] = err
+               ctx.LogE("tx", sds, "sent")
        }
        return err
 }
 
-func (ctx *Ctx) TxMail(node *Node, nice uint8, recipient string, body []byte, minSize int64) error {
-       pkt, err := NewPkt(PktTypeMail, nice, recipient)
+func (ctx *Ctx) TxExec(node *Node, nice, replyNice uint8, handle string, args []string, body []byte, minSize int64) error {
+       path := make([][]byte, 0, 1+len(args))
+       path = append(path, []byte(handle))
+       for _, arg := range args {
+               path = append(path, []byte(arg))
+       }
+       pkt, err := NewPkt(PktTypeExec, replyNice, bytes.Join(path, []byte{0}))
        if err != nil {
                return err
        }
@@ -395,34 +366,31 @@ func (ctx *Ctx) TxMail(node *Node, nice uint8, recipient string, body []byte, mi
        compressor.Close()
        size := int64(compressed.Len())
        _, err = ctx.Tx(node, pkt, nice, size, minSize, &compressed)
+       sds := SDS{
+               "type":      "exec",
+               "node":      node.Id,
+               "nice":      strconv.Itoa(int(nice)),
+               "replynice": strconv.Itoa(int(replyNice)),
+               "dst":       strings.Join(append([]string{handle}, args...), " "),
+               "size":      strconv.FormatInt(size, 10),
+       }
        if err == nil {
-               ctx.LogI("tx", SDS{
-                       "type": "mail",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "dst":  recipient,
-                       "size": strconv.FormatInt(size, 10),
-               }, "sent")
+               ctx.LogI("tx", sds, "sent")
        } else {
-               ctx.LogE("tx", SDS{
-                       "type": "mail",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "dst":  recipient,
-                       "size": strconv.FormatInt(size, 10),
-                       "err":  err,
-               }, "sent")
+               sds["err"] = err
+               ctx.LogE("tx", sds, "sent")
        }
        return err
 }
 
 func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error {
-       ctx.LogD("tx", SDS{
+       sds := SDS{
                "type": "trns",
                "node": node.Id,
                "nice": strconv.Itoa(int(nice)),
                "size": strconv.FormatInt(size, 10),
-       }, "taken")
+       }
+       ctx.LogD("tx", sds, "taken")
        tmp, err := ctx.NewTmpFileWHash()
        if err != nil {
                return err
@@ -433,20 +401,10 @@ func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error
        nodePath := filepath.Join(ctx.Spool, node.Id.String())
        err = tmp.Commit(filepath.Join(nodePath, string(TTx)))
        if err == nil {
-               ctx.LogI("tx", SDS{
-                       "type": "trns",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "size": strconv.FormatInt(size, 10),
-               }, "sent")
+               ctx.LogI("tx", sds, "sent")
        } else {
-               ctx.LogI("tx", SDS{
-                       "type": "trns",
-                       "node": node.Id,
-                       "nice": strconv.Itoa(int(nice)),
-                       "size": strconv.FormatInt(size, 10),
-                       "err":  err,
-               }, "sent")
+               sds["err"] = err
+               ctx.LogI("tx", sds, "sent")
        }
        os.Symlink(nodePath, filepath.Join(ctx.Spool, node.Name))
        return err
index 0a4485f6b04f816333b1d31df468ab430a02f9f9..6ea7ef2cb7b9613c4e78fe7020f9c6420af794c7 100644 (file)
@@ -33,7 +33,7 @@ import (
 )
 
 func TestTx(t *testing.T) {
-       f := func(hops uint8, pathSrc, data string, nice uint8, padSize int16) bool {
+       f := func(hops uint8, pathSrc, data string, nice, replyNice uint8, padSize int16) bool {
                if len(pathSrc) > int(MaxPathSize) {
                        pathSrc = pathSrc[:MaxPathSize]
                }
@@ -76,7 +76,7 @@ func TestTx(t *testing.T) {
                        privates[*node.Id] = node
                        nodeTgt.Via = append(nodeTgt.Via, node.Id)
                }
-               pkt, err := NewPkt(PktTypeMail, 123, pathSrc)
+               pkt, err := NewPkt(PktTypeExec, replyNice, []byte(pathSrc))
                src := strings.NewReader(data)
                dstNode, err := ctx.Tx(
                        nodeTgt,
@@ -121,7 +121,10 @@ func TestTx(t *testing.T) {
                                return false
                        }
                        if *hopId == *nodeTgt.Id {
-                               if pkt.Type != PktTypeMail {
+                               if pkt.Type != PktTypeExec {
+                                       return false
+                               }
+                               if pkt.Nice != replyNice {
                                        return false
                                }
                                if !bytes.HasPrefix(pkt.Path[:], []byte(pathSrc)) {