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