rewrite table_cb() to better handle errors

This commit is contained in:
Thomas Bernard 2020-06-07 20:00:52 +02:00
parent 70b9526834
commit a64d4f937b
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
1 changed files with 76 additions and 71 deletions

View File

@ -472,7 +472,12 @@ rule_expr_cb(struct nftnl_expr *e, void *data)
return MNL_CB_OK; 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 static int
table_cb(const struct nlmsghdr *nlh, void *data) table_cb(const struct nlmsghdr *nlh, void *data)
{ {
@ -482,90 +487,90 @@ table_cb(const struct nlmsghdr *nlh, void *data)
struct nftnl_expr *expr; struct nftnl_expr *expr;
struct nftnl_expr_iter *itr; struct nftnl_expr_iter *itr;
rule_t *r; rule_t *r;
char *chain;
UNUSED(data); UNUSED(data);
r = malloc(sizeof(rule_t)); rule = nftnl_rule_alloc();
if (rule == NULL) {
if (r == NULL) { log_error("nftnl_rule_alloc() FAILED");
log_error("out of memory: %m"); return MNL_CB_ERROR;
}
if (nftnl_rule_nlmsg_parse(nlh, rule) < 0) {
log_error("nftnl_rule_nlmsg_parse FAILED");
result = MNL_CB_ERROR;
} else { } else {
memset(r, 0, sizeof(rule_t)); r = malloc(sizeof(rule_t));
rule = nftnl_rule_alloc(); if (r == NULL) {
if (rule == NULL) { syslog(LOG_ERR, "%s: failed to allocate %u bytes",
log_error("nftnl_rule_alloc() FAILED"); "table_cb", (unsigned)sizeof(rule_t));
result = MNL_CB_ERROR;
} else { } else {
const char *chain;
memset(r, 0, sizeof(rule_t));
if (nftnl_rule_nlmsg_parse(nlh, rule) < 0) { chain = (const char *) nftnl_rule_get_data(rule, NFTNL_RULE_CHAIN, &len);
log_error("nftnl_rule_nlmsg_parse FAILED"); if (strcmp(chain, nft_prerouting_chain) == 0 ||
} else { strcmp(chain, nft_postrouting_chain) == 0 ||
chain = (char *) nftnl_rule_get_data(rule, NFTNL_RULE_CHAIN, &len); strcmp(chain, nft_forward_chain) == 0) {
if (strcmp(chain, nft_prerouting_chain) == 0 || r->table = strdup((const char *) nftnl_rule_get_data(rule, NFTNL_RULE_TABLE, &len));
strcmp(chain, nft_postrouting_chain) == 0 || r->chain = strdup(chain);
strcmp(chain, nft_forward_chain) == 0) { r->family = *(uint32_t *) nftnl_rule_get_data(rule, NFTNL_RULE_FAMILY,
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,
&len); &len);
if (nftnl_rule_is_set(rule, NFTNL_RULE_USERDATA)) { if (nftnl_rule_is_set(rule, NFTNL_RULE_USERDATA)) {
char *descr; const char *descr;
descr = (char *) nftnl_rule_get_data(rule, NFTNL_RULE_USERDATA, descr = (const char *) nftnl_rule_get_data(rule, NFTNL_RULE_USERDATA,
&r->desc_len); &r->desc_len);
if (r->desc_len > 0) { if (r->desc_len > 0) {
r->desc = malloc(r->desc_len + 1); r->desc = malloc(r->desc_len + 1);
if (r->desc != NULL) { if (r->desc != NULL) {
memcpy(r->desc, descr, r->desc_len); memcpy(r->desc, descr, r->desc_len);
r->desc[r->desc_len] = '\0'; r->desc[r->desc_len] = '\0';
} else { } else {
syslog(LOG_ERR, "failed to allocate %u bytes for desc", r->desc_len); 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;
}
itr = nftnl_expr_iter_create(rule);
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_rule_free(rule); 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);
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_rule_free(rule);
return result; return result;
} }