diff --git a/miniupnpd/netfilter_nft/nftnlrdr.c b/miniupnpd/netfilter_nft/nftnlrdr.c index bb0d21f..7fa8580 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr.c +++ b/miniupnpd/netfilter_nft/nftnlrdr.c @@ -66,11 +66,17 @@ static struct timestamp_entry * timestamp_list = NULL; /* init and shutdown functions */ int -init_redirect(void) { +init_redirect(void) +{ int result; + /* requires elevated privileges */ + result = nft_mnl_connect(); + /* 'inet' family */ - result = table_op(NFT_MSG_NEWTABLE, NFPROTO_INET, nft_table); + if (result == 0) { + result = table_op(NFT_MSG_NEWTABLE, NFPROTO_INET, nft_table); + } if (result == 0) { result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_INET, nft_table, nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER - 25); @@ -140,7 +146,7 @@ shutdown_redirect(void) { result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV6, nft_table); } - finish_batch(); + nft_mnl_disconnect(); } /** diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.c b/miniupnpd/netfilter_nft/nftnlrdr_misc.c index 2da1f69..5beea04 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.c +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.c @@ -68,8 +68,9 @@ const char * nft_prerouting_chain = "prerouting"; const char * nft_postrouting_chain = "postrouting"; const char * nft_forward_chain = "forward"; -static struct mnl_socket *nl = NULL; -static uint32_t nl_seq = 0; +static struct mnl_socket *mnl_sock = NULL; +static uint32_t mnl_portid = 0; +static uint32_t mnl_seq = 0; // FILTER struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter); @@ -82,6 +83,34 @@ static uint32_t rule_list_filter_validate = RULE_CACHE_INVALID; static uint32_t rule_list_redirect_validate = RULE_CACHE_INVALID; static uint32_t rule_list_peer_validate = RULE_CACHE_INVALID; + +int +nft_mnl_connect(void) +{ + int result = 0; + + mnl_sock = mnl_socket_open(NETLINK_NETFILTER); + if (mnl_sock == NULL) { + log_error("mnl_socket_open() FAILED: %m"); + result = errno; + } else { + if (mnl_socket_bind(mnl_sock, 0, MNL_SOCKET_AUTOPID) < 0) { + log_error("mnl_socket_bind() FAILED: %m"); + result = errno; + } else { + mnl_portid = mnl_socket_get_portid(mnl_sock); + } + } + return result; +} + +void +nft_mnl_disconnect(void) +{ + mnl_socket_close(mnl_sock); + mnl_sock = NULL; +} + #ifdef DEBUG static const char * get_family_string(uint32_t family) @@ -706,59 +735,44 @@ refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; - uint32_t portid, seq, type = NFTNL_OUTPUT_DEFAULT; - struct nftnl_rule *t; + uint32_t type = NFTNL_OUTPUT_DEFAULT; + struct nftnl_rule *rule; int ret; flush_nft_cache(head); - if (nl == NULL) { - nl = mnl_socket_open(NETLINK_NETFILTER); - if (nl == NULL) { - log_error("mnl_socket_open() FAILED: %m"); - return; - } - - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - log_error("mnl_socket_bind() FAILED: %m"); - return; - } - } - portid = mnl_socket_get_portid(nl); - - t = nftnl_rule_alloc(); - if (t == NULL) { + rule = nftnl_rule_alloc(); + if (rule == NULL) { log_error("nftnl_rule_alloc() FAILED"); return; } - seq = time(NULL); + mnl_seq = time(NULL); nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, - NLM_F_DUMP, seq); - nftnl_rule_set(t, NFTNL_RULE_TABLE, table); - nftnl_rule_set(t, NFTNL_RULE_CHAIN, chain); - nftnl_rule_nlmsg_build_payload(nlh, t); - nftnl_rule_free(t); + NLM_F_DUMP, mnl_seq); + nftnl_rule_set(rule, NFTNL_RULE_TABLE, table); + nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain); + nftnl_rule_nlmsg_build_payload(nlh, rule); + nftnl_rule_free(rule); - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + if (mnl_socket_sendto(mnl_sock, nlh, nlh->nlmsg_len) < 0) { log_error("mnl_socket_sendto() FAILED: %m"); return; } - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + ret = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf)); while (ret > 0) { - ret = mnl_cb_run(buf, ret, seq, portid, table_cb, &type); - if (ret <= 0) - break; - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + ret = mnl_cb_run(buf, ret, mnl_seq, mnl_portid, table_cb, &type); + if (ret > 0) + { + ret = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf)); + } } if (ret == -1) { log_error("mnl_socket_recvfrom() FAILED: %m"); } - /* mnl_socket_close(nl); */ - return; } @@ -1287,7 +1301,7 @@ nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain cmd, nftnl_rule_get_u32(rule, NFTNL_RULE_FAMILY), NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, - nl_seq++); + mnl_seq++); nftnl_rule_nlmsg_build_payload(nlh, rule); nftnl_rule_free(rule); @@ -1326,7 +1340,7 @@ table_op( enum nf_tables_msg_types op, uint16_t family, const char * name) nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), op, family, (op == NFT_MSG_NEWTABLE ? NLM_F_CREATE : 0) | NLM_F_ACK, - nl_seq++); + mnl_seq++); nftnl_table_nlmsg_build_payload(nlh, table); result = send_batch(batch); @@ -1371,7 +1385,7 @@ chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table, nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), op, family, (op == NFT_MSG_NEWCHAIN ? NLM_F_CREATE : 0) | NLM_F_ACK, - nl_seq++); + mnl_seq++); if (nlh == NULL) { log_error("failed to build header: %m"); @@ -1391,77 +1405,61 @@ chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table, struct mnl_nlmsg_batch * start_batch( char *buf, size_t buf_size) { - struct mnl_nlmsg_batch *batch; - nl_seq = time(NULL); + struct mnl_nlmsg_batch *result; + mnl_seq = time(NULL); - if (nl == NULL) { - nl = mnl_socket_open(NETLINK_NETFILTER); - if (nl == NULL) { - log_error("mnl_socket_open() FAILED: %m"); - return NULL; - } - - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - log_error("mnl_socket_bind() FAILED: %m"); - return NULL; - } + if (mnl_sock == NULL) { + log_error("netlink not connected"); + result = NULL; + } else { + result = mnl_nlmsg_batch_start(buf, buf_size); + if (result != NULL) { + nft_mnl_batch_put(mnl_nlmsg_batch_current(result), + NFNL_MSG_BATCH_BEGIN, mnl_seq++); + mnl_nlmsg_batch_next(result); + } } - batch = mnl_nlmsg_batch_start(buf, buf_size); - if (batch != NULL) { - nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), - NFNL_MSG_BATCH_BEGIN, nl_seq++); - mnl_nlmsg_batch_next(batch); - } - return batch; + return result; } int -send_batch(struct mnl_nlmsg_batch * batch) +send_batch(struct mnl_nlmsg_batch *batch) { - int ret; - char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + char buf[MNL_SOCKET_BUFFER_SIZE]; - mnl_nlmsg_batch_next(batch); + mnl_nlmsg_batch_next(batch); - nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, - nl_seq++); - mnl_nlmsg_batch_next(batch); + nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, mnl_seq++); + mnl_nlmsg_batch_next(batch); - if (nl == NULL) { - log_error("netlink not connected"); - return -1; - } else { - ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), - mnl_nlmsg_batch_size(batch)); - if (ret == -1) { - log_error("mnl_socket_sendto() FAILED: %m"); - return -2; - } + if (mnl_sock == NULL) { + log_error("netlink not connected"); + return -1; + } else { + ret = mnl_socket_sendto(mnl_sock, mnl_nlmsg_batch_head(batch), + mnl_nlmsg_batch_size(batch)); + if (ret == -1) { + log_error("mnl_socket_sendto() FAILED: %m"); + return -2; + } else { + mnl_nlmsg_batch_stop(batch); - mnl_nlmsg_batch_stop(batch); - - do { - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - log_error("mnl_socket_recvfrom() FAILED: %m"); - return -3; - } else if (ret > 0) { - ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL); + do { + ret = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf)); if (ret == -1) { - log_error("mnl_cb_run() FAILED: %m"); - return -4; + log_error("mnl_socket_recvfrom() FAILED: %m"); + return -3; + } else if (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, mnl_portid, NULL, NULL); + if (ret == -1) { + log_error("mnl_cb_run() FAILED: %m"); + return -4; + } } - } - } while (ret > 0); - } - /* mnl_socket_close(nl); */ - return 0; -} - -void -finish_batch(void) -{ - mnl_socket_close(nl); - nl = NULL; + } while (ret > 0); + } + } + return 0; } diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.h b/miniupnpd/netfilter_nft/nftnlrdr_misc.h index 400ee13..fe94fc5 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.h +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.h @@ -83,6 +83,15 @@ extern struct rule_list head_filter; extern struct rule_list head_redirect; extern struct rule_list head_peer; +/** called at initialization. + * establishes persistent connection to mnl/netfilter socket, needs elevated privilege */ +int +nft_mnl_connect(void); + +/** called at shutdown, to release the mnl/netfilter socket */ +void +nft_mnl_disconnect(void); + int nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type type); struct nftnl_rule * @@ -129,5 +138,3 @@ struct mnl_nlmsg_batch * start_batch( char *buf, size_t buf_size); int send_batch(struct mnl_nlmsg_batch * batch); -void -finish_batch(void);