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
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) шифрование применяется ко всем
nncp-cfgnew \
nncp-check \
nncp-daemon \
+ nncp-exec \
nncp-file \
nncp-freq \
nncp-log \
- nncp-mail \
nncp-pkt \
nncp-reass \
nncp-rm \
nncp-daemon:
GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-daemon
+nncp-exec:
+ GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-exec
+
nncp-file:
GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/nncp/cmd/nncp-file
nncp-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
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,
точка-точка}, аутентифицируются известными публичными ключами
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,
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
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
@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,
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
@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
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
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
@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 Нет
@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
* Web feeds: Feeds.
* Web pages: WARCs.
* BitTorrent and huge files: BitTorrent.
+* Downloading service: DownloadService.
* Git::
* Multimedia streaming: Multimedia.
@end menu
@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.
@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.
@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.
@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
--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
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
@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} можно
@item
Команде @command{nncp-toss} можно сказать не обрабатывать определённые
типы пакетов, за счёт опций @option{-nofile}, @option{-nofreq},
-@option{-nomail}, @option{-notrns}.
+@option{-noexec}, @option{-notrns}.
@item
По-умолчанию @command{nncp-file} команда для
@option{-minsize}/@option{-chunked} опций использует
@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
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!
@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.
@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
@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
@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
@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
KISS}!
Просто скажите вашим обоим Postfix-ам (на сервере и ноутбуке) отправлять
-сообщения через NNCP (@ref{nncp-mail}) на заданный узел. Это делается
+сообщения через NNCP (@ref{nncp-exec}) на заданный узел. Это делается
аналогично тому как с UUCP, и описано в
@url{http://www.postfix.org/UUCP_README.html, документации Postfix}.
@ref{nncp-daemon} может быть соединён с @ref{nncp-caller} длительное
время -- он создаёт TCP соединение на многие часы. Когда SMTP сервер
-получает письмо, то вызывает @ref{nncp-mail} для создания исходящего
+получает письмо, то вызывает @ref{nncp-exec} для создания исходящего
зашифрованного пакета. Демон ежесекундно проверяет исходящую директорию
и сразу же посылает оповещение о недоставленных пакетах противоположной
стороне, которая сразу же их может скачать.
проблематично получить. Более того, каждый обрыв может приводить к
отсылке данных с самого начала, что не всегда по карману.
-Просто отправьте вашу @ref{nncp-mail, почту} и @ref{nncp-file, файлы}
+Просто отправьте вашу @ref{nncp-exec, почту} и @ref{nncp-file, файлы}
через NNCP. Вы сможете использовать или offline методы доставки --
читайте о них в следующем разделе, либо использовать поставляемый NNCP
@ref{nncp-daemon, TCP демон}.
@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}.
@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.
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}.
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
@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
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
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) шифрование применяется ко всем
# $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
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
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
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`
Id: nodeId,
ExchPub: new([32]byte),
SignPub: ed25519.PublicKey(signPub),
- Sendmail: yml.Sendmail,
+ Exec: yml.Exec,
Incoming: incoming,
Freq: freq,
FreqChunked: freqChunked,
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,
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-// Send email via NNCP
+// Send execution command via NNCP
package main
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()
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 {
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 {
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:
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")
*doSeen,
*noFile,
*noFreq,
- *noMail,
+ *noExec,
*noTrns,
)
}
"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(
}
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)
ExchPub *[32]byte
SignPub ed25519.PublicKey
NoisePub *[32]byte
- Sendmail []string
+ Exec map[string][]string
Incoming *string
Freq *string
FreqChunked int64
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
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
}
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)
}
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)
}
))
}
-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())
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
}
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)...,
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)...,
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
}
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 {
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
}
}
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
for k, data := range datum {
if bytes.Compare(dataRead, data) == 0 {
delete(datum, k)
- break
}
}
}
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()
}, "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)
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
}
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
}
}
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
}
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
}
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])
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
}
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
}
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
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
)
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]
}
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,
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)) {