NNCP: Difference between revisions
Add configuration example for receiving email. |
Add configurations examples for relaying email. |
||
Line 59: | Line 59: | ||
secrets = [ "/etc/secrets/nncp.hjson" ]; | secrets = [ "/etc/secrets/nncp.hjson" ]; | ||
neigh = { | neigh = { | ||
carol = { | |||
# information that | # information that Carol has given us about her "self". | ||
id = "D6BOO…YTYWQ"; | id = "D6BOO…YTYWQ"; | ||
exchpub = "V4WJ6…4VA3Q"; | exchpub = "V4WJ6…4VA3Q"; | ||
signpub = "NZLTN…HCGOA"; | signpub = "NZLTN…HCGOA"; | ||
noisepub = "UNL2J…7FRDA"; | noisepub = "UNL2J…7FRDA"; | ||
# We can connect directly to | # We can connect directly to Carol over network. | ||
addr = { | addr = { | ||
lan = "[fe80::1234%igb0]:5400"; | lan = "[fe80::1234%igb0]:5400"; | ||
internet = " | internet = "carol.example.com:3389"; | ||
proxied = "|ssh remote.host nncp-daemon -ucspi"; | proxied = "|ssh remote.host nncp-daemon -ucspi"; | ||
}; | }; | ||
Line 78: | Line 78: | ||
signpub = "E6XSC…5VYRA"; | signpub = "E6XSC…5VYRA"; | ||
noisepub = "TAKXG…Z6MZQ"; | noisepub = "TAKXG…Z6MZQ"; | ||
# We | # We cannot connect to Bob but we can relay packets to him thru Carol. | ||
via = [ " | via = [ "carol" ]; | ||
}; | }; | ||
}; | }; | ||
Line 104: | Line 104: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Copying Nix store paths == | ||
NNCP can be use to transport the closures of Nix store paths between machines. | |||
NNCP config: | NNCP config: | ||
Line 120: | Line 120: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Receiving | == Email == | ||
NNCP is an ideal transport for secure email. | |||
=== Receiving email === | |||
<syntaxhighlight lang="nix"> | |||
# NixOS module for Alice that allows reception of mail from Bob and Carol as well as mail relayed thru her mailserver. | |||
{ | |||
config, | |||
lib, | |||
pkgs, | |||
... | |||
}: | |||
{ | |||
programs.nncp.settings.neigh = | |||
let | |||
mailer.exec.sendmail = [ | |||
"/run/wrappers/bin/sendmail" # Pipe mail into the system sendmail. | |||
"alice" # Redirect messages to the "alice" user. | |||
]; | |||
in | |||
{ | |||
bob = mailer; | |||
carol = mailer; | |||
mailserver = mailer; # This is Alice's mailserver, described later. | |||
}; | |||
# Use opensmtpd for the system sendmail command. | |||
services.opensmtpd = { | |||
enable = true; | |||
setSendmail = true; | |||
serverConfiguration = '' | |||
listen on lo | |||
# Deliver mail into Alice's home directory. | |||
action "inbox" maildir "%{user.directory}/mail" | |||
match for local action "inbox" | |||
''; | |||
}; | |||
} | |||
</syntaxhighlight> | |||
=== Sending mail === | |||
To send mail alice configures her client send mail to her mailserver by using nncp-exec as if it were <code>sendmail</code>. | |||
<code> | |||
nncp-exec -noprogress mailserver sendmail -f alice@example.org -t | |||
</code> | |||
=== Relaying email === | |||
To send mail to domains via STMP a relay is required that implements the [[wikipedia:Sender Policy Framework|SPF]] standard. Configuring SPF and other DNS based standards is not described here. | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
# NixOS module | # NixOS module for Alice's STMP relay server. | ||
{ config, lib, ... }: | |||
let | let | ||
domain = "example.org"; | |||
fqdn = "example.org"; | |||
certCfg = config.security.acme.certs.${fqdn}; | |||
certDir = certCfg.directory; | |||
smtpdCertDir = "/var/lib/smtp"; | |||
in | in | ||
{ | { | ||
programs.nncp.settings.neigh = { | # Allow incoming SMTP connections. | ||
networking.firewall.allowedTCPPorts = [ | |||
25 | |||
465 | |||
]; | |||
# Receive mail from Alice's NNCP node and pipe it into sendmail unaltered. | |||
programs.nncp.settings.neigh.alice.exec.sendmail = [ | |||
"/run/wrappers/bin/sendmail" | |||
]; | |||
# Get a certificate for SMTP from ACME. | |||
security.acme = { | |||
acceptTerms = true; | |||
certs.${fqdn} = { | |||
email = "admin@${domain}"; | |||
reloadServices = [ "opensmtpd.service" ]; | |||
postRun = '' | |||
mkdir -p ${smtpdCertDir} | |||
cp ${certDir}/cert.pem ${smtpdCertDir}/cert | |||
cp ${certDir}/key.pem ${smtpdCertDir}/key | |||
chown 0:0 ${smtpdCertDir}/* | |||
''; | |||
}; | |||
}; | |||
# Wrap nncp-exec so that the unpriviledged | |||
# smtpd can produce outgoing NNCP packets. | |||
security.wrappers.nncp-exec = { | |||
setuid = true; | |||
owner = "root"; | |||
group = "uucp"; | |||
source = "${config.programs.nncp.package}/bin/nncp-exec"; | |||
}; | |||
# Configure an smtpd. | |||
services.opensmtpd = { | |||
enable = true; | |||
setSendmail = true; # Create the sendmail command for incoming NNCP mails. | |||
serverConfiguration = '' | |||
# Use the ACME certificate. | |||
pki ${fqdn} cert "${smtpdCertDir}/cert" | |||
pki ${fqdn} key "${smtpdCertDir}/key" | |||
# Configure SMTP listeners. | |||
# Authentication is by domain only, there are no logins here. | |||
listen on lo | |||
listen on eth0 smtps pki ${fqdn} # Classical SMTP. | |||
listen on eth0 tls pki ${fqdn} # Listen with TLS. | |||
listen on tun0 mask-src # Listen on a tunnel interface but | |||
# omit the details from headers. | |||
# Configure a NNCP Mail Delivery Agent (MDA) for local users. | |||
action "nncp" mda "/run/wrappers/bin/nncp-exec -quiet %{rcpt.user} sendmail" | |||
# Configure SMTP relaying to external domains. | |||
action "relay" relay tls helo ${domain} | |||
# Rules for mail received at this smtpd. | |||
match from any for domain "${domain}" action "nncp" | |||
match from local for any action "relay" | |||
''; | |||
}; | }; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 09:52, 29 April 2025
NNCP (Node to Node copy) is a collection of utilities simplifying secure store-and-forward files, mail and command exchanging.
These utilities are intended to help build up small size (dozens of 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, 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. Also there is multicasting areas support.
Out-of-box offline sneakernet/floppynet, dead drops, sequential and append-only CD-ROM/tape storages, air-gapped computers support. But online TCP daemon with full-duplex resumable data transmission exists.
Configuration
NNCP can be installed and configured manually or via NixOS configuration.
In any case the first step is to generate a configuration file.
$ nncp-cfgnew -nocomments > /etc/secrets/nncp.hjson
This generated file should be stripped down to include only the self
and neigh
sections:
{ self: { # DO NOT show anyone your private keys!!! id: HFTEI…SITTA exchpub: RG2SF…7JEYA exchprv: 4YAON…LWCMA signpub: ASKTA…EFVSQ signprv: Z6Q4R…SC2ZI noiseprv: ACJVW…7G7NA noisepub: J2W5C…SZM6Q } neigh: { self: { id: HFTEI…SITTA exchpub: RG2SF…7JEYA signpub: ASKTA…EFVSQ noisepub: J2W5C…SZM6Q } } }
The location of this file should be defined in your NixOS configuration at programs.nncp.secrets:
{
programs.nncp = {
enable = true;
secrets = [ "/etc/secrets/nncp.hjson" ];
};
}
In this example the secret keys are stored outside the Nix store an we will add public keys for neighboring nodes in the NixOS configuration.
{
programs.nncp = {
enable = true;
secrets = [ "/etc/secrets/nncp.hjson" ];
neigh = {
carol = {
# information that Carol has given us about her "self".
id = "D6BOO…YTYWQ";
exchpub = "V4WJ6…4VA3Q";
signpub = "NZLTN…HCGOA";
noisepub = "UNL2J…7FRDA";
# We can connect directly to Carol over network.
addr = {
lan = "[fe80::1234%igb0]:5400";
internet = "carol.example.com:3389";
proxied = "|ssh remote.host nncp-daemon -ucspi";
};
};
bob = {
# information that Bob has given us about his "self".
id = "3I3HC…F4P4Q";
exchpub = "7VJN7…BWUTQ";
signpub = "E6XSC…5VYRA";
noisepub = "TAKXG…Z6MZQ";
# We cannot connect to Bob but we can relay packets to him thru Carol.
via = [ "carol" ];
};
};
};
}
Callers and Daemons
The NNCP caller and daemon can be enabled for NixOS using the options services.nncp.caller
and services.nncp.daemon
.
{
services.nncp = let
attrs = {
enable = true;
extraArgs = [ "-autotoss" ];
};
in {
caller = attrs;
daemon = attrs;
};
}
Copying Nix store paths
NNCP can be use to transport the closures of Nix store paths between machines.
NNCP config:
{
programs.nncp.settings.neigh.${NODE}.exec.nix-store-import = "nix-store --import";
}
Export command:
$ nix-store --export ./result | nncp-exec "$NODE" nix-store-import
NNCP is an ideal transport for secure email.
Receiving email
# NixOS module for Alice that allows reception of mail from Bob and Carol as well as mail relayed thru her mailserver.
{
config,
lib,
pkgs,
...
}:
{
programs.nncp.settings.neigh =
let
mailer.exec.sendmail = [
"/run/wrappers/bin/sendmail" # Pipe mail into the system sendmail.
"alice" # Redirect messages to the "alice" user.
];
in
{
bob = mailer;
carol = mailer;
mailserver = mailer; # This is Alice's mailserver, described later.
};
# Use opensmtpd for the system sendmail command.
services.opensmtpd = {
enable = true;
setSendmail = true;
serverConfiguration = ''
listen on lo
# Deliver mail into Alice's home directory.
action "inbox" maildir "%{user.directory}/mail"
match for local action "inbox"
'';
};
}
Sending mail
To send mail alice configures her client send mail to her mailserver by using nncp-exec as if it were sendmail
.
nncp-exec -noprogress mailserver sendmail -f alice@example.org -t
Relaying email
To send mail to domains via STMP a relay is required that implements the SPF standard. Configuring SPF and other DNS based standards is not described here.
# NixOS module for Alice's STMP relay server.
{ config, lib, ... }:
let
domain = "example.org";
fqdn = "example.org";
certCfg = config.security.acme.certs.${fqdn};
certDir = certCfg.directory;
smtpdCertDir = "/var/lib/smtp";
in
{
# Allow incoming SMTP connections.
networking.firewall.allowedTCPPorts = [
25
465
];
# Receive mail from Alice's NNCP node and pipe it into sendmail unaltered.
programs.nncp.settings.neigh.alice.exec.sendmail = [
"/run/wrappers/bin/sendmail"
];
# Get a certificate for SMTP from ACME.
security.acme = {
acceptTerms = true;
certs.${fqdn} = {
email = "admin@${domain}";
reloadServices = [ "opensmtpd.service" ];
postRun = ''
mkdir -p ${smtpdCertDir}
cp ${certDir}/cert.pem ${smtpdCertDir}/cert
cp ${certDir}/key.pem ${smtpdCertDir}/key
chown 0:0 ${smtpdCertDir}/*
'';
};
};
# Wrap nncp-exec so that the unpriviledged
# smtpd can produce outgoing NNCP packets.
security.wrappers.nncp-exec = {
setuid = true;
owner = "root";
group = "uucp";
source = "${config.programs.nncp.package}/bin/nncp-exec";
};
# Configure an smtpd.
services.opensmtpd = {
enable = true;
setSendmail = true; # Create the sendmail command for incoming NNCP mails.
serverConfiguration = ''
# Use the ACME certificate.
pki ${fqdn} cert "${smtpdCertDir}/cert"
pki ${fqdn} key "${smtpdCertDir}/key"
# Configure SMTP listeners.
# Authentication is by domain only, there are no logins here.
listen on lo
listen on eth0 smtps pki ${fqdn} # Classical SMTP.
listen on eth0 tls pki ${fqdn} # Listen with TLS.
listen on tun0 mask-src # Listen on a tunnel interface but
# omit the details from headers.
# Configure a NNCP Mail Delivery Agent (MDA) for local users.
action "nncp" mda "/run/wrappers/bin/nncp-exec -quiet %{rcpt.user} sendmail"
# Configure SMTP relaying to external domains.
action "relay" relay tls helo ${domain}
# Rules for mail received at this smtpd.
match from any for domain "${domain}" action "nncp"
match from local for any action "relay"
'';
};
}