aboutsummaryrefslogtreecommitdiffstats
path: root/executor/common_linux.h
diff options
context:
space:
mode:
Diffstat (limited to 'executor/common_linux.h')
-rw-r--r--executor/common_linux.h97
1 files changed, 97 insertions, 0 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 5128009dd..37cc9c5ea 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -1232,8 +1232,104 @@ static void reset_arptables()
close(fd);
}
+#include <linux/netfilter_bridge/ebtables.h>
+
+struct ebt_table_desc {
+ const char* name;
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+};
+
+static struct ebt_table_desc ebt_tables[] = {
+ {.name = "filter"},
+ {.name = "nat"},
+ {.name = "broute"},
+};
+
+static void checkpoint_ebtables(void)
+{
+ socklen_t optlen;
+ unsigned i;
+ int fd;
+
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1)
+ fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ strcpy(table->replace.name, table->name);
+ optlen = sizeof(table->replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace, &optlen)) {
+ switch (errno) {
+ case EPERM:
+ case ENOENT:
+ case ENOPROTOOPT:
+ continue;
+ }
+ fail("getsockopt(EBT_SO_GET_INIT_INFO)");
+ }
+ debug("checkpoint ebtable %s: entries=%d hooks=%x size=%d\n", table->name, table->replace.nentries, table->replace.valid_hooks, table->replace.entries_size);
+ if (table->replace.entries_size > sizeof(table->entrytable))
+ fail("table size is too large: %u", table->replace.entries_size);
+ table->replace.num_counters = 0;
+ table->replace.entries = table->entrytable;
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace, &optlen))
+ fail("getsockopt(EBT_SO_GET_INIT_ENTRIES)");
+ }
+ close(fd);
+}
+
+static void reset_ebtables()
+{
+ struct ebt_replace replace;
+ char entrytable[XT_TABLE_SIZE];
+ socklen_t optlen;
+ unsigned i, j, h;
+ int fd;
+
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd == -1)
+ fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
+ for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
+ struct ebt_table_desc* table = &ebt_tables[i];
+ if (table->replace.valid_hooks == 0)
+ continue;
+ memset(&replace, 0, sizeof(replace));
+ strcpy(replace.name, table->name);
+ optlen = sizeof(replace);
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
+ fail("getsockopt(EBT_SO_GET_INFO)");
+ replace.num_counters = 0;
+ for (h = 0; h < NF_BR_NUMHOOKS; h++)
+ table->replace.hook_entry[h] = 0;
+ if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
+ memset(&entrytable, 0, sizeof(entrytable));
+ replace.entries = entrytable;
+ optlen = sizeof(replace) + replace.entries_size;
+ if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
+ fail("getsockopt(EBT_SO_GET_ENTRIES)");
+ if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
+ continue;
+ }
+ debug("resetting ebtable %s\n", table->name);
+ // Kernel does not seem to return actual entry points (wat?).
+ for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
+ if (table->replace.valid_hooks & (1 << h)) {
+ table->replace.hook_entry[h] = (struct ebt_entries*)table->entrytable + j;
+ j++;
+ }
+ }
+ optlen = sizeof(table->replace) + table->replace.entries_size;
+ if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
+ fail("setsockopt(EBT_SO_SET_ENTRIES)");
+ }
+ close(fd);
+}
+
static void checkpoint_net_namespace(void)
{
+ checkpoint_ebtables();
checkpoint_arptables();
checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP);
checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6);
@@ -1241,6 +1337,7 @@ static void checkpoint_net_namespace(void)
static void reset_net_namespace(void)
{
+ reset_ebtables();
reset_arptables();
reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP);
reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6);