diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-06-14 17:50:59 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-07-23 23:52:35 +0900 |
commit | 295942cb4629c620d3a3f01b6dcda7a2a716d672 (patch) | |
tree | 81bc553cd93d80133f757e042dc0981e0cb2ce97 | |
parent | 8547260579397c6b7912133e2c06931d5f2451e3 (diff) | |
download | systemd-295942cb4629c620d3a3f01b6dcda7a2a716d672.tar.gz |
firewall-util-nft: various cleanups
- add missing assertions,
- align enum elements,
- use cleanup attribute, and so on.
-rw-r--r-- | src/shared/firewall-util-nft.c | 516 |
1 files changed, 333 insertions, 183 deletions
diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index 87a326cafd..e04304838d 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -24,13 +24,27 @@ #include "time-util.h" #define NFT_SYSTEMD_DNAT_MAP_NAME "map_port_ipport" -#define NFT_SYSTEMD_TABLE_NAME "io.systemd.nat" +#define NFT_SYSTEMD_TABLE_NAME "io.systemd.nat" #define NFT_SYSTEMD_MASQ_SET_NAME "masq_saddr" #define NFNL_DEFAULT_TIMEOUT_USECS (1ULL * USEC_PER_SEC) #define UDP_DPORT_OFFSET 2 +static sd_netlink_message **netlink_message_unref_many(sd_netlink_message **m) { + if (!m) + return NULL; + + /* This does not free array. The end of the array must be NULL. */ + + for (sd_netlink_message **p = m; *p; p++) + *p = sd_netlink_message_unref(*p); + + return m; +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink_message**, netlink_message_unref_many); + static int nfnl_netlink_sendv( sd_netlink *nfnl, sd_netlink_message *messages[static 1], @@ -63,6 +77,9 @@ static int nfnl_netlink_sendv( static int nfnl_add_open_expr_container(sd_netlink_message *m, const char *name) { int r; + assert(m); + assert(name); + r = sd_netlink_message_open_array(m, NFTA_LIST_ELEM); if (r < 0) return r; @@ -74,11 +91,16 @@ static int nfnl_add_open_expr_container(sd_netlink_message *m, const char *name) return sd_netlink_message_open_container_union(m, NFTA_EXPR_DATA, name); } -static int nfnl_add_expr_fib(sd_netlink_message *m, uint32_t nft_fib_flags, - enum nft_fib_result result, - enum nft_registers dreg) { +static int nfnl_add_expr_fib( + sd_netlink_message *m, + uint32_t nft_fib_flags, + enum nft_fib_result result, + enum nft_registers dreg) { + int r; + assert(m); + r = nfnl_add_open_expr_container(m, "fib"); if (r < 0) return r; @@ -86,9 +108,11 @@ static int nfnl_add_expr_fib(sd_netlink_message *m, uint32_t nft_fib_flags, r = sd_netlink_message_append_u32(m, NFTA_FIB_FLAGS, htobe32(nft_fib_flags)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_FIB_RESULT, htobe32(result)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_FIB_DREG, htobe32(dreg)); if (r < 0) return r; @@ -100,10 +124,15 @@ static int nfnl_add_expr_fib(sd_netlink_message *m, uint32_t nft_fib_flags, return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_meta(sd_netlink_message *m, enum nft_meta_keys key, - enum nft_registers dreg) { +static int nfnl_add_expr_meta( + sd_netlink_message *m, + enum nft_meta_keys key, + enum nft_registers dreg) { + int r; + assert(m); + r = nfnl_add_open_expr_container(m, "meta"); if (r < 0) return r; @@ -123,10 +152,17 @@ static int nfnl_add_expr_meta(sd_netlink_message *m, enum nft_meta_keys key, return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_payload(sd_netlink_message *m, enum nft_payload_bases pb, - uint32_t offset, uint32_t len, enum nft_registers dreg) { +static int nfnl_add_expr_payload( + sd_netlink_message *m, + enum nft_payload_bases pb, + uint32_t offset, + uint32_t len, + enum nft_registers dreg) { + int r; + assert(m); + r = nfnl_add_open_expr_container(m, "payload"); if (r < 0) return r; @@ -134,12 +170,15 @@ static int nfnl_add_expr_payload(sd_netlink_message *m, enum nft_payload_bases p r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_DREG, htobe32(dreg)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_BASE, htobe32(pb)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_OFFSET, htobe32(offset)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_LEN, htobe32(len)); if (r < 0) return r; @@ -147,13 +186,20 @@ static int nfnl_add_expr_payload(sd_netlink_message *m, enum nft_payload_bases p r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ if (r < 0) return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_lookup_set_data(sd_netlink_message *m, const char *set_name, - enum nft_registers sreg) { +static int nfnl_add_expr_lookup_set_data( + sd_netlink_message *m, + const char *set_name, + enum nft_registers sreg) { + int r; + assert(m); + assert(set_name); + r = nfnl_add_open_expr_container(m, "lookup"); if (r < 0) return r; @@ -165,10 +211,16 @@ static int nfnl_add_expr_lookup_set_data(sd_netlink_message *m, const char *set_ return sd_netlink_message_append_u32(m, NFTA_LOOKUP_SREG, htobe32(sreg)); } -static int nfnl_add_expr_lookup_set(sd_netlink_message *m, const char *set_name, - enum nft_registers sreg) { +static int nfnl_add_expr_lookup_set( + sd_netlink_message *m, + const char *set_name, + enum nft_registers sreg) { + int r; + assert(m); + assert(set_name); + r = nfnl_add_expr_lookup_set_data(m, set_name, sreg); if (r < 0) return r; @@ -176,13 +228,21 @@ static int nfnl_add_expr_lookup_set(sd_netlink_message *m, const char *set_name, r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ if (r < 0) return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_lookup_map(sd_netlink_message *m, const char *set_name, - enum nft_registers sreg, enum nft_registers dreg) { +static int nfnl_add_expr_lookup_map( + sd_netlink_message *m, + const char *set_name, + enum nft_registers sreg, + enum nft_registers dreg) { + int r; + assert(m); + assert(set_name); + r = nfnl_add_expr_lookup_set_data(m, set_name, sreg); if (r < 0) return r; @@ -198,12 +258,21 @@ static int nfnl_add_expr_lookup_map(sd_netlink_message *m, const char *set_name, return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_data(sd_netlink_message *m, int attr, const void *data, uint32_t dlen) { +static int nfnl_add_expr_data( + sd_netlink_message *m, + int attr, + const void *data, + uint32_t dlen) { + int r; + assert(m); + assert(data); + r = sd_netlink_message_open_container(m, attr); if (r < 0) return r; + r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen); if (r < 0) return r; @@ -211,14 +280,18 @@ static int nfnl_add_expr_data(sd_netlink_message *m, int attr, const void *data, return sd_netlink_message_close_container(m); /* attr */ } -static int nfnl_add_expr_cmp_data(sd_netlink_message *m, const void *data, uint32_t dlen) { - return nfnl_add_expr_data(m, NFTA_CMP_DATA, data, dlen); -} +static int nfnl_add_expr_cmp( + sd_netlink_message *m, + enum nft_cmp_ops cmp_op, + enum nft_registers sreg, + const void *data, + uint32_t dlen) { -static int nfnl_add_expr_cmp(sd_netlink_message *m, enum nft_cmp_ops cmp_op, - enum nft_registers sreg, const void *data, uint32_t dlen) { int r; + assert(m); + assert(data); + r = nfnl_add_open_expr_container(m, "cmp"); if (r < 0) return r; @@ -226,27 +299,36 @@ static int nfnl_add_expr_cmp(sd_netlink_message *m, enum nft_cmp_ops cmp_op, r = sd_netlink_message_append_u32(m, NFTA_CMP_OP, htobe32(cmp_op)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_CMP_SREG, htobe32(sreg)); if (r < 0) return r; - r = nfnl_add_expr_cmp_data(m, data, dlen); + r = nfnl_add_expr_data(m, NFTA_CMP_DATA, data, dlen); if (r < 0) return r; r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ if (r < 0) return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_bitwise(sd_netlink_message *m, - enum nft_registers sreg, - enum nft_registers dreg, - const void *and, - const void *xor, uint32_t len) { +static int nfnl_add_expr_bitwise( + sd_netlink_message *m, + enum nft_registers sreg, + enum nft_registers dreg, + const void *and, + const void *xor, + uint32_t len) { + int r; + assert(m); + assert(and); + assert(xor); + r = nfnl_add_open_expr_container(m, "bitwise"); if (r < 0) return r; @@ -254,9 +336,11 @@ static int nfnl_add_expr_bitwise(sd_netlink_message *m, r = sd_netlink_message_append_u32(m, NFTA_BITWISE_SREG, htobe32(sreg)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_BITWISE_DREG, htobe32(dreg)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_BITWISE_LEN, htobe32(len)); if (r < 0) return r; @@ -272,15 +356,20 @@ static int nfnl_add_expr_bitwise(sd_netlink_message *m, r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ if (r < 0) return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int nfnl_add_expr_dnat(sd_netlink_message *m, - int family, - enum nft_registers areg, - enum nft_registers preg) { +static int nfnl_add_expr_dnat( + sd_netlink_message *m, + int family, + enum nft_registers areg, + enum nft_registers preg) { + int r; + assert(m); + r = nfnl_add_open_expr_container(m, "nat"); if (r < 0) return r; @@ -296,9 +385,11 @@ static int nfnl_add_expr_dnat(sd_netlink_message *m, r = sd_netlink_message_append_u32(m, NFTA_NAT_REG_ADDR_MIN, htobe32(areg)); if (r < 0) return r; + r = sd_netlink_message_append_u32(m, NFTA_NAT_REG_PROTO_MIN, htobe32(preg)); if (r < 0) return r; + r = sd_netlink_message_close_container(m); if (r < 0) return r; @@ -320,13 +411,22 @@ static int nfnl_add_expr_masq(sd_netlink_message *m) { return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ } -static int sd_nfnl_message_new_masq_rule(sd_netlink *nfnl, sd_netlink_message **ret, int family, - const char *chain) { +static int sd_nfnl_message_new_masq_rule( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *chain) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; /* -t nat -A POSTROUTING -p protocol -s source/pflen -o out_interface -d destination/pflen -j MASQUERADE */ + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(chain); + r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain); if (r < 0) return r; @@ -358,12 +458,17 @@ static int sd_nfnl_message_new_masq_rule(sd_netlink *nfnl, sd_netlink_message ** r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */ if (r < 0) return r; + *ret = TAKE_PTR(m); return 0; } -static int sd_nfnl_message_new_dnat_rule_pre(sd_netlink *nfnl, sd_netlink_message **ret, int family, - const char *chain) { +static int sd_nfnl_message_new_dnat_rule_pre( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *chain) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; enum nft_registers proto_reg; uint32_t local = RTN_LOCAL; @@ -372,6 +477,11 @@ static int sd_nfnl_message_new_dnat_rule_pre(sd_netlink *nfnl, sd_netlink_messag /* -t nat -A PREROUTING -p protocol --dport local_port -i in_interface -s source/pflen * -d destination/pflen -j DNAT --to-destination remote_addr:remote_port */ + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(chain); + r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain); if (r < 0) return r; @@ -401,8 +511,7 @@ static int sd_nfnl_message_new_dnat_rule_pre(sd_netlink *nfnl, sd_netlink_messag return r; /* 3rd statement: lookup 'l4proto . dport', e.g. 'tcp . 22' as key and - * store address and port for the dnat mapping in REG1/REG2. - */ + * store address and port for the dnat mapping in REG1/REG2. */ r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); if (r < 0) return r; @@ -415,18 +524,27 @@ static int sd_nfnl_message_new_dnat_rule_pre(sd_netlink *nfnl, sd_netlink_messag r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */ if (r < 0) return r; + *ret = TAKE_PTR(m); return 0; } -static int sd_nfnl_message_new_dnat_rule_out(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *chain) { - static const uint32_t zero = 0, one = 1; +static int sd_nfnl_message_new_dnat_rule_out( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *chain) { + static const uint32_t zero = 0, one = 1; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; enum nft_registers proto_reg; int r; + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(chain); + r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain); if (r < 0) return r; @@ -488,8 +606,7 @@ static int sd_nfnl_message_new_dnat_rule_out(sd_netlink *nfnl, sd_netlink_messag * the new destination ip and port number. * * reg1 and reg2 are clobbered and will then contain the new - * address/port number. - */ + * address/port number. */ r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); if (r < 0) return r; @@ -504,18 +621,29 @@ static int sd_nfnl_message_new_dnat_rule_out(sd_netlink *nfnl, sd_netlink_messag r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */ if (r < 0) return r; + *ret = TAKE_PTR(m); return 0; } -static int nft_new_set(struct sd_netlink *nfnl, - sd_netlink_message **ret, - int family, const char *set_name, - uint32_t set_id, - uint32_t flags, uint32_t type, uint32_t klen) { +static int nft_new_set( + struct sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *set_name, + uint32_t set_id, + uint32_t flags, + uint32_t type, + uint32_t klen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(set_name); + r = sd_nfnl_nft_message_new_set(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name, set_id, klen); if (r < 0) return r; @@ -534,13 +662,26 @@ static int nft_new_set(struct sd_netlink *nfnl, return r; } -static int nft_new_map(struct sd_netlink *nfnl, - sd_netlink_message **ret, - int family, const char *set_name, uint32_t set_id, - uint32_t flags, uint32_t type, uint32_t klen, uint32_t dtype, uint32_t dlen) { +static int nft_new_map( + struct sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *set_name, + uint32_t set_id, + uint32_t flags, + uint32_t type, + uint32_t klen, + uint32_t dtype, + uint32_t dlen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(set_name); + r = nft_new_set(nfnl, &m, family, set_name, set_id, flags | NFT_SET_MAP, type, klen); if (r < 0) return r; @@ -552,17 +693,31 @@ static int nft_new_map(struct sd_netlink *nfnl, r = sd_netlink_message_append_u32(m, NFTA_SET_DATA_LEN, htobe32(dlen)); if (r < 0) return r; + *ret = TAKE_PTR(m); return 0; } -static int nft_add_element(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *set_name, - const void *key, uint32_t klen, - const void *data, uint32_t dlen) { +static int nft_add_element( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *set_name, + const void *key, + uint32_t klen, + const void *data, + uint32_t dlen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(set_name); + assert(key); + assert(data); + /* * Ideally there would be an API that provides: * @@ -588,17 +743,31 @@ static int nft_add_element(sd_netlink *nfnl, sd_netlink_message **ret, r = sd_nfnl_nft_message_add_setelem_end(m); if (r < 0) return r; + *ret = TAKE_PTR(m); return 0; } -static int nft_del_element(sd_netlink *nfnl, - sd_netlink_message **ret, int family, const char *set_name, - const void *key, uint32_t klen, - const void *data, uint32_t dlen) { +static int nft_del_element( + sd_netlink *nfnl, + sd_netlink_message **ret, + int family, + const char *set_name, + const void *key, + uint32_t klen, + const void *data, + uint32_t dlen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; + assert(nfnl); + assert(ret); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(set_name); + assert(key); + assert(data); + r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name); if (r < 0) return r; @@ -610,6 +779,7 @@ static int nft_del_element(sd_netlink *nfnl, r = sd_nfnl_nft_message_add_setelem_end(m); if (r < 0) return r; + *ret = TAKE_PTR(m); return 0; } @@ -617,15 +787,14 @@ static int nft_del_element(sd_netlink *nfnl, /* This is needed so 'nft' userspace tool can properly format the contents * of the set/map when someone uses 'nft' to inspect their content. * - * The values cannot be changed, they are part of the nft tool type identifier ABI. - */ + * The values cannot be changed, they are part of the nft tool type identifier ABI. */ #define TYPE_BITS 6 enum nft_key_types { - TYPE_IPADDR = 7, - TYPE_IP6ADDR = 8, + TYPE_IPADDR = 7, + TYPE_IP6ADDR = 8, TYPE_INET_PROTOCOL = 12, - TYPE_INET_SERVICE = 13, + TYPE_INET_SERVICE = 13, }; static uint32_t concat_types2(enum nft_key_types a, enum nft_key_types b) { @@ -637,51 +806,42 @@ static uint32_t concat_types2(enum nft_key_types a, enum nft_key_types b) { return type; } -/* enough space to hold netlink messages for table skeleton */ -#define NFT_INIT_MSGS 16 static int fw_nftables_init_family(sd_netlink *nfnl, int family) { - sd_netlink_message *batch[NFT_INIT_MSGS] = {}; - size_t msgcnt = 0, i, ip_type_size; + sd_netlink_message *messages[12] = {}; + _unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages; + size_t msgcnt = 0, ip_type_size; uint32_t set_id = 0; int ip_type, r; + assert(nfnl); assert(IN_SET(family, AF_INET, AF_INET6)); - r = sd_nfnl_message_batch_begin(nfnl, &batch[msgcnt]); + r = sd_nfnl_message_batch_begin(nfnl, &messages[msgcnt++]); if (r < 0) - goto out_unref; + return r; - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); /* Set F_EXCL so table add fails if the table already exists. */ - r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME); + r = sd_nfnl_nft_message_new_table(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_TABLE_NAME); if (r < 0) - goto out_unref; - - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); + return r; - r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, + r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_TABLE_NAME, "prerouting", "nat", NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST + 1); if (r < 0) - goto out_unref; + return r; - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); - r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, + r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_TABLE_NAME, "output", "nat", NF_INET_LOCAL_OUT, NF_IP_PRI_NAT_DST + 1); if (r < 0) - goto out_unref; + return r; - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); - r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, + r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_TABLE_NAME, "postrouting", "nat", NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC + 1); if (r < 0) - goto out_unref; + return r; if (family == AF_INET) { ip_type_size = sizeof(uint32_t); @@ -691,12 +851,10 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) { ip_type_size = sizeof(struct in6_addr); ip_type = TYPE_IP6ADDR; } - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); /* set to store ip address ranges we should masquerade for */ - r = nft_new_set(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_MASQ_SET_NAME, ++set_id, NFT_SET_INTERVAL, ip_type, ip_type_size); + r = nft_new_set(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_MASQ_SET_NAME, ++set_id, NFT_SET_INTERVAL, ip_type, ip_type_size); if (r < 0) - goto out_unref; + return r; /* * map to store ip address:port pair to dnat to. elements in concatenation @@ -705,54 +863,43 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) { * Example: ip protocol . tcp daddr is sizeof(uint32_t) + sizeof(uint32_t), not * sizeof(uint8_t) + sizeof(uint16_t). */ - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); - r = nft_new_map(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_DNAT_MAP_NAME, ++set_id, 0, + r = nft_new_map(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_DNAT_MAP_NAME, ++set_id, 0, concat_types2(TYPE_INET_PROTOCOL, TYPE_INET_SERVICE), sizeof(uint32_t) * 2, concat_types2(ip_type, TYPE_INET_SERVICE), ip_type_size + sizeof(uint32_t)); if (r < 0) - goto out_unref; + return r; - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); - r = sd_nfnl_message_new_dnat_rule_pre(nfnl, &batch[msgcnt], family, "prerouting"); + r = sd_nfnl_message_new_dnat_rule_pre(nfnl, &messages[msgcnt++], family, "prerouting"); if (r < 0) - goto out_unref; + return r; - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); - r = sd_nfnl_message_new_dnat_rule_out(nfnl, &batch[msgcnt], family, "output"); + r = sd_nfnl_message_new_dnat_rule_out(nfnl, &messages[msgcnt++], family, "output"); if (r < 0) - goto out_unref; + return r; - msgcnt++; - r = sd_nfnl_message_new_masq_rule(nfnl, &batch[msgcnt], family, "postrouting"); + r = sd_nfnl_message_new_masq_rule(nfnl, &messages[msgcnt++], family, "postrouting"); if (r < 0) - goto out_unref; + return r; - msgcnt++; - assert(msgcnt < NFT_INIT_MSGS); - r = sd_nfnl_message_batch_end(nfnl, &batch[msgcnt]); + r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); if (r < 0) - goto out_unref; - - msgcnt++; - assert(msgcnt <= NFT_INIT_MSGS); - r = nfnl_netlink_sendv(nfnl, batch, msgcnt); - if (r == -EEXIST) - r = 0; + return r; -out_unref: - for (i = 0; i < msgcnt; i++) - sd_netlink_message_unref(batch[i]); + assert(msgcnt < ELEMENTSOF(messages)); + r = nfnl_netlink_sendv(nfnl, messages, msgcnt); + if (r < 0 && r != -EEXIST) + return r; - return r; + return 0; } int fw_nftables_init(FirewallContext *ctx) { _cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL; int r; + assert(ctx); + assert(!ctx->nfnl); + r = sd_nfnl_socket_open(&nfnl); if (r < 0) return r; @@ -772,17 +919,24 @@ int fw_nftables_init(FirewallContext *ctx) { } void fw_nftables_exit(FirewallContext *ctx) { + assert(ctx); + ctx->nfnl = sd_netlink_unref(ctx->nfnl); } -static int nft_message_add_setelem_iprange(sd_netlink_message *m, - const union in_addr_union *source, - unsigned int prefixlen) { +static int nft_message_add_setelem_iprange( + sd_netlink_message *m, + const union in_addr_union *source, + unsigned int prefixlen) { + uint32_t mask, start, end; unsigned int nplen; int r; + assert(m); + assert(source); assert(prefixlen <= 32); + nplen = 32 - prefixlen; mask = (1U << nplen) - 1U; @@ -810,11 +964,7 @@ static int nft_message_add_setelem_iprange(sd_netlink_message *m, if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem_end(m); - if (r < 0) - return r; - - return 0; + return sd_nfnl_nft_message_add_setelem_end(m); } static int nft_message_add_setelem_ip6range( @@ -825,6 +975,9 @@ static int nft_message_add_setelem_ip6range( union in_addr_union start, end; int r; + assert(m); + assert(source); + r = in_addr_prefix_range(AF_INET6, source, prefixlen, &start, &end); if (r < 0) return r; @@ -848,56 +1001,55 @@ static int nft_message_add_setelem_ip6range( return sd_nfnl_nft_message_add_setelem_end(m); } -#define NFT_MASQ_MSGS 3 - static int fw_nftables_add_masquerade_internal( - FirewallContext *ctx, + sd_netlink *nfnl, bool add, int af, const union in_addr_union *source, unsigned int source_prefixlen) { - sd_netlink_message *transaction[NFT_MASQ_MSGS] = {}; - size_t tsize; + sd_netlink_message *messages[4] = {}; + _unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages; + size_t msgcnt = 0; int r; + assert(nfnl); + assert(IN_SET(af, AF_INET, AF_INET6)); + if (!source || source_prefixlen == 0) return -EINVAL; if (af == AF_INET6 && source_prefixlen < 8) return -EINVAL; - r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]); + r = sd_nfnl_message_batch_begin(nfnl, &messages[msgcnt++]); if (r < 0) return r; - tsize = 1; + if (add) - r = sd_nfnl_nft_message_new_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); + r = sd_nfnl_nft_message_new_setelems_begin(nfnl, &messages[msgcnt++], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); else - r = sd_nfnl_nft_message_del_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); + r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &messages[msgcnt++], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); if (r < 0) - goto out_unref; + return r; if (af == AF_INET) - r = nft_message_add_setelem_iprange(transaction[tsize], source, source_prefixlen); + r = nft_message_add_setelem_iprange(messages[msgcnt-1], source, source_prefixlen); else - r = nft_message_add_setelem_ip6range(transaction[tsize], source, source_prefixlen); + r = nft_message_add_setelem_ip6range(messages[msgcnt-1], source, source_prefixlen); if (r < 0) - goto out_unref; + return r; - ++tsize; - assert(tsize < NFT_MASQ_MSGS); - r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]); + r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); if (r < 0) return r; - ++tsize; - r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize); + assert(msgcnt < ELEMENTSOF(messages)); + r = nfnl_netlink_sendv(nfnl, messages, msgcnt); + if (r < 0) + return r; -out_unref: - while (tsize > 0) - sd_netlink_message_unref(transaction[--tsize]); - return r < 0 ? r : 0; + return 0; } int fw_nftables_add_masquerade( @@ -909,10 +1061,14 @@ int fw_nftables_add_masquerade( int r; + assert(ctx); + assert(ctx->nfnl); + assert(IN_SET(af, AF_INET, AF_INET6)); + if (!socket_ipv6_is_supported() && af == AF_INET6) return -EOPNOTSUPP; - r = fw_nftables_add_masquerade_internal(ctx, add, af, source, source_prefixlen); + r = fw_nftables_add_masquerade_internal(ctx->nfnl, add, af, source, source_prefixlen); if (r != -ENOENT) return r; @@ -937,13 +1093,11 @@ int fw_nftables_add_masquerade( if (r < 0) return r; - return fw_nftables_add_masquerade_internal(ctx, add, af, source, source_prefixlen); + return fw_nftables_add_masquerade_internal(ctx->nfnl, add, af, source, source_prefixlen); } -#define NFT_DNAT_MSGS 4 - static int fw_nftables_add_local_dnat_internal( - FirewallContext *ctx, + sd_netlink *nfnl, bool add, int af, int protocol, @@ -952,13 +1106,16 @@ static int fw_nftables_add_local_dnat_internal( uint16_t remote_port, const union in_addr_union *previous_remote) { - sd_netlink_message *transaction[NFT_DNAT_MSGS] = {}; + sd_netlink_message *messages[5] = {}; + _unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages; static bool ipv6_supported = true; uint32_t data[5], key[2], dlen; - size_t tsize; + size_t msgcnt = 0; int r; + assert(nfnl); assert(add || !previous_remote); + assert(IN_SET(af, AF_INET, AF_INET6)); if (!ipv6_supported && af == AF_INET6) return -EOPNOTSUPP; @@ -987,11 +1144,10 @@ static int fw_nftables_add_local_dnat_internal( data[4] = htobe16(remote_port); } - r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]); + r = sd_nfnl_message_batch_begin(nfnl, &messages[msgcnt++]); if (r < 0) return r; - tsize = 1; /* If a previous remote is set, remove its entry */ if (add && previous_remote && !in_addr_equal(af, previous_remote, remote)) { if (af == AF_INET) @@ -999,11 +1155,9 @@ static int fw_nftables_add_local_dnat_internal( else memcpy(data, &previous_remote->in6, sizeof(previous_remote->in6)); - r = nft_del_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); + r = nft_del_element(nfnl, &messages[msgcnt++], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); if (r < 0) - goto out_unref; - - tsize++; + return r; } if (af == AF_INET) @@ -1011,39 +1165,31 @@ static int fw_nftables_add_local_dnat_internal( else memcpy(data, &remote->in6, sizeof(remote->in6)); - assert(tsize < NFT_DNAT_MSGS); if (add) - r = nft_add_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); + r = nft_add_element(nfnl, &messages[msgcnt++], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); else - r = nft_del_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); + r = nft_del_element(nfnl, &messages[msgcnt++], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); if (r < 0) - goto out_unref; - - tsize++; - assert(tsize < NFT_DNAT_MSGS); + return r; - r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]); + r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); if (r < 0) - goto out_unref; - - tsize++; - assert(tsize <= NFT_DNAT_MSGS); + return r; - r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize); + assert(msgcnt < ELEMENTSOF(messages)); + r = nfnl_netlink_sendv(nfnl, messages, msgcnt); if (r == -EOVERFLOW && af == AF_INET6) { /* The current implementation of DNAT in systemd requires kernel's * fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns * -EOVERFLOW. Let's treat the error as -EOPNOTSUPP. */ log_debug_errno(r, "The current implementation of IPv6 DNAT in systemd requires kernel 5.8 or newer, ignoring: %m"); ipv6_supported = false; - r = -EOPNOTSUPP; + return -EOPNOTSUPP; } + if (r < 0) + return r; -out_unref: - while (tsize > 0) - sd_netlink_message_unref(transaction[--tsize]); - - return r < 0 ? r : 0; + return 0; } int fw_nftables_add_local_dnat( @@ -1058,10 +1204,14 @@ int fw_nftables_add_local_dnat( int r; + assert(ctx); + assert(ctx->nfnl); + assert(IN_SET(af, AF_INET, AF_INET6)); + if (!socket_ipv6_is_supported() && af == AF_INET6) return -EOPNOTSUPP; - r = fw_nftables_add_local_dnat_internal(ctx, add, af, protocol, local_port, remote, remote_port, previous_remote); + r = fw_nftables_add_local_dnat_internal(ctx->nfnl, add, af, protocol, local_port, remote, remote_port, previous_remote); if (r != -ENOENT) return r; @@ -1071,5 +1221,5 @@ int fw_nftables_add_local_dnat( return r; /* table created anew; previous address already gone */ - return fw_nftables_add_local_dnat_internal(ctx, add, af, protocol, local_port, remote, remote_port, NULL); + return fw_nftables_add_local_dnat_internal(ctx->nfnl, add, af, protocol, local_port, remote, remote_port, NULL); } |