Merge pull request #475 from miniupnp/issue-474

improve netfilter_nft code
This commit is contained in:
Thomas BERNARD 2020-06-11 14:53:38 +02:00 committed by GitHub
commit 1e7fb305b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 310 additions and 248 deletions

View File

@ -1,7 +1,8 @@
$Id: Changelog.txt,v 1.464 2020/05/10 17:57:56 nanard Exp $
$Id: Changelog.txt,v 1.465 2020/06/06 18:02:19 nanard Exp $
2020/06/05:
fix handling of ipv4 M-SEARCH received on ipv6 sockets
numerous fixes in linux/nftables implementation
2020/06/03:
configure --disable-fork to disable going to background

View File

@ -1 +1 @@
2.1
2.2.0-RC1

View File

@ -1,5 +1,5 @@
/* $Id: nftnlrdr_misc.c,v 1.9 2020/05/29 16:09:21 nanard Exp $ */
/*
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* (c) 2015 Tomofumi Hayashi
@ -84,24 +84,24 @@ static uint32_t rule_list_redirect_validate = RULE_CACHE_INVALID;
static uint32_t rule_list_peer_validate = RULE_CACHE_INVALID;
/*
* return : 0 for OK, -1 for error
*/
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 -1;
}
return result;
if (mnl_socket_bind(mnl_sock, 0, MNL_SOCKET_AUTOPID) < 0) {
log_error("mnl_socket_bind() FAILED: %m");
return -1;
}
mnl_portid = mnl_socket_get_portid(mnl_sock);
syslog(LOG_INFO, "mnl_socket bound, port_id=%u", mnl_portid);
return 0;
}
void
@ -251,7 +251,8 @@ static void
parse_rule_nat(struct nftnl_expr *e, rule_t *r)
{
uint32_t addr_min_reg, addr_max_reg, proto_min_reg, proto_max_reg;
uint16_t proto_min_val;
uint16_t proto_min_val = 0;
uint32_t * reg_val_ptr;
r->type = RULE_NAT;
r->nat_type = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_TYPE);
@ -266,15 +267,25 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r)
log_error( "Unsupport proto/addr range for NAT");
}
proto_min_val = htons((uint16_t)*get_reg_val_ptr(r, proto_min_reg));
if (r->nat_type == NFT_NAT_DNAT) {
r->iaddr = (in_addr_t)*get_reg_val_ptr(r, addr_min_reg);
r->iport = proto_min_val;
} else if (r->nat_type == NFT_NAT_SNAT) {
r->eaddr = (in_addr_t)*get_reg_val_ptr(r, addr_min_reg);
if (proto_min_reg == NFT_REG_1) {
r->eport = proto_min_val;
reg_val_ptr = get_reg_val_ptr(r, proto_min_reg);
if (reg_val_ptr != NULL) {
proto_min_val = htons((uint16_t)*reg_val_ptr);
} else {
syslog(LOG_ERR, "%s: invalid proto_min_reg %u", "parse_rule_nat", proto_min_reg);
}
reg_val_ptr = get_reg_val_ptr(r, addr_min_reg);
if (reg_val_ptr != NULL) {
if (r->nat_type == NFT_NAT_DNAT) {
r->iaddr = (in_addr_t)*reg_val_ptr;
r->iport = proto_min_val;
} else if (r->nat_type == NFT_NAT_SNAT) {
r->eaddr = (in_addr_t)*reg_val_ptr;
if (proto_min_reg == NFT_REG_1) {
r->eport = proto_min_val;
}
}
} else {
syslog(LOG_ERR, "%s: invalid addr_min_reg %u", "parse_rule_nat", addr_min_reg);
}
set_reg(r, NFT_REG_1, RULE_REG_NONE, 0);
@ -292,6 +303,10 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r)
offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
regptr = get_reg_type_ptr(r, dreg);
if (regptr == NULL) {
syslog(LOG_ERR, "%s: unsupported dreg %u", "parse_rule_payload", dreg);
return;
}
switch (base) {
case NFT_PAYLOAD_NETWORK_HEADER:
@ -331,9 +346,9 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r)
}
break;
default:
syslog(LOG_DEBUG,
"Unsupported payload: (dreg:%d, base:%d, offset:%d, len:%d)",
dreg, base, offset, len);
syslog(LOG_WARNING,
"%s: Unsupported payload: (dreg:%u, base:%u, offset:%u, len:%u)",
"parse_rule_payload", dreg, base, offset, len);
break;
}
@ -448,9 +463,8 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r)
}
static int
rule_expr_cb(struct nftnl_expr *e, void *data)
rule_expr_cb(struct nftnl_expr *e, rule_t *r)
{
rule_t *r = data;
const char *attr_name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
if (strncmp("cmp", attr_name, sizeof("cmp")) == 0) {
@ -472,128 +486,155 @@ rule_expr_cb(struct nftnl_expr *e, void *data)
return MNL_CB_OK;
}
/* callback.
* return values :
* MNL_CB_ERROR : an error has occurred. Stop callback runqueue.
* MNL_CB_STOP : top callback runqueue.
* MNL_CB_OK : no problems has occurred.
*/
static int
table_cb(const struct nlmsghdr *nlh, void *data)
{
int result = MNL_CB_OK;
struct nftnl_rule *rule;
uint32_t len;
struct nftnl_expr *expr;
struct nftnl_expr_iter *itr;
rule_t *r;
char *chain;
UNUSED(data);
r = malloc(sizeof(rule_t));
if (r == NULL) {
log_error("out of memory: %m");
rule = nftnl_rule_alloc();
if (rule == NULL) {
log_error("nftnl_rule_alloc() FAILED");
return MNL_CB_ERROR;
}
if (nftnl_rule_nlmsg_parse(nlh, rule) < 0) {
log_error("nftnl_rule_nlmsg_parse FAILED");
result = MNL_CB_ERROR;
} else {
memset(r, 0, sizeof(rule_t));
rule = nftnl_rule_alloc();
if (rule == NULL) {
log_error("nftnl_rule_alloc() FAILED");
rule_t *r = malloc(sizeof(rule_t));
if (r == NULL) {
syslog(LOG_ERR, "%s: failed to allocate %u bytes",
"table_cb", (unsigned)sizeof(rule_t));
result = MNL_CB_ERROR;
} else {
const char *chain;
uint32_t len;
if (nftnl_rule_nlmsg_parse(nlh, rule) < 0) {
log_error("nftnl_rule_nlmsg_parse FAILED");
} else {
chain = (char *) nftnl_rule_get_data(rule, NFTNL_RULE_CHAIN, &len);
if (strcmp(chain, nft_prerouting_chain) == 0 ||
strcmp(chain, nft_postrouting_chain) == 0 ||
strcmp(chain, nft_forward_chain) == 0) {
r->table = strdup(
(char *) nftnl_rule_get_data(rule, NFTNL_RULE_TABLE, &len));
r->chain = strdup(chain);
r->family = *(uint32_t *) nftnl_rule_get_data(rule, NFTNL_RULE_FAMILY,
memset(r, 0, sizeof(rule_t));
chain = (const char *) nftnl_rule_get_data(rule, NFTNL_RULE_CHAIN, &len);
if (strcmp(chain, nft_prerouting_chain) == 0 ||
strcmp(chain, nft_postrouting_chain) == 0 ||
strcmp(chain, nft_forward_chain) == 0) {
r->table = strdup((const char *) nftnl_rule_get_data(rule, NFTNL_RULE_TABLE, &len));
r->chain = strdup(chain);
r->family = *(uint32_t *) nftnl_rule_get_data(rule, NFTNL_RULE_FAMILY,
&len);
if (nftnl_rule_is_set(rule, NFTNL_RULE_USERDATA)) {
char *descr;
descr = (char *) nftnl_rule_get_data(rule, NFTNL_RULE_USERDATA,
if (nftnl_rule_is_set(rule, NFTNL_RULE_USERDATA)) {
const char *descr;
descr = (const char *) nftnl_rule_get_data(rule, NFTNL_RULE_USERDATA,
&r->desc_len);
if (r->desc_len > 0) {
r->desc = malloc(r->desc_len + 1);
if (r->desc != NULL) {
memcpy(r->desc, descr, r->desc_len);
r->desc[r->desc_len] = '\0';
} else {
syslog(LOG_ERR, "failed to allocate %u bytes for desc", r->desc_len);
}
if (r->desc_len > 0) {
r->desc = malloc(r->desc_len + 1);
if (r->desc != NULL) {
memcpy(r->desc, descr, r->desc_len);
r->desc[r->desc_len] = '\0';
} else {
syslog(LOG_ERR, "failed to allocate %u bytes for desc", r->desc_len);
}
}
}
r->handle = *(uint32_t *) nftnl_rule_get_data(rule,
NFTNL_RULE_HANDLE,
&len);
r->type = RULE_NONE;
if (strcmp(chain, nft_prerouting_chain) == 0 ||
strcmp(chain, nft_postrouting_chain) == 0) {
r->type = RULE_NAT;
} else if (strcmp(chain, nft_forward_chain) == 0) {
r->type = RULE_FILTER;
}
r->handle = *(uint32_t *) nftnl_rule_get_data(rule,
NFTNL_RULE_HANDLE,
&len);
r->type = RULE_NONE;
if (strcmp(chain, nft_prerouting_chain) == 0 ||
strcmp(chain, nft_postrouting_chain) == 0) {
r->type = RULE_NAT;
} else if (strcmp(chain, nft_forward_chain) == 0) {
r->type = RULE_FILTER;
}
itr = nftnl_expr_iter_create(rule);
itr = nftnl_expr_iter_create(rule);
if (itr == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_iter_create() FAILED",
"table_cb");
} else {
struct nftnl_expr *expr;
while ((expr = nftnl_expr_iter_next(itr)) != NULL) {
rule_expr_cb(expr, r);
}
switch (r->type) {
case RULE_NAT:
switch (r->nat_type) {
case NFT_NAT_SNAT:
LIST_INSERT_HEAD(&head_peer, r, entry);
break;
case NFT_NAT_DNAT:
LIST_INSERT_HEAD(&head_redirect, r, entry);
break;
}
break;
case RULE_FILTER:
LIST_INSERT_HEAD(&head_filter, r, entry);
break;
default:
free(r);
break;
}
nftnl_expr_iter_destroy(itr);
}
nftnl_rule_free(rule);
switch (r->type) {
case RULE_NAT:
switch (r->nat_type) {
case NFT_NAT_SNAT:
LIST_INSERT_HEAD(&head_peer, r, entry);
r = NULL;
break;
case NFT_NAT_DNAT:
LIST_INSERT_HEAD(&head_redirect, r, entry);
r = NULL;
break;
default:
syslog(LOG_WARNING, "unknown nat type %d", r->nat_type);
}
break;
case RULE_FILTER:
LIST_INSERT_HEAD(&head_filter, r, entry);
r = NULL;
break;
default:
syslog(LOG_WARNING, "unknown rule type %d", r->type);
break;
}
} else {
syslog(LOG_WARNING, "unknown chain '%s'", chain);
}
if (r != NULL) {
free(r);
}
}
}
nftnl_rule_free(rule);
return result;
}
void
int
refresh_nft_cache_filter(void)
{
if (rule_list_filter_validate != RULE_CACHE_VALID) {
refresh_nft_cache(&head_filter, nft_table, nft_forward_chain, NFPROTO_INET);
if (refresh_nft_cache(&head_filter, nft_table, nft_forward_chain, NFPROTO_INET) < 0)
return -1;
rule_list_filter_validate = RULE_CACHE_VALID;
}
return 0;
}
void
int
refresh_nft_cache_peer(void)
{
if (rule_list_peer_validate != RULE_CACHE_VALID) {
refresh_nft_cache(&head_peer, nft_table, nft_postrouting_chain, NFPROTO_IPV4);
if (refresh_nft_cache(&head_peer, nft_table, nft_postrouting_chain, NFPROTO_IPV4) < 0)
return -1;
rule_list_peer_validate = RULE_CACHE_VALID;
}
return 0;
}
void
int
refresh_nft_cache_redirect(void)
{
if (rule_list_redirect_validate != RULE_CACHE_VALID) {
refresh_nft_cache(&head_redirect, nft_table, nft_prerouting_chain, NFPROTO_IPV4);
if (refresh_nft_cache(&head_redirect, nft_table, nft_prerouting_chain, NFPROTO_IPV4) < 0)
return -1;
rule_list_redirect_validate = RULE_CACHE_VALID;
}
return 0;
}
void
@ -602,26 +643,27 @@ flush_nft_cache(struct rule_list *head)
rule_t *p1, *p2;
p1 = LIST_FIRST(head);
if (p1 != NULL) {
while (p1 != NULL) {
p2 = (rule_t *)LIST_NEXT(p1, entry);
if (p1->desc != NULL) {
free(p1->desc);
}
if (p1->table != NULL) {
free(p1->table);
}
if (p1->chain != NULL) {
free(p1->chain);
}
free(p1);
p1 = p2;
while (p1 != NULL) {
p2 = (rule_t *)LIST_NEXT(p1, entry);
if (p1->desc != NULL) {
free(p1->desc);
}
if (p1->table != NULL) {
free(p1->table);
}
if (p1->chain != NULL) {
free(p1->chain);
}
free(p1);
p1 = p2;
}
LIST_INIT(head);
}
void
/*
* return -1 in case of error, 0 if OK
*/
int
refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
@ -629,42 +671,52 @@ refresh_nft_cache(struct rule_list *head, const char *table, const char *chain,
uint32_t type = NFTNL_OUTPUT_DEFAULT;
struct nftnl_rule *rule;
int ret;
ssize_t n;
if (mnl_sock == NULL) {
log_error("netlink not connected");
return -1;
}
flush_nft_cache(head);
rule = nftnl_rule_alloc();
if (rule == NULL) {
log_error("nftnl_rule_alloc() FAILED");
return;
return -1;
}
mnl_seq = time(NULL);
nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
NLM_F_DUMP, mnl_seq);
nftnl_rule_set(rule, NFTNL_RULE_TABLE, table);
nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, table);
nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, chain);
nftnl_rule_nlmsg_build_payload(nlh, rule);
nftnl_rule_free(rule);
if (mnl_socket_sendto(mnl_sock, nlh, nlh->nlmsg_len) < 0) {
log_error("mnl_socket_sendto() FAILED: %m");
return;
return -1;
}
ret = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf));
while (ret > 0) {
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));
do {
n = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf));
if (n < 0) {
syslog(LOG_ERR, "%s: mnl_socket_recvfrom: %m",
"refresh_nft_cache");
return -1;
} else if (n == 0) {
break;
}
}
ret = mnl_cb_run(buf, n, mnl_seq, mnl_portid, table_cb, &type);
if (ret <= -1 /*== MNL_CB_ERROR*/) {
syslog(LOG_ERR, "%s: mnl_cb_run returned %d",
"refresh_nft_cache", ret);
return -1;
}
} while(ret >= 1 /*== MNL_CB_OK*/);
/* ret == MNL_CB_STOP */
if (ret == -1) {
log_error("mnl_socket_recvfrom() FAILED: %m");
}
return;
return 0;
}
static void
@ -812,8 +864,8 @@ rule_set_snat(uint8_t family, uint8_t proto,
}
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
nftnl_rule_set(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_postrouting_chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, nft_postrouting_chain);
if (descr != NULL && *descr != '\0') {
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
@ -890,8 +942,8 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
}
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
nftnl_rule_set(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_prerouting_chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, nft_prerouting_chain);
if (descr != NULL && *descr != '\0') {
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
@ -1035,8 +1087,8 @@ rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname
UNUSED(eport);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
nftnl_rule_set(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_forward_chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, nft_forward_chain);
if (descr != NULL && *descr != '\0') {
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
@ -1093,8 +1145,8 @@ rule_del_handle(rule_t *rule)
return NULL;
}
nftnl_rule_set(r, NFTNL_RULE_TABLE, rule->table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, rule->chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, rule->table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, rule->chain);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, rule->family);
nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, rule->handle);
@ -1121,36 +1173,36 @@ nft_mnl_batch_put(char *buf, uint16_t type, uint32_t seq)
int
nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain_type)
{
int result = -1;
int result = -1;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE*2];
batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE);
if (batch != NULL)
{
switch (chain_type) {
case RULE_CHAIN_FILTER:
rule_list_filter_validate = RULE_CACHE_INVALID;
break;
case RULE_CHAIN_PEER:
rule_list_peer_validate = RULE_CACHE_INVALID;
break;
case RULE_CHAIN_REDIRECT:
rule_list_redirect_validate = RULE_CACHE_INVALID;
break;
}
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
cmd,
nftnl_rule_get_u32(rule, NFTNL_RULE_FAMILY),
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
mnl_seq++);
{
switch (chain_type) {
case RULE_CHAIN_FILTER:
rule_list_filter_validate = RULE_CACHE_INVALID;
break;
case RULE_CHAIN_PEER:
rule_list_peer_validate = RULE_CACHE_INVALID;
break;
case RULE_CHAIN_REDIRECT:
rule_list_redirect_validate = RULE_CACHE_INVALID;
break;
}
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
cmd,
nftnl_rule_get_u32(rule, NFTNL_RULE_FAMILY),
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
mnl_seq++);
nftnl_rule_nlmsg_build_payload(nlh, rule);
nftnl_rule_free(rule);
nftnl_rule_nlmsg_build_payload(nlh, rule);
nftnl_rule_free(rule);
result = send_batch(batch);
}
result = send_batch(batch);
}
return result;
}
@ -1158,78 +1210,84 @@ nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain
int
table_op( enum nf_tables_msg_types op, uint16_t family, const char * name)
{
int result;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE*2];
int result;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE*2];
struct nftnl_table *table;
struct nftnl_table *table;
// log_debug("(%d, %d, %s)", op, family, name);
table = nftnl_table_alloc();
if (table == NULL) {
log_error("out of memory: %m");
result = -1;
} else {
nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
table = nftnl_table_alloc();
if (table == NULL) {
log_error("out of memory: %m");
result = -1;
} else {
nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE);
if (batch == NULL) {
log_error("out of memory: %m");
result = -2;
} else {
nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
op, family,
(op == NFT_MSG_NEWTABLE ? NLM_F_CREATE : 0) | NLM_F_ACK,
mnl_seq++);
nftnl_table_nlmsg_build_payload(nlh, table);
batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE);
if (batch == NULL) {
log_error("out of memory: %m");
result = -2;
} else {
nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
op, family,
(op == NFT_MSG_NEWTABLE ? NLM_F_CREATE : 0) | NLM_F_ACK,
mnl_seq++);
nftnl_table_nlmsg_build_payload(nlh, table);
result = send_batch(batch);
}
nftnl_table_free(table);
}
return result;
result = send_batch(batch);
}
nftnl_table_free(table);
}
return result;
}
/*
* return values :
* -2 : out of memory (nftnl_chain_alloc)
* -3 : out of memory (start batch)
* -4 : failed to build header
*/
int
chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table,
const char * name, const char * type, uint32_t hooknum, signed int priority )
{
int result = -1;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE*2];
int result = -1;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE*2];
struct nftnl_chain *chain;
struct nftnl_chain *chain;
// log_debug("(%d, %d, %s, %s, %s, %d, %d)", op, family, table, name, type, hooknum, priority);
// log_debug("(%d, %d, %s, %s, %s, %d, %d)", op, family, table, name, type, hooknum, priority);
chain = nftnl_chain_alloc();
if (chain == NULL) {
log_error("out of memory: %m");
result = -2;
} else {
chain = nftnl_chain_alloc();
if (chain == NULL) {
log_error("out of memory: %m");
result = -2;
} else {
nftnl_chain_set_u32(chain, NFTNL_CHAIN_FAMILY, family);
nftnl_chain_set(chain, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set(chain, NFTNL_CHAIN_NAME, name);
nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, name);
if (op == NFT_MSG_NEWCHAIN) {
nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum);
nftnl_chain_set_s32(chain, NFTNL_CHAIN_PRIO, priority);
}
batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE);
if (batch == NULL) {
batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE);
if (batch == NULL) {
log_error("out of memory: %m");
result = -3;
} else {
nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
op, family,
(op == NFT_MSG_NEWCHAIN ? NLM_F_CREATE : 0) | NLM_F_ACK,
mnl_seq++);
if (nlh == NULL)
result = -3;
} else {
nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
op, family,
(op == NFT_MSG_NEWCHAIN ? NLM_F_CREATE : 0) | NLM_F_ACK,
mnl_seq++);
if (nlh == NULL)
{
log_error("failed to build header: %m");
result = -4;
@ -1237,11 +1295,11 @@ chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table,
nftnl_chain_nlmsg_build_payload(nlh, chain);
result = send_batch(batch);
}
}
nftnl_chain_free(chain);
}
return result;
}
}
nftnl_chain_free(chain);
}
return result;
}
/**
@ -1252,8 +1310,8 @@ 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 *result;
mnl_seq = time(NULL);
struct mnl_nlmsg_batch *result;
mnl_seq = time(NULL);
if (mnl_sock == NULL) {
log_error("netlink not connected");
@ -1265,9 +1323,9 @@ start_batch(char *buf, size_t buf_size)
NFNL_MSG_BATCH_BEGIN, mnl_seq++);
mnl_nlmsg_batch_next(result);
}
}
}
return result;
return result;
}
/**
@ -1282,6 +1340,7 @@ int
send_batch(struct mnl_nlmsg_batch *batch)
{
int ret;
ssize_t n;
char buf[MNL_SOCKET_BUFFER_SIZE];
mnl_nlmsg_batch_next(batch);
@ -1292,29 +1351,31 @@ send_batch(struct mnl_nlmsg_batch *batch)
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);
do {
ret = mnl_socket_recvfrom(mnl_sock, 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_portid, NULL, NULL);
if (ret == -1) {
log_error("mnl_cb_run() FAILED: %m");
return -4;
}
}
} while (ret > 0);
}
}
n = mnl_socket_sendto(mnl_sock, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch));
if (n == -1) {
log_error("mnl_socket_sendto() FAILED: %m");
return -2;
}
mnl_nlmsg_batch_stop(batch);
do {
n = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf));
if (n == -1) {
log_error("mnl_socket_recvfrom() FAILED: %m");
return -3;
} else if (n == 0) {
break;
}
ret = mnl_cb_run(buf, n, 0, mnl_portid, NULL, NULL);
if (ret <= -1 /*== MNL_CB_ERROR*/) {
syslog(LOG_ERR, "%s: mnl_cb_run returned %d",
"send_batch", ret);
return -4;
}
} while (ret >= 1 /*== MNL_CB_OK*/);
/* ret == MNL_CB_STOP */
return 0;
}

View File

@ -134,10 +134,10 @@ rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname
uint8_t proto, unsigned short eport, unsigned short iport,
unsigned short rport, const char *descr, const char *handle);
struct nftnl_rule *rule_del_handle(rule_t *r);
void refresh_nft_cache_filter(void);
void refresh_nft_cache_redirect(void);
void refresh_nft_cache_peer(void);
void refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family);
int refresh_nft_cache_filter(void);
int refresh_nft_cache_redirect(void);
int refresh_nft_cache_peer(void);
int refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family);
int
table_op(enum nf_tables_msg_types op, uint16_t family, const char * name);