diff options
Diffstat (limited to 'nixos/tests/bittorrent.nix')
-rw-r--r-- | nixos/tests/bittorrent.nix | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix new file mode 100644 index 00000000000..11420cba9dc --- /dev/null +++ b/nixos/tests/bittorrent.nix @@ -0,0 +1,164 @@ +# This test runs a Bittorrent tracker on one machine, and verifies +# that two client machines can download the torrent using +# `transmission'. The first client (behind a NAT router) downloads +# from the initial seeder running on the tracker. Then we kill the +# initial seeder. The second client downloads from the first client, +# which only works if the first client successfully uses the UPnP-IGD +# protocol to poke a hole in the NAT. + +import ./make-test-python.nix ({ pkgs, ... }: + +let + + # Some random file to serve. + file = pkgs.hello.src; + + 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"; + + download-dir = "/var/lib/transmission/Downloads"; + transmissionConfig = { ... }: { + environment.systemPackages = [ pkgs.transmission ]; + services.transmission = { + enable = true; + settings = { + dht-enabled = false; + message-level = 2; + inherit download-dir; + }; + }; + }; +in + +{ + name = "bittorrent"; + meta = with pkgs.lib.maintainers; { + maintainers = [ domenkozar eelco rob bobvanderlinden ]; + }; + + nodes = { + tracker = { pkgs, ... }: { + imports = [ transmissionConfig ]; + + virtualisation.vlans = [ 1 ]; + networking.firewall.enable = false; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalTrackerAddress; prefixLength = 24; } + ]; + + # We need Apache on the tracker to serve the torrents. + services.httpd = { + enable = true; + virtualHosts = { + "torrentserver.org" = { + adminAddr = "foo@example.org"; + documentRoot = "/tmp"; + }; + }; + }; + services.opentracker.enable = true; + }; + + 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, ... }: { + imports = [ transmissionConfig ]; + environment.systemPackages = [ 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; + }; + + client2 = { pkgs, ... }: { + imports = [ transmissionConfig ]; + + virtualisation.vlans = [ 1 ]; + networking.interfaces.eth0.ipv4.addresses = []; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalClient2Address; prefixLength = 24; } + ]; + networking.firewall.enable = false; + }; + }; + + testScript = { nodes, ... }: '' + start_all() + + # Wait for network and miniupnpd. + router.wait_for_unit("network-online.target") + router.wait_for_unit("miniupnpd") + + # Create the torrent. + tracker.succeed("mkdir ${download-dir}/data") + tracker.succeed( + "cp ${file} ${download-dir}/data/test.tar.bz2" + ) + tracker.succeed( + "transmission-create ${download-dir}/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent" + ) + tracker.succeed("chmod 644 /tmp/test.torrent") + + # Start the tracker. !!! use a less crappy tracker + tracker.wait_for_unit("network-online.target") + tracker.wait_for_unit("opentracker.service") + tracker.wait_for_open_port(6969) + + # Start the initial seeder. + tracker.succeed( + "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir ${download-dir}/data" + ) + + # Now we should be able to download from the client behind the NAT. + tracker.wait_for_unit("httpd") + client1.wait_for_unit("network-online.target") + client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &") + client1.wait_for_file("${download-dir}/test.tar.bz2") + client1.succeed( + "cmp ${download-dir}/test.tar.bz2 ${file}" + ) + + # Bring down the initial seeder. + # tracker.stop_job("transmission") + + # Now download from the second client. This can only succeed if + # the first client created a NAT hole in the router. + client2.wait_for_unit("network-online.target") + client2.succeed( + "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &" + ) + client2.wait_for_file("${download-dir}/test.tar.bz2") + client2.succeed( + "cmp ${download-dir}/test.tar.bz2 ${file}" + ) + ''; +}) |