代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/criu 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 099fe7c10a7eaac7df82d268d4d6bd831a68d44b Mon Sep 17 00:00:00 2001
From: "fu.lin" <fu.lin10@huawei.com>
Date: Wed, 11 Aug 2021 16:50:49 +0800
Subject: [PATCH 59/72] nftables: implement nft api for tcp
Signed-off-by: fu.lin <fulin10@huawei.com>
---
criu/Makefile.crtools | 1 +
criu/include/nftables.h | 138 +++++++
criu/nftables.c | 823 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 962 insertions(+)
create mode 100644 criu/nftables.c
diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
index a132810..b2a7641 100644
--- a/criu/Makefile.crtools
+++ b/criu/Makefile.crtools
@@ -99,6 +99,7 @@ obj-y += orphan-inode.o
obj-y += kmsg.o
obj-y += taskqueue.o
obj-y += mnl.o
+obj-y += nftables.o
obj-$(CONFIG_HAS_LIBBPF) += bpfmap.o
obj-$(CONFIG_COMPAT) += pie-util-vdso-elf32.o
CFLAGS_pie-util-vdso-elf32.o += -DCONFIG_VDSO_32
diff --git a/criu/include/nftables.h b/criu/include/nftables.h
index 0bdab31..3b51a3d 100644
--- a/criu/include/nftables.h
+++ b/criu/include/nftables.h
@@ -3,6 +3,99 @@
#include <libmnl/libmnl.h>
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/set.h>
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#define construct_buf(buf, type, family, flags, seq, payload, cb_prefix) \
+ ({ \
+ struct nlmsghdr *_nlh; \
+ \
+ _nlh = nftnl_##cb_prefix##_nlmsg_build_hdr((buf), \
+ (type), (family), (flags), (seq)); \
+ nftnl_##cb_prefix##_nlmsg_build_payload(_nlh, (payload)); \
+ nftnl_##cb_prefix##_free((payload)); \
+ _nlh; \
+ })
+
+#define construct_table_buf(buf, type, family, flags, seq, payload) \
+ construct_buf((buf), (type), (family), (flags), (seq), \
+ (payload), table)
+
+#define construct_chain_buf(buf, type, family, flags, seq, payload) \
+ construct_buf((buf), (type), (family), (flags), (seq), \
+ (payload), chain)
+
+#define construct_batch(batch, type, family, flags, seq, payload, cb_prefix) \
+ { \
+ struct nlmsghdr *_nlh; \
+ \
+ _nlh = nftnl_##cb_prefix##_nlmsg_build_hdr( \
+ mnl_nlmsg_batch_current(batch), \
+ (type), (family), (flags), (seq)); \
+ nftnl_##cb_prefix##_nlmsg_build_payload(_nlh, (payload)); \
+ nftnl_##cb_prefix##_free((payload)); \
+ mnl_nlmsg_batch_next((batch)); \
+ }
+
+#define construct_table_batch(batch, type, family, flags, seq, payload) \
+ construct_batch((batch), (type), (family), (flags), (seq), \
+ (payload), table)
+
+#define construct_chain_batch(batch, type, family, flags, seq, payload) \
+ construct_batch((batch), (type), (family), (flags), (seq), \
+ (payload), chain)
+
+#define construct_set_batch(batch, type, family, flags, seq, payload) \
+ construct_batch((batch), (type), (family), (flags), (seq), \
+ (payload), set)
+
+#define construct_rule_batch(batch, type, family, flags, seq, payload) \
+ construct_batch((batch), (type), (family), (flags), (seq), \
+ (payload), rule)
+
+#define construct_set_elems_batch(batch, type, family, flags, seq, payload) \
+ { \
+ struct nlmsghdr *_nlh; \
+ \
+ _nlh = nftnl_nlmsg_build_hdr( \
+ mnl_nlmsg_batch_current(batch), \
+ (type), (family), (flags), (seq)); \
+ nftnl_set_elems_nlmsg_build_payload(_nlh, (payload)); \
+ nftnl_set_free((payload)); \
+ mnl_nlmsg_batch_next((batch)); \
+ }
+
+#define TABLE_NAME "filter"
+#define INPUT_CHAIN_NAME "criu-input"
+#define OUTPUT_CHAIN_NAME "criu-output"
+#define INPUT_IPV4_SET_NAME "criu-input-ipv4-blacklist-%d"
+#define INPUT_IPV6_SET_NAME "criu-input-ipv6-blacklist-%d"
+#define OUTPUT_IPV4_SET_NAME "criu-output-ipv4-blacklist-%d"
+#define OUTPUT_IPV6_SET_NAME "criu-output-ipv6-blacklist-%d"
+
+/* set key type, see nftables/include/datatypes.h
+ * The rule of the datatype calculation:
+ * Each type occupies 6 bits, type:
+ * - ipaddr: 7, 4 bytes
+ * - ip6addr: 8, 16 types
+ * - inet_service: 13, 2 bytes (pading to 4 bytes)
+ *
+ * 0x1cd1cd: 0b 000111 001101 000111 001101
+ * 0x20d20d: 0b 001000 001101 001000 001101
+ */
+#define INET_SERVICE_LEN 2
+#define IPADDR_LEN 4
+#define IP6ADDR_LEN 16
+#define div_round_up(n, d) (((n) + (d) - 1) / (d))
+
+#define IPv4_KEY_TYPE 0x1cd1cd
+#define IPv4_KEY_LEN div_round_up(IPADDR_LEN + INET_SERVICE_LEN, 4) * 4 * 2
+#define IPv6_KEY_TYPE 0x20d20d
+#define IPv6_KEY_LEN div_round_up(IP6ADDR_LEN + INET_SERVICE_LEN, 4) * 4 * 2
+
struct mnl_params {
struct mnl_socket *nl;
char *buf;
@@ -25,4 +118,49 @@ int mnl_common(mnl_func_t mnl_cb, void *arg1, void *arg2);
int mnl_batch_send_and_recv(struct mnl_params *mnl_params, batch_func_t cb, void *args, int *result);
int mnl_buf_send_and_recv(struct mnl_params *mnl_params, buf_func_t cb, void *args, int *result);
+struct nft_chain_params {
+ char *name;
+ uint32_t hooknum;
+ char *type;
+ uint32_t prio;
+ uint32_t policy;
+};
+
+struct nft_set_params {
+ char name[128];
+ uint32_t id;
+ uint32_t datatype;
+ uint32_t key_len;
+};
+
+struct nft_rule_params {
+ char *chain_name;
+ char set_name[128];
+ uint32_t mark;
+ uint16_t mark_op;
+ uint32_t nfproto;
+ uint8_t l4proto;
+ unsigned int stmt;
+ bool ipv6;
+};
+
+struct nft_set_elem_params {
+ char set_name[128];
+ char data[40];
+ size_t data_len;
+};
+
+struct nf_conn_params {
+ uint8_t family;
+ uint32_t *src_addr;
+ uint16_t src_port;
+ uint32_t *dst_addr;
+ uint16_t dst_port;
+ bool lock;
+ pid_t tree_id;
+};
+
+struct inet_sk_desc;
+int nft_connection_switch(struct inet_sk_desc *sk, bool lock, pid_t tree_id);
+
#endif /* __CR_NFTABLES_H__ */
diff --git a/criu/nftables.c b/criu/nftables.c
new file mode 100644
index 0000000..57774e6
--- /dev/null
+++ b/criu/nftables.c
@@ -0,0 +1,823 @@
+#include <libmnl/libmnl.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+#include "sk-inet.h"
+#include "nftables.h"
+
+#include "../soccr/soccr.h"
+
+#include "log.h"
+
+static struct nftnl_table *setup_table(uint8_t family, const char *table)
+{
+ struct nftnl_table *t;
+
+ t = nftnl_table_alloc();
+ if (t == NULL)
+ return NULL;
+
+ nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, family);
+ if (nftnl_table_set_str(t, NFTNL_TABLE_NAME, table) < 0)
+ goto err;
+
+ return t;
+err:
+ nftnl_table_free(t);
+ return NULL;
+}
+
+static struct nftnl_chain *setup_chain(const char *table,
+ struct nft_chain_params *params,
+ bool create)
+{
+ struct nftnl_chain *c;
+
+ c = nftnl_chain_alloc();
+ if (c == NULL)
+ return NULL;
+
+ if (nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table) < 0)
+ goto err;
+ if (nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, params->name) < 0)
+ goto err;
+ if (create) {
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, params->hooknum);
+ if (nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, params->type) < 0)
+ goto err;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, params->prio);
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, params->policy);
+ }
+
+ return c;
+err:
+ nftnl_chain_free(c);
+ return NULL;
+}
+
+static struct nftnl_set *setup_set(uint8_t family, const char *table,
+ struct nft_set_params *params,
+ bool create)
+{
+ struct nftnl_set *s;
+
+ s = nftnl_set_alloc();
+ if (s == NULL)
+ return NULL;
+
+ if (nftnl_set_set_str(s, NFTNL_SET_TABLE, table) < 0)
+ goto err;
+ if (nftnl_set_set_str(s, NFTNL_SET_NAME, params->name) < 0)
+ goto err;
+ if (create) {
+ nftnl_set_set_u32(s, NFTNL_SET_FAMILY, family);
+ nftnl_set_set_u32(s, NFTNL_SET_ID, params->id);
+
+ nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, params->datatype);
+ nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, params->key_len);
+ }
+
+ return s;
+err:
+ nftnl_set_free(s);
+ return NULL;
+}
+
+static int add_mark(struct nftnl_rule *r, uint32_t meta_key, enum nft_registers dreg)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("meta");
+ if (e == NULL)
+ return -1;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_META_KEY, meta_key);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_META_DREG, dreg);
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int add_proto(struct nftnl_rule *r, enum nft_registers dreg)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("meta");
+ if (e == NULL)
+ return -1;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_META_KEY, NFT_META_L4PROTO);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_META_DREG, dreg);
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg,
+ uint32_t offset, uint32_t len)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("payload");
+ if (e == NULL)
+ return -1;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int add_cmp(struct nftnl_rule *r, enum nft_registers sreg, uint32_t op,
+ const void *data, uint32_t data_len)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("cmp");
+ if (e == NULL)
+ return -1;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_OP, op);
+ nftnl_expr_set(e, NFTNL_EXPR_CMP_DATA, data, data_len);
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int add_lookup(struct nftnl_rule *r, enum nft_registers sreg,
+ const char *set)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("lookup");
+ if (e == NULL)
+ return -1;
+
+ if (nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set) < 0)
+ goto err;
+ nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+err:
+ nftnl_expr_free(e);
+ return -1;
+}
+
+static int add_counter(struct nftnl_rule *r)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("counter");
+ if (e == NULL)
+ return -1;
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int add_verdict(struct nftnl_rule *r, const char *chain, int verdict)
+{
+ struct nftnl_expr *e;
+
+ e = nftnl_expr_alloc("immediate");
+ if (e == NULL)
+ return -1;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_VERDICT, verdict);
+
+ nftnl_rule_add_expr(r, e);
+
+ return 0;
+}
+
+static int __setup_rule(struct nftnl_rule *r, struct nft_rule_params *params)
+{
+ /* meta nfproto == <nfproto> */
+ if (add_mark(r, NFT_META_PROTOCOL, NFT_REG32_00) < 0)
+ return -1;
+ if (add_cmp(r, NFT_REG32_00, NFT_CMP_EQ, ¶ms->nfproto, sizeof(uint32_t))< 0)
+ return -1;
+
+ /* meta l4proto == <l4proto> */
+ if (add_proto(r, NFT_REG32_00) < 0)
+ return -1;
+ if (add_cmp(r, NFT_REG32_00, NFT_CMP_EQ, ¶ms->l4proto, sizeof(uint8_t)) < 0)
+ return -1;
+
+ /* ip saddr . sport . daddr . dport @<set> */
+ if (params->ipv6 == false) {
+ if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_00,
+ offsetof(struct iphdr, saddr), IPADDR_LEN) < 0)
+ return -1;
+ if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_01,
+ offsetof(struct tcphdr, source), INET_SERVICE_LEN) < 0)
+ return -1;
+ if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_02,
+ offsetof(struct iphdr, daddr), IPADDR_LEN) < 0)
+ return -1;
+ if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_03,
+ offsetof(struct tcphdr, dest), INET_SERVICE_LEN) < 0)
+ return -1;
+
+ if (add_lookup(r, NFT_REG32_00, params->set_name) < 0)
+ return -1;
+ } else {
+ if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_00,
+ offsetof(struct ipv6hdr, saddr), IP6ADDR_LEN) < 0)
+ return -1;
+ if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_04,
+ offsetof(struct tcphdr, source), INET_SERVICE_LEN) < 0)
+ return -1;
+ if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_05,
+ offsetof(struct ipv6hdr, daddr), IP6ADDR_LEN) < 0)
+ return -1;
+ if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_09,
+ offsetof(struct tcphdr, dest), INET_SERVICE_LEN) < 0)
+ return -1;
+
+ if (add_lookup(r, NFT_REG32_00, params->set_name) < 0)
+ return -1;
+ }
+
+ /* counter */
+ if (add_counter(r) < 0)
+ return -1;
+
+ return 0;
+}
+
+static struct nftnl_rule *setup_rule(uint8_t family, const char *table,
+ struct nft_rule_params *params,
+ bool create, bool ns)
+{
+ struct nftnl_rule *r = NULL;
+
+ r = nftnl_rule_alloc();
+ if (r == NULL)
+ return NULL;
+
+ if (nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table) < 0)
+ goto err;
+ nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
+ if (nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, params->chain_name) < 0)
+ goto err;
+
+ if (params->mark != 0) {
+ /* meta mark != <mark> */
+ if (add_mark(r, NFT_META_MARK, NFT_REG32_00) < 0)
+ goto err;
+ if (add_cmp(r, NFT_REG32_00, params->mark_op, ¶ms->mark, sizeof(uint32_t)) < 0)
+ goto err;
+ }
+
+ if (!ns && __setup_rule(r, params) < 0)
+ goto err;
+
+ /* drop */
+ if (add_verdict(r, params->chain_name, params->stmt) < 0)
+ goto err;
+
+ return r;
+
+err:
+ nftnl_rule_free(r);
+ return NULL;
+}
+
+static struct nlmsghdr *nft_table_detect(struct mnl_params *mnl_params, void *args)
+{
+ struct nftnl_table *table;
+
+ table = setup_table(NFPROTO_INET, TABLE_NAME);
+ if (table == NULL)
+ return NULL;
+
+ return construct_table_buf(mnl_params->buf, NFT_MSG_GETTABLE, NFPROTO_INET,
+ NLM_F_ACK, mnl_params->seq++, table);
+}
+
+static int nft_table_create(struct mnl_params *mnl_params, void *args)
+{
+ struct nftnl_table *table;
+
+ table = setup_table(NFPROTO_INET, TABLE_NAME);
+ if (table == NULL)
+ return -1;
+
+ construct_table_batch(mnl_params->batch, NFT_MSG_NEWTABLE, NFPROTO_INET,
+ NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK,
+ mnl_params->seq++, table);
+
+ return 0;
+}
+
+static int nft_table_prepare(struct mnl_params *mnl_params)
+{
+ int result = 0;
+
+ if (mnl_buf_send_and_recv(mnl_params, nft_table_detect, NULL, &result) == 0)
+ return 0;
+
+ pr_debug("%s: detect table result %d\n", __func__, result);
+
+ if (result == ENOENT &&
+ (mnl_batch_send_and_recv(mnl_params, nft_table_create, NULL, &result) < 0
+ && (result != 0 && result != EEXIST))) {
+ pr_err("%s: create nftables table failed!\n", __func__);
+ return -1;
+ } else if (result != 0) {
+ pr_err("%s: detect table result %d\n", __func__, -result);
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct nlmsghdr *nft_chain_detect(struct mnl_params *mnl_params, void *args)
+{
+ struct nftnl_chain *chain;
+
+ chain = setup_chain(TABLE_NAME, args, false);
+ if (chain == NULL)
+ return NULL;
+
+ return construct_chain_buf(mnl_params->buf, NFT_MSG_GETCHAIN, NFPROTO_INET,
+ NLM_F_ACK, mnl_params->seq++, chain);
+}
+
+static int nft_chain_create(struct mnl_params *mnl_params, void *args)
+{
+ struct nftnl_chain *chain;
+
+ chain = setup_chain(TABLE_NAME, args, true);
+ if (chain == NULL)
+ return -1;
+
+ construct_chain_batch(mnl_params->batch, NFT_MSG_NEWCHAIN, NFPROTO_INET,
+ NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK, mnl_params->seq++, chain);
+
+ return 0;
+}
+
+static int nft_chain_prepare_internal(struct mnl_params *mnl_params,
+ struct nft_chain_params *params)
+{
+ int result = 0;
+
+ if (mnl_buf_send_and_recv(mnl_params, nft_chain_detect, params, &result) == 0)
+ return 0;
+
+ pr_debug("%s: detect chain result %d\n", __func__, result);
+
+ if (result == ENOENT &&
+ (mnl_batch_send_and_recv(mnl_params, nft_chain_create, params, &result) < 0
+ && (result != 0 && result != EEXIST))) {
+ pr_err("%s: nftables create chain %s failed!\n",
+ __func__, params->name);
+ return -1;
+ } else if (result != 0) {
+ pr_err("%s: detect chain result %d\n", __func__, -result);
+ return -1;
+ }
+
+ return result;
+}
+
+static int nft_chain_prepare(struct mnl_params *mnl_params)
+{
+ struct nft_chain_params params = {
+ .type = "filter",
+ .prio = NF_IP_PRI_FILTER,
+ .policy = NF_ACCEPT,
+ };
+
+ /* prepare ipv4 input chain in filter table */
+ params.name = INPUT_CHAIN_NAME;
+ params.hooknum = NF_INET_LOCAL_IN;
+
+ if (nft_chain_prepare_internal(mnl_params, ¶ms) < 0)
+ return -1;
+
+ /* prepare ipv4 output chain in filter table */
+ params.name = OUTPUT_CHAIN_NAME;
+ params.hooknum = NF_INET_LOCAL_OUT;
+
+ if (nft_chain_prepare_internal(mnl_params, ¶ms) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int nft_set_internal(uint8_t family, struct mnl_params *mnl_params,
+ struct nft_set_params *params, bool create)
+{
+ struct nftnl_set *set;
+
+ set = setup_set(family, TABLE_NAME, params, create);
+ if (set == NULL)
+ return -1;
+
+ if (create) {
+ construct_set_batch(mnl_params->batch, NFT_MSG_NEWSET, family,
+ NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK, mnl_params->seq++, set);
+ } else {
+ construct_set_batch(mnl_params->batch, NFT_MSG_DELSET, family,
+ 0, mnl_params->seq++, set);
+ }
+
+ return 0;
+}
+
+static int nft_set_raw(struct mnl_params *mnl_params,
+ struct mnl_cb_params *args, bool input)
+{
+ const uint32_t set_id_base = input ? 0x12315 : 0x17173;
+ const uint8_t family = NFPROTO_INET;
+ struct nft_set_params params = { 0 };
+ char *set_name;
+ int idx = 0;
+
+ if (!args->ipv6) {
+ params.datatype = IPv4_KEY_TYPE;
+ params.key_len = IPv4_KEY_LEN;
+ idx = 4;
+ } else {
+ params.datatype = IPv6_KEY_TYPE;
+ params.key_len = IPv6_KEY_LEN;
+ idx = 6;
+ }
+
+ if (args->ipv6 && input)
+ set_name = INPUT_IPV6_SET_NAME;
+ else if (args->ipv6 && !input)
+ set_name = OUTPUT_IPV6_SET_NAME;
+ else if (!args->ipv6 && input)
+ set_name = INPUT_IPV4_SET_NAME;
+ else
+ set_name = OUTPUT_IPV4_SET_NAME;
+
+ snprintf(params.name, sizeof(params.name)-1, set_name, args->tree_id);
+ params.id = set_id_base + args->tree_id + idx;
+
+ if (nft_set_internal(family, mnl_params, ¶ms, args->create) < 0) {
+ pr_err("%s: create nftables %s %s set failed!\n", __func__,
+ args->ipv6 ? "ipv6" : "ipv4",
+ input ? "input" : "output");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int nft_set(struct mnl_params *mnl_params, void *args)
+{
+ struct mnl_cb_params *params = args;
+
+ params->ipv6 = false;
+ if (nft_set_raw(mnl_params, params, true) < 0)
+ return -1;
+
+ if (nft_set_raw(mnl_params, params, false) < 0)
+ return -1;
+
+ params->ipv6 = true;
+ if (nft_set_raw(mnl_params, params, true) < 0)
+ return -1;
+
+ if (nft_set_raw(mnl_params, params, false) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int nft_set_common(struct mnl_params *mnl_params, pid_t tree_id, bool create)
+{
+ struct mnl_cb_params params = {
+ .tree_id = tree_id,
+ .create = create,
+ };
+ int result = 0;
+
+ if (create &&
+ (mnl_batch_send_and_recv(mnl_params, nft_set, ¶ms, &result) < 0
+ && (result != 0 && result != EEXIST))) {
+ pr_err("%s: create set failed!\n", __func__);
+ return -1;
+ } else if (!create &&
+ mnl_batch_send_and_recv(mnl_params, nft_set, ¶ms, NULL) < 0) {
+ pr_err("%s: delete set failed!\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int nft_rule_internal(uint8_t family, struct mnl_params *mnl_params,
+ struct nft_rule_params *params, bool create)
+{
+ struct nftnl_rule *rule;
+
+ rule = setup_rule(family, TABLE_NAME, params, create, false);
+ if (rule == NULL)
+ return -1;
+
+ if (create) {
+ construct_rule_batch(mnl_params->batch, NFT_MSG_NEWRULE, family,
+ NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK,
+ mnl_params->seq++, rule);
+ } else {
+ construct_rule_batch(mnl_params->batch, NFT_MSG_DELRULE, family,
+ 0, mnl_params->seq++, rule);
+ }
+
+ return 0;
+}
+
+static int nft_rule_raw(struct mnl_params *mnl_params, struct mnl_cb_params *args,
+ struct nft_rule_params *params)
+{
+ char *set_name;
+
+ params->nfproto = params->ipv6 ? htons(ETH_P_IPV6) : htons(ETH_P_IP);
+
+ set_name = params->ipv6 ? INPUT_IPV6_SET_NAME : INPUT_IPV4_SET_NAME;
+ params->chain_name = INPUT_CHAIN_NAME;
+ snprintf(params->set_name, sizeof(params->set_name)-1, set_name, args->tree_id);
+ if (nft_rule_internal(NFPROTO_INET, mnl_params, params, args->create) < 0) {
+ pr_err("%s: create nft %s input rule failed!\n",
+ __func__, params->ipv6 ? "ipv6" : "ipv4");
+ return -1;
+ }
+
+ set_name = params->ipv6 ? OUTPUT_IPV6_SET_NAME : OUTPUT_IPV4_SET_NAME;
+ params->chain_name = OUTPUT_CHAIN_NAME;
+ snprintf(params->set_name, sizeof(params->set_name)-1, set_name, args->tree_id);
+ if (nft_rule_internal(NFPROTO_INET, mnl_params, params, args->create) < 0) {
+ pr_err("%s: create nftables %s output rule failed!\n",
+ __func__, params->ipv6 ? "ipv6" : "ipv4");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int nft_rule(struct mnl_params *mnl_params, void *args)
+{
+ struct nft_rule_params params = {
+ .l4proto = IPPROTO_TCP,
+ .mark = SOCCR_MARK,
+ .mark_op = NFT_CMP_NEQ,
+ .stmt = NF_DROP,
+ };
+
+ params.ipv6 = false;
+ if (nft_rule_raw(mnl_params, args, ¶ms) < 0)
+ return -1;
+
+ params.ipv6 = true;
+ if (nft_rule_raw(mnl_params, args, ¶ms) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int nft_rule_common(struct mnl_params *mnl_params, pid_t tree_id, bool create)
+{
+ struct mnl_cb_params params = {
+ .tree_id = tree_id,
+ .create = create,
+ };
+ int result = 0;
+
+ if (create &&
+ (mnl_batch_send_and_recv(mnl_params, nft_rule, ¶ms, &result) < 0
+ && (result != 0 && result != EEXIST))) {
+ pr_err("%s: create rule failed!\n", __func__);
+ return -1;
+ } else if (!create &&
+ mnl_batch_send_and_recv(mnl_params, nft_rule, ¶ms, NULL) < 0) {
+ pr_err("%s: delete rule failed!\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int network_prepare_internal(struct mnl_params *params, batch_func_t _, void *args)
+{
+ pid_t tree_id = *(pid_t *)args;
+
+ if (nft_table_prepare(params) < 0)
+ return -1;
+
+ if (nft_chain_prepare(params) < 0)
+ return -1;
+
+ if (nft_set_common(params, tree_id, true) < 0)
+ return -1;
+
+ if (nft_rule_common(params, tree_id, true) < 0)
+ return -1;
+
+ return 0;
+}
+
+int network_prepare(pid_t tree_id)
+{
+ pr_info("Prepare network\n");
+
+ return mnl_common(network_prepare_internal, NULL, &tree_id);
+}
+
+static int network_unprepare_internal(struct mnl_params *params,
+ batch_func_t _, void *args)
+{
+ pid_t tree_id = *(pid_t *)args;
+
+ if (nft_rule_common(params, tree_id, false) < 0)
+ return -1;
+
+ if (nft_set_common(params, tree_id, false) < 0)
+ return -1;
+
+ return 0;
+}
+
+void network_unprepare(pid_t tree_id)
+{
+ pr_info("Unprepare network\n");
+
+ mnl_common(network_unprepare_internal, NULL, &tree_id);
+}
+
+static int add_set_elem_internal(struct nftnl_set *s, void *data, size_t len)
+{
+ struct nftnl_set_elem *e;
+
+ e = nftnl_set_elem_alloc();
+ if (e == NULL)
+ return -1;
+
+ nftnl_set_elem_set(e, NFTNL_SET_ELEM_KEY, data, len);
+
+ nftnl_set_elem_add(s, e);
+
+ return 0;
+}
+
+static struct nftnl_set *add_set_elem(const char *table, const char *set,
+ void *data, size_t len)
+{
+ struct nftnl_set *s;
+
+ s = nftnl_set_alloc();
+ if (s == NULL)
+ return NULL;
+
+ if (nftnl_set_set_str(s, NFTNL_SET_TABLE, table) < 0)
+ goto err;
+ if (nftnl_set_set_str(s, NFTNL_SET_NAME, set) < 0)
+ goto err;
+
+ if (add_set_elem_internal(s, data, len) < 0)
+ goto err;
+
+ return s;
+
+err:
+ nftnl_set_free(s);
+ return NULL;
+}
+
+static int nft_set_elem(uint8_t family, struct mnl_params *mnl_param,
+ struct nft_set_elem_params *elem_param,
+ bool lock)
+{
+ struct nftnl_set *set;
+
+ set = add_set_elem(TABLE_NAME, elem_param->set_name,
+ elem_param->data, elem_param->data_len);
+ if (set == NULL)
+ return -1;
+
+ if (lock) {
+ construct_set_elems_batch(mnl_param->batch, NFT_MSG_NEWSETELEM,
+ family, NLM_F_CREATE|NLM_F_EXCL,
+ mnl_param->seq++, set);
+ } else {
+ construct_set_elems_batch(mnl_param->batch, NFT_MSG_DELSETELEM,
+ family, 0, mnl_param->seq++, set);
+ }
+
+ return 0;
+}
+
+static void construct_set_elem_key(void *data, struct nf_conn_params *param, bool output)
+{
+ size_t offset = 0;
+ size_t addr_len = param->family == AF_INET ? IPADDR_LEN : IP6ADDR_LEN;
+
+ memcpy(data+offset, output ? param->src_addr : param->dst_addr, addr_len);
+ offset = addr_len;
+ *(uint32_t *)(data + offset) = htons(output ? param->src_port : param->dst_port);
+ offset += sizeof(uint32_t);
+ memcpy(data+offset, output ? param->dst_addr : param->src_addr, addr_len);
+ offset += addr_len;
+ *(uint32_t *)(data + offset) = htons(output ? param->dst_port : param->src_port);
+}
+
+static int nf_connection_switch_raw(struct mnl_params *mnl_params, void *args)
+{
+ struct nf_conn_params *param = args;
+ char *input_set_name, *output_set_name;
+ struct nft_set_elem_params elem;
+
+ switch (param->family) {
+ case AF_INET:
+ input_set_name = INPUT_IPV4_SET_NAME;
+ output_set_name = OUTPUT_IPV4_SET_NAME;
+ elem.data_len = IPv4_KEY_LEN;
+ break;
+ case AF_INET6:
+ input_set_name = INPUT_IPV6_SET_NAME;
+ output_set_name = OUTPUT_IPV6_SET_NAME;
+ elem.data_len = IPv6_KEY_LEN;
+ break;
+ default:
+ pr_err("Unknown socket family %d\n", param->family);
+ return -1;
+ }
+
+ construct_set_elem_key(elem.data, param, false);
+ snprintf(elem.set_name, sizeof(elem.set_name)-1, input_set_name, param->tree_id);
+ if (nft_set_elem(NFPROTO_INET, mnl_params, &elem, param->lock) < 0)
+ return -1;
+
+ construct_set_elem_key(elem.data, param, true);
+ snprintf(elem.set_name, sizeof(elem.set_name)-1, output_set_name, param->tree_id);
+ if (nft_set_elem(NFPROTO_INET, mnl_params, &elem, param->lock) < 0)
+ return -1;
+
+ return 0;
+}
+
+/* IPv4-Mapped IPv6 Addresses */
+static int ipv6_addr_mapped(uint32_t *addr)
+{
+ return (addr[2] == htonl(0x0000ffff));
+}
+
+int nft_connection_switch(struct inet_sk_desc *sk, bool lock, pid_t tree_id)
+{
+ char sip[INET_ADDR_LEN], dip[INET_ADDR_LEN];
+ struct nf_conn_params param = {
+ .family = sk->sd.family,
+ .src_addr = sk->src_addr,
+ .src_port = sk->src_port,
+ .dst_addr = sk->dst_addr,
+ .dst_port = sk->dst_port,
+ .lock = lock,
+ .tree_id = tree_id,
+ };
+
+ if (param.family == AF_INET6 && ipv6_addr_mapped(param.dst_addr)) {
+ param.family = AF_INET;
+ param.src_addr = ¶m.src_addr[3];
+ param.dst_addr = ¶m.dst_addr[3];
+ }
+
+ if (!inet_ntop(param.family, (void *)param.src_addr, sip, INET_ADDR_LEN) ||
+ !inet_ntop(param.family, (void *)param.dst_addr, dip, INET_ADDR_LEN)) {
+ pr_perror("nf: Can't translate ip addr");
+ return -1;
+ }
+
+ pr_info("%s %s:%d - %s:%d connection\n", lock ? "Locked" : "Unlocked",
+ sip, (int)param.src_port, dip, (int)param.dst_port);
+
+ return mnl_sendmsg(nf_connection_switch_raw, ¶m);
+}
--
2.34.1
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。