From 13c026ca83ea857cb74a9fb5250cd7ae15956280 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Jun 2022 16:36:17 +0900 Subject: [PATCH 01/11] sd-netlink: move rtnl_message_type_is_*() to netlink-message-rtnl.c --- .../sd-netlink/netlink-message-rtnl.c | 40 +++++++++++++++++++ src/libsystemd/sd-netlink/netlink-util.h | 40 ------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-message-rtnl.c b/src/libsystemd/sd-netlink/netlink-message-rtnl.c index 289eb41ca9..0ff25f8e6c 100644 --- a/src/libsystemd/sd-netlink/netlink-message-rtnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-rtnl.c @@ -17,6 +17,46 @@ #include "socket-util.h" #include "util.h" +static bool rtnl_message_type_is_neigh(uint16_t type) { + return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH); +} + +static bool rtnl_message_type_is_route(uint16_t type) { + return IN_SET(type, RTM_NEWROUTE, RTM_GETROUTE, RTM_DELROUTE); +} + +static bool rtnl_message_type_is_nexthop(uint16_t type) { + return IN_SET(type, RTM_NEWNEXTHOP, RTM_GETNEXTHOP, RTM_DELNEXTHOP); +} + +static bool rtnl_message_type_is_link(uint16_t type) { + return IN_SET(type, + RTM_NEWLINK, RTM_SETLINK, RTM_GETLINK, RTM_DELLINK, + RTM_NEWLINKPROP, RTM_DELLINKPROP, RTM_GETLINKPROP); +} + +static bool rtnl_message_type_is_addr(uint16_t type) { + return IN_SET(type, RTM_NEWADDR, RTM_GETADDR, RTM_DELADDR); +} + +static bool rtnl_message_type_is_addrlabel(uint16_t type) { + return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL); +} + +static bool rtnl_message_type_is_routing_policy_rule(uint16_t type) { + return IN_SET(type, RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE); +} + +static bool rtnl_message_type_is_traffic_control(uint16_t type) { + return IN_SET(type, + RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC, + RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS); +} + +static bool rtnl_message_type_is_mdb(uint16_t type) { + return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB); +} + _public_ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) { struct rtmsg *rtm; diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 606d14eeaf..9473e15700 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -29,46 +29,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free); int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret); -static inline bool rtnl_message_type_is_neigh(uint16_t type) { - return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH); -} - -static inline bool rtnl_message_type_is_route(uint16_t type) { - return IN_SET(type, RTM_NEWROUTE, RTM_GETROUTE, RTM_DELROUTE); -} - -static inline bool rtnl_message_type_is_nexthop(uint16_t type) { - return IN_SET(type, RTM_NEWNEXTHOP, RTM_GETNEXTHOP, RTM_DELNEXTHOP); -} - -static inline bool rtnl_message_type_is_link(uint16_t type) { - return IN_SET(type, - RTM_NEWLINK, RTM_SETLINK, RTM_GETLINK, RTM_DELLINK, - RTM_NEWLINKPROP, RTM_DELLINKPROP, RTM_GETLINKPROP); -} - -static inline bool rtnl_message_type_is_addr(uint16_t type) { - return IN_SET(type, RTM_NEWADDR, RTM_GETADDR, RTM_DELADDR); -} - -static inline bool rtnl_message_type_is_addrlabel(uint16_t type) { - return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL); -} - -static inline bool rtnl_message_type_is_routing_policy_rule(uint16_t type) { - return IN_SET(type, RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE); -} - -static inline bool rtnl_message_type_is_traffic_control(uint16_t type) { - return IN_SET(type, - RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC, - RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS); -} - -static inline bool rtnl_message_type_is_mdb(uint16_t type) { - return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB); -} - int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name); int rtnl_set_link_properties( sd_netlink **rtnl, From 8547260579397c6b7912133e2c06931d5f2451e3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Jun 2022 16:36:45 +0900 Subject: [PATCH 02/11] tree-wide: drop unnecessary inclusion of netlink-util.h --- src/libsystemd-network/test-acd.c | 1 - src/libsystemd-network/test-ipv4ll-manual.c | 1 - src/libsystemd/sd-netlink/netlink-socket.c | 1 - src/libsystemd/sd-netlink/test-netlink.c | 1 - 4 files changed, 4 deletions(-) diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c index e369f5a592..73105f5a04 100644 --- a/src/libsystemd-network/test-acd.c +++ b/src/libsystemd-network/test-acd.c @@ -12,7 +12,6 @@ #include "sd-netlink.h" #include "in-addr-util.h" -#include "netlink-util.h" #include "tests.h" #include "util.h" diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c index d5ef3535ea..5453ef93a4 100644 --- a/src/libsystemd-network/test-ipv4ll-manual.c +++ b/src/libsystemd-network/test-ipv4ll-manual.c @@ -12,7 +12,6 @@ #include "alloc-util.h" #include "in-addr-util.h" -#include "netlink-util.h" #include "parse-util.h" #include "string-util.h" #include "tests.h" diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 70f5b85a54..e834f31122 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -13,7 +13,6 @@ #include "io-util.h" #include "netlink-internal.h" #include "netlink-types.h" -#include "netlink-util.h" #include "socket-util.h" #include "util.h" diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index fbc3ef0609..1117814332 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -16,7 +16,6 @@ #include "macro.h" #include "netlink-genl.h" #include "netlink-internal.h" -#include "netlink-util.h" #include "socket-util.h" #include "stdio-util.h" #include "string-util.h" From 295942cb4629c620d3a3f01b6dcda7a2a716d672 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Jun 2022 17:50:59 +0900 Subject: [PATCH 03/11] firewall-util-nft: various cleanups - add missing assertions, - align enum elements, - use cleanup attribute, and so on. --- src/shared/firewall-util-nft.c | 520 +++++++++++++++++++++------------ 1 file changed, 335 insertions(+), 185 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; + 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, "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; + return r; - msgcnt++; - assert(msgcnt <= NFT_INIT_MSGS); - r = nfnl_netlink_sendv(nfnl, batch, msgcnt); - if (r == -EEXIST) - r = 0; + assert(msgcnt < ELEMENTSOF(messages)); + r = nfnl_netlink_sendv(nfnl, messages, msgcnt); + if (r < 0 && r != -EEXIST) + return r; -out_unref: - for (i = 0; i < msgcnt; i++) - sd_netlink_message_unref(batch[i]); - - 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); - if (r < 0) - goto out_unref; - - ++tsize; - assert(tsize < NFT_MASQ_MSGS); - r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]); + r = nft_message_add_setelem_ip6range(messages[msgcnt-1], source, source_prefixlen); if (r < 0) return r; - ++tsize; - r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize); + r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); + if (r < 0) + return r; -out_unref: - while (tsize > 0) - sd_netlink_message_unref(transaction[--tsize]); - return r < 0 ? r : 0; + assert(msgcnt < ELEMENTSOF(messages)); + r = nfnl_netlink_sendv(nfnl, messages, msgcnt); + if (r < 0) + return r; + + 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; + return r; - tsize++; - assert(tsize < NFT_DNAT_MSGS); - - 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; + return r; - tsize++; - assert(tsize <= NFT_DNAT_MSGS); - - 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); } From 35cca046cf65be01db33c4a17076491c1c7682a3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jun 2022 12:53:32 +0900 Subject: [PATCH 04/11] firewall-util: drop unnecessary string attribute As `sd_netlink_message_open_container_union()` also appends the string attribute. --- src/shared/firewall-util-nft.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index e04304838d..0a8fc08f99 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -84,10 +84,6 @@ static int nfnl_add_open_expr_container(sd_netlink_message *m, const char *name) if (r < 0) return r; - r = sd_netlink_message_append_string(m, NFTA_EXPR_NAME, name); - if (r < 0) - return r; - return sd_netlink_message_open_container_union(m, NFTA_EXPR_DATA, name); } From 64f090a61ab0886e70384c9c486ea9162b58c1a5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Jun 2022 22:22:54 +0900 Subject: [PATCH 05/11] sd-netlink: several cleanups for netfilter - rename family -> nfproto, and other arguments, - check specified nfproto, - change type of several function arguments that specify data length, - add several assertions, - drop unnecessary headers. --- src/libsystemd/sd-netlink/netlink-internal.h | 20 +++--- .../sd-netlink/netlink-message-nfnl.c | 71 +++++++++++-------- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 497ffe9112..c0d7fa8336 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -179,23 +179,23 @@ int sd_nfnl_socket_open(sd_netlink **ret); int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table); + int nfproto, const char *table); int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table); + int nfproto, const char *table); int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *chain, + int nfproto, const char *table, const char *chain, const char *type, uint8_t hook, int prio); int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *chain); + int nfproto, const char *table, const char *chain); int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *set_name, + int nfproto, const char *table, const char *set_name, uint32_t setid, uint32_t klen); int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *set_name); + int nfproto, const char *table, const char *set_name); int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, - int family, const char *table, const char *set_name); + int nfproto, const char *table, const char *set_name); int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, - uint32_t num, - const void *key, uint32_t klen, - const void *data, uint32_t dlen); + uint32_t index, + const void *key, size_t key_len, + const void *data, size_t data_len); int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m); diff --git a/src/libsystemd/sd-netlink/netlink-message-nfnl.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index 6f32167772..e70cf52631 100644 --- a/src/libsystemd/sd-netlink/netlink-message-nfnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -1,26 +1,35 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include #include #include -#include -#include -#include +#include #include "sd-netlink.h" -#include "format-util.h" #include "netlink-internal.h" #include "netlink-types.h" -#include "socket-util.h" -static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t msg_type, uint16_t flags) { +static bool nfproto_is_valid(int nfproto) { + return IN_SET(nfproto, + NFPROTO_UNSPEC, + NFPROTO_INET, + NFPROTO_IPV4, + NFPROTO_ARP, + NFPROTO_NETDEV, + NFPROTO_BRIDGE, + NFPROTO_IPV6, + NFPROTO_DECNET); +} + +static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, uint16_t msg_type, uint16_t flags) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert_return(nfnl, -EINVAL); assert_return(ret, -EINVAL); + assert_return(nfproto_is_valid(nfproto), -EINVAL); + assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL); r = message_new(nfnl, &m, NFNL_SUBSYS_NFTABLES << 8 | msg_type); if (r < 0) @@ -29,7 +38,7 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int famil m->hdr->nlmsg_flags |= flags; *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { - .nfgen_family = family, + .nfgen_family = nfproto, .version = NFNETLINK_V0, .res_id = nfnl->serial, }; @@ -42,12 +51,16 @@ static int nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, uint16 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; + assert_return(nfnl, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL); + r = message_new(nfnl, &m, NFNL_SUBSYS_NONE << 8 | msg_type); if (r < 0) return r; *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { - .nfgen_family = AF_UNSPEC, + .nfgen_family = NFPROTO_UNSPEC, .version = NFNETLINK_V0, .res_id = NFNL_SUBSYS_NFTABLES, }; @@ -67,7 +80,7 @@ int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) { int sd_nfnl_nft_message_new_basechain( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table, const char *chain, const char *type, @@ -77,7 +90,7 @@ int sd_nfnl_nft_message_new_basechain( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWCHAIN, NLM_F_CREATE); if (r < 0) return r; @@ -116,13 +129,13 @@ int sd_nfnl_nft_message_new_basechain( int sd_nfnl_nft_message_del_table( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_DELTABLE, NLM_F_CREATE); if (r < 0) return r; @@ -137,13 +150,13 @@ int sd_nfnl_nft_message_del_table( int sd_nfnl_nft_message_new_table( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL); if (r < 0) return r; @@ -158,14 +171,14 @@ int sd_nfnl_nft_message_new_table( int sd_nfnl_nft_message_new_rule( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table, const char *chain) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWRULE, NLM_F_CREATE); if (r < 0) return r; @@ -184,7 +197,7 @@ int sd_nfnl_nft_message_new_rule( int sd_nfnl_nft_message_new_set( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table, const char *set_name, uint32_t set_id, @@ -193,7 +206,7 @@ int sd_nfnl_nft_message_new_set( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWSET, NLM_F_CREATE); if (r < 0) return r; @@ -220,14 +233,14 @@ int sd_nfnl_nft_message_new_set( int sd_nfnl_nft_message_new_setelems_begin( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table, const char *set_name) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWSETELEM, NLM_F_CREATE); if (r < 0) return r; @@ -250,14 +263,14 @@ int sd_nfnl_nft_message_new_setelems_begin( int sd_nfnl_nft_message_del_setelems_begin( sd_netlink *nfnl, sd_netlink_message **ret, - int family, + int nfproto, const char *table, const char *set_name) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, 0); + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_DELSETELEM, 0); if (r < 0) return r; @@ -293,24 +306,24 @@ static int add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint int sd_nfnl_nft_message_add_setelem( sd_netlink_message *m, - uint32_t num, + uint32_t index, const void *key, - uint32_t klen, + size_t key_len, const void *data, - uint32_t dlen) { + size_t data_len) { int r; - r = sd_netlink_message_open_array(m, num); + r = sd_netlink_message_open_array(m, index); if (r < 0) return r; - r = add_data(m, NFTA_SET_ELEM_KEY, key, klen); + r = add_data(m, NFTA_SET_ELEM_KEY, key, key_len); if (r < 0) goto cancel; if (data) { - r = add_data(m, NFTA_SET_ELEM_DATA, data, dlen); + r = add_data(m, NFTA_SET_ELEM_DATA, data, data_len); if (r < 0) goto cancel; } From 2c08455eedbedbd62fc712e239f76f34e7ac0de1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jun 2022 13:55:20 +0900 Subject: [PATCH 06/11] sd-netlink: introduce sd_netlink_message_append_container_data() --- src/libsystemd/libsystemd.sym | 1 + .../sd-netlink/netlink-message-nfnl.c | 18 ++---------- src/libsystemd/sd-netlink/netlink-message.c | 23 +++++++++++++++ src/shared/firewall-util-nft.c | 28 ++----------------- src/systemd/sd-netlink.h | 6 ++++ 5 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 24dfee7095..fb6e6f6431 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -818,6 +818,7 @@ global: sd_netlink_message_append_s32; sd_netlink_message_append_s64; sd_netlink_message_append_data; + sd_netlink_message_append_container_data; sd_netlink_message_append_in_addr; sd_netlink_message_append_in6_addr; sd_netlink_message_append_sockaddr_in; diff --git a/src/libsystemd/sd-netlink/netlink-message-nfnl.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index e70cf52631..ed83a61804 100644 --- a/src/libsystemd/sd-netlink/netlink-message-nfnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -290,20 +290,6 @@ int sd_nfnl_nft_message_del_setelems_begin( return r; } -static int add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) { - int r; - - 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; - - return sd_netlink_message_close_container(m); /* attr */ -} - int sd_nfnl_nft_message_add_setelem( sd_netlink_message *m, uint32_t index, @@ -318,12 +304,12 @@ int sd_nfnl_nft_message_add_setelem( if (r < 0) return r; - r = add_data(m, NFTA_SET_ELEM_KEY, key, key_len); + r = sd_netlink_message_append_container_data(m, NFTA_SET_ELEM_KEY, NFTA_DATA_VALUE, key, key_len); if (r < 0) goto cancel; if (data) { - r = add_data(m, NFTA_SET_ELEM_DATA, data, data_len); + r = sd_netlink_message_append_container_data(m, NFTA_SET_ELEM_DATA, NFTA_DATA_VALUE, data, data_len); if (r < 0) goto cancel; } diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 34b4c23bd5..192feac47d 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -452,6 +452,29 @@ _public_ int sd_netlink_message_append_data(sd_netlink_message *m, unsigned shor return 0; } +_public_ int sd_netlink_message_append_container_data( + sd_netlink_message *m, + unsigned short container_type, + unsigned short type, + const void *data, + size_t len) { + + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + r = sd_netlink_message_open_container(m, container_type); + if (r < 0) + return r; + + r = sd_netlink_message_append_data(m, type, data, len); + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); +} + int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) { int r; diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index 0a8fc08f99..66ea8ee0bd 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -254,28 +254,6 @@ static int nfnl_add_expr_lookup_map( 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) { - - 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; - - return sd_netlink_message_close_container(m); /* attr */ -} - static int nfnl_add_expr_cmp( sd_netlink_message *m, enum nft_cmp_ops cmp_op, @@ -300,7 +278,7 @@ static int nfnl_add_expr_cmp( if (r < 0) return r; - r = nfnl_add_expr_data(m, NFTA_CMP_DATA, data, dlen); + r = sd_netlink_message_append_container_data(m, NFTA_CMP_DATA, NFTA_DATA_VALUE, data, dlen); if (r < 0) return r; @@ -341,11 +319,11 @@ static int nfnl_add_expr_bitwise( if (r < 0) return r; - r = nfnl_add_expr_data(m, NFTA_BITWISE_MASK, and, len); + r = sd_netlink_message_append_container_data(m, NFTA_BITWISE_MASK, NFTA_DATA_VALUE, and, len); if (r < 0) return r; - r = nfnl_add_expr_data(m, NFTA_BITWISE_XOR, xor, len); + r = sd_netlink_message_append_container_data(m, NFTA_BITWISE_XOR, NFTA_DATA_VALUE, xor, len); if (r < 0) return r; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index dcdf77c4fe..541eb1110a 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -83,6 +83,12 @@ int sd_netlink_message_append_s16(sd_netlink_message *m, unsigned short type, in int sd_netlink_message_append_s32(sd_netlink_message *m, unsigned short type, int32_t data); int sd_netlink_message_append_s64(sd_netlink_message *m, unsigned short type, int64_t data); int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len); +int sd_netlink_message_append_container_data( + sd_netlink_message *m, + unsigned short container_type, + unsigned short type, + const void *data, + size_t len); int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data); int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data); int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data); From 9d884ac36d60f58fcf981c348b0e9bebd9a4cbf4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jun 2022 12:57:41 +0900 Subject: [PATCH 07/11] sd-netlink: drop unused sd_nfnl_nft_message_del_table() --- src/libsystemd/sd-netlink/netlink-internal.h | 2 -- .../sd-netlink/netlink-message-nfnl.c | 21 ------------------- 2 files changed, 23 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index c0d7fa8336..894f9c12a7 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -178,8 +178,6 @@ int netlink_add_match_internal( int sd_nfnl_socket_open(sd_netlink **ret); int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret); int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret); -int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, - int nfproto, const char *table); int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, const char *table); int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, diff --git a/src/libsystemd/sd-netlink/netlink-message-nfnl.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index ed83a61804..0b370b30f4 100644 --- a/src/libsystemd/sd-netlink/netlink-message-nfnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -126,27 +126,6 @@ int sd_nfnl_nft_message_new_basechain( return 0; } -int sd_nfnl_nft_message_del_table( - sd_netlink *nfnl, - sd_netlink_message **ret, - int nfproto, - const char *table) { - - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - int r; - - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_DELTABLE, NLM_F_CREATE); - if (r < 0) - return r; - - r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table); - if (r < 0) - return r; - - *ret = TAKE_PTR(m); - return r; -} - int sd_nfnl_nft_message_new_table( sd_netlink *nfnl, sd_netlink_message **ret, From df7371708e1023b7c253a83c757ba7ccc4426d5b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jun 2022 13:04:46 +0900 Subject: [PATCH 08/11] sd-netlink: merge sd_nfnl_nft_message_{new,del}_setelems_begin() And this makes the new merged function `sd_nfnl_nft_message_new_setelems()` not open container, as containers should be opened and closed in the same function in general. Otherwise, it is hard to understand which level we are in the nested attribute tree. --- src/libsystemd/sd-netlink/netlink-internal.h | 16 +++-- .../sd-netlink/netlink-message-nfnl.c | 61 ++++++------------- src/shared/firewall-util-nft.c | 58 +++++++++--------- 3 files changed, 52 insertions(+), 83 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 894f9c12a7..22df5c86fd 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -188,12 +188,10 @@ int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, const char *table, const char *set_name, uint32_t setid, uint32_t klen); -int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, - int nfproto, const char *table, const char *set_name); -int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, - int nfproto, const char *table, const char *set_name); -int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, - uint32_t index, - const void *key, size_t key_len, - const void *data, size_t data_len); -int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m); +int sd_nfnl_nft_message_new_setelems(sd_netlink *nfnl, sd_netlink_message **ret, + int add, int nfproto, const char *table, const char *set_name); +int sd_nfnl_nft_message_append_setelem(sd_netlink_message *m, + uint32_t index, + const void *key, size_t key_len, + const void *data, size_t data_len, + uint32_t flags); diff --git a/src/libsystemd/sd-netlink/netlink-message-nfnl.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index 0b370b30f4..28f6c7e330 100644 --- a/src/libsystemd/sd-netlink/netlink-message-nfnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -209,9 +209,10 @@ int sd_nfnl_nft_message_new_set( return r; } -int sd_nfnl_nft_message_new_setelems_begin( +int sd_nfnl_nft_message_new_setelems( sd_netlink *nfnl, sd_netlink_message **ret, + int add, /* boolean */ int nfproto, const char *table, const char *set_name) { @@ -219,7 +220,10 @@ int sd_nfnl_nft_message_new_setelems_begin( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWSETELEM, NLM_F_CREATE); + if (add) + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWSETELEM, NLM_F_CREATE); + else + r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_DELSETELEM, 0); if (r < 0) return r; @@ -231,51 +235,18 @@ int sd_nfnl_nft_message_new_setelems_begin( if (r < 0) return r; - r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); - if (r < 0) - return r; - *ret = TAKE_PTR(m); return r; } -int sd_nfnl_nft_message_del_setelems_begin( - sd_netlink *nfnl, - sd_netlink_message **ret, - int nfproto, - const char *table, - const char *set_name) { - - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - int r; - - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_DELSETELEM, 0); - if (r < 0) - return r; - - r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table); - if (r < 0) - return r; - - r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name); - if (r < 0) - return r; - - r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); - if (r < 0) - return r; - - *ret = TAKE_PTR(m); - return r; -} - -int sd_nfnl_nft_message_add_setelem( +int sd_nfnl_nft_message_append_setelem( sd_netlink_message *m, uint32_t index, const void *key, size_t key_len, const void *data, - size_t data_len) { + size_t data_len, + uint32_t flags) { int r; @@ -293,17 +264,19 @@ int sd_nfnl_nft_message_add_setelem( goto cancel; } - return 0; + if (flags != 0) { + r = sd_netlink_message_append_u32(m, NFTA_SET_ELEM_FLAGS, htobe32(flags)); + if (r < 0) + goto cancel; + } + + return sd_netlink_message_close_container(m); /* array */ cancel: - sd_netlink_message_cancel_array(m); + (void) sd_netlink_message_cancel_array(m); return r; } -int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m) { - return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ -} - int sd_nfnl_socket_open(sd_netlink **ret) { return netlink_open_family(ret, NETLINK_NETFILTER); } diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index 66ea8ee0bd..f0cf50a2ae 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -705,16 +705,21 @@ static int nft_add_element( * This replicated here and each element gets added to the set * one-by-one. */ - r = sd_nfnl_nft_message_new_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name); + r = sd_nfnl_nft_message_new_setelems(nfnl, &m, /* add = */ true, family, NFT_SYSTEMD_TABLE_NAME, set_name); if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem(m, 0, key, klen, data, dlen); + r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_append_setelem(m, 0, key, klen, data, dlen, 0); if (r < 0) return r; /* could theoretically append more set elements to add here */ - r = sd_nfnl_nft_message_add_setelem_end(m); + + r = sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ if (r < 0) return r; @@ -742,15 +747,19 @@ static int nft_del_element( assert(key); assert(data); - r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name); + r = sd_nfnl_nft_message_new_setelems(nfnl, &m, /* add = */ false, family, NFT_SYSTEMD_TABLE_NAME, set_name); if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem(m, 0, key, klen, data, dlen); + r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_append_setelem(m, 0, key, klen, data, dlen, 0); if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem_end(m); + r = sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ if (r < 0) return r; @@ -898,7 +907,7 @@ void fw_nftables_exit(FirewallContext *ctx) { ctx->nfnl = sd_netlink_unref(ctx->nfnl); } -static int nft_message_add_setelem_iprange( +static int nft_message_append_setelem_iprange( sd_netlink_message *m, const union in_addr_union *source, unsigned int prefixlen) { @@ -917,11 +926,11 @@ static int nft_message_add_setelem_iprange( mask = htobe32(~mask); start = source->in.s_addr & mask; - r = sd_nfnl_nft_message_add_setelem(m, 0, &start, sizeof(start), NULL, 0); + r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem_end(m); + r = sd_nfnl_nft_message_append_setelem(m, 0, &start, sizeof(start), NULL, 0, 0); if (r < 0) return r; @@ -930,18 +939,14 @@ static int nft_message_add_setelem_iprange( end = 0U; end = htobe32(end); - r = sd_nfnl_nft_message_add_setelem(m, 1, &end, sizeof(end), NULL, 0); + r = sd_nfnl_nft_message_append_setelem(m, 1, &end, sizeof(end), NULL, 0, NFT_SET_ELEM_INTERVAL_END); if (r < 0) return r; - r = sd_netlink_message_append_u32(m, NFTA_SET_ELEM_FLAGS, htobe32(NFT_SET_ELEM_INTERVAL_END)); - if (r < 0) - return r; - - return sd_nfnl_nft_message_add_setelem_end(m); + return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ } -static int nft_message_add_setelem_ip6range( +static int nft_message_append_setelem_ip6range( sd_netlink_message *m, const union in_addr_union *source, unsigned int prefixlen) { @@ -956,23 +961,19 @@ static int nft_message_add_setelem_ip6range( if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem(m, 0, &start.in6, sizeof(start.in6), NULL, 0); + r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem_end(m); + r = sd_nfnl_nft_message_append_setelem(m, 0, &start.in6, sizeof(start.in6), NULL, 0, 0); if (r < 0) return r; - r = sd_nfnl_nft_message_add_setelem(m, 1, &end.in6, sizeof(end.in6), NULL, 0); + r = sd_nfnl_nft_message_append_setelem(m, 1, &end.in6, sizeof(end.in6), NULL, 0, NFT_SET_ELEM_INTERVAL_END); if (r < 0) return r; - r = sd_netlink_message_append_u32(m, NFTA_SET_ELEM_FLAGS, htobe32(NFT_SET_ELEM_INTERVAL_END)); - if (r < 0) - return r; - - return sd_nfnl_nft_message_add_setelem_end(m); + return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ } static int fw_nftables_add_masquerade_internal( @@ -1000,17 +1001,14 @@ static int fw_nftables_add_masquerade_internal( if (r < 0) return r; - if (add) - 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(nfnl, &messages[msgcnt++], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); + r = sd_nfnl_nft_message_new_setelems(nfnl, &messages[msgcnt++], add, af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); if (r < 0) return r; if (af == AF_INET) - r = nft_message_add_setelem_iprange(messages[msgcnt-1], source, source_prefixlen); + r = nft_message_append_setelem_iprange(messages[msgcnt-1], source, source_prefixlen); else - r = nft_message_add_setelem_ip6range(messages[msgcnt-1], source, source_prefixlen); + r = nft_message_append_setelem_ip6range(messages[msgcnt-1], source, source_prefixlen); if (r < 0) return r; From 665bc9e6e287271ecab140fbb1a8b0328ffff2f0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Jun 2022 13:45:37 +0900 Subject: [PATCH 09/11] firewall-util: introduce nfnl_close_expr_container() helper function And merge nfnl_add_expr_lookup_set() and nfnl_add_expr_lookup_map(). --- src/shared/firewall-util-nft.c | 128 +++++++++++---------------------- 1 file changed, 40 insertions(+), 88 deletions(-) diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index f0cf50a2ae..b4ef166499 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -74,7 +74,7 @@ static int nfnl_netlink_sendv( return r; } -static int nfnl_add_open_expr_container(sd_netlink_message *m, const char *name) { +static int nfnl_open_expr_container(sd_netlink_message *m, const char *name) { int r; assert(m); @@ -87,6 +87,18 @@ 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_close_expr_container(sd_netlink_message *m) { + int r; + + assert(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_fib( sd_netlink_message *m, uint32_t nft_fib_flags, @@ -97,7 +109,7 @@ static int nfnl_add_expr_fib( assert(m); - r = nfnl_add_open_expr_container(m, "fib"); + r = nfnl_open_expr_container(m, "fib"); if (r < 0) return r; @@ -113,11 +125,7 @@ static int nfnl_add_expr_fib( 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 */ + return nfnl_close_expr_container(m); } static int nfnl_add_expr_meta( @@ -129,7 +137,7 @@ static int nfnl_add_expr_meta( assert(m); - r = nfnl_add_open_expr_container(m, "meta"); + r = nfnl_open_expr_container(m, "meta"); if (r < 0) return r; @@ -141,11 +149,7 @@ static int nfnl_add_expr_meta( 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 */ + return nfnl_close_expr_container(m); } static int nfnl_add_expr_payload( @@ -159,7 +163,7 @@ static int nfnl_add_expr_payload( assert(m); - r = nfnl_add_open_expr_container(m, "payload"); + r = nfnl_open_expr_container(m, "payload"); if (r < 0) return r; @@ -179,56 +183,10 @@ static int nfnl_add_expr_payload( 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 */ + return nfnl_close_expr_container(m); } -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; - - r = sd_netlink_message_append_string(m, NFTA_LOOKUP_SET, set_name); - if (r < 0) - return r; - - 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) { - - int r; - - assert(m); - assert(set_name); - - r = nfnl_add_expr_lookup_set_data(m, set_name, sreg); - 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_lookup_map( +static int nfnl_add_expr_lookup( sd_netlink_message *m, const char *set_name, enum nft_registers sreg, @@ -239,19 +197,25 @@ static int nfnl_add_expr_lookup_map( assert(m); assert(set_name); - r = nfnl_add_expr_lookup_set_data(m, set_name, sreg); + r = nfnl_open_expr_container(m, "lookup"); if (r < 0) return r; - r = sd_netlink_message_append_u32(m, NFTA_LOOKUP_DREG, htobe32(dreg)); + r = sd_netlink_message_append_string(m, NFTA_LOOKUP_SET, set_name); if (r < 0) return r; - r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + r = sd_netlink_message_append_u32(m, NFTA_LOOKUP_SREG, htobe32(sreg)); if (r < 0) return r; - return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ + if (dreg != 0) { + r = sd_netlink_message_append_u32(m, NFTA_LOOKUP_DREG, htobe32(dreg)); + if (r < 0) + return r; + } + + return nfnl_close_expr_container(m); } static int nfnl_add_expr_cmp( @@ -259,14 +223,14 @@ static int nfnl_add_expr_cmp( enum nft_cmp_ops cmp_op, enum nft_registers sreg, const void *data, - uint32_t dlen) { + size_t dlen) { int r; assert(m); assert(data); - r = nfnl_add_open_expr_container(m, "cmp"); + r = nfnl_open_expr_container(m, "cmp"); if (r < 0) return r; @@ -282,11 +246,7 @@ static int nfnl_add_expr_cmp( 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 */ + return nfnl_close_expr_container(m); } static int nfnl_add_expr_bitwise( @@ -303,7 +263,7 @@ static int nfnl_add_expr_bitwise( assert(and); assert(xor); - r = nfnl_add_open_expr_container(m, "bitwise"); + r = nfnl_open_expr_container(m, "bitwise"); if (r < 0) return r; @@ -327,11 +287,7 @@ static int nfnl_add_expr_bitwise( 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 */ + return nfnl_close_expr_container(m); } static int nfnl_add_expr_dnat( @@ -344,7 +300,7 @@ static int nfnl_add_expr_dnat( assert(m); - r = nfnl_add_open_expr_container(m, "nat"); + r = nfnl_open_expr_container(m, "nat"); if (r < 0) return r; @@ -364,11 +320,7 @@ static int nfnl_add_expr_dnat( if (r < 0) return r; - r = sd_netlink_message_close_container(m); - if (r < 0) - return r; - - return sd_netlink_message_close_container(m); + return nfnl_close_expr_container(m); } static int nfnl_add_expr_masq(sd_netlink_message *m) { @@ -420,7 +372,7 @@ static int sd_nfnl_message_new_masq_rule( return r; /* 1st statement: use reg1 content to make lookup in @masq_saddr set. */ - r = nfnl_add_expr_lookup_set(m, NFT_SYSTEMD_MASQ_SET_NAME, NFT_REG32_01); + r = nfnl_add_expr_lookup(m, NFT_SYSTEMD_MASQ_SET_NAME, NFT_REG32_01, 0); if (r < 0) return r; @@ -486,7 +438,7 @@ static int sd_nfnl_message_new_dnat_rule_pre( /* 3rd statement: lookup 'l4proto . dport', e.g. 'tcp . 22' as key and * 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); + r = nfnl_add_expr_lookup(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); if (r < 0) return r; @@ -581,7 +533,7 @@ static int sd_nfnl_message_new_dnat_rule_out( * * reg1 and reg2 are clobbered and will then contain the new * address/port number. */ - r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); + r = nfnl_add_expr_lookup(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); if (r < 0) return r; From 04d200371885cf5b64411ba40aeb18e8940626ff Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 25 Jun 2022 15:38:06 +0900 Subject: [PATCH 10/11] sd-netlink: do not compare pointer with 0 --- src/libsystemd/sd-netlink/netlink-message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 192feac47d..f76827d42c 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -148,7 +148,7 @@ _public_ sd_netlink_message* sd_netlink_message_unref(sd_netlink_message *m) { _public_ int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) { assert_return(m, -EINVAL); - assert_return(type != 0, -EINVAL); + assert_return(type, -EINVAL); *type = m->hdr->nlmsg_type; From 573bb24df716f18b7deb95844b5a2d57c5f97971 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 26 Jun 2022 03:52:59 +0900 Subject: [PATCH 11/11] sd-netlink: introduce sd_nfnl_{send,call}_batch() This also introduces sd_nfnl_message_new() which can be also used for non-nftables subsystems. --- src/libsystemd/sd-netlink/netlink-internal.h | 20 +- .../sd-netlink/netlink-message-nfnl.c | 178 ++++++++++++++++-- src/shared/firewall-util-nft.c | 78 +------- 3 files changed, 185 insertions(+), 91 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 22df5c86fd..e3bb80e496 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -176,8 +176,24 @@ int netlink_add_match_internal( /* nfnl */ /* TODO: to be exported later */ int sd_nfnl_socket_open(sd_netlink **ret); -int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret); -int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret); +int sd_nfnl_send_batch( + sd_netlink *nfnl, + sd_netlink_message **messages, + size_t msgcount, + uint32_t **ret_serials); +int sd_nfnl_call_batch( + sd_netlink *nfnl, + sd_netlink_message **messages, + size_t n_messages, + uint64_t usec, + sd_netlink_message ***ret_messages); +int sd_nfnl_message_new( + sd_netlink *nfnl, + sd_netlink_message **ret, + int nfproto, + uint16_t subsys, + uint16_t msg_type, + uint16_t flags); int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, const char *table); int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, diff --git a/src/libsystemd/sd-netlink/netlink-message-nfnl.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index 28f6c7e330..582f623efe 100644 --- a/src/libsystemd/sd-netlink/netlink-message-nfnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -7,8 +7,10 @@ #include "sd-netlink.h" +#include "io-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" static bool nfproto_is_valid(int nfproto) { return IN_SET(nfproto, @@ -22,7 +24,7 @@ static bool nfproto_is_valid(int nfproto) { NFPROTO_DECNET); } -static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, uint16_t msg_type, uint16_t flags) { +int sd_nfnl_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, uint16_t subsys, uint16_t msg_type, uint16_t flags) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -31,7 +33,7 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfpro assert_return(nfproto_is_valid(nfproto), -EINVAL); assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL); - r = message_new(nfnl, &m, NFNL_SUBSYS_NFTABLES << 8 | msg_type); + r = message_new(nfnl, &m, subsys << 8 | msg_type); if (r < 0) return r; @@ -40,14 +42,40 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfpro *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { .nfgen_family = nfproto, .version = NFNETLINK_V0, - .res_id = nfnl->serial, }; *ret = TAKE_PTR(m); return 0; } -static int nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, uint16_t msg_type) { +static int nfnl_message_set_res_id(sd_netlink_message *m, uint16_t res_id) { + struct nfgenmsg *nfgen; + + assert(m); + assert(m->hdr); + + nfgen = NLMSG_DATA(m->hdr); + nfgen->res_id = htobe16(res_id); + + return 0; +} + +static int nfnl_message_get_subsys(sd_netlink_message *m, uint16_t *ret) { + uint16_t t; + int r; + + assert(m); + assert(ret); + + r = sd_netlink_message_get_type(m, &t); + if (r < 0) + return r; + + *ret = NFNL_SUBSYS_ID(t); + return 0; +} + +static int nfnl_message_new_batch(sd_netlink *nfnl, sd_netlink_message **ret, uint16_t subsys, uint16_t msg_type) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -55,26 +83,136 @@ static int nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, uint16 assert_return(ret, -EINVAL); assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL); - r = message_new(nfnl, &m, NFNL_SUBSYS_NONE << 8 | msg_type); + r = sd_nfnl_message_new(nfnl, &m, NFPROTO_UNSPEC, NFNL_SUBSYS_NONE, msg_type, 0); if (r < 0) return r; - *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { - .nfgen_family = NFPROTO_UNSPEC, - .version = NFNETLINK_V0, - .res_id = NFNL_SUBSYS_NFTABLES, - }; + r = nfnl_message_set_res_id(m, subsys); + if (r < 0) + return r; *ret = TAKE_PTR(m); return 0; } -int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) { - return nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN); +int sd_nfnl_send_batch( + sd_netlink *nfnl, + sd_netlink_message **messages, + size_t n_messages, + uint32_t **ret_serials) { + + /* iovs refs batch_begin and batch_end, hence, free iovs first, then free batch_begin and batch_end. */ + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *batch_begin = NULL, *batch_end = NULL; + _cleanup_free_ struct iovec *iovs = NULL; + _cleanup_free_ uint32_t *serials = NULL; + uint16_t subsys; + ssize_t k; + size_t c = 0; + int r; + + assert_return(nfnl, -EINVAL); + assert_return(!netlink_pid_changed(nfnl), -ECHILD); + assert_return(messages, -EINVAL); + assert_return(n_messages > 0, -EINVAL); + + iovs = new(struct iovec, n_messages + 2); + if (!iovs) + return -ENOMEM; + + if (ret_serials) { + serials = new(uint32_t, n_messages); + if (!serials) + return -ENOMEM; + } + + r = nfnl_message_get_subsys(messages[0], &subsys); + if (r < 0) + return r; + + r = nfnl_message_new_batch(nfnl, &batch_begin, subsys, NFNL_MSG_BATCH_BEGIN); + if (r < 0) + return r; + + netlink_seal_message(nfnl, batch_begin); + iovs[c++] = IOVEC_MAKE(batch_begin->hdr, batch_begin->hdr->nlmsg_len); + + for (size_t i = 0; i < n_messages; i++) { + uint16_t s; + + r = nfnl_message_get_subsys(messages[i], &s); + if (r < 0) + return r; + + if (s != subsys) + return -EINVAL; + + netlink_seal_message(nfnl, messages[i]); + if (serials) + serials[i] = message_get_serial(messages[i]); + + /* It seems that the kernel accepts an arbitrary number. Let's set the serial of the + * first message. */ + nfnl_message_set_res_id(messages[i], message_get_serial(batch_begin)); + + iovs[c++] = IOVEC_MAKE(messages[i]->hdr, messages[i]->hdr->nlmsg_len); + } + + r = nfnl_message_new_batch(nfnl, &batch_end, subsys, NFNL_MSG_BATCH_END); + if (r < 0) + return r; + + netlink_seal_message(nfnl, batch_end); + iovs[c++] = IOVEC_MAKE(batch_end->hdr, batch_end->hdr->nlmsg_len); + + assert(c == n_messages + 2); + k = writev(nfnl->fd, iovs, n_messages + 2); + if (k < 0) + return -errno; + + if (ret_serials) + *ret_serials = TAKE_PTR(serials); + + return 0; } -int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) { - return nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END); +int sd_nfnl_call_batch( + sd_netlink *nfnl, + sd_netlink_message **messages, + size_t n_messages, + uint64_t usec, + sd_netlink_message ***ret_messages) { + + _cleanup_free_ sd_netlink_message **replies = NULL; + _cleanup_free_ uint32_t *serials = NULL; + int k, r; + + assert_return(nfnl, -EINVAL); + assert_return(!netlink_pid_changed(nfnl), -ECHILD); + assert_return(messages, -EINVAL); + assert_return(n_messages > 0, -EINVAL); + + if (ret_messages) { + replies = new0(sd_netlink_message*, n_messages); + if (!replies) + return -ENOMEM; + } + + r = sd_nfnl_send_batch(nfnl, messages, n_messages, &serials); + if (r < 0) + return r; + + for (size_t i = 0; i < n_messages; i++) { + k = sd_netlink_read(nfnl, serials[i], usec, ret_messages ? replies + i : NULL); + if (k < 0 && r >= 0) + r = k; + } + if (r < 0) + return r; + + if (ret_messages) + *ret_messages = TAKE_PTR(replies); + + return 0; } int sd_nfnl_nft_message_new_basechain( @@ -90,7 +228,7 @@ int sd_nfnl_nft_message_new_basechain( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWCHAIN, NLM_F_CREATE); + r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWCHAIN, NLM_F_CREATE); if (r < 0) return r; @@ -135,7 +273,7 @@ int sd_nfnl_nft_message_new_table( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL); + r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL); if (r < 0) return r; @@ -157,7 +295,7 @@ int sd_nfnl_nft_message_new_rule( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWRULE, NLM_F_CREATE); + r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWRULE, NLM_F_CREATE); if (r < 0) return r; @@ -185,7 +323,7 @@ int sd_nfnl_nft_message_new_set( _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWSET, NLM_F_CREATE); + r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSET, NLM_F_CREATE); if (r < 0) return r; @@ -221,9 +359,9 @@ int sd_nfnl_nft_message_new_setelems( int r; if (add) - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_NEWSETELEM, NLM_F_CREATE); + r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSETELEM, NLM_F_CREATE); else - r = nft_message_new(nfnl, &m, nfproto, NFT_MSG_DELSETELEM, 0); + r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELSETELEM, 0); if (r < 0) return r; diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c index b4ef166499..b5f0d1bab7 100644 --- a/src/shared/firewall-util-nft.c +++ b/src/shared/firewall-util-nft.c @@ -45,35 +45,6 @@ static sd_netlink_message **netlink_message_unref_many(sd_netlink_message **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], - size_t msgcount) { - - _cleanup_free_ uint32_t *serial = NULL; - int r; - - assert(nfnl); - assert(messages); - assert(msgcount > 0); - - r = sd_netlink_sendv(nfnl, messages, msgcount, &serial); - if (r < 0) - return r; - - r = 0; - for (size_t i = 1; i < msgcount - 1; i++) { - int tmp; - - /* If message is an error, this returns embedded errno */ - tmp = sd_netlink_read(nfnl, serial[i], NFNL_DEFAULT_TIMEOUT_USECS, NULL); - if (tmp < 0 && r == 0) - r = tmp; - } - - return r; -} - static int nfnl_open_expr_container(sd_netlink_message *m, const char *name) { int r; @@ -742,7 +713,7 @@ static uint32_t concat_types2(enum nft_key_types a, enum nft_key_types b) { } static int fw_nftables_init_family(sd_netlink *nfnl, int family) { - sd_netlink_message *messages[12] = {}; + sd_netlink_message *messages[10] = {}; _unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages; size_t msgcnt = 0, ip_type_size; uint32_t set_id = 0; @@ -751,10 +722,6 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) { assert(nfnl); assert(IN_SET(family, AF_INET, AF_INET6)); - r = sd_nfnl_message_batch_begin(nfnl, &messages[msgcnt++]); - if (r < 0) - return r; - /* Set F_EXCL so table add fails if the table already exists. */ r = sd_nfnl_nft_message_new_table(nfnl, &messages[msgcnt++], family, NFT_SYSTEMD_TABLE_NAME); if (r < 0) @@ -816,12 +783,8 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) { if (r < 0) return r; - r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); - if (r < 0) - return r; - assert(msgcnt < ELEMENTSOF(messages)); - r = nfnl_netlink_sendv(nfnl, messages, msgcnt); + r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS, NULL); if (r < 0 && r != -EEXIST) return r; @@ -935,9 +898,7 @@ static int fw_nftables_add_masquerade_internal( const union in_addr_union *source, unsigned int source_prefixlen) { - sd_netlink_message *messages[4] = {}; - _unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages; - size_t msgcnt = 0; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(nfnl); @@ -949,31 +910,18 @@ static int fw_nftables_add_masquerade_internal( if (af == AF_INET6 && source_prefixlen < 8) return -EINVAL; - r = sd_nfnl_message_batch_begin(nfnl, &messages[msgcnt++]); - if (r < 0) - return r; - - r = sd_nfnl_nft_message_new_setelems(nfnl, &messages[msgcnt++], add, af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); + r = sd_nfnl_nft_message_new_setelems(nfnl, &m, add, af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); if (r < 0) return r; if (af == AF_INET) - r = nft_message_append_setelem_iprange(messages[msgcnt-1], source, source_prefixlen); + r = nft_message_append_setelem_iprange(m, source, source_prefixlen); else - r = nft_message_append_setelem_ip6range(messages[msgcnt-1], source, source_prefixlen); + r = nft_message_append_setelem_ip6range(m, source, source_prefixlen); if (r < 0) return r; - r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); - if (r < 0) - return r; - - assert(msgcnt < ELEMENTSOF(messages)); - r = nfnl_netlink_sendv(nfnl, messages, msgcnt); - if (r < 0) - return r; - - return 0; + return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL); } int fw_nftables_add_masquerade( @@ -1030,7 +978,7 @@ static int fw_nftables_add_local_dnat_internal( uint16_t remote_port, const union in_addr_union *previous_remote) { - sd_netlink_message *messages[5] = {}; + sd_netlink_message *messages[3] = {}; _unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages; static bool ipv6_supported = true; uint32_t data[5], key[2], dlen; @@ -1068,10 +1016,6 @@ static int fw_nftables_add_local_dnat_internal( data[4] = htobe16(remote_port); } - r = sd_nfnl_message_batch_begin(nfnl, &messages[msgcnt++]); - if (r < 0) - return r; - /* If a previous remote is set, remove its entry */ if (add && previous_remote && !in_addr_equal(af, previous_remote, remote)) { if (af == AF_INET) @@ -1096,12 +1040,8 @@ static int fw_nftables_add_local_dnat_internal( if (r < 0) return r; - r = sd_nfnl_message_batch_end(nfnl, &messages[msgcnt++]); - if (r < 0) - return r; - assert(msgcnt < ELEMENTSOF(messages)); - r = nfnl_netlink_sendv(nfnl, messages, msgcnt); + r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS, NULL); if (r == -EOVERFLOW && af == AF_INET6) { /* The current implementation of DNAT in systemd requires kernel's * fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns