Jump to content

NNCP: Difference between revisions

From NixOS Wiki
Ehmry (talk | contribs)
Add configuration example for receiving email.
Ehmry (talk | contribs)
Add configurations examples for relaying email.
Line 59: Line 59:
     secrets = [ "/etc/secrets/nncp.hjson" ];
     secrets = [ "/etc/secrets/nncp.hjson" ];
     neigh = {
     neigh = {
       alice = {
       carol = {
         # information that Alice has given us about her "self".
         # 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 Alice over network.
         # We can connect directly to Carol over network.
         addr = {
         addr = {
           lan = "[fe80::1234%igb0]:5400";
           lan = "[fe80::1234%igb0]:5400";
           internet = "alice.com:3389";
           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 cannoct connect to Bob but be can relay packets to him thru Alice.
         # We cannot connect to Bob but we can relay packets to him thru Carol.
         via = [ "alice" ];
         via = [ "carol" ];
       };
       };
     };
     };
Line 104: Line 104:
</syntaxhighlight>
</syntaxhighlight>


== Remote command execution ==
== Copying Nix store paths ==


=== Store path importing ===
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 ===
== 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 that allows Bob and Carol to send email to Alice.
# NixOS module for Alice's STMP relay server.
#
{ config, lib, ... }:
 
let
let
   mailer.exec.sendmail = [
   domain = "example.org";
    "/run/wrappers/bin/sendmail" # Use the system `sendmail`.
  fqdn = "example.org";
    "alice"                      # Redirect all messages to the `alice` user.
  certCfg = config.security.acme.certs.${fqdn};
  ];
  certDir = certCfg.directory;
  smtpdCertDir = "/var/lib/smtp";
in
in
{
{
   programs.nncp.settings.neigh = {
  # Allow incoming SMTP connections.
     bob = mailer;
  networking.firewall.allowedTCPPorts = [
     carol = mailer;
    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.

http://www.nncpgo.org/

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

Email

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"
    '';
  };
}