mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 22:35:33 +00:00
net: skip iptables dump if it has nft backend and nft dump is supported
On modern Linux distributions iptables binaries using new nftables API. We dump iptables rules using "iptables-save", and nftables rules using libnftables API. This breaks network unlock on modern systems because technically, we dump rules (including network lock rules) two times. There is another problem - on host we can have modern distribution, but in Docker container we can use iptables with netfilter (legacy) API. So, in this case this legacy rules will be skipped. This patch handles all of that cases. It tries to find iptables legacy and dump legacy rules by using appropriate iptables binaries, dump nftables rules by using libnftables. Fixes #1435 Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
This commit is contained in:
committed by
Andrei Vagin
parent
e26949cfed
commit
d8821d9a8f
@@ -1201,6 +1201,44 @@ static int check_compat_cr(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int check_nftables_cr(void)
|
||||
{
|
||||
#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1)
|
||||
return 0;
|
||||
#else
|
||||
pr_warn("CRIU was built without nftables support - nftables rules will "
|
||||
"not be preserved during C/R\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int check_ipt_legacy(void)
|
||||
{
|
||||
char *ipt_legacy_bin;
|
||||
char *ip6t_legacy_bin;
|
||||
|
||||
ipt_legacy_bin = get_legacy_iptables_bin(false);
|
||||
if (!ipt_legacy_bin) {
|
||||
pr_warn("Couldn't find iptables version which is using iptables legacy API\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_info("iptables cmd: %s\n", ipt_legacy_bin);
|
||||
|
||||
if (!kdat.ipv6)
|
||||
return 0;
|
||||
|
||||
ip6t_legacy_bin = get_legacy_iptables_bin(true);
|
||||
if (!ip6t_legacy_bin) {
|
||||
pr_warn("Couldn't find ip6tables version which is using iptables legacy API\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_info("ip6tables cmd: %s\n", ip6t_legacy_bin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_uffd(void)
|
||||
{
|
||||
if (!kdat.has_uffd) {
|
||||
@@ -1511,6 +1549,8 @@ static struct feature_list feature_list[] = {
|
||||
{ "external_net_ns", check_external_net_ns},
|
||||
{ "clone3_set_tid", check_clone3_set_tid},
|
||||
{ "newifindex", check_newifindex},
|
||||
{ "nftables", check_nftables_cr },
|
||||
{ "has_ipt_legacy", check_ipt_legacy },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
|
@@ -383,4 +383,6 @@ static inline void print_stack_trace(pid_t pid) {}
|
||||
|
||||
extern int mount_detached_fs(const char *fsname);
|
||||
|
||||
extern char *get_legacy_iptables_bin(bool ipv6);
|
||||
|
||||
#endif /* __CR_UTIL_H__ */
|
||||
|
32
criu/net.c
32
criu/net.c
@@ -2065,14 +2065,36 @@ static inline int dump_rule(struct cr_imgset *fds)
|
||||
static inline int dump_iptables(struct cr_imgset *fds)
|
||||
{
|
||||
struct cr_img *img;
|
||||
char *iptables_cmd = "iptables-save";
|
||||
char *ip6tables_cmd = "ip6tables-save";
|
||||
|
||||
img = img_from_set(fds, CR_FD_IPTABLES);
|
||||
if (run_iptables_tool("iptables-save", -1, img_raw_fd(img)))
|
||||
return -1;
|
||||
/*
|
||||
* Let's skip iptables dump if we have nftables support compiled in,
|
||||
* and iptables backend is nft to prevent duplicate dumps.
|
||||
*/
|
||||
#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1)
|
||||
iptables_cmd = get_legacy_iptables_bin(false);
|
||||
|
||||
if (kdat.ipv6) {
|
||||
if (kdat.ipv6)
|
||||
ip6tables_cmd = get_legacy_iptables_bin(true);
|
||||
#endif
|
||||
|
||||
if (!iptables_cmd) {
|
||||
pr_info("skipping iptables dump - no legacy version present\n");
|
||||
} else {
|
||||
img = img_from_set(fds, CR_FD_IPTABLES);
|
||||
if (run_iptables_tool(iptables_cmd, -1, img_raw_fd(img)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!kdat.ipv6)
|
||||
return 0;
|
||||
|
||||
if (!ip6tables_cmd) {
|
||||
pr_info("skipping ip6tables dump - no legacy version present\n");
|
||||
} else {
|
||||
img = img_from_set(fds, CR_FD_IP6TABLES);
|
||||
if (run_iptables_tool("ip6tables-save", -1, img_raw_fd(img)))
|
||||
if (run_iptables_tool(ip6tables_cmd, -1, img_raw_fd(img)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
88
criu/util.c
88
criu/util.c
@@ -1495,4 +1495,92 @@ int cut_path_ending(char *path, char *ending)
|
||||
|
||||
path[ending_pos - 1] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_iptables_nft(char *bin)
|
||||
{
|
||||
int pfd[2] = { -1, -1 }, ret = -1;
|
||||
char *cmd[] = { bin, "-V", NULL };
|
||||
char buf[100];
|
||||
|
||||
if (pipe(pfd) < 0) {
|
||||
pr_perror("Unable to create pipe");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = cr_system(-1, pfd[1], -1, cmd[0], cmd, 0);
|
||||
if (ret) {
|
||||
pr_err("%s -V failed\n", cmd[0]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
close_safe(&pfd[1]);
|
||||
|
||||
ret = read(pfd[0], buf, sizeof(buf) - 1);
|
||||
if (ret < 0) {
|
||||
pr_perror("Unable to read %s -V output", cmd[0]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
buf[ret] = '\0';
|
||||
ret = 0;
|
||||
|
||||
if (strstr(buf, "nf_tables")) {
|
||||
pr_info("iptables has nft backend: %s\n", buf);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
err:
|
||||
close_safe(&pfd[1]);
|
||||
close_safe(&pfd[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *get_legacy_iptables_bin(bool ipv6)
|
||||
{
|
||||
static char iptables_bin[2][32];
|
||||
/* 0 - means we don't know yet,
|
||||
* -1 - not present,
|
||||
* 1 - present.
|
||||
*/
|
||||
static int iptables_present[2] = { 0, 0 };
|
||||
char bins[2][2][32] = {
|
||||
{
|
||||
"iptables-save",
|
||||
"iptables-legacy-save"
|
||||
},
|
||||
{
|
||||
"ip6tables-save",
|
||||
"ip6tables-legacy-save"
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (iptables_present[ipv6] == -1)
|
||||
return NULL;
|
||||
|
||||
if (iptables_present[ipv6] == 1)
|
||||
return iptables_bin[ipv6];
|
||||
|
||||
memcpy(iptables_bin[ipv6], bins[ipv6][0], strlen(bins[ipv6][0]) + 1);
|
||||
ret = is_iptables_nft(iptables_bin[ipv6]);
|
||||
|
||||
/*
|
||||
* iptables on host uses nft backend (or not installed),
|
||||
* let's try iptables-legacy
|
||||
*/
|
||||
if (ret < 0 || ret == 1) {
|
||||
memcpy(iptables_bin[ipv6], bins[ipv6][1],
|
||||
strlen(bins[ipv6][1]) + 1);
|
||||
ret = is_iptables_nft(iptables_bin[ipv6]);
|
||||
if (ret < 0 || ret == 1) {
|
||||
iptables_present[ipv6] = -1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* we can come here with iptables-save or iptables-legacy-save */
|
||||
iptables_present[ipv6] = 1;
|
||||
|
||||
return iptables_bin[ipv6];
|
||||
}
|
Reference in New Issue
Block a user