establish persistent mnl/netlink socket at init_redirect (needs elevated privileges)

This commit is contained in:
Paul Chambers 2019-10-04 23:48:22 -07:00 committed by Thomas Bernard
parent 22223da9a1
commit 123e589266
3 changed files with 113 additions and 102 deletions

View File

@ -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();
}
/**

View File

@ -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;
}

View File

@ -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);