anchor.diff:    # Some random file to serve.
     file = pkgs.hello.src;
   
  -  miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf"
  -    ''
  -      ext_ifname=eth1
  -      listening_ip=${(pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address}/24
  -      allow 1024-65535 192.168.2.0/24 1024-65535
  -    '';
  -
  +  internalRouterAddress = "192.168.3.1";
  +  internalClient1Address = "192.168.3.2";
  +  externalRouterAddress = "80.100.100.1";
  +  externalClient2Address = "80.100.100.2";
  +  externalTrackerAddress = "80.100.100.3";
   in
   
   {
  
positive.code:     ''
        startAll;
  
        # Enable NAT on the router and start miniupnpd.
        $router->waitForUnit("nat");
        $router->succeed(
            "iptables -w -t nat -N MINIUPNPD",
            "iptables -w -t nat -A PREROUTING -i eth1 -j MINIUPNPD",
            "echo 1 > /proc/sys/net/ipv4/ip_forward",
            "miniupnpd -f ${miniupnpdConf nodes}"
        );
  
        # Create the torrent.
        $tracker->succeed("mkdir /tmp/data");
        $tracker->succeed("cp ${file} /tmp/data/test.tar.bz2");
        $tracker->succeed("transmission-create /tmp/data/test.tar.bz2 -p -t http://${(pkgs.lib.head nodes.tracker.config.networking.interfaces.eth1.ipv4.addresses).address}:6969/announce -o /tmp/test.torrent");
        $tracker->succeed("chmod 644 /tmp/test.torrent");
  
        # Start the tracker.  !!! use a less crappy tracker
        $tracker->waitForUnit("network.target");
        $tracker->succeed("opentracker -p 6969 >&2 &");
        $tracker->waitForOpenPort(6969);
  
        # Start the initial seeder.
        my $pid = $tracker->succeed("transmission-cli /tmp/test.torrent -M -w /tmp/data >&2 & echo \$!");
  
        # Now we should be able to download from the client behind the NAT.
        $tracker->waitForUnit("httpd");
        $client1->waitForUnit("network.target");
        $client1->succeed("transmission-cli http://tracker/test.torrent -w /tmp >&2 &");
        $client1->waitForFile("/tmp/test.tar.bz2");
        $client1->succeed("cmp /tmp/test.tar.bz2 ${file}");
  
        # Bring down the initial seeder.
        $tracker->succeed("kill -9 $pid");
  
        # Now download from the second client.  This can only succeed if
        # the first client created a NAT hole in the router.
        $client2->waitForUnit("network.target");
        $client2->succeed("transmission-cli http://tracker/test.torrent -M -w /tmp >&2 &");
        $client2->waitForFile("/tmp/test.tar.bz2");
        $client2->succeed("cmp /tmp/test.tar.bz2 ${file}");
      '';
  
negative.code:   nodes =
      { tracker =
          { pkgs, ... }:
          { environment.systemPackages = [ pkgs.transmission ];
  
            virtualisation.vlans = [ 1 ];
            networking.interfaces.eth1.ipv4.addresses = [
              { address = externalTrackerAddress; prefixLength = 24; }
            ];
  
            # We need Apache on the tracker to serve the torrents.
            services.httpd.enable = true;
            services.httpd.adminAddr = "foo@example.org";
            services.httpd.documentRoot = "/tmp";
  
            networking.firewall.enable = false;
  
            services.opentracker.enable = true;
  
            services.transmission.enable = true;
            services.transmission.settings.dht-enabled = false;
            services.transmission.settings.port-forwaring-enabled = false;
          };
  
        router =
          { pkgs, nodes, ... }:
          { virtualisation.vlans = [ 1 2 ];
            networking.nat.enable = true;
            networking.nat.internalInterfaces = [ "eth2" ];
            networking.nat.externalInterface = "eth1";
            networking.firewall.enable = true;
            networking.firewall.trustedInterfaces = [ "eth2" ];
            networking.interfaces.eth0.ipv4.addresses = [];
            networking.interfaces.eth1.ipv4.addresses = [
              { address = externalRouterAddress; prefixLength = 24; }
            ];
            networking.interfaces.eth2.ipv4.addresses = [
              { address = internalRouterAddress; prefixLength = 24; }
            ];
            services.miniupnpd = {
              enable = true;
              externalInterface = "eth1";
              internalIPs = [ "eth2" ];
              appendConfig = ''
                ext_ip=${externalRouterAddress}
              '';
            };
          };
  
        client1 =
          { pkgs, nodes, ... }:
          { environment.systemPackages = [ pkgs.transmission pkgs.miniupnpc ];
            virtualisation.vlans = [ 2 ];
            networking.interfaces.eth0.ipv4.addresses = [];
            networking.interfaces.eth1.ipv4.addresses = [
              { address = internalClient1Address; prefixLength = 24; }
            ];
            networking.defaultGateway = internalRouterAddress;
            networking.firewall.enable = false;
            services.transmission.enable = true;
            services.transmission.settings.dht-enabled = false;
            services.transmission.settings.message-level = 3;
          };
  
        client2 =
          { pkgs, ... }:
          { environment.systemPackages = [ pkgs.transmission ];
            virtualisation.vlans = [ 1 ];
            networking.interfaces.eth0.ipv4.addresses = [];
            networking.interfaces.eth1.ipv4.addresses = [
              { address = externalClient2Address; prefixLength = 24; }
            ];
            networking.firewall.enable = false;
            services.transmission.enable = true;
            services.transmission.settings.dht-enabled = false;
            services.transmission.settings.port-forwaring-enabled = false;
          };
      };
  
  