]> git.meshlink.io Git - meshlink/blob - test/blackbox/common/containers.c
Ensure NDEBUG is not set in the test suite.
[meshlink] / test / blackbox / common / containers.c
1 /*
2     containers.h -- Container Management API
3     Copyright (C) 2018  Guus Sliepen <guus@meshlink.io>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifdef NDEBUG
21 #undef NDEBUG
22 #endif
23
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <pthread.h>
29 #include "containers.h"
30 #include "common_handlers.h"
31
32 char *lxc_path = NULL;
33 char *choose_arch;
34 static char container_ips[10][100];
35
36 /* Return the handle to an existing container after finding it by container name */
37 struct lxc_container *find_container(const char *name) {
38         struct lxc_container **test_containers;
39         char **container_names;
40         int num_containers, i;
41
42         assert((num_containers = list_all_containers(lxc_path, &container_names,
43                                  &test_containers)) != -1);
44
45         for(i = 0; i < num_containers; i++) {
46                 if(strcmp(container_names[i], name) == 0) {
47                         return test_containers[i];
48                 }
49         }
50
51         return NULL;
52 }
53
54 /* Rename a Container */
55 void rename_container(const char *old_name, const char *new_name) {
56         char rename_command[200];
57         int rename_status;
58         struct lxc_container *old_container;
59
60         /* Stop the old container if its still running */
61         assert((old_container = find_container(old_name)));
62         old_container->shutdown(old_container, CONTAINER_SHUTDOWN_TIMEOUT);
63         /* Call stop() in case shutdown() fails - one of these two will always succeed */
64         old_container->stop(old_container);
65         /* Rename the Container */
66         /* TO DO: Perform this operation using the LXC API - currently does not work via the API,
67             need to investigate and determine why it doesn't work, and make it work */
68         assert(snprintf(rename_command, sizeof(rename_command),
69                         "%s/" LXC_UTIL_REL_PATH "/" LXC_RENAME_SCRIPT " %s %s %s", meshlink_root_path, lxc_path,
70                         old_name, new_name) >= 0);
71         rename_status = system(rename_command);
72         PRINT_TEST_CASE_MSG("Container '%s' rename status: %d\n", old_name, rename_status);
73         assert(rename_status == 0);
74 }
75
76 char *run_in_container(const char *cmd, const char *container_name, bool daemonize) {
77         char container_find_name[1000];
78         struct lxc_container *container;
79
80         assert(cmd);
81         assert(container_name);
82         assert(snprintf(container_find_name, sizeof(container_find_name), "%s_%s",
83                         state_ptr->test_case_name, container_name) >= 0);
84         assert((container = find_container(container_find_name)));
85
86         return run_in_container_ex(cmd, container, daemonize);
87 }
88
89 char *execute_in_container(const char *cmd, const char *container_name, bool daemonize) {
90         struct lxc_container *container;
91
92         assert(cmd);
93         assert(container_name);
94         assert((container = find_container(container_name)));
95
96         return run_in_container_ex(cmd, container, daemonize);
97 }
98
99 /* Run 'cmd' inside the Container created for 'node' and return the first line of the output
100     or NULL if there is no output - useful when, for example, a meshlink invite is generated
101     by a node running inside a Container
102     'cmd' is run as a daemon if 'daemonize' is true - this mode is useful for running node
103     simulations in Containers
104     The caller is responsible for freeing the returned string */
105 char *run_in_container_ex(const char *cmd, struct lxc_container *container, bool daemonize) {
106         char *output = NULL;
107         size_t output_len = 0;
108
109         /* Run the command within the Container, either as a daemon or foreground process */
110         /* TO DO: Perform this operation using the LXC API - currently does not work using the API
111             Need to determine why it doesn't work, and make it work */
112         if(daemonize) {
113                 char run_script_path[100];
114                 char *attach_argv[4];
115
116                 assert(snprintf(run_script_path, sizeof(run_script_path), "%s/" LXC_UTIL_REL_PATH "/" LXC_RUN_SCRIPT,
117                                 meshlink_root_path) >= 0);
118                 attach_argv[0] = run_script_path;
119                 attach_argv[1] = (char *)cmd;
120                 attach_argv[2] = container->name;
121                 attach_argv[3] = NULL;
122
123                 /* To daemonize, create a child process and detach it from its parent (this program) */
124                 if(fork() == 0) {
125                         assert(daemon(1, 0) != -1);    // Detach from the parent process
126                         assert(execv(attach_argv[0], attach_argv) != -1);   // Run exec() in the child process
127                 }
128         } else {
129                 char *attach_command;
130                 size_t attach_command_len;
131                 int i;
132                 attach_command_len = strlen(meshlink_root_path) + strlen(LXC_UTIL_REL_PATH) + strlen(LXC_RUN_SCRIPT) + strlen(cmd) + strlen(container->name) + 10;
133                 attach_command = malloc(attach_command_len);
134                 assert(attach_command);
135
136                 assert(snprintf(attach_command, attach_command_len,
137                                 "%s/" LXC_UTIL_REL_PATH "/" LXC_RUN_SCRIPT " \"%s\" %s", meshlink_root_path, cmd,
138                                 container->name) >= 0);
139                 FILE *attach_fp;
140                 assert((attach_fp = popen(attach_command, "r")));
141                 free(attach_command);
142                 /* If the command has an output, strip out any trailing carriage returns or newlines and
143                     return it, otherwise return NULL */
144                 output = NULL;
145                 output_len = 0;
146
147                 if(getline(&output, &output_len, attach_fp) != -1) {
148                         i = strlen(output) - 1;
149
150                         while(output[i] == '\n' || output[i] == '\r') {
151                                 i--;
152                         }
153
154                         output[i + 1] = '\0';
155                 } else {
156                         free(output);
157                         output = NULL;
158                 }
159
160                 assert(pclose(attach_fp) != -1);
161         }
162
163         return output;
164 }
165
166 /* Wait for a starting Container to obtain an IP Address, then save that IP for future use */
167 void container_wait_ip(int node) {
168         char container_name[100];
169         char *ip;
170
171         assert(snprintf(container_name, sizeof(container_name), "%s_%s", state_ptr->test_case_name,
172                         state_ptr->node_names[node]) >= 0);
173         ip = container_wait_ip_ex(container_name);
174
175         strncpy(container_ips[node], ip, sizeof(container_ips[node])); // Save the IP for future use
176         PRINT_TEST_CASE_MSG("Node '%s' has IP Address %s\n", state_ptr->node_names[node],
177                             container_ips[node]);
178         free(ip);
179 }
180
181 char *container_wait_ip_ex(const char *container_name) {
182         struct lxc_container *test_container;
183         char  lxcls_command[200];
184         char *ip;
185         size_t ip_len;
186         bool ip_found;
187         int i;
188         int timeout;
189         FILE *lxcls_fp;
190
191         assert((test_container = find_container(container_name)));
192         assert(snprintf(lxcls_command, sizeof(lxcls_command),
193                         "lxc-ls -f | grep %s | tr -s ' ' | cut -d ' ' -f 5", test_container->name) >= 0);
194         PRINT_TEST_CASE_MSG("Waiting for Container '%s' to acquire IP\n", test_container->name);
195         assert((ip = malloc(20)));
196         ip_len = sizeof(ip);
197         ip_found = false;
198         timeout = 60;
199
200         while(!ip_found && timeout) {
201                 assert((lxcls_fp = popen(lxcls_command, "r")));   // Run command
202                 assert(getline((char **)&ip, &ip_len, lxcls_fp) != -1); // Read its output
203                 /* Strip newlines and carriage returns from output */
204                 i = strlen(ip) - 1;
205
206                 while(ip[i] == '\n' || ip[i] == '\r') {
207                         i--;
208                 }
209
210                 ip[i + 1] = '\0';
211                 ip_found = (strcmp(ip, "-") != 0);  // If the output is not "-", IP has been acquired
212                 assert(pclose(lxcls_fp) != -1);
213                 sleep(1);
214                 timeout--;
215         }
216
217         // Fail if IP cannot be read
218         assert(timeout);
219
220         return ip;
221 }
222
223 /* Create all required test containers */
224 void create_containers(const char *node_names[], int num_nodes) {
225         int i;
226         char container_name[100];
227         int create_status, snapshot_status, snap_restore_status;
228         struct lxc_container *first_container = NULL;
229
230         for(i = 0; i < num_nodes; i++) {
231                 assert(snprintf(container_name, sizeof(container_name), "run_%s", node_names[i]) >= 0);
232
233                 /* If this is the first Container, create it otherwise restore the snapshot saved
234                     for the first Container to create an additional Container */
235                 if(i == 0) {
236                         assert((first_container = lxc_container_new(container_name, NULL)));
237                         assert(!first_container->is_defined(first_container));
238                         create_status = first_container->createl(first_container, "download", NULL, NULL,
239                                         LXC_CREATE_QUIET, "-d", "ubuntu", "-r", "trusty", "-a", choose_arch, NULL);
240                         fprintf(stderr, "Container '%s' create status: %d - %s\n", container_name,
241                                 first_container->error_num, first_container->error_string);
242                         assert(create_status);
243                         snapshot_status = first_container->snapshot(first_container, NULL);
244                         fprintf(stderr, "Container '%s' snapshot status: %d - %s\n", container_name,
245                                 first_container->error_num, first_container->error_string);
246                         assert(snapshot_status != -1);
247                 } else {
248                         assert(first_container);
249                         snap_restore_status = first_container->snapshot_restore(first_container, "snap0",
250                                               container_name);
251                         fprintf(stderr, "Snapshot restore to Container '%s' status: %d - %s\n", container_name,
252                                 first_container->error_num, first_container->error_string);
253                         assert(snap_restore_status);
254                 }
255         }
256 }
257
258 /* Setup Containers required for a test
259     This function should always be invoked in a CMocka context
260     after setting the state of the test case to an instance of black_box_state_t */
261 void setup_containers(void **state) {
262         black_box_state_t *test_state = (black_box_state_t *)(*state);
263         int i;
264         char build_command[200];
265         struct lxc_container *test_container, *new_container;
266         char container_find_name[100];
267         char container_new_name[100];
268         int create_status, build_status;
269
270         PRINT_TEST_CASE_HEADER();
271
272         for(i = 0; i < test_state->num_nodes; i++) {
273                 /* Find the run_<node-name> Container or create it if it doesn't exist */
274                 assert(snprintf(container_find_name, sizeof(container_find_name), "run_%s",
275                                 test_state->node_names[i]) >= 0);
276
277                 if(!(test_container = find_container(container_find_name))) {
278                         assert((test_container = lxc_container_new(container_find_name, NULL)));
279                         assert(!test_container->is_defined(test_container));
280                         create_status = test_container->createl(test_container, "download", NULL, NULL,
281                                                                 LXC_CREATE_QUIET, "-d", "ubuntu", "-r", "trusty", "-a", choose_arch, NULL);
282                         PRINT_TEST_CASE_MSG("Container '%s' create status: %d - %s\n", container_find_name,
283                                             test_container->error_num, test_container->error_string);
284                         assert(create_status);
285                 }
286
287                 /* Stop the Container if it's running */
288                 test_container->shutdown(test_container, CONTAINER_SHUTDOWN_TIMEOUT);
289                 /* Call stop() in case shutdown() fails
290                     One of these two calls will always succeed */
291                 test_container->stop(test_container);
292                 /* Rename the Container to make it specific to this test case,
293                     if a Container with the target name already exists, skip this step */
294                 assert(snprintf(container_new_name, sizeof(container_new_name), "%s_%s",
295                                 test_state->test_case_name, test_state->node_names[i]) >= 0);
296
297                 if(!(new_container = find_container(container_new_name))) {
298                         rename_container(test_container->name, container_new_name);
299                         assert((new_container = find_container(container_new_name)));
300                 }
301
302                 /* Start the Container */
303                 assert(new_container->start(new_container, 0, NULL));
304                 /* Build the Container by copying required files into it */
305                 assert(snprintf(build_command, sizeof(build_command),
306                                 "%s/" LXC_UTIL_REL_PATH "/" LXC_BUILD_SCRIPT " %s %s %s +x >/dev/null",
307                                 meshlink_root_path, test_state->test_case_name, test_state->node_names[i],
308                                 meshlink_root_path) >= 0);
309                 build_status = system(build_command);
310                 PRINT_TEST_CASE_MSG("Container '%s' build Status: %d\n", new_container->name,
311                                     build_status);
312                 assert(build_status == 0);
313                 /* Restart the Container after building it and wait for it to acquire an IP */
314                 new_container->shutdown(new_container, CONTAINER_SHUTDOWN_TIMEOUT);
315                 new_container->stop(new_container);
316                 new_container->start(new_container, 0, NULL);
317                 container_wait_ip(i);
318         }
319 }
320
321 /* Destroy all Containers with names containing 'run_' - Containers saved for debugging will
322     have names beginning with test_case_ ; 'run_' is reserved for temporary Containers
323     intended to be re-used for the next test */
324 void destroy_containers(void) {
325         struct lxc_container **test_containers;
326         char **container_names;
327         int num_containers, i;
328
329         assert((num_containers = list_all_containers(lxc_path, &container_names,
330                                  &test_containers)) != -1);
331
332         for(i = 0; i < num_containers; i++) {
333                 if(strstr(container_names[i], "run_")) {
334                         fprintf(stderr, "Destroying Container '%s'\n", container_names[i]);
335                         /* Stop the Container - it cannot be destroyed till it is stopped */
336                         test_containers[i]->shutdown(test_containers[i], CONTAINER_SHUTDOWN_TIMEOUT);
337                         /* Call stop() in case shutdown() fails
338                             One of these two calls will always succeed */
339                         test_containers[i]->stop(test_containers[i]);
340                         /* Destroy the Container */
341                         test_containers[i]->destroy(test_containers[i]);
342                         /* Call destroy_with_snapshots() in case destroy() fails
343                             one of these two calls will always succeed */
344                         test_containers[i]->destroy_with_snapshots(test_containers[i]);
345                 }
346         }
347 }
348
349 /* Restart all the Containers being used in the current test case i.e. Containers with
350     names beginning with <test-case-name>_<node-name> */
351 void restart_all_containers(void) {
352         char container_name[100];
353         struct lxc_container *test_container;
354         int i;
355
356         for(i = 0; i < state_ptr->num_nodes; i++) {
357                 /* Shutdown, then start the Container, then wait for it to acquire an IP Address */
358                 assert(snprintf(container_name, sizeof(container_name), "%s_%s", state_ptr->test_case_name,
359                                 state_ptr->node_names[i]) >= 0);
360                 assert((test_container = find_container(container_name)));
361                 test_container->shutdown(test_container, CONTAINER_SHUTDOWN_TIMEOUT);
362                 test_container->stop(test_container);
363                 test_container->start(test_container, 0, NULL);
364                 container_wait_ip(i);
365         }
366 }
367
368 /* Run the gen_invite command inside the 'inviter' container to generate an invite
369     for 'invitee', and return the generated invite which is output on the terminal */
370 char *invite_in_container(const char *inviter, const char *invitee) {
371         char invite_command[200];
372         char *invite_url;
373
374         assert(snprintf(invite_command, sizeof(invite_command),
375                         "LD_LIBRARY_PATH=/home/ubuntu/test/.libs /home/ubuntu/test/gen_invite %s %s "
376                         "2> gen_invite.log", inviter, invitee) >= 0);
377         assert((invite_url = run_in_container(invite_command, inviter, false)));
378         PRINT_TEST_CASE_MSG("Invite Generated from '%s' to '%s': %s\n", inviter,
379                             invitee, invite_url);
380
381         return invite_url;
382 }
383
384 /* Run the gen_invite command inside the 'inviter' container to generate an invite
385     for 'invitee' belonging to pparticular submesh, and return the generated invite
386     which is output on the terminal */
387 char *submesh_invite_in_container(const char *inviter, const char *invitee, const char *submesh) {
388         char invite_command[200];
389         char *invite_url;
390
391         assert(snprintf(invite_command, sizeof(invite_command),
392                         "LD_LIBRARY_PATH=/home/ubuntu/test/.libs /home/ubuntu/test/gen_invite %s %s %s "
393                         "2> gen_invite.log", inviter, invitee, submesh) >= 0);
394         assert((invite_url = run_in_container(invite_command, inviter, false)));
395         PRINT_TEST_CASE_MSG("Invite Generated from '%s' to '%s': %s\n", inviter,
396                             invitee, invite_url);
397
398         return invite_url;
399 }
400
401 /* Run the node_sim_<nodename> program inside the 'node''s container */
402 void node_sim_in_container(const char *node, const char *device_class, const char *invite_url) {
403         char *node_sim_command;
404         size_t node_sim_command_len;
405
406         node_sim_command_len = 500 + (invite_url ? strlen(invite_url) : 0);
407         node_sim_command = calloc(1, node_sim_command_len);
408         assert(node_sim_command);
409         assert(snprintf(node_sim_command, node_sim_command_len,
410                         "LD_LIBRARY_PATH=/home/ubuntu/test/.libs /home/ubuntu/test/node_sim_%s %s %s %s "
411                         "1>&2 2>> node_sim_%s.log", node, node, device_class,
412                         (invite_url) ? invite_url : "", node) >= 0);
413         run_in_container(node_sim_command, node, true);
414         PRINT_TEST_CASE_MSG("node_sim_%s started in Container\n", node);
415
416         free(node_sim_command);
417 }
418
419 /* Run the node_sim_<nodename> program inside the 'node''s container with event handling capable */
420 void node_sim_in_container_event(const char *node, const char *device_class,
421                                  const char *invite_url, const char *clientId, const char *import) {
422         char *node_sim_command;
423         size_t node_sim_command_len;
424
425         assert(node && device_class && clientId && import);
426         node_sim_command_len = 500 + (invite_url ? strlen(invite_url) : 0);
427         node_sim_command = calloc(1, node_sim_command_len);
428         assert(node_sim_command);
429         assert(snprintf(node_sim_command, node_sim_command_len,
430                         "LD_LIBRARY_PATH=/home/ubuntu/test/.libs /home/ubuntu/test/node_sim_%s %s %s %s %s %s "
431                         "1>&2 2>> node_sim_%s.log", node, node, device_class,
432                         clientId, import, (invite_url) ? invite_url : "", node) >= 0);
433         run_in_container(node_sim_command, node, true);
434         PRINT_TEST_CASE_MSG("node_sim_%s(Client Id :%s) started in Container with event handling\n%s\n",
435                             node, clientId, node_sim_command);
436
437         free(node_sim_command);
438 }
439
440 /* Run the node_step.sh script inside the 'node''s container to send the 'sig' signal to the
441     node_sim program in the container */
442 void node_step_in_container(const char *node, const char *sig) {
443         char node_step_command[1000];
444
445         assert(snprintf(node_step_command, sizeof(node_step_command),
446                         "/home/ubuntu/test/node_step.sh lt-node_sim_%s %s 1>&2 2> node_step.log",
447                         node, sig) >= 0);
448         run_in_container(node_step_command, node, false);
449         PRINT_TEST_CASE_MSG("Signal %s sent to node_sim_%s\n", sig, node);
450 }
451
452 /* Change the IP Address of the Container running 'node'
453     Changes begin from X.X.X.254 and continue iteratively till an available address is found */
454 void change_ip(int node) {
455         char *gateway_addr;
456         char new_ip[20] = "";
457         char *netmask;
458         char *last_dot_in_ip;
459         int last_ip_byte = 254;
460         FILE *if_fp;
461         char copy_command[200];
462         char container_name[100];
463         struct lxc_container *container;
464         int copy_file_stat;
465
466         /* Get IP Address of LXC Bridge Interface - this will be set up as the Gateway Address
467             of the Static IP assigned to the Container */
468         assert((gateway_addr = get_ip(lxc_bridge)));
469         /* Get Netmask of LXC Brdige Interface */
470         assert((netmask = get_netmask(lxc_bridge)));
471
472         /* Replace last byte of Container's IP with 254 to form the new Container IP */
473         assert(container_ips[node]);
474         strncpy(new_ip, container_ips[node], sizeof(new_ip) - 1);
475         assert((last_dot_in_ip = strrchr(new_ip, '.')));
476         assert(snprintf(last_dot_in_ip + 1, 4, "%d", last_ip_byte) >= 0);
477
478         /* Check that the new IP does not match the Container's existing IP
479             if it does, iterate till it doesn't */
480         /* TO DO: Make sure the IP does not conflict with any other running Container */
481         while(strcmp(new_ip, container_ips[node]) == 0) {
482                 last_ip_byte--;
483                 assert(snprintf(last_dot_in_ip + 1, 4, "%d", last_ip_byte) >= 0);
484         }
485
486         /* Create new 'interfaces' file for Container */
487         assert((if_fp = fopen("interfaces", "w")));
488         fprintf(if_fp, "auto lo\n");
489         fprintf(if_fp, "iface lo inet loopback\n");
490         fprintf(if_fp, "\n");
491         fprintf(if_fp, "auto eth0\n");
492         fprintf(if_fp, "iface eth0 inet static\n");
493         fprintf(if_fp, "\taddress %s\n", new_ip);
494         fprintf(if_fp, "\tnetmask %s\n", netmask);
495         fprintf(if_fp, "\tgateway %s\n", gateway_addr);
496         assert(fclose(if_fp) != EOF);
497
498         /* Copy 'interfaces' file into Container's /etc/network path */
499         assert(snprintf(copy_command, sizeof(copy_command),
500                         "%s/" LXC_UTIL_REL_PATH "/" LXC_COPY_SCRIPT " interfaces %s_%s /etc/network/interfaces",
501                         meshlink_root_path, state_ptr->test_case_name, state_ptr->node_names[node]) >= 0);
502         copy_file_stat = system(copy_command);
503         PRINT_TEST_CASE_MSG("Container '%s_%s' 'interfaces' file copy status: %d\n",
504                             state_ptr->test_case_name, state_ptr->node_names[node], copy_file_stat);
505         assert(copy_file_stat == 0);
506
507         /* Restart Container to apply new IP Address */
508         assert(snprintf(container_name, sizeof(container_name), "%s_%s", state_ptr->test_case_name,
509                         state_ptr->node_names[node]) >= 0);
510         assert((container = find_container(container_name)));
511         container->shutdown(container, CONTAINER_SHUTDOWN_TIMEOUT);
512         /* Call stop() in case shutdown() fails
513             One of these two calls with always succeed */
514         container->stop(container);
515         assert(container->start(container, 0, NULL));
516
517         strncpy(container_ips[node], new_ip, sizeof(container_ips[node]));   // Save the new IP Address
518         PRINT_TEST_CASE_MSG("Node '%s' IP Address changed to %s\n", state_ptr->node_names[node],
519                             container_ips[node]);
520 }
521
522 char **get_container_interface_ips(const char *container_name, const char *interface_name) {
523         char **ips;
524         struct lxc_container *container = find_container(container_name);
525         assert(container);
526
527         char **interfaces = container->get_interfaces(container);
528         assert(interfaces);
529
530         int i;
531         ips = NULL;
532
533         for(i = 0; interfaces[i]; i++) {
534                 if(!strcasecmp(interfaces[i], interface_name)) {
535                         ips = container->get_ips(container, interface_name, "inet", 0);
536                         assert(ips);
537                         break;
538                 }
539         }
540
541         free(interfaces);
542
543         return ips;
544 }
545
546 /* Install an app in a container */
547 void install_in_container(const char *node, const char *app) {
548         char install_cmd[100];
549
550         assert(snprintf(install_cmd, sizeof(install_cmd),
551                         "apt-get install %s -y >> /dev/null", app) >= 0);
552         run_in_container(install_cmd, node, false);
553         // TODO: Check in container whether app has installed or not with a timeout
554         sleep(10);
555 }
556
557 /* Return container's IP address */
558 char *get_container_ip(const char *node_name) {
559         int node = -1, i;
560
561         for(i = 0; i < state_ptr->num_nodes; i++) {
562                 if(!strcasecmp(state_ptr->node_names[i], node_name)) {
563                         node = i;
564                         break;
565                 }
566         }
567
568         if(i == state_ptr->num_nodes) {
569                 return NULL;
570         }
571
572         char *ip = strdup(container_ips[node]);
573         assert(ip);
574
575         return ip;
576 }
577
578 /* Simulate a network failure by adding NAT rule in the container with it's IP address */
579 void block_node_ip(const char *node) {
580         char block_cmd[100];
581         char *node_ip;
582
583         node_ip = get_container_ip(node);
584         assert(node_ip);
585         assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A OUTPUT -p all -s %s -j DROP", node_ip) >= 0);
586         run_in_container(block_cmd, node, false);
587
588         assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A INPUT -p all -s %s -j DROP", node_ip) >= 0);
589         run_in_container(block_cmd, node, false);
590
591         assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A FORWARD -p all -s %s -j DROP", node_ip) >= 0);
592         run_in_container(block_cmd, node, false);
593
594         free(node_ip);
595 }
596
597 void accept_port_rule(const char *node, const char *chain, const char *protocol, int port) {
598         char block_cmd[100];
599
600         assert(port >= 0 && port < 65536);
601         assert(!strcmp(chain, "INPUT") || !strcmp(chain, "FORWARD") || !strcmp(chain, "OUTPUT"));
602         assert(!strcmp(protocol, "all") || !strcmp(protocol, "tcp") || !strcmp(protocol, "udp") || !strcmp(protocol, "icmp"));
603         assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A %s -p %s --dport %d -j ACCEPT", chain, protocol, port) >= 0);
604         run_in_container(block_cmd, node, false);
605 }
606
607 /* Restore the network that was blocked before by the NAT rule with it's own IP address */
608 void unblock_node_ip(const char *node) {
609         char unblock_cmd[100];
610         char *node_ip;
611
612         node_ip = get_container_ip(node);
613         assert(node_ip);
614         assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D OUTPUT -p all -s %s -j DROP", node_ip) >= 0);
615         run_in_container(unblock_cmd, node, false);
616
617         assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D INPUT -p all -s %s -j DROP", node_ip) >= 0);
618         run_in_container(unblock_cmd, node, false);
619
620         assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D FORWARD -p all -s %s -j DROP", node_ip) >= 0);
621         run_in_container(unblock_cmd, node, false);
622 }
623
624 char *block_icmp(const char *container_name) {
625         char block_cmd[500];
626         assert(container_name);
627         assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A FORWARD -p icmp -j DROP") >= 0);
628         return execute_in_container(block_cmd, container_name, false);
629 }
630
631 char *unblock_icmp(const char *container_name) {
632         char block_cmd[500];
633         assert(container_name);
634         assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -D FORWARD -p icmp -j DROP") >= 0);
635         return execute_in_container(block_cmd, container_name, false);
636 }
637
638 char *change_container_mtu(const char *container_name, const char *interface_name, int mtu) {
639         char cmd[500];
640         assert(container_name);
641         assert(snprintf(cmd, sizeof(cmd), "ifconfig %s mtu %d", interface_name, mtu) >= 0);
642         return execute_in_container(cmd, container_name, false);
643 }
644
645 char *flush_conntrack(const char *container_name) {
646         assert(container_name);
647
648         return execute_in_container("conntrack -F", container_name, false);
649 }
650
651 void flush_nat_rules(const char *container_name, const char *chain) {
652         char *ret;
653         char flush_cmd[500];
654
655         assert(container_name);
656         assert(snprintf(flush_cmd, sizeof(flush_cmd), "iptables -F %s", chain ? chain : "") >= 0);
657         ret = execute_in_container("iptables -F", container_name, false);
658         assert(ret == NULL);
659 }
660
661 void add_full_cone_nat_rules(const char *container_name, const char *pub_interface, const char *priv_interface_listen_address) {
662         char nat_cmd[500];
663
664         char **pub_interface_ips = get_container_interface_ips(container_name, pub_interface);
665         assert(pub_interface_ips[0]);
666         char *pub_interface_ip = pub_interface_ips[0];
667
668         assert(snprintf(nat_cmd, sizeof(nat_cmd),
669                         "%s/" LXC_UTIL_REL_PATH "/" LXC_NAT_FULL_CONE " %s %s %s %s >/dev/null",
670                         meshlink_root_path, container_name, pub_interface, pub_interface_ip, priv_interface_listen_address) >= 0);
671         assert(system(nat_cmd) == 0);
672         free(pub_interface_ips);
673 }
674
675 /* Create a NAT and a bridge, bridge connected to NAT and containers to be NATed can be switched
676     to the NAT bridge from lxcbr0 */
677 void nat_create(const char *nat_name, const char *nat_bridge, int nat_type) {
678         (void)nat_type;
679
680         char build_command[200];
681         assert(snprintf(build_command, sizeof(build_command),
682                         "%s/" LXC_UTIL_REL_PATH "/" LXC_NAT_BUILD " %s %s %s >/dev/stderr",
683                         meshlink_root_path, nat_name, nat_bridge, meshlink_root_path) >= 0);
684         assert(system(build_command) == 0);
685 }
686
687 void nat_destroy(const char *nat_name) {
688         char build_command[200];
689         assert(snprintf(build_command, sizeof(build_command),
690                         "%s/" LXC_UTIL_REL_PATH "/" LXC_NAT_DESTROY " %s +x >/dev/null",
691                         meshlink_root_path, nat_name) >= 0);
692         assert(system(build_command) == 0);
693 }
694
695 /* Switches a container from current bridge to a new bridge */
696 void container_switch_bridge(const char *container_name, char *lxc_conf_path, const char *current_bridge, const char *new_bridge) {
697         char config_path[500];
698         char buffer[500];
699         struct lxc_container *container;
700         char *lxc_path_temp;
701         char *ip;
702
703         PRINT_TEST_CASE_MSG("Switiching container %s from bridge '%s' to bridge '%s'", container_name, current_bridge, new_bridge);
704         lxc_path_temp = lxc_path;
705         lxc_path = lxc_conf_path;
706         container = find_container(container_name);
707         assert(container);
708         lxc_path = lxc_path_temp;
709         assert(snprintf(config_path, sizeof(config_path), "%s/%s/config", lxc_conf_path, container_name) >= 0);
710         FILE *fp = fopen(config_path, "r");
711         assert(fp);
712         FILE *fp_temp = fopen(".temp_file", "w");
713         assert(fp_temp);
714
715         int net_no;
716
717         while((fgets(buffer, sizeof(buffer), fp)) != NULL) {
718                 if(sscanf(buffer, "lxc.net.%d.link", &net_no) == 1) {
719                         char *ptr;
720                         int len;
721
722                         if((ptr = strstr(buffer, current_bridge)) != NULL) {
723                                 len = strlen(current_bridge);
724
725                                 if(((*(ptr - 1) == ' ') || (*(ptr - 1) == '\t') || (*(ptr - 1) == '=')) && ((ptr[len] == '\n') || (ptr[len] == '\t') || (ptr[len] == '\0') || (ptr[len] == ' '))) {
726                                         sprintf(buffer, "lxc.net.%d.link = %s\n", net_no, new_bridge);
727                                 }
728                         }
729                 }
730
731                 fputs(buffer, fp_temp);
732         }
733
734         fclose(fp_temp);
735         fclose(fp);
736         remove(config_path);
737         rename(".temp_file", config_path);
738
739         /* Restart the Container after building it and wait for it to acquire an IP */
740         char cmd[200];
741         int sys_ret;
742         assert(snprintf(cmd, sizeof(cmd), "lxc-stop %s", container_name) >= 0);
743         sys_ret = system(cmd);
744         assert(snprintf(cmd, sizeof(cmd), "lxc-start %s", container_name) >= 0);
745         sys_ret = system(cmd);
746         assert(sys_ret == 0);
747         ip = container_wait_ip_ex(container_name);
748         PRINT_TEST_CASE_MSG("Obtained IP address: %s for container %s after switching bridge", ip, container_name);
749         free(ip);
750 }
751
752 /* Takes bridgeName as input parameter and creates a bridge */
753 void create_bridge(const char *bridgeName) {
754         char command[100] = "brctl addbr ";
755         strcat(command, bridgeName);
756         int create_bridge_status = system(command);
757         assert(create_bridge_status == 0);
758         PRINT_TEST_CASE_MSG("%s bridge created\n", bridgeName);
759 }
760
761 /* Add interface for the bridge created */
762 void add_interface(const char *bridgeName, const char *interfaceName) {
763         char command[100] = "brctl addif ";
764         char cmd[100] = "dhclient ";
765
766         strcat(command, bridgeName);
767         strcat(command, " ");
768         strcat(command, interfaceName);
769         int addif_status = system(command);
770         assert(addif_status == 0);
771         strcat(cmd, bridgeName);
772         int dhclient_status = system(cmd);
773         assert(dhclient_status == 0);
774         PRINT_TEST_CASE_MSG("Added interface for %s\n", bridgeName);
775 }
776
777 /* Create a veth pair and bring them up */
778 void add_veth_pair(const char *vethName1, const char *vethName2) {
779         char command[100] = "ip link add ";
780         char upCommand1[100] = "ip link set ";
781         char upCommand2[100] = "ip link set ";
782
783         strcat(command, vethName1);
784         strcat(command, " type veth peer name ");
785         strcat(command, vethName2);
786         int link_add_status = system(command);
787         assert(link_add_status == 0);
788         strcat(upCommand1, vethName1);
789         strcat(upCommand1, " up");
790         int link_set_veth1_status = system(upCommand1);
791         assert(link_set_veth1_status == 0);
792         strcat(upCommand2, vethName2);
793         strcat(upCommand2, " up");
794         int link_set_veth2_status = system(upCommand2);
795         assert(link_set_veth2_status == 0);
796         PRINT_TEST_CASE_MSG("Added veth pairs %s and %s\n", vethName1, vethName2);
797 }
798
799 /* Bring the interface up for the bridge created */
800 void bring_if_up(const char *bridgeName) {
801         char command[300] = "ifconfig ";
802         strcat(command, bridgeName);
803         strcat(command, " up");
804         int if_up_status = system(command);
805         assert(if_up_status == 0);
806         sleep(2);
807         PRINT_TEST_CASE_MSG("Interface brought up for %s created\n", bridgeName);
808 }
809
810 /**
811  * Replace all occurrences of a given a word in string.
812  */
813 void replaceAll(char *str, const char *oldWord, const char *newWord) {
814         char *pos, temp[BUFSIZ];
815         int index = 0;
816         int owlen;
817         owlen = strlen(oldWord);
818
819         while((pos = strstr(str, oldWord)) != NULL) {
820                 strcpy(temp, str);
821                 index = pos - str;
822                 str[index] = '\0';
823                 strcat(str, newWord);
824                 strcat(str, temp + index + owlen);
825         }
826 }
827
828 /* Switches the bridge for a given container */
829 void switch_bridge(const char *containerName, const char *currentBridge, const char *newBridge) {
830         char command[100] = "lxc-stop -n ";
831         char command_start[100] = "lxc-start -n ";
832         PRINT_TEST_CASE_MSG("Switching %s container to %s\n", containerName, newBridge);
833         strcat(command, containerName);
834         strcat(command_start, containerName);
835         int container_stop_status = system(command);
836         assert(container_stop_status == 0);
837         sleep(2);
838         FILE *fPtr;
839         FILE *fTemp;
840         char path[300] = "/var/lib/lxc/";
841         strcat(path, containerName);
842         strcat(path, "/config");
843
844         char buffer[BUFSIZ];
845         /*  Open all required files */
846         fPtr  = fopen(path, "r");
847         fTemp = fopen("replace.tmp", "w");
848
849         if(fPtr == NULL || fTemp == NULL) {
850                 PRINT_TEST_CASE_MSG("\nUnable to open file.\n");
851                 PRINT_TEST_CASE_MSG("Please check whether file exists and you have read/write privilege.\n");
852                 exit(EXIT_SUCCESS);
853         }
854
855         while((fgets(buffer, BUFSIZ, fPtr)) != NULL) {
856                 replaceAll(buffer, currentBridge, newBridge);
857                 fputs(buffer, fTemp);
858         }
859
860         fclose(fPtr);
861         fclose(fTemp);
862         remove(path);
863         rename("replace.tmp", path);
864         PRINT_TEST_CASE_MSG("Switching procedure done successfully\n");
865         int container_start_status = system(command_start);
866         assert(container_start_status == 0);
867         sleep(2);
868 }
869
870 /* Bring the interface down for the bridge created */
871 void bring_if_down(const char *bridgeName) {
872         char command[300] = "ip link set dev ";
873         strcat(command, bridgeName);
874         strcat(command, " down");
875         int if_down_status = system(command);
876         assert(if_down_status == 0);
877         PRINT_TEST_CASE_MSG("Interface brought down for %s created\n", bridgeName);
878 }
879
880 /* Delete interface for the bridge created */
881 void del_interface(const char *bridgeName, const char *interfaceName) {
882         char command[300] = "brctl delif ";
883         strcat(command, bridgeName);
884         strcat(command, interfaceName);
885         int if_delete_status = system(command);
886         assert(if_delete_status == 0);
887         PRINT_TEST_CASE_MSG("Deleted interface for %s\n", bridgeName);
888 }
889
890 /* Takes bridgeName as input parameter and deletes a bridge */
891 void delete_bridge(const char *bridgeName) {
892         bring_if_down(bridgeName);
893         char command[300] = "brctl delbr ";
894         strcat(command, bridgeName);
895         int bridge_delete = system(command);
896         assert(bridge_delete == 0);
897         PRINT_TEST_CASE_MSG("%s bridge deleted\n", bridgeName);
898         sleep(2);
899 }
900
901 /* Creates container on a specified bridge with added interface */
902 void create_container_on_bridge(const char *containerName, const char *bridgeName, const char *ifName) {
903         char command[100] = "lxc-create -t download -n ";
904         char cmd[100] = " -- -d ubuntu -r trusty -a ";
905         char start[100] = "lxc-start -n ";
906         FILE *fPtr;
907         char path[300] = "/var/lib/lxc/";
908         strcat(path, containerName);
909         strcat(path, "/config");
910         strcat(command, containerName);
911         strcat(command, cmd);
912         strcat(command, choose_arch);
913         int container_create_status = system(command);
914         assert(container_create_status == 0);
915         sleep(3);
916         assert((fPtr = fopen(path, "a+")));
917         fprintf(fPtr, "lxc.net.0.name = eth0\n");
918         fprintf(fPtr, "\n");
919         fprintf(fPtr, "lxc.net.1.type = veth\n");
920         fprintf(fPtr, "lxc.net.1.flags = up\n");
921         fprintf(fPtr, "lxc.net.1.link = %s\n", bridgeName);
922         fprintf(fPtr, "lxc.net.1.name = %s\n", ifName);
923         fprintf(fPtr, "lxc.net.1.hwaddr = 00:16:3e:ab:xx:xx\n");
924         fclose(fPtr);
925         strcat(start, containerName);
926         int container_start_status = system(start);
927         assert(container_start_status == 0);
928         sleep(3);
929         PRINT_TEST_CASE_MSG("Created %s on %s with interface name %s\n", containerName, bridgeName, ifName);
930 }
931
932 /* Configures dnsmasq and iptables for the specified container with inputs of listen address and dhcp range */
933 void config_dnsmasq(const char *containerName, const char *ifName, const char *listenAddress, const char *dhcpRange) {
934         char command[500] = "echo \"apt-get install dnsmasq iptables -y\" | lxc-attach -n ";
935         strcat(command, containerName);
936         strcat(command, " --");
937         int iptables_install_status = system(command);
938         assert(iptables_install_status == 0);
939         sleep(5);
940         char com1[300] = "echo \"echo \"interface=eth1\" >> /etc/dnsmasq.conf\" | lxc-attach -n ";
941         strcat(com1, containerName);
942         strcat(com1, " --");
943         int dnsmasq_status = system(com1);
944         assert(dnsmasq_status == 0);
945         sleep(5);
946         char com2[300] = "echo \"echo \"bind-interfaces\" >> /etc/dnsmasq.conf\" | lxc-attach -n ";
947         strcat(com2, containerName);
948         strcat(com2, " --");
949         dnsmasq_status = system(com2);
950         assert(dnsmasq_status == 0);
951         sleep(5);
952         char com3[300] = "echo \"echo \"listen-address=";
953         strcat(com3, listenAddress);
954         strcat(com3, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n ");
955         strcat(com3, containerName);
956         strcat(com3, " --");
957         dnsmasq_status = system(com3);
958         assert(dnsmasq_status == 0);
959         sleep(5);
960         char com4[300] = "echo \"echo \"dhcp-range=";
961         strcat(com4, dhcpRange);
962         strcat(com4, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n ");
963         strcat(com4, containerName);
964         strcat(com4, " --");
965         dnsmasq_status = system(com4);
966         assert(dnsmasq_status == 0);
967         sleep(5);
968         char cmd[300] = "echo \"ifconfig ";
969         strcat(cmd, ifName);
970         strcat(cmd, " ");
971         strcat(cmd, listenAddress);
972         strcat(cmd, " netmask 255.255.255.0 up\" | lxc-attach -n ");
973         strcat(cmd, containerName);
974         strcat(cmd, " --");
975         dnsmasq_status = system(cmd);
976         assert(dnsmasq_status == 0);
977         sleep(2);
978         char com[500] = "echo \"service dnsmasq restart >> /dev/null\" | lxc-attach -n ";
979         strcat(com, containerName);
980         strcat(com, " --");
981         dnsmasq_status = system(com);
982         assert(dnsmasq_status == 0);
983         sleep(2);
984         PRINT_TEST_CASE_MSG("Configured dnsmasq in %s with interface name %s, listen-address = %s, dhcp-range = %s\n", containerName, ifName, listenAddress, dhcpRange);
985 }
986
987 /* Configure the NAT rules inside the container */
988 void config_nat(const char *containerName, const char *listenAddress) {
989         char *last_dot_in_ip;
990         int last_ip_byte = 0;
991         char new_ip[300] = {0};
992         strncpy(new_ip, listenAddress, sizeof(new_ip) - 1);
993         assert((last_dot_in_ip = strrchr(new_ip, '.')));
994         assert(snprintf(last_dot_in_ip + 1, 4, "%d", last_ip_byte) >= 0);
995         char comd[300] = "echo \"iptables -t nat -A POSTROUTING -s ";
996         strcat(comd, new_ip);
997         strcat(comd, "/24 ! -d ");
998         strcat(comd, new_ip);
999         strcat(comd, "/24 -j MASQUERADE\" | lxc-attach -n ");
1000         strcat(comd, containerName);
1001         strcat(comd, " --");
1002         int conf_nat_status = system(comd);
1003         assert(conf_nat_status == 0);
1004         sleep(2);
1005         PRINT_TEST_CASE_MSG("Configured NAT on %s\n", containerName);
1006 }
1007
1008 /* Creates a NAT layer on a specified bridge with certain dhcp range to allocate ips for nodes */
1009 void create_nat_layer(const char *containerName, const char *bridgeName, const char *ifName, const char *listenAddress, char *dhcpRange) {
1010         create_bridge(bridgeName);
1011         bring_if_up(bridgeName);
1012         create_container_on_bridge(containerName, bridgeName, ifName);
1013         config_dnsmasq(containerName, ifName, listenAddress, dhcpRange);
1014         config_nat(containerName, listenAddress);
1015         PRINT_TEST_CASE_MSG("NAT layer created with %s\n", containerName);
1016 }
1017
1018 /* Destroys the NAT layer created */
1019 void destroy_nat_layer(const char *containerName, const char *bridgeName) {
1020         bring_if_down(bridgeName);
1021         delete_bridge(bridgeName);
1022         char command[100] = "lxc-stop -n ";
1023         strcat(command, containerName);
1024         int container_stop_status = system(command);
1025         assert(container_stop_status == 0);
1026         char destroy[100] = "lxc-destroy -n ";
1027         strcat(destroy, containerName);
1028         strcat(destroy, " -s");
1029         int container_destroy_status = system(destroy);
1030         assert(container_destroy_status == 0);
1031         PRINT_TEST_CASE_MSG("NAT layer destroyed with %s\n", containerName);
1032 }
1033
1034 /* Add incoming firewall rules for ipv4 addresses with packet type and port number */
1035 void incoming_firewall_ipv4(const char *packetType, int portNumber) {
1036         char buf[5];
1037         snprintf(buf, sizeof(buf), "%d", portNumber);
1038         assert(system("iptables -F") == 0);
1039         assert(system("iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
1040         assert(system("iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0);
1041         char command[100] = "iptables -A INPUT -p ";
1042         strcat(command, packetType);
1043         strcat(command, " --dport ");
1044         strcat(command, buf);
1045         strcat(command, " -j ACCEPT");
1046         assert(system(command) == 0);
1047         sleep(2);
1048         assert(system("iptables -A INPUT -j DROP") == 0);
1049         PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv4");
1050         assert(system("iptables -L") == 0);
1051 }
1052
1053 /* Add incoming firewall rules for ipv6 addresses with packet type and port number */
1054 void incoming_firewall_ipv6(const char *packetType, int portNumber) {
1055         char buf[5];
1056         snprintf(buf, sizeof(buf), "%d", portNumber);
1057         assert(system("ip6tables -F") == 0);
1058         assert(system("ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
1059         assert(system("ip6tables -A INPUT -s ::1 -d ::1 -j ACCEPT") == 0);
1060         char command[100] = "ip6tables -A INPUT -p ";
1061         strcat(command, packetType);
1062         strcat(command, " --dport ");
1063         strcat(command, buf);
1064         strcat(command, " -j ACCEPT");
1065         assert(system(command) == 0);
1066         sleep(2);
1067         assert(system("ip6tables -A INPUT -j DROP") == 0);
1068         PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv6");
1069         assert(system("ip6tables -L") == 0);
1070 }
1071
1072 /* Add outgoing firewall rules for ipv4 addresses with packet type and port number */
1073 void outgoing_firewall_ipv4(const char *packetType, int portNumber) {
1074         char buf[5];
1075         snprintf(buf, sizeof(buf), "%d", portNumber);
1076         assert(system("iptables -F") == 0);
1077         assert(system("iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
1078         assert(system("iptables -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0);
1079         char command[100] = "iptables -A OUTPUT -p ";
1080         strcat(command, packetType);
1081         strcat(command, " --dport ");
1082         strcat(command, buf);
1083         strcat(command, " -j ACCEPT");
1084         assert(system(command) == 0);
1085         sleep(2);
1086         assert(system("iptables -A OUTPUT -j DROP") == 0);
1087         PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv4");
1088         assert(system("iptables -L") == 0);
1089 }
1090
1091 /* Add outgoing firewall rules for ipv6 addresses with packet type and port number */
1092 void outgoing_firewall_ipv6(const char *packetType, int portNumber) {
1093         char buf[5];
1094         snprintf(buf, sizeof(buf), "%d", portNumber);
1095         assert(system("ip6tables -F") == 0);
1096         assert(system("ip6tables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
1097         assert(system("ip6tables -A OUTPUT -s ::1 -d ::1 -j ACCEPT") == 0);
1098         char command[100] = "ip6tables -A OUTPUT -p ";
1099         strcat(command, packetType);
1100         strcat(command, " --dport ");
1101         strcat(command, buf);
1102         strcat(command, " -j ACCEPT");
1103         assert(system(command) == 0);
1104         sleep(2);
1105         assert(system("ip6tables -A OUTPUT -j DROP") == 0);
1106         PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv6");
1107         assert(system("ip6tables -L") == 0);
1108 }
1109
1110 void bridge_add(const char *bridge_name) {
1111         char cmd[500];
1112
1113         assert(bridge_name);
1114         assert(snprintf(cmd, sizeof(cmd), "brctl addbr %s", bridge_name) >= 0);
1115         assert(system(cmd) == 0);
1116         assert(snprintf(cmd, sizeof(cmd), "ifconfig %s up", bridge_name) >= 0);
1117         assert(system(cmd) == 0);
1118 }
1119
1120 void bridge_delete(const char *bridge_name) {
1121         char cmd[500];
1122
1123         assert(bridge_name);
1124         assert(snprintf(cmd, sizeof(cmd), "brctl delbr %s", bridge_name) >= 0);
1125         assert(system(cmd) == 0);
1126 }
1127
1128 void bridge_add_interface(const char *bridge_name, const char *interface_name) {
1129         char cmd[500];
1130
1131         assert(bridge_name || interface_name);
1132         assert(snprintf(cmd, sizeof(cmd), "brctl addif %s %s", bridge_name, interface_name) >= 0);
1133         assert(system(cmd) == 0);
1134 }