at 23.11-pre 5.4 kB view raw
1# This test runs a Bittorrent tracker on one machine, and verifies 2# that two client machines can download the torrent using 3# `transmission'. The first client (behind a NAT router) downloads 4# from the initial seeder running on the tracker. Then we kill the 5# initial seeder. The second client downloads from the first client, 6# which only works if the first client successfully uses the UPnP-IGD 7# protocol to poke a hole in the NAT. 8 9import ./make-test-python.nix ({ pkgs, ... }: 10 11let 12 13 # Some random file to serve. 14 file = pkgs.hello.src; 15 16 internalRouterAddress = "192.168.3.1"; 17 internalClient1Address = "192.168.3.2"; 18 externalRouterAddress = "80.100.100.1"; 19 externalClient2Address = "80.100.100.2"; 20 externalTrackerAddress = "80.100.100.3"; 21 22 download-dir = "/var/lib/transmission/Downloads"; 23 transmissionConfig = { ... }: { 24 environment.systemPackages = [ pkgs.transmission ]; 25 services.transmission = { 26 enable = true; 27 settings = { 28 dht-enabled = false; 29 message-level = 2; 30 inherit download-dir; 31 }; 32 }; 33 }; 34in 35 36{ 37 name = "bittorrent"; 38 meta = with pkgs.lib.maintainers; { 39 maintainers = [ domenkozar eelco rob bobvanderlinden ]; 40 }; 41 42 nodes = { 43 tracker = { pkgs, ... }: { 44 imports = [ transmissionConfig ]; 45 46 virtualisation.vlans = [ 1 ]; 47 networking.firewall.enable = false; 48 networking.interfaces.eth1.ipv4.addresses = [ 49 { address = externalTrackerAddress; prefixLength = 24; } 50 ]; 51 52 # We need Apache on the tracker to serve the torrents. 53 services.httpd = { 54 enable = true; 55 virtualHosts = { 56 "torrentserver.org" = { 57 adminAddr = "foo@example.org"; 58 documentRoot = "/tmp"; 59 }; 60 }; 61 }; 62 services.opentracker.enable = true; 63 }; 64 65 router = { pkgs, nodes, ... }: { 66 virtualisation.vlans = [ 1 2 ]; 67 networking.nat.enable = true; 68 networking.nat.internalInterfaces = [ "eth2" ]; 69 networking.nat.externalInterface = "eth1"; 70 networking.firewall.enable = true; 71 networking.firewall.trustedInterfaces = [ "eth2" ]; 72 networking.interfaces.eth0.ipv4.addresses = []; 73 networking.interfaces.eth1.ipv4.addresses = [ 74 { address = externalRouterAddress; prefixLength = 24; } 75 ]; 76 networking.interfaces.eth2.ipv4.addresses = [ 77 { address = internalRouterAddress; prefixLength = 24; } 78 ]; 79 services.miniupnpd = { 80 enable = true; 81 externalInterface = "eth1"; 82 internalIPs = [ "eth2" ]; 83 appendConfig = '' 84 ext_ip=${externalRouterAddress} 85 ''; 86 }; 87 }; 88 89 client1 = { pkgs, nodes, ... }: { 90 imports = [ transmissionConfig ]; 91 environment.systemPackages = [ pkgs.miniupnpc ]; 92 93 virtualisation.vlans = [ 2 ]; 94 networking.interfaces.eth0.ipv4.addresses = []; 95 networking.interfaces.eth1.ipv4.addresses = [ 96 { address = internalClient1Address; prefixLength = 24; } 97 ]; 98 networking.defaultGateway = internalRouterAddress; 99 networking.firewall.enable = false; 100 }; 101 102 client2 = { pkgs, ... }: { 103 imports = [ transmissionConfig ]; 104 105 virtualisation.vlans = [ 1 ]; 106 networking.interfaces.eth0.ipv4.addresses = []; 107 networking.interfaces.eth1.ipv4.addresses = [ 108 { address = externalClient2Address; prefixLength = 24; } 109 ]; 110 networking.firewall.enable = false; 111 }; 112 }; 113 114 testScript = { nodes, ... }: '' 115 start_all() 116 117 # Wait for network and miniupnpd. 118 router.wait_for_unit("network-online.target") 119 router.wait_for_unit("miniupnpd") 120 121 # Create the torrent. 122 tracker.succeed("mkdir ${download-dir}/data") 123 tracker.succeed( 124 "cp ${file} ${download-dir}/data/test.tar.bz2" 125 ) 126 tracker.succeed( 127 "transmission-create ${download-dir}/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent" 128 ) 129 tracker.succeed("chmod 644 /tmp/test.torrent") 130 131 # Start the tracker. !!! use a less crappy tracker 132 tracker.wait_for_unit("network-online.target") 133 tracker.wait_for_unit("opentracker.service") 134 tracker.wait_for_open_port(6969) 135 136 # Start the initial seeder. 137 tracker.succeed( 138 "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir ${download-dir}/data" 139 ) 140 141 # Now we should be able to download from the client behind the NAT. 142 tracker.wait_for_unit("httpd") 143 client1.wait_for_unit("network-online.target") 144 client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &") 145 client1.wait_for_file("${download-dir}/test.tar.bz2") 146 client1.succeed( 147 "cmp ${download-dir}/test.tar.bz2 ${file}" 148 ) 149 150 # Bring down the initial seeder. 151 # tracker.stop_job("transmission") 152 153 # Now download from the second client. This can only succeed if 154 # the first client created a NAT hole in the router. 155 client2.wait_for_unit("network-online.target") 156 client2.succeed( 157 "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &" 158 ) 159 client2.wait_for_file("${download-dir}/test.tar.bz2") 160 client2.succeed( 161 "cmp ${download-dir}/test.tar.bz2 ${file}" 162 ) 163 ''; 164})