]> git.meshlink.io Git - meshlink/blob - test/netns_utils.c
Never automatically try to bind to ports >= 32768.
[meshlink] / test / netns_utils.c
1 #define _GNU_SOURCE 1
2
3 #ifndef NDEBUG
4 #undef NDEBUG
5 #endif
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12
13 #include "../src/meshlink.h"
14 #include "netns_utils.h"
15 #include "utils.h"
16
17 static int ip = 1;
18
19 /// Create meshlink instances and network namespaces for a list of peers
20 static void create_peers(peer_config_t *peers, int npeers, const char *prefix) {
21         // We require root for network namespaces
22         if(getuid() != 0) {
23                 exit(77);
24         }
25
26         for(int i = 0; i < npeers; i++) {
27                 assert(asprintf(&peers[i].netns_name, "%s%d", prefix, i) > 0);
28                 char *command = NULL;
29                 assert(asprintf(&command,
30                                 "/bin/ip netns delete %1$s 2>/dev/null || true;"
31                                 "/bin/ip netns add %1$s;"
32                                 "/bin/ip netns exec %1$s ip link set dev lo up;",
33                                 peers[i].netns_name));
34                 assert(command);
35                 assert(system(command) == 0);
36                 free(command);
37
38                 char *netns_path = NULL;
39                 assert(asprintf(&netns_path, "/run/netns/%s", peers[i].netns_name));
40                 assert(netns_path);
41                 peers[i].netns = open(netns_path, O_RDONLY);
42                 assert(peers[i].netns != -1);
43                 free(netns_path);
44
45                 char *conf_path = NULL;
46                 assert(asprintf(&conf_path, "%s_conf.%d", prefix, i + 1) > 0);
47                 assert(conf_path);
48                 assert(meshlink_destroy(conf_path));
49
50                 meshlink_open_params_t *params = meshlink_open_params_init(conf_path, peers[i].name, prefix, peers[i].devclass);
51                 assert(params);
52                 assert(meshlink_open_params_set_netns(params, peers[i].netns));
53
54                 peers[i].mesh = meshlink_open_ex(params);
55                 assert(peers[i].mesh);
56                 free(params);
57                 free(conf_path);
58
59                 meshlink_enable_discovery(peers[i].mesh, false);
60         }
61 }
62
63 /// Set up a LAN topology where all peers can see each other directly
64 static void setup_lan_topology(peer_config_t *peers, int npeers) {
65         // Set up the LAN bridge
66         {
67                 char *command = NULL;
68                 assert(asprintf(&command,
69                                 "/bin/ip netns exec %1$s /bin/ip link add eth0 type bridge;"
70                                 "/bin/ip netns exec %1$s /bin/ip link set eth0 up;",
71                                 peers[0].netns_name));
72                 assert(command);
73                 assert(system(command) == 0);
74         }
75
76         // Add an interface to each peer that is connected to the bridge
77         for(int i = 1; i < npeers; i++) {
78                 char *command = NULL;
79                 assert(asprintf(&command,
80                                 "/bin/ip netns exec %1$s /bin/ip link add eth0 type veth peer eth%3$d netns %2$s;"
81                                 "/bin/ip netns exec %1$s /bin/ip link set dev eth0 up;"
82                                 "/bin/ip netns exec %2$s /bin/ip link set dev eth%3$d master eth0 up;",
83                                 peers[i].netns_name, peers[0].netns_name, i));
84                 assert(command);
85                 assert(system(command) == 0);
86                 free(command);
87         }
88
89         // Configure addresses
90         for(int i = 0; i < npeers; i++) {
91                 change_peer_ip(&peers[i]);
92         }
93 }
94
95 /// Set up an indirect topology where all peers can only access the relay
96 static void setup_indirect_topology(peer_config_t *peers, int npeers) {
97         // Add an interface to each peer that is connected to the relay
98         for(int i = 1; i < npeers; i++) {
99                 char *command = NULL;
100                 assert(asprintf(&command,
101                                 "/bin/ip netns exec %1$s /bin/ip link add eth0 type veth peer eth%3$d netns %2$s;"
102                                 "/bin/ip netns exec %1$s ip addr flush dev eth0;"
103                                 "/bin/ip netns exec %1$s ip addr add 192.168.%3$d.2/24 dev eth0;"
104                                 "/bin/ip netns exec %1$s /bin/ip link set dev eth0 up;"
105                                 "/bin/ip netns exec %2$s ip addr flush dev eth%3$d;"
106                                 "/bin/ip netns exec %2$s ip addr add 192.168.%3$d.1/24 dev eth%3$d;"
107                                 "/bin/ip netns exec %2$s /bin/ip link set dev eth%3$d up;",
108                                 peers[i].netns_name, peers[0].netns_name, i));
109                 assert(command);
110                 assert(system(command) == 0);
111                 free(command);
112         }
113 }
114
115 /// Give a peer a unique IP address
116 void change_peer_ip(peer_config_t *peer) {
117         char *command = NULL;
118         assert(asprintf(&command,
119                         "/bin/ip netns exec %1$s ip addr flush dev eth0;"
120                         "/bin/ip netns exec %1$s ip addr add 203.0.113.%2$d/24 dev eth0;",
121                         peer->netns_name, ip));
122         ip++;
123         assert(command);
124         assert(system(command) == 0);
125         free(command);
126 }
127
128 /// Let the first peer in a list invite all the subsequent peers
129 static void invite_peers(peer_config_t *peers, int npeers) {
130         assert(meshlink_start(peers[0].mesh));
131
132         for(int i = 1; i < npeers; i++) {
133                 char *invitation = meshlink_invite_ex(peers[0].mesh, NULL, peers[i].name, MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_NUMERIC);
134                 assert(invitation);
135                 printf("%s\n", invitation);
136                 assert(meshlink_join(peers[i].mesh, invitation));
137                 free(invitation);
138         }
139
140         meshlink_stop(peers[0].mesh);
141 }
142
143 /// Close meshlink instances and clean up
144 static void close_peers(peer_config_t *peers, int npeers) {
145         for(int i = 0; i < npeers; i++) {
146                 meshlink_close(peers[i].mesh);
147                 close(peers[i].netns);
148                 free(peers[i].netns_name);
149         }
150 }
151
152 /// Set up relay, peer and NUT that are directly connected
153 peer_config_t *setup_relay_peer_nut(const char *prefix) {
154         static peer_config_t peers[] = {
155                 {"relay", DEV_CLASS_BACKBONE, NULL, 0, NULL},
156                 {"peer", DEV_CLASS_STATIONARY, NULL, 0, NULL},
157                 {"nut", DEV_CLASS_STATIONARY, NULL, 0, NULL},
158         };
159
160         create_peers(peers, 3, prefix);
161         setup_lan_topology(peers, 3);
162         invite_peers(peers, 3);
163
164         return peers;
165 }
166
167 /// Set up relay, peer and NUT that are directly connected
168 peer_config_t *setup_relay_peer_nut_indirect(const char *prefix) {
169         static peer_config_t peers[] = {
170                 {"relay", DEV_CLASS_BACKBONE, NULL, 0, NULL},
171                 {"peer", DEV_CLASS_STATIONARY, NULL, 0, NULL},
172                 {"nut", DEV_CLASS_STATIONARY, NULL, 0, NULL},
173         };
174
175         create_peers(peers, 3, prefix);
176         setup_indirect_topology(peers, 3);
177         assert(meshlink_add_invitation_address(peers[0].mesh, "192.168.1.1", NULL));
178         assert(meshlink_add_invitation_address(peers[0].mesh, "192.168.2.1", NULL));
179         invite_peers(peers, 3);
180
181         return peers;
182 }
183
184 /// Make all nodes only be able to communicate via TCP
185 void set_peers_tcponly(peer_config_t *peers, int npeers) {
186         for(int i = 0; i < npeers; i++) {
187                 char *command = NULL;
188                 assert(asprintf(&command,
189                                 "/bin/ip netns exec %1$s iptables -A INPUT -p udp -j DROP;"
190                                 "/bin/ip netns exec %1$s iptables -A OUTPUT -p udp -j DROP;",
191                                 peers[i].netns_name));
192                 assert(command);
193                 assert(system(command) == 0);
194                 free(command);
195         }
196 }
197
198 void close_relay_peer_nut(peer_config_t *peers) {
199         close_peers(peers, 3);
200 }