Skip to content

Commit

Permalink
criu: add nftables connection locking/unlocking
Browse files Browse the repository at this point in the history
This adds nftables based connection locking as an alernative
for iptables. This avoid the external dependency of
iptables-restore.

It works by creating a 'connection set', which is a set of
connection identifying tuples. Rules are added to drop packets that
match the connection tuples in the set. Locking is now reduced to
just adding the connection identifying tuple to the set.

Unlocking is just as simple as deleteing the CRIU table.

v2: split ip string conversion into two if conditions
v3: add better message when CRIU is build without libnftables support
v4: fix indentation in nftables_lock_connection_raw()
v5: move 'ret = -1' below err: lable to avoid redundancy
v6: add better error message on lock failure
v7: run make indent

Signed-off-by: Zeyad Yasser <zeyady98@gmail.com>
  • Loading branch information
ZeyadYasser authored and avagin committed Aug 17, 2021
1 parent 3b932c0 commit 9756526
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 1 deletion.
3 changes: 3 additions & 0 deletions criu/include/netfilter.h
Expand Up @@ -10,6 +10,9 @@ extern int iptables_unlock_connection_info(struct inet_sk_info *);

extern void preload_netfilter_modules(void);

extern int nftables_init_connection_lock(void);
extern int nftables_lock_connection(struct inet_sk_desc *);

#if defined(CONFIG_HAS_NFTABLES_LIB_API_0)
#define NFT_RUN_CMD(nft, cmd) nft_run_cmd_from_buffer(nft, cmd, strlen(cmd))
#elif defined(CONFIG_HAS_NFTABLES_LIB_API_1)
Expand Down
7 changes: 6 additions & 1 deletion criu/net.c
Expand Up @@ -3160,8 +3160,11 @@ int network_lock(void)
pr_info("Lock network\n");

/* Each connection will be locked on dump */
if (!(root_ns_mask & CLONE_NEWNET))
if (!(root_ns_mask & CLONE_NEWNET)) {
if (opts.network_lock_method == NETWORK_LOCK_NFTABLES)
nftables_init_connection_lock();
return 0;
}

if (run_scripts(ACT_NET_LOCK))
return -1;
Expand All @@ -3180,6 +3183,8 @@ void network_unlock(void)
/* coverity[check_return] */
run_scripts(ACT_NET_UNLOCK);
network_unlock_internal();
} else if (opts.network_lock_method == NETWORK_LOCK_NFTABLES) {
nftables_network_unlock();
}
}

Expand Down
125 changes: 125 additions & 0 deletions criu/netfilter.c
Expand Up @@ -5,6 +5,10 @@
#include <sys/wait.h>
#include <stdlib.h>

#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1)
#include <nftables/libnftables.h>
#endif

#include "../soccr/soccr.h"

#include "util.h"
Expand All @@ -17,6 +21,8 @@

static char buf[512];

#define NFTABLES_CONN_CMD "add element inet CRIU conns%c { %s . %d . %s . %d }"

/*
* Need to configure simple netfilter rules for blocking connections
* Any brave soul to write it using xtables-devel?
Expand Down Expand Up @@ -145,3 +151,122 @@ int iptables_unlock_connection_info(struct inet_sk_info *si)

return ret;
}

int nftables_init_connection_lock(void)
{
#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1)
struct nft_ctx *nft;
int ret = 0;

nft = nft_ctx_new(NFT_CTX_DEFAULT);
if (!nft)
return -1;

if (NFT_RUN_CMD(nft, "add table inet CRIU"))
goto err2;

if (NFT_RUN_CMD(nft, "add chain inet CRIU output { type filter hook output priority 0; }"))
goto err1;

if (NFT_RUN_CMD(nft, "add rule inet CRIU output meta mark " __stringify(SOCCR_MARK) " accept"))
goto err1;

if (NFT_RUN_CMD(nft, "add chain inet CRIU input { type filter hook input priority 0; }"))
goto err1;

if (NFT_RUN_CMD(nft, "add rule inet CRIU input meta mark " __stringify(SOCCR_MARK) " accept"))
goto err1;

/* IPv4 */
if (NFT_RUN_CMD(nft, "add set inet CRIU conns4 { type ipv4_addr . inet_service . ipv4_addr . inet_service ; }"))
goto err1;

if (NFT_RUN_CMD(nft, "add rule inet CRIU output ip saddr . tcp sport . ip daddr . tcp dport @conns4 drop"))
goto err1;

if (NFT_RUN_CMD(nft, "add rule inet CRIU input ip saddr . tcp sport . ip daddr . tcp dport @conns4 drop"))
goto err1;

/* IPv6 */
if (NFT_RUN_CMD(nft, "add set inet CRIU conns6 { type ipv6_addr . inet_service . ipv6_addr . inet_service ; }"))
goto err1;

if (NFT_RUN_CMD(nft, "add rule inet CRIU output ip6 saddr . tcp sport . ip6 daddr . tcp dport @conns6 drop"))
goto err1;

if (NFT_RUN_CMD(nft, "add rule inet CRIU input ip6 saddr . tcp sport . ip6 daddr . tcp dport @conns6 drop"))
goto err1;

goto out;

err1:
NFT_RUN_CMD(nft, "delete table inet CRIU");
pr_err("Locking network failed using nftables\n");
err2:
ret = -1;
out:
nft_ctx_free(nft);
return ret;
#else
pr_err("CRIU was built without libnftables support\n");
return -1;
#endif
}

static int nftables_lock_connection_raw(int family, u32 *src_addr, u16 src_port, u32 *dst_addr, u16 dst_port)
{
#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1)
struct nft_ctx *nft;
int ret = 0;
char sip[INET_ADDR_LEN], dip[INET_ADDR_LEN];

if (family == AF_INET6 && ipv6_addr_mapped(dst_addr)) {
family = AF_INET;
src_addr = &src_addr[3];
dst_addr = &dst_addr[3];
}

if (!inet_ntop(family, (void *)src_addr, sip, INET_ADDR_LEN)) {
pr_perror("nf: Can't convert src ip addr");
return -1;
}

if (!inet_ntop(family, (void *)dst_addr, dip, INET_ADDR_LEN)) {
pr_perror("nf: Can't convert dst ip addr");
return -1;
}

nft = nft_ctx_new(NFT_CTX_DEFAULT);
if (!nft)
return -1;

snprintf(buf, sizeof(buf), NFTABLES_CONN_CMD, family == AF_INET ? '4' : '6', dip, (int)dst_port, sip,
(int)src_port);

pr_debug("\tRunning nftables [%s]\n", buf);

if (NFT_RUN_CMD(nft, buf)) {
ret = -1;
pr_err("Locking connection failed using nftables\n");
}

nft_ctx_free(nft);
return ret;
#else
pr_err("CRIU was built without libnftables support\n");
return -1;
#endif
}

int nftables_lock_connection(struct inet_sk_desc *sk)
{
int ret = 0;

ret = nftables_lock_connection_raw(sk->sd.family, sk->src_addr, sk->src_port, sk->dst_addr, sk->dst_port);
if (ret)
return -1;

ret = nftables_lock_connection_raw(sk->sd.family, sk->dst_addr, sk->dst_port, sk->src_addr, sk->src_port);

return ret;
}
8 changes: 8 additions & 0 deletions criu/sk-tcp.c
Expand Up @@ -37,6 +37,8 @@ static int lock_connection(struct inet_sk_desc *sk)
{
if (opts.network_lock_method == NETWORK_LOCK_IPTABLES)
return iptables_lock_connection(sk);
else if (opts.network_lock_method == NETWORK_LOCK_NFTABLES)
return nftables_lock_connection(sk);

return -1;
}
Expand All @@ -45,6 +47,9 @@ static int unlock_connection(struct inet_sk_desc *sk)
{
if (opts.network_lock_method == NETWORK_LOCK_IPTABLES)
return iptables_unlock_connection(sk);
else if (opts.network_lock_method == NETWORK_LOCK_NFTABLES)
/* All connections will be unlocked in network_unlock(void) */
return 0;

return -1;
}
Expand Down Expand Up @@ -475,6 +480,9 @@ static int unlock_connection_info(struct inet_sk_info *si)
{
if (opts.network_lock_method == NETWORK_LOCK_IPTABLES)
return iptables_unlock_connection_info(si);
else if (opts.network_lock_method == NETWORK_LOCK_NFTABLES)
/* All connections will be unlocked in network_unlock(void) */
return 0;

return -1;
}
Expand Down

0 comments on commit 9756526

Please sign in to comment.