1# This tests whether UPnP port mappings can be created using Miniupnpd
2# and Miniupnpc.
3# It runs a Miniupnpd service on one machine, and verifies
4# a client can indeed create a port mapping using Miniupnpc. If
5# this succeeds an external client will try to connect to the port
6# mapping.
7
8import ./make-test-python.nix (
9 { pkgs, useNftables, ... }:
10
11 let
12 internalRouterAddress = "192.168.3.1";
13 internalClient1Address = "192.168.3.2";
14 externalRouterAddress = "80.100.100.1";
15 externalClient2Address = "80.100.100.2";
16 in
17 {
18 name = "upnp";
19 meta = with pkgs.lib.maintainers; {
20 maintainers = [ bobvanderlinden ];
21 };
22
23 nodes = {
24 router =
25 { pkgs, nodes, ... }:
26 {
27 virtualisation.vlans = [
28 1
29 2
30 ];
31 networking.nat.enable = true;
32 networking.nat.internalInterfaces = [ "eth2" ];
33 networking.nat.externalInterface = "eth1";
34 networking.nftables.enable = useNftables;
35 networking.firewall.enable = true;
36 networking.firewall.trustedInterfaces = [ "eth2" ];
37 networking.interfaces.eth1.ipv4.addresses = [
38 {
39 address = externalRouterAddress;
40 prefixLength = 24;
41 }
42 ];
43 networking.interfaces.eth2.ipv4.addresses = [
44 {
45 address = internalRouterAddress;
46 prefixLength = 24;
47 }
48 ];
49 services.miniupnpd = {
50 enable = true;
51 externalInterface = "eth1";
52 internalIPs = [ "eth2" ];
53 appendConfig = ''
54 ext_ip=${externalRouterAddress}
55 '';
56 };
57 };
58
59 client1 =
60 { pkgs, nodes, ... }:
61 {
62 environment.systemPackages = [
63 pkgs.miniupnpc
64 pkgs.netcat
65 ];
66 virtualisation.vlans = [ 2 ];
67 networking.defaultGateway = internalRouterAddress;
68 networking.interfaces.eth1.ipv4.addresses = [
69 {
70 address = internalClient1Address;
71 prefixLength = 24;
72 }
73 ];
74 networking.firewall.enable = false;
75
76 services.httpd.enable = true;
77 services.httpd.virtualHosts.localhost = {
78 listen = [
79 {
80 ip = "*";
81 port = 9000;
82 }
83 ];
84 adminAddr = "foo@example.org";
85 documentRoot = "/tmp";
86 };
87 };
88
89 client2 =
90 { pkgs, ... }:
91 {
92 environment.systemPackages = [ pkgs.miniupnpc ];
93 virtualisation.vlans = [ 1 ];
94 networking.interfaces.eth1.ipv4.addresses = [
95 {
96 address = externalClient2Address;
97 prefixLength = 24;
98 }
99 ];
100 networking.firewall.enable = false;
101 };
102 };
103
104 testScript =
105 { nodes, ... }:
106 ''
107 start_all()
108
109 # Wait for network and miniupnpd.
110 router.systemctl("start network-online.target")
111 router.wait_for_unit("network-online.target")
112 # $router.wait_for_unit("nat")
113 router.wait_for_unit("${if useNftables then "nftables" else "firewall"}.service")
114 router.wait_for_unit("miniupnpd")
115
116 client1.systemctl("start network-online.target")
117 client1.wait_for_unit("network-online.target")
118
119 client1.succeed("upnpc -a ${internalClient1Address} 9000 9000 TCP")
120
121 client1.wait_for_unit("httpd")
122 client2.wait_until_succeeds("curl -f http://${externalRouterAddress}:9000/")
123 '';
124
125 }
126)