]> git.meshlink.io Git - meshlink/blobdiff - test/blackbox/common/containers.c
Add the blackbox channel connection tests.
[meshlink] / test / blackbox / common / containers.c
index 263cbf976ddd878da19d27be9c956ce0ee821095..d96b1a3715c4b987389f26dc1bf78deda1fa6a2c 100644 (file)
@@ -302,7 +302,7 @@ void destroy_containers(void) {
                        test_containers[i]->stop(test_containers[i]);
                        /* Destroy the Container */
                        test_containers[i]->destroy(test_containers[i]);
-                       /* call destroy_with_snapshots() in case destroy() fails
+                       /* Call destroy_with_snapshots() in case destroy() fails
                            one of these two calls will always succeed */
                        test_containers[i]->destroy_with_snapshots(test_containers[i]);
                }
@@ -356,7 +356,7 @@ void node_sim_in_container(const char *node, const char *device_class, const cha
        PRINT_TEST_CASE_MSG("node_sim_%s started in Container\n", node);
 }
 
-/* Run the node_sim_<nodename> program inside the 'node''s container with event handling capable*/
+/* Run the node_sim_<nodename> program inside the 'node''s container with event handling capable */
 void node_sim_in_container_event(const char *node, const char *device_class,
                                  const char *invite_url, const char *clientId, const char *import) {
        char node_sim_command[200];
@@ -368,8 +368,6 @@ void node_sim_in_container_event(const char *node, const char *device_class,
        run_in_container(node_sim_command, node, true);
        PRINT_TEST_CASE_MSG("node_sim_%s(Client Id :%s) started in Container with event handling\n",
                            node, clientId);
-       PRINT_TEST_CASE_MSG("node_sim_%s mesh event import string : %s\n",
-                           node, import);
 }
 
 /* Run the node_step.sh script inside the 'node''s container to send the 'sig' signal to the
@@ -453,3 +451,443 @@ void change_ip(int node) {
        PRINT_TEST_CASE_MSG("Node '%s' IP Address changed to %s\n", state_ptr->node_names[node],
                            container_ips[node]);
 }
+
+/* Return container's IP address */
+char *get_container_ip(const char *node_name) {
+       char *ip;
+       int n, node = -1, i;
+
+       for(i = 0; i < state_ptr->num_nodes; i++) {
+               if(!strcasecmp(state_ptr->node_names[i], node_name)) {
+                       node = i;
+                       break;
+               }
+       }
+
+       if(i == state_ptr->num_nodes) {
+               return NULL;
+       }
+
+       n = strlen(container_ips[node]) + 1;
+       ip = malloc(n);
+       assert(ip);
+       strncpy(ip, container_ips[node], n);
+
+       return ip;
+}
+
+/* Install an app in a container */
+void install_in_container(const char *node, const char *app) {
+       char install_cmd[100];
+
+       assert(snprintf(install_cmd, sizeof(install_cmd),
+                       "apt-get install %s -y >> /dev/null", app) >= 0);
+       char *ret = run_in_container(install_cmd, node, false);
+       // TODO: Check in container whether app has installed or not with a timeout
+       sleep(10);
+}
+
+/* Simulate a network failure by adding NAT rule in the container with it's IP address */
+void block_node_ip(const char *node) {
+       char block_cmd[100];
+       char *node_ip;
+
+       node_ip = get_container_ip(node);
+       assert(node_ip);
+       assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A OUTPUT -p all -s %s -j DROP", node_ip) >= 0);
+       run_in_container(block_cmd, node, false);
+
+       assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A INPUT -p all -s %s -j DROP", node_ip) >= 0);
+       run_in_container(block_cmd, node, false);
+
+       assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A FORWARD -p all -s %s -j DROP", node_ip) >= 0);
+       run_in_container(block_cmd, node, false);
+
+       free(node_ip);
+}
+
+void accept_port_rule(const char *node, const char *chain, const char *protocol, int port) {
+       char block_cmd[100];
+
+       assert(port >= 0 && port < 65536);
+       assert(!strcmp(chain, "INPUT") || !strcmp(chain, "FORWARD") || !strcmp(chain, "OUTPUT"));
+       assert(!strcmp(protocol, "all") || !strcmp(protocol, "tcp") || !strcmp(protocol, "udp"));
+       assert(snprintf(block_cmd, sizeof(block_cmd), "iptables -A %s -p %s --dport %d -j ACCEPT", chain, protocol, port) >= 0);
+       run_in_container(block_cmd, node, false);
+}
+
+/* Restore the network that was blocked before by the NAT rule with it's own IP address */
+void unblock_node_ip(const char *node) {
+       char unblock_cmd[100];
+       char *node_ip;
+
+       node_ip = get_container_ip(node);
+       assert(node_ip);
+       assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D OUTPUT -p all -s %s -j DROP", node_ip) >= 0);
+       run_in_container(unblock_cmd, node, false);
+
+       assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D INPUT -p all -s %s -j DROP", node_ip) >= 0);
+       run_in_container(unblock_cmd, node, false);
+
+       assert(snprintf(unblock_cmd, sizeof(unblock_cmd), "iptables -D FORWARD -p all -s %s -j DROP", node_ip) >= 0);
+       run_in_container(unblock_cmd, node, false);
+}
+
+/* Takes bridgeName as input parameter and creates a bridge */
+void create_bridge(const char *bridgeName) {
+       char command[100] = "brctl addbr ";
+       strcat(command, bridgeName);
+       int create_bridge_status = system(command);
+       assert(create_bridge_status == 0);
+       PRINT_TEST_CASE_MSG("%s bridge created\n", bridgeName);
+}
+
+/* Add interface for the bridge created */
+void add_interface(const char *bridgeName, const char *interfaceName) {
+       char command[100] = "brctl addif ";
+       char cmd[100] = "dhclient ";
+
+       strcat(command, bridgeName);
+       strcat(command, " ");
+       strcat(command, interfaceName);
+       int addif_status = system(command);
+       assert(addif_status == 0);
+       strcat(cmd, bridgeName);
+       int dhclient_status = system(cmd);
+       assert(dhclient_status == 0);
+       PRINT_TEST_CASE_MSG("Added interface for %s\n", bridgeName);
+}
+
+/* Create a veth pair and bring them up */
+void add_veth_pair(const char *vethName1, const char *vethName2) {
+       char command[100] = "ip link add ";
+       char upCommand1[100] = "ip link set ";
+       char upCommand2[100] = "ip link set ";
+
+       strcat(command, vethName1);
+       strcat(command, " type veth peer name ");
+       strcat(command, vethName2);
+       int link_add_status = system(command);
+       assert(link_add_status == 0);
+       strcat(upCommand1, vethName1);
+       strcat(upCommand1, " up");
+       int link_set_veth1_status = system(upCommand1);
+       assert(link_set_veth1_status == 0);
+       strcat(upCommand2, vethName2);
+       strcat(upCommand2, " up");
+       int link_set_veth2_status = system(upCommand2);
+       assert(link_set_veth2_status == 0);
+       PRINT_TEST_CASE_MSG("Added veth pairs %s and %s\n", vethName1, vethName2);
+}
+
+/* Bring the interface up for the bridge created */
+void bring_if_up(const char *bridgeName) {
+       char command[300] = "ifconfig ";
+       char dhcommand[300] = "dhclient ";
+       strcat(command, bridgeName);
+       strcat(command, " up");
+       int if_up_status = system(command);
+       assert(if_up_status == 0);
+       sleep(2);
+       PRINT_TEST_CASE_MSG("Interface brought up for %s created\n", bridgeName);
+}
+
+/**
+ * Replace all occurrences of a given a word in string.
+ */
+void replaceAll(char *str, const char *oldWord, const char *newWord) {
+       char *pos, temp[BUFSIZ];
+       int index = 0;
+       int owlen;
+       owlen = strlen(oldWord);
+
+       while((pos = strstr(str, oldWord)) != NULL) {
+               strcpy(temp, str);
+               index = pos - str;
+               str[index] = '\0';
+               strcat(str, newWord);
+               strcat(str, temp + index + owlen);
+       }
+}
+
+/* Switches the bridge for a given container */
+void switch_bridge(const char *containerName, const char *currentBridge, const char *newBridge) {
+       char command[100] = "lxc-stop -n ";
+       char command_start[100] = "lxc-start -n ";
+       PRINT_TEST_CASE_MSG("Switching %s container to %s\n", containerName, newBridge);
+       strcat(command, containerName);
+       strcat(command_start, containerName);
+       int container_stop_status = system(command);
+       assert(container_stop_status == 0);
+       sleep(2);
+       FILE *fPtr;
+       FILE *fTemp;
+       char path[300] = "/var/lib/lxc/";
+       strcat(path, containerName);
+       strcat(path, "/config");
+
+       char buffer[BUFSIZ];
+       /*  Open all required files */
+       fPtr  = fopen(path, "r");
+       fTemp = fopen("replace.tmp", "w");
+
+       if(fPtr == NULL || fTemp == NULL) {
+               PRINT_TEST_CASE_MSG("\nUnable to open file.\n");
+               PRINT_TEST_CASE_MSG("Please check whether file exists and you have read/write privilege.\n");
+               exit(EXIT_SUCCESS);
+       }
+
+       while((fgets(buffer, BUFSIZ, fPtr)) != NULL) {
+               replaceAll(buffer, currentBridge, newBridge);
+               fputs(buffer, fTemp);
+       }
+
+       fclose(fPtr);
+       fclose(fTemp);
+       remove(path);
+       rename("replace.tmp", path);
+       PRINT_TEST_CASE_MSG("Switching procedure done successfully\n");
+       int container_start_status = system(command_start);
+       assert(container_start_status == 0);
+       sleep(2);
+}
+
+/* Bring the interface down for the bridge created */
+void bring_if_down(const char *bridgeName) {
+       char command[300] = "ip link set dev ";
+       strcat(command, bridgeName);
+       strcat(command, " down");
+       int if_down_status = system(command);
+       assert(if_down_status == 0);
+       PRINT_TEST_CASE_MSG("Interface brought down for %s created\n", bridgeName);
+}
+
+/* Delete interface for the bridge created */
+void del_interface(const char *bridgeName, const char *interfaceName) {
+       char command[300] = "brctl delif ";
+       strcat(command, bridgeName);
+       strcat(command, interfaceName);
+       int if_delete_status = system(command);
+       assert(if_delete_status == 0);
+       PRINT_TEST_CASE_MSG("Deleted interface for %s\n", bridgeName);
+}
+
+/* Takes bridgeName as input parameter and deletes a bridge */
+void delete_bridge(const char *bridgeName) {
+       bring_if_down(bridgeName);
+       char command[300] = "brctl delbr ";
+       strcat(command, bridgeName);
+       int bridge_delete = system(command);
+       assert(bridge_delete == 0);
+       PRINT_TEST_CASE_MSG("%s bridge deleted\n", bridgeName);
+       sleep(2);
+}
+
+/* Creates container on a specified bridge with added interface */
+void create_container_on_bridge(const char *containerName, const char *bridgeName, const char *ifName) {
+       char command[100] = "lxc-create -t download -n ";
+       char cmd[100] = " -- -d ubuntu -r trusty -a ";
+       char start[100] = "lxc-start -n ";
+       FILE *fPtr;
+       char path[300] = "/var/lib/lxc/";
+       strcat(path, containerName);
+       strcat(path, "/config");
+       strcat(command, containerName);
+       strcat(command, cmd);
+       strcat(command, choose_arch);
+       int container_create_status = system(command);
+       assert(container_create_status == 0);
+       sleep(3);
+       assert(fPtr = fopen(path, "a+"));
+       fprintf(fPtr, "lxc.net.0.name = eth0\n");
+       fprintf(fPtr, "\n");
+       fprintf(fPtr, "lxc.net.1.type = veth\n");
+       fprintf(fPtr, "lxc.net.1.flags = up\n");
+       fprintf(fPtr, "lxc.net.1.link = %s\n", bridgeName);
+       fprintf(fPtr, "lxc.net.1.name = %s\n", ifName);
+       fprintf(fPtr, "lxc.net.1.hwaddr = 00:16:3e:ab:xx:xx\n");
+       fclose(fPtr);
+       strcat(start, containerName);
+       int container_start_status = system(start);
+       assert(container_start_status == 0);
+       sleep(3);
+       PRINT_TEST_CASE_MSG("Created %s on %s with interface name %s\n", containerName, bridgeName, ifName);
+}
+
+/* Configures dnsmasq and iptables for the specified container with inputs of listen address and dhcp range */
+void config_dnsmasq(const char *containerName, const char *ifName, const char *listenAddress, const char *dhcpRange) {
+       char command[500] = "echo \"apt-get install dnsmasq iptables -y\" | lxc-attach -n ";
+       strcat(command, containerName);
+       strcat(command, " --");
+       int iptables_install_status = system(command);
+       assert(iptables_install_status == 0);
+       sleep(5);
+       char com1[300] = "echo \"echo \"interface=eth1\" >> /etc/dnsmasq.conf\" | lxc-attach -n ";
+       strcat(com1, containerName);
+       strcat(com1, " --");
+       int dnsmasq_status = system(com1);
+       assert(dnsmasq_status == 0);
+       sleep(5);
+       char com2[300] = "echo \"echo \"bind-interfaces\" >> /etc/dnsmasq.conf\" | lxc-attach -n ";
+       strcat(com2, containerName);
+       strcat(com2, " --");
+       dnsmasq_status = system(com2);
+       assert(dnsmasq_status == 0);
+       sleep(5);
+       char com3[300] = "echo \"echo \"listen-address=";
+       strcat(com3, listenAddress);
+       strcat(com3, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n ");
+       strcat(com3, containerName);
+       strcat(com3, " --");
+       dnsmasq_status = system(com3);
+       assert(dnsmasq_status == 0);
+       sleep(5);
+       char com4[300] = "echo \"echo \"dhcp-range=";
+       strcat(com4, dhcpRange);
+       strcat(com4, "\" >> /etc/dnsmasq.conf\" | lxc-attach -n ");
+       strcat(com4, containerName);
+       strcat(com4, " --");
+       dnsmasq_status = system(com4);
+       assert(dnsmasq_status == 0);
+       sleep(5);
+       char cmd[300] = "echo \"ifconfig ";
+       strcat(cmd, ifName);
+       strcat(cmd, " ");
+       strcat(cmd, listenAddress);
+       strcat(cmd, " netmask 255.255.255.0 up\" | lxc-attach -n ");
+       strcat(cmd, containerName);
+       strcat(cmd, " --");
+       dnsmasq_status = system(cmd);
+       assert(dnsmasq_status == 0);
+       sleep(2);
+       char com[500] = "echo \"service dnsmasq restart >> /dev/null\" | lxc-attach -n ";
+       strcat(com, containerName);
+       strcat(com, " --");
+       dnsmasq_status = system(com);
+       assert(dnsmasq_status == 0);
+       sleep(2);
+       PRINT_TEST_CASE_MSG("Configured dnsmasq in %s with interface name %s, listen-address = %s, dhcp-range = %s\n", containerName, ifName, listenAddress, dhcpRange);
+}
+
+/* Configure the NAT rules inside the container */
+void config_nat(const char *containerName, const char *listenAddress) {
+       char *last_dot_in_ip;
+       int last_ip_byte = 0;
+       char new_ip[300] = {0};
+       strncpy(new_ip, listenAddress, sizeof(new_ip));
+       assert(last_dot_in_ip = strrchr(new_ip, '.'));
+       assert(snprintf(last_dot_in_ip + 1, 4, "%d", last_ip_byte) >= 0);
+       char comd[300] = "echo \"iptables -t nat -A POSTROUTING -s ";
+       strcat(comd, new_ip);
+       strcat(comd, "/24 ! -d ");
+       strcat(comd, new_ip);
+       strcat(comd, "/24 -j MASQUERADE\" | lxc-attach -n ");
+       strcat(comd, containerName);
+       strcat(comd, " --");
+       int conf_nat_status = system(comd);
+       assert(conf_nat_status == 0);
+       sleep(2);
+       PRINT_TEST_CASE_MSG("Configured NAT on %s\n", containerName);
+}
+
+/* Creates a NAT layer on a specified bridge with certain dhcp range to allocate ips for nodes */
+void create_nat_layer(const char *containerName, const char *bridgeName, const char *ifName, const char *listenAddress, char *dhcpRange) {
+       create_bridge(bridgeName);
+       bring_if_up(bridgeName);
+       create_container_on_bridge(containerName, bridgeName, ifName);
+       config_dnsmasq(containerName, ifName, listenAddress, dhcpRange);
+       config_nat(containerName, listenAddress);
+       PRINT_TEST_CASE_MSG("NAT layer created with %s\n", containerName);
+}
+
+/* Destroys the NAT layer created */
+void destroy_nat_layer(const char *containerName, const char *bridgeName) {
+       bring_if_down(bridgeName);
+       delete_bridge(bridgeName);
+       char command[100] = "lxc-stop -n ";
+       strcat(command, containerName);
+       int container_stop_status = system(command);
+       assert(container_stop_status == 0);
+       char destroy[100] = "lxc-destroy -n ";
+       strcat(destroy, containerName);
+       strcat(destroy, " -s");
+       int container_destroy_status = system(destroy);
+       assert(container_destroy_status == 0);
+       PRINT_TEST_CASE_MSG("NAT layer destroyed with %s\n", containerName);
+}
+
+/* Add incoming firewall rules for ipv4 addresses with packet type and port number */
+void incoming_firewall_ipv4(const char *packetType, int portNumber) {
+       char buf[5];
+       snprintf(buf, sizeof(buf), "%d", portNumber);
+       assert(system("iptables -F") == 0);
+       assert(system("iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+       assert(system("iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0);
+       char command[100] = "iptables -A INPUT -p ";
+       strcat(command, packetType);
+       strcat(command, " --dport ");
+       strcat(command, buf);
+       strcat(command, " -j ACCEPT");
+       assert(system(command) == 0);
+       sleep(2);
+       assert(system("iptables -A INPUT -j DROP") == 0);
+       PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv4");
+       assert(system("iptables -L") == 0);
+}
+
+/* Add incoming firewall rules for ipv6 addresses with packet type and port number */
+void incoming_firewall_ipv6(const char *packetType, int portNumber) {
+       char buf[5];
+       snprintf(buf, sizeof(buf), "%d", portNumber);
+       assert(system("ip6tables -F") == 0);
+       assert(system("ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+       assert(system("ip6tables -A INPUT -s ::1 -d ::1 -j ACCEPT") == 0);
+       char command[100] = "ip6tables -A INPUT -p ";
+       strcat(command, packetType);
+       strcat(command, " --dport ");
+       strcat(command, buf);
+       strcat(command, " -j ACCEPT");
+       assert(system(command) == 0);
+       sleep(2);
+       assert(system("ip6tables -A INPUT -j DROP") == 0);
+       PRINT_TEST_CASE_MSG("Firewall for incoming requests added on IPv6");
+       assert(system("ip6tables -L") == 0);
+}
+
+/* Add outgoing firewall rules for ipv4 addresses with packet type and port number */
+void outgoing_firewall_ipv4(const char *packetType, int portNumber) {
+       char buf[5];
+       snprintf(buf, sizeof(buf), "%d", portNumber);
+       assert(system("iptables -F") == 0);
+       assert(system("iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+       assert(system("iptables -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT") == 0);
+       char command[100] = "iptables -A OUTPUT -p ";
+       strcat(command, packetType);
+       strcat(command, " --dport ");
+       strcat(command, buf);
+       strcat(command, " -j ACCEPT");
+       assert(system(command) == 0);
+       sleep(2);
+       assert(system("iptables -A OUTPUT -j DROP") == 0);
+       PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv4");
+       assert(system("iptables -L") == 0);
+}
+
+/* Add outgoing firewall rules for ipv6 addresses with packet type and port number */
+void outgoing_firewall_ipv6(const char *packetType, int portNumber) {
+       char buf[5];
+       snprintf(buf, sizeof(buf), "%d", portNumber);
+       assert(system("ip6tables -F") == 0);
+       assert(system("ip6tables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT") == 0);
+       assert(system("ip6tables -A OUTPUT -s ::1 -d ::1 -j ACCEPT") == 0);
+       char command[100] = "ip6tables -A OUTPUT -p ";
+       strcat(command, packetType);
+       strcat(command, " --dport ");
+       strcat(command, buf);
+       strcat(command, " -j ACCEPT");
+       assert(system(command) == 0);
+       sleep(2);
+       assert(system("ip6tables -A OUTPUT -j DROP") == 0);
+       PRINT_TEST_CASE_MSG("Firewall for outgoing requests added on IPv6");
+       assert(system("ip6tables -L") == 0);
+}