Merge pull request #475 from miniupnp/issue-474
improve netfilter_nft code
This commit is contained in:
commit
1e7fb305b6
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.1
|
||||
2.2.0-RC1
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue