at 25.11-pre 6.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 ( 10 { pkgs, ... }: 11 12 let 13 14 # Some random file to serve. 15 file = pkgs.hello.src; 16 17 internalRouterAddress = "192.168.3.1"; 18 internalClient1Address = "192.168.3.2"; 19 externalRouterAddress = "80.100.100.1"; 20 externalClient2Address = "80.100.100.2"; 21 externalTrackerAddress = "80.100.100.3"; 22 23 download-dir = "/var/lib/transmission/Downloads"; 24 transmissionConfig = 25 { pkgs, ... }: 26 { 27 environment.systemPackages = [ pkgs.transmission_3 ]; 28 services.transmission = { 29 enable = true; 30 settings = { 31 dht-enabled = false; 32 message-level = 2; 33 inherit download-dir; 34 }; 35 }; 36 }; 37 in 38 39 { 40 name = "bittorrent"; 41 meta = with pkgs.lib.maintainers; { 42 maintainers = [ 43 domenkozar 44 rob 45 bobvanderlinden 46 ]; 47 }; 48 49 nodes = { 50 tracker = 51 { pkgs, ... }: 52 { 53 imports = [ transmissionConfig ]; 54 55 virtualisation.vlans = [ 1 ]; 56 networking.firewall.enable = false; 57 networking.interfaces.eth1.ipv4.addresses = [ 58 { 59 address = externalTrackerAddress; 60 prefixLength = 24; 61 } 62 ]; 63 64 # We need Apache on the tracker to serve the torrents. 65 services.httpd = { 66 enable = true; 67 virtualHosts = { 68 "torrentserver.org" = { 69 adminAddr = "foo@example.org"; 70 documentRoot = "/tmp"; 71 }; 72 }; 73 }; 74 services.opentracker.enable = true; 75 }; 76 77 router = 78 { pkgs, nodes, ... }: 79 { 80 virtualisation.vlans = [ 81 1 82 2 83 ]; 84 networking.nat.enable = true; 85 networking.nat.internalInterfaces = [ "eth2" ]; 86 networking.nat.externalInterface = "eth1"; 87 networking.firewall.enable = true; 88 networking.firewall.trustedInterfaces = [ "eth2" ]; 89 networking.interfaces.eth0.ipv4.addresses = [ ]; 90 networking.interfaces.eth1.ipv4.addresses = [ 91 { 92 address = externalRouterAddress; 93 prefixLength = 24; 94 } 95 ]; 96 networking.interfaces.eth2.ipv4.addresses = [ 97 { 98 address = internalRouterAddress; 99 prefixLength = 24; 100 } 101 ]; 102 services.miniupnpd = { 103 enable = true; 104 externalInterface = "eth1"; 105 internalIPs = [ "eth2" ]; 106 appendConfig = '' 107 ext_ip=${externalRouterAddress} 108 ''; 109 }; 110 }; 111 112 client1 = 113 { pkgs, nodes, ... }: 114 { 115 imports = [ transmissionConfig ]; 116 environment.systemPackages = [ pkgs.miniupnpc ]; 117 118 virtualisation.vlans = [ 2 ]; 119 networking.interfaces.eth0.ipv4.addresses = [ ]; 120 networking.interfaces.eth1.ipv4.addresses = [ 121 { 122 address = internalClient1Address; 123 prefixLength = 24; 124 } 125 ]; 126 networking.defaultGateway = internalRouterAddress; 127 networking.firewall.enable = false; 128 }; 129 130 client2 = 131 { pkgs, ... }: 132 { 133 imports = [ transmissionConfig ]; 134 135 virtualisation.vlans = [ 1 ]; 136 networking.interfaces.eth0.ipv4.addresses = [ ]; 137 networking.interfaces.eth1.ipv4.addresses = [ 138 { 139 address = externalClient2Address; 140 prefixLength = 24; 141 } 142 ]; 143 networking.firewall.enable = false; 144 }; 145 }; 146 147 testScript = 148 { nodes, ... }: 149 '' 150 start_all() 151 152 # Wait for network and miniupnpd. 153 router.systemctl("start network-online.target") 154 router.wait_for_unit("network-online.target") 155 router.wait_for_unit("miniupnpd") 156 157 # Create the torrent. 158 tracker.succeed("mkdir ${download-dir}/data") 159 tracker.succeed( 160 "cp ${file} ${download-dir}/data/test.tar.bz2" 161 ) 162 tracker.succeed( 163 "transmission-create ${download-dir}/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent" 164 ) 165 tracker.succeed("chmod 644 /tmp/test.torrent") 166 167 # Start the tracker. !!! use a less crappy tracker 168 tracker.systemctl("start network-online.target") 169 tracker.wait_for_unit("network-online.target") 170 tracker.wait_for_unit("opentracker.service") 171 tracker.wait_for_open_port(6969) 172 173 # Start the initial seeder. 174 tracker.succeed( 175 "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir ${download-dir}/data" 176 ) 177 178 # Now we should be able to download from the client behind the NAT. 179 tracker.wait_for_unit("httpd") 180 client1.systemctl("start network-online.target") 181 client1.wait_for_unit("network-online.target") 182 client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &") 183 client1.wait_for_file("${download-dir}/test.tar.bz2") 184 client1.succeed( 185 "cmp ${download-dir}/test.tar.bz2 ${file}" 186 ) 187 188 # Bring down the initial seeder. 189 tracker.stop_job("transmission") 190 191 # Now download from the second client. This can only succeed if 192 # the first client created a NAT hole in the router. 193 client2.systemctl("start network-online.target") 194 client2.wait_for_unit("network-online.target") 195 client2.succeed( 196 "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &" 197 ) 198 client2.wait_for_file("${download-dir}/test.tar.bz2") 199 client2.succeed( 200 "cmp ${download-dir}/test.tar.bz2 ${file}" 201 ) 202 ''; 203 } 204)