|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2015 Arturo Borrero Gonzalez <arturo@netfilter.org>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <fcntl.h>
|
|
Packit |
c5a612 |
#include <errno.h>
|
|
Packit |
c5a612 |
#include <libmnl/libmnl.h>
|
|
Packit |
c5a612 |
#include <netinet/in.h>
|
|
Packit |
c5a612 |
#include <arpa/inet.h>
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <inttypes.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <libnftnl/table.h>
|
|
Packit |
c5a612 |
#include <libnftnl/trace.h>
|
|
Packit |
c5a612 |
#include <libnftnl/chain.h>
|
|
Packit |
c5a612 |
#include <libnftnl/expr.h>
|
|
Packit |
c5a612 |
#include <libnftnl/object.h>
|
|
Packit |
c5a612 |
#include <libnftnl/set.h>
|
|
Packit |
c5a612 |
#include <libnftnl/flowtable.h>
|
|
Packit |
c5a612 |
#include <libnftnl/udata.h>
|
|
Packit |
c5a612 |
#include <libnftnl/ruleset.h>
|
|
Packit |
c5a612 |
#include <libnftnl/common.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter/nfnetlink.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter/nf_tables.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <nftables.h>
|
|
Packit |
c5a612 |
#include <netlink.h>
|
|
Packit |
c5a612 |
#include <mnl.h>
|
|
Packit |
c5a612 |
#include <expression.h>
|
|
Packit |
c5a612 |
#include <statement.h>
|
|
Packit |
c5a612 |
#include <gmputil.h>
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <erec.h>
|
|
Packit |
c5a612 |
#include <iface.h>
|
|
Packit |
c5a612 |
#include <json.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table *nlt;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt = nftnl_table_alloc();
|
|
Packit |
c5a612 |
if (nlt == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (nftnl_table_nlmsg_parse(nlh, nlt) < 0)
|
|
Packit |
c5a612 |
netlink_abi_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlt;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_chain *netlink_chain_alloc(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_chain *nlc;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlc = nftnl_chain_alloc();
|
|
Packit |
c5a612 |
if (nlc == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (nftnl_chain_nlmsg_parse(nlh, nlc) < 0)
|
|
Packit |
c5a612 |
netlink_abi_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlc;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_set *netlink_set_alloc(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (nls == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (nftnl_set_nlmsg_parse(nlh, nls) < 0)
|
|
Packit |
c5a612 |
netlink_abi_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nls;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static struct nftnl_set *netlink_setelem_alloc(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (nls == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (nftnl_set_elems_nlmsg_parse(nlh, nls) < 0)
|
|
Packit |
c5a612 |
netlink_abi_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nls;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr = nftnl_rule_alloc();
|
|
Packit |
c5a612 |
if (nlr == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (nftnl_rule_nlmsg_parse(nlh, nlr) < 0)
|
|
Packit |
c5a612 |
netlink_abi_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlr;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_obj *netlink_obj_alloc(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_obj *nlo;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlo = nftnl_obj_alloc();
|
|
Packit |
c5a612 |
if (nlo == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (nftnl_obj_nlmsg_parse(nlh, nlo) < 0)
|
|
Packit |
c5a612 |
netlink_abi_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlo;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static uint32_t netlink_msg2nftnl_of(uint32_t msg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (msg) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWTABLE:
|
|
Packit |
c5a612 |
case NFT_MSG_NEWCHAIN:
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSET:
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSETELEM:
|
|
Packit |
c5a612 |
case NFT_MSG_NEWRULE:
|
|
Packit |
c5a612 |
case NFT_MSG_NEWOBJ:
|
|
Packit |
c5a612 |
case NFT_MSG_NEWFLOWTABLE:
|
|
Packit |
c5a612 |
return NFTNL_OF_EVENT_NEW;
|
|
Packit |
c5a612 |
case NFT_MSG_DELTABLE:
|
|
Packit |
c5a612 |
case NFT_MSG_DELCHAIN:
|
|
Packit |
c5a612 |
case NFT_MSG_DELSET:
|
|
Packit |
c5a612 |
case NFT_MSG_DELSETELEM:
|
|
Packit |
c5a612 |
case NFT_MSG_DELRULE:
|
|
Packit |
c5a612 |
case NFT_MSG_DELOBJ:
|
|
Packit |
c5a612 |
case NFT_MSG_DELFLOWTABLE:
|
|
Packit |
c5a612 |
return NFTNL_OF_EVENT_DEL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *nftnl_of2cmd(uint32_t of)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (of) {
|
|
Packit |
c5a612 |
case NFTNL_OF_EVENT_NEW:
|
|
Packit |
c5a612 |
return "add";
|
|
Packit |
c5a612 |
case NFTNL_OF_EVENT_DEL:
|
|
Packit |
c5a612 |
return "delete";
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
return "???";
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *netlink_msg2cmd(uint32_t msg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return nftnl_of2cmd(netlink_msg2nftnl_of(msg));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void nlr_for_each_set(struct nftnl_rule *nlr,
|
|
Packit |
c5a612 |
void (*cb)(struct set *s, void *data),
|
|
Packit |
c5a612 |
void *data, struct nft_cache *cache)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_expr_iter *nlrei;
|
|
Packit |
c5a612 |
struct nftnl_expr *nlre;
|
|
Packit |
c5a612 |
const char *set_name, *table;
|
|
Packit |
c5a612 |
const char *name;
|
|
Packit |
c5a612 |
struct set *s;
|
|
Packit |
c5a612 |
uint32_t family;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlrei = nftnl_expr_iter_create(nlr);
|
|
Packit |
c5a612 |
if (nlrei == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
|
|
Packit |
c5a612 |
table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlre = nftnl_expr_iter_next(nlrei);
|
|
Packit |
c5a612 |
while (nlre != NULL) {
|
|
Packit |
c5a612 |
name = nftnl_expr_get_str(nlre, NFTNL_EXPR_NAME);
|
|
Packit |
c5a612 |
if (strcmp(name, "lookup") != 0)
|
|
Packit |
c5a612 |
goto next;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
set_name = nftnl_expr_get_str(nlre, NFTNL_EXPR_LOOKUP_SET);
|
|
Packit |
c5a612 |
s = set_lookup_global(family, table, set_name, cache);
|
|
Packit |
c5a612 |
if (s == NULL)
|
|
Packit |
c5a612 |
goto next;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
cb(s, data);
|
|
Packit |
c5a612 |
next:
|
|
Packit |
c5a612 |
nlre = nftnl_expr_iter_next(nlrei);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_expr_iter_destroy(nlrei);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table *nlt;
|
|
Packit |
c5a612 |
struct table *t;
|
|
Packit |
c5a612 |
const char *cmd;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt = netlink_table_alloc(nlh);
|
|
Packit |
c5a612 |
t = netlink_delinearize_table(monh->ctx, nlt);
|
|
Packit |
c5a612 |
cmd = netlink_msg2cmd(type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (monh->format) {
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_DEFAULT:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s table ", cmd);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s %s", family2str(t->handle.family),
|
|
Packit |
c5a612 |
t->handle.table.name);
|
|
Packit |
c5a612 |
if (nft_output_handle(&monh->ctx->nft->output))
|
|
Packit |
c5a612 |
nft_mon_print(monh, " # handle %" PRIu64 "",
|
|
Packit |
c5a612 |
t->handle.handle.id);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_JSON:
|
|
Packit |
c5a612 |
monitor_print_table_json(monh, cmd, t);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
table_free(t);
|
|
Packit |
c5a612 |
nftnl_table_free(nlt);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_chain *nlc;
|
|
Packit |
c5a612 |
struct chain *c;
|
|
Packit |
c5a612 |
const char *cmd;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlc = netlink_chain_alloc(nlh);
|
|
Packit |
c5a612 |
c = netlink_delinearize_chain(monh->ctx, nlc);
|
|
Packit |
c5a612 |
cmd = netlink_msg2cmd(type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (monh->format) {
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_DEFAULT:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s ", cmd);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (type) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWCHAIN:
|
|
Packit |
c5a612 |
chain_print_plain(c, &monh->ctx->nft->output);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELCHAIN:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "chain %s %s %s",
|
|
Packit |
c5a612 |
family2str(c->handle.family),
|
|
Packit |
c5a612 |
c->handle.table.name,
|
|
Packit |
c5a612 |
c->handle.chain.name);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_JSON:
|
|
Packit |
c5a612 |
monitor_print_chain_json(monh, cmd, c);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
chain_free(c);
|
|
Packit |
c5a612 |
nftnl_chain_free(nlc);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
const char *family, *cmd;
|
|
Packit |
c5a612 |
struct set *set;
|
|
Packit |
c5a612 |
uint32_t flags;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = netlink_set_alloc(nlh);
|
|
Packit |
c5a612 |
flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
|
|
Packit |
c5a612 |
if (set_is_anonymous(flags))
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
set = netlink_delinearize_set(monh->ctx, nls);
|
|
Packit |
c5a612 |
if (set == NULL) {
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
family = family2str(set->handle.family);
|
|
Packit |
c5a612 |
cmd = netlink_msg2cmd(type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (monh->format) {
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_DEFAULT:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s ", cmd);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (type) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSET:
|
|
Packit |
c5a612 |
set_print_plain(set, &monh->ctx->nft->output);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELSET:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "set %s %s %s", family,
|
|
Packit |
c5a612 |
set->handle.table.name,
|
|
Packit |
c5a612 |
set->handle.set.name);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_JSON:
|
|
Packit |
c5a612 |
monitor_print_set_json(monh, cmd, set);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
set_free(set);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* returns true if the event should be ignored (i.e. null element) */
|
|
Packit |
c5a612 |
static bool netlink_event_ignore_range_event(struct nftnl_set_elem *nlse)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint32_t flags = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
|
|
Packit |
c5a612 |
flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
|
|
Packit |
c5a612 |
if (!(flags & NFT_SET_ELEM_INTERVAL_END))
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_KEY) != 0)
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return true;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static bool set_elem_is_open_interval(struct expr *elem)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
switch (elem->etype) {
|
|
Packit |
c5a612 |
case EXPR_SET_ELEM:
|
|
Packit |
c5a612 |
return elem->elem_flags & NFTNL_SET_ELEM_F_INTERVAL_OPEN;
|
|
Packit |
c5a612 |
case EXPR_MAPPING:
|
|
Packit |
c5a612 |
return set_elem_is_open_interval(elem->left);
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* returns true if the we cached the range element */
|
|
Packit |
c5a612 |
static bool netlink_event_range_cache(struct set *cached_set,
|
|
Packit |
c5a612 |
struct set *dummyset)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct expr *elem;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* not an interval ? */
|
|
Packit |
c5a612 |
if (!(cached_set->flags & NFT_SET_INTERVAL))
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* if cache exists, dummyset must contain the other end of the range */
|
|
Packit |
c5a612 |
if (cached_set->rg_cache) {
|
|
Packit |
c5a612 |
compound_expr_add(dummyset->init, cached_set->rg_cache);
|
|
Packit |
c5a612 |
cached_set->rg_cache = NULL;
|
|
Packit |
c5a612 |
goto out_decompose;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* don't cache half-open range elements */
|
|
Packit |
c5a612 |
elem = list_entry(dummyset->init->expressions.prev, struct expr, list);
|
|
Packit |
c5a612 |
if (!set_elem_is_open_interval(elem)) {
|
|
Packit |
c5a612 |
cached_set->rg_cache = expr_clone(elem);
|
|
Packit |
c5a612 |
return true;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
out_decompose:
|
|
Packit |
c5a612 |
interval_map_decompose(dummyset->init);
|
|
Packit |
c5a612 |
return false;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_set_elems_iter *nlsei;
|
|
Packit |
c5a612 |
struct nftnl_set_elem *nlse;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
struct set *dummyset;
|
|
Packit |
c5a612 |
struct set *set;
|
|
Packit |
c5a612 |
const char *setname, *table, *cmd;
|
|
Packit |
c5a612 |
uint32_t family;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = netlink_setelem_alloc(nlh);
|
|
Packit |
c5a612 |
table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
|
|
Packit |
c5a612 |
setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
|
|
Packit |
c5a612 |
family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
|
|
Packit |
c5a612 |
cmd = netlink_msg2cmd(type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
set = set_lookup_global(family, table, setname, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
if (set == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr, "W: Received event for an unknown set.\n");
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (set_is_anonymous(set->flags))
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* we want to 'delinearize' the set_elem, but don't
|
|
Packit |
c5a612 |
* modify the original cached set. This path is only
|
|
Packit |
c5a612 |
* used by named sets, so use a dummy set.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
dummyset = set_alloc(monh->loc);
|
|
Packit |
c5a612 |
dummyset->key = expr_clone(set->key);
|
|
Packit |
c5a612 |
dummyset->datatype = set->datatype;
|
|
Packit |
c5a612 |
dummyset->flags = set->flags;
|
|
Packit |
c5a612 |
dummyset->init = set_expr_alloc(monh->loc, set);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlsei = nftnl_set_elems_iter_create(nls);
|
|
Packit |
c5a612 |
if (nlsei == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlse = nftnl_set_elems_iter_next(nlsei);
|
|
Packit |
c5a612 |
while (nlse != NULL) {
|
|
Packit |
c5a612 |
if (netlink_event_ignore_range_event(nlse)) {
|
|
Packit |
c5a612 |
set_free(dummyset);
|
|
Packit |
c5a612 |
nftnl_set_elems_iter_destroy(nlsei);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (netlink_delinearize_setelem(nlse, dummyset,
|
|
Packit |
c5a612 |
&monh->ctx->nft->cache) < 0) {
|
|
Packit |
c5a612 |
set_free(dummyset);
|
|
Packit |
c5a612 |
nftnl_set_elems_iter_destroy(nlsei);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nlse = nftnl_set_elems_iter_next(nlsei);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_set_elems_iter_destroy(nlsei);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (netlink_event_range_cache(set, dummyset)) {
|
|
Packit |
c5a612 |
set_free(dummyset);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (monh->format) {
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_DEFAULT:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s element %s %s %s ",
|
|
Packit |
c5a612 |
cmd, family2str(family), table, setname);
|
|
Packit |
c5a612 |
expr_print(dummyset->init, &monh->ctx->nft->output);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_JSON:
|
|
Packit |
c5a612 |
dummyset->handle.family = family;
|
|
Packit |
c5a612 |
dummyset->handle.set.name = setname;
|
|
Packit |
c5a612 |
dummyset->handle.table.name = table;
|
|
Packit |
c5a612 |
monitor_print_element_json(monh, cmd, dummyset);
|
|
Packit |
c5a612 |
/* prevent set_free() from trying to free those */
|
|
Packit |
c5a612 |
dummyset->handle.set.name = NULL;
|
|
Packit |
c5a612 |
dummyset->handle.table.name = NULL;
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
set_free(dummyset);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const char *family, *cmd;
|
|
Packit |
c5a612 |
struct nftnl_obj *nlo;
|
|
Packit |
c5a612 |
struct obj *obj;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlo = netlink_obj_alloc(nlh);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
obj = netlink_delinearize_obj(monh->ctx, nlo);
|
|
Packit |
c5a612 |
if (obj == NULL) {
|
|
Packit |
c5a612 |
nftnl_obj_free(nlo);
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
family = family2str(obj->handle.family);
|
|
Packit |
c5a612 |
cmd = netlink_msg2cmd(type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (monh->format) {
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_DEFAULT:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s ", cmd);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (type) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWOBJ:
|
|
Packit |
c5a612 |
obj_print_plain(obj, &monh->ctx->nft->output);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELOBJ:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s %s %s %s",
|
|
Packit |
c5a612 |
obj_type_name(obj->type),
|
|
Packit |
c5a612 |
family,
|
|
Packit |
c5a612 |
obj->handle.table.name,
|
|
Packit |
c5a612 |
obj->handle.obj.name);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_JSON:
|
|
Packit |
c5a612 |
monitor_print_obj_json(monh, cmd, obj);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
obj_free(obj);
|
|
Packit |
c5a612 |
nftnl_obj_free(nlo);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void rule_map_decompose_cb(struct set *s, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit Service |
1227cd |
if (s->flags & NFT_SET_INTERVAL)
|
|
Packit |
c5a612 |
interval_map_decompose(s->init);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const char *family, *cmd;
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr;
|
|
Packit |
c5a612 |
struct rule *r;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr = netlink_rule_alloc(nlh);
|
|
Packit |
c5a612 |
r = netlink_delinearize_rule(monh->ctx, nlr);
|
|
Packit |
c5a612 |
nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
|
|
Packit |
c5a612 |
&monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
cmd = netlink_msg2cmd(type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (monh->format) {
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_DEFAULT:
|
|
Packit |
c5a612 |
family = family2str(r->handle.family);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_mon_print(monh, "%s rule %s %s %s ",
|
|
Packit |
c5a612 |
cmd,
|
|
Packit |
c5a612 |
family,
|
|
Packit |
c5a612 |
r->handle.table.name,
|
|
Packit |
c5a612 |
r->handle.chain.name);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (type) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWRULE:
|
|
Packit |
c5a612 |
rule_print(r, &monh->ctx->nft->output);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELRULE:
|
|
Packit |
c5a612 |
nft_mon_print(monh, "handle %" PRIu64,
|
|
Packit |
c5a612 |
r->handle.handle.id);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTNL_OUTPUT_JSON:
|
|
Packit |
c5a612 |
monitor_print_rule_json(monh, cmd, r);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
rule_free(r);
|
|
Packit |
c5a612 |
nftnl_rule_free(nlr);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_addtable(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table *nlt;
|
|
Packit |
c5a612 |
struct table *t;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt = netlink_table_alloc(nlh);
|
|
Packit |
c5a612 |
t = netlink_delinearize_table(monh->ctx, nlt);
|
|
Packit |
c5a612 |
nftnl_table_free(nlt);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
table_add_hash(t, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table *nlt;
|
|
Packit |
c5a612 |
struct table *t;
|
|
Packit |
c5a612 |
struct handle h;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt = netlink_table_alloc(nlh);
|
|
Packit |
c5a612 |
h.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
|
|
Packit |
c5a612 |
h.table.name = nftnl_table_get_str(nlt, NFTNL_TABLE_NAME);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
t = table_lookup(&h, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
if (t == NULL)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_del(&t->list);
|
|
Packit |
c5a612 |
table_free(t);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_table_free(nlt);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_addset(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct netlink_ctx set_tmpctx;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
struct table *t;
|
|
Packit |
c5a612 |
struct set *s;
|
|
Packit |
c5a612 |
LIST_HEAD(msgs);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
memset(&set_tmpctx, 0, sizeof(set_tmpctx));
|
|
Packit |
c5a612 |
init_list_head(&set_tmpctx.list);
|
|
Packit |
c5a612 |
init_list_head(&msgs);
|
|
Packit |
c5a612 |
set_tmpctx.msgs = &msg;;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = netlink_set_alloc(nlh);
|
|
Packit |
c5a612 |
s = netlink_delinearize_set(&set_tmpctx, nls);
|
|
Packit |
c5a612 |
if (s == NULL)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
s->init = set_expr_alloc(monh->loc, s);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
t = table_lookup(&s->handle, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
if (t == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr, "W: Unable to cache set: table not found.\n");
|
|
Packit |
c5a612 |
set_free(s);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_echo(&monh->ctx->nft->output) &&
|
|
Packit |
c5a612 |
!set_is_anonymous(s->flags)) {
|
|
Packit |
c5a612 |
set_free(s);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
set_add_hash(s, t);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_addsetelem(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_set_elems_iter *nlsei;
|
|
Packit |
c5a612 |
struct nftnl_set_elem *nlse;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
struct set *set;
|
|
Packit |
c5a612 |
const char *table, *setname;
|
|
Packit |
c5a612 |
uint32_t family;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = netlink_setelem_alloc(nlh);
|
|
Packit |
c5a612 |
family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
|
|
Packit |
c5a612 |
table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
|
|
Packit |
c5a612 |
setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
set = set_lookup_global(family, table, setname, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
if (set == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr,
|
|
Packit |
c5a612 |
"W: Unable to cache set_elem. Set not found.\n");
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_echo(&monh->ctx->nft->output) &&
|
|
Packit |
c5a612 |
!set_is_anonymous(set->flags))
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlsei = nftnl_set_elems_iter_create(nls);
|
|
Packit |
c5a612 |
if (nlsei == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlse = nftnl_set_elems_iter_next(nlsei);
|
|
Packit |
c5a612 |
while (nlse != NULL) {
|
|
Packit |
c5a612 |
if (netlink_delinearize_setelem(nlse, set,
|
|
Packit |
c5a612 |
&monh->ctx->nft->cache) < 0) {
|
|
Packit |
c5a612 |
fprintf(stderr,
|
|
Packit |
c5a612 |
"W: Unable to cache set_elem. "
|
|
Packit |
c5a612 |
"Delinearize failed.\n");
|
|
Packit |
c5a612 |
nftnl_set_elems_iter_destroy(nlsei);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nlse = nftnl_set_elems_iter_next(nlsei);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nftnl_set_elems_iter_destroy(nlsei);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_delset_cb(struct set *s,
|
|
Packit |
c5a612 |
void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
list_del(&s->list);
|
|
Packit |
c5a612 |
set_free(s);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_delsets(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr = netlink_rule_alloc(nlh);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr_for_each_set(nlr, netlink_events_cache_delset_cb, NULL,
|
|
Packit |
c5a612 |
&monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
nftnl_rule_free(nlr);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_addobj(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct netlink_ctx obj_tmpctx;
|
|
Packit |
c5a612 |
struct nftnl_obj *nlo;
|
|
Packit |
c5a612 |
struct table *t;
|
|
Packit |
c5a612 |
struct obj *obj;
|
|
Packit |
c5a612 |
LIST_HEAD(msgs);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
memset(&obj_tmpctx, 0, sizeof(obj_tmpctx));
|
|
Packit |
c5a612 |
init_list_head(&obj_tmpctx.list);
|
|
Packit |
c5a612 |
init_list_head(&msgs);
|
|
Packit |
c5a612 |
obj_tmpctx.msgs = &msg;;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlo = netlink_obj_alloc(nlh);
|
|
Packit |
c5a612 |
obj = netlink_delinearize_obj(&obj_tmpctx, nlo);
|
|
Packit |
c5a612 |
if (obj == NULL)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
t = table_lookup(&obj->handle, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
if (t == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr, "W: Unable to cache object: table not found.\n");
|
|
Packit |
c5a612 |
obj_free(obj);
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
obj_add_hash(obj, t);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_obj_free(nlo);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_delobj(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_obj *nlo;
|
|
Packit |
c5a612 |
const char *name;
|
|
Packit |
c5a612 |
struct obj *obj;
|
|
Packit |
c5a612 |
struct handle h;
|
|
Packit |
c5a612 |
struct table *t;
|
|
Packit |
c5a612 |
uint32_t type;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlo = netlink_obj_alloc(nlh);
|
|
Packit |
c5a612 |
h.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
|
|
Packit |
c5a612 |
h.table.name = nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
name = nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME);
|
|
Packit |
c5a612 |
type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
|
|
Packit |
c5a612 |
h.handle.id = nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
t = table_lookup(&h, &monh->ctx->nft->cache);
|
|
Packit |
c5a612 |
if (t == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr, "W: Unable to cache object: table not found.\n");
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
obj = obj_lookup(t, name, type);
|
|
Packit |
c5a612 |
if (obj == NULL) {
|
|
Packit |
c5a612 |
fprintf(stderr, "W: Unable to find object in cache\n");
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_del(&obj->list);
|
|
Packit |
c5a612 |
obj_free(obj);
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
nftnl_obj_free(nlo);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_cache_update(struct netlink_mon_handler *monh,
|
|
Packit |
c5a612 |
const struct nlmsghdr *nlh, int type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (nft_output_echo(&monh->ctx->nft->output) &&
|
|
Packit |
c5a612 |
type != NFT_MSG_NEWSET && type != NFT_MSG_NEWSETELEM)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (type) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWTABLE:
|
|
Packit |
c5a612 |
netlink_events_cache_addtable(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELTABLE:
|
|
Packit |
c5a612 |
netlink_events_cache_deltable(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSET:
|
|
Packit |
c5a612 |
netlink_events_cache_addset(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSETELEM:
|
|
Packit |
c5a612 |
netlink_events_cache_addsetelem(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELRULE:
|
|
Packit |
c5a612 |
/* there are no notification for anon-set deletion */
|
|
Packit |
c5a612 |
netlink_events_cache_delsets(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWOBJ:
|
|
Packit |
c5a612 |
netlink_events_cache_addobj(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_DELOBJ:
|
|
Packit |
c5a612 |
netlink_events_cache_delobj(monh, nlh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* only those which could be useful listening to events */
|
|
Packit |
c5a612 |
static const char *const nftnl_msg_types[NFT_MSG_MAX] = {
|
|
Packit |
c5a612 |
[NFT_MSG_NEWTABLE] = "NFT_MSG_NEWTABLE",
|
|
Packit |
c5a612 |
[NFT_MSG_DELTABLE] = "NFT_MSG_DELTABLE",
|
|
Packit |
c5a612 |
[NFT_MSG_NEWCHAIN] = "NFT_MSG_NEWCHAIN",
|
|
Packit |
c5a612 |
[NFT_MSG_DELCHAIN] = "NFT_MSG_DELCHAIN",
|
|
Packit |
c5a612 |
[NFT_MSG_NEWSET] = "NFT_MSG_NEWSET",
|
|
Packit |
c5a612 |
[NFT_MSG_DELSET] = "NFT_MSG_DELSET",
|
|
Packit |
c5a612 |
[NFT_MSG_NEWSETELEM] = "NFT_MSG_NEWSETELEM",
|
|
Packit |
c5a612 |
[NFT_MSG_DELSETELEM] = "NFT_MSG_DELSETELEM",
|
|
Packit |
c5a612 |
[NFT_MSG_NEWRULE] = "NFT_MSG_NEWRULE",
|
|
Packit |
c5a612 |
[NFT_MSG_DELRULE] = "NFT_MSG_DELRULE",
|
|
Packit |
c5a612 |
[NFT_MSG_TRACE] = "NFT_MSG_TRACE",
|
|
Packit |
c5a612 |
[NFT_MSG_NEWGEN] = "NFT_MSG_NEWGEN",
|
|
Packit |
c5a612 |
[NFT_MSG_NEWOBJ] = "NFT_MSG_NEWOBJ",
|
|
Packit |
c5a612 |
[NFT_MSG_DELOBJ] = "NFT_MSG_DELOBJ",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *nftnl_msgtype2str(uint16_t type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (type >= NFT_MSG_MAX || !nftnl_msg_types[type])
|
|
Packit |
c5a612 |
return "unknown";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nftnl_msg_types[type];
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void netlink_events_debug(uint16_t type, unsigned int debug_mask)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (!(debug_mask & NFT_DEBUG_NETLINK))
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
printf("netlink event: %s\n", nftnl_msgtype2str(type));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_newgen_cb(const struct nlmsghdr *nlh, int type,
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct nlattr *attr;
|
|
Packit |
c5a612 |
char name[256] = "";
|
|
Packit |
c5a612 |
int genid = -1, pid = -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_attr_for_each(attr, nlh, sizeof(struct nfgenmsg)) {
|
|
Packit |
c5a612 |
switch (mnl_attr_get_type(attr)) {
|
|
Packit |
c5a612 |
case NFTA_GEN_ID:
|
|
Packit |
c5a612 |
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
genid = ntohl(mnl_attr_get_u32(attr));
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTA_GEN_PROC_NAME:
|
|
Packit |
c5a612 |
if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
snprintf(name, sizeof(name), "%s", mnl_attr_get_str(attr));
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFTA_GEN_PROC_PID:
|
|
Packit |
c5a612 |
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
pid = ntohl(mnl_attr_get_u32(attr));
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (genid >= 0) {
|
|
Packit |
c5a612 |
nft_mon_print(monh, "# new generation %d", genid);
|
|
Packit |
c5a612 |
if (pid >= 0)
|
|
Packit |
c5a612 |
nft_mon_print(monh, " by process %d (%s)", pid, name);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_mon_print(monh, "\n");
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int ret = MNL_CB_OK;
|
|
Packit |
c5a612 |
uint16_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
|
Packit |
c5a612 |
struct netlink_mon_handler *monh = (struct netlink_mon_handler *)data;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_events_debug(type, monh->ctx->nft->debug_mask);
|
|
Packit |
c5a612 |
netlink_events_cache_update(monh, nlh, type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!(monh->monitor_flags & (1 << type)))
|
|
Packit |
c5a612 |
return ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (type) {
|
|
Packit |
c5a612 |
case NFT_MSG_NEWTABLE:
|
|
Packit |
c5a612 |
case NFT_MSG_DELTABLE:
|
|
Packit |
c5a612 |
ret = netlink_events_table_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWCHAIN:
|
|
Packit |
c5a612 |
case NFT_MSG_DELCHAIN:
|
|
Packit |
c5a612 |
ret = netlink_events_chain_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSET:
|
|
Packit |
c5a612 |
case NFT_MSG_DELSET: /* nft {add|delete} set */
|
|
Packit |
c5a612 |
ret = netlink_events_set_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWSETELEM:
|
|
Packit |
c5a612 |
case NFT_MSG_DELSETELEM: /* nft {add|delete} element */
|
|
Packit |
c5a612 |
ret = netlink_events_setelem_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWRULE:
|
|
Packit |
c5a612 |
case NFT_MSG_DELRULE:
|
|
Packit |
c5a612 |
ret = netlink_events_rule_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_TRACE:
|
|
Packit |
c5a612 |
ret = netlink_events_trace_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWOBJ:
|
|
Packit |
c5a612 |
case NFT_MSG_DELOBJ:
|
|
Packit |
c5a612 |
ret = netlink_events_obj_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_MSG_NEWGEN:
|
|
Packit |
c5a612 |
ret = netlink_events_newgen_cb(nlh, type, monh);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return ret;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int netlink_echo_callback(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct netlink_ctx *ctx = data;
|
|
Packit |
c5a612 |
struct netlink_mon_handler echo_monh = {
|
|
Packit |
c5a612 |
.format = NFTNL_OUTPUT_DEFAULT,
|
|
Packit |
c5a612 |
.ctx = ctx,
|
|
Packit |
c5a612 |
.loc = &netlink_location,
|
|
Packit |
c5a612 |
.monitor_flags = 0xffffffff,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!nft_output_echo(&echo_monh.ctx->nft->output))
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_json(&ctx->nft->output))
|
|
Packit |
c5a612 |
return json_events_cb(nlh, &echo_monh);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return netlink_events_cb(nlh, &echo_monh);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int netlink_monitor(struct netlink_mon_handler *monhandler,
|
|
Packit |
c5a612 |
struct mnl_socket *nf_sock)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int group;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (monhandler->monitor_flags & (1 << NFT_MSG_TRACE)) {
|
|
Packit |
c5a612 |
group = NFNLGRP_NFTRACE;
|
|
Packit |
c5a612 |
if (mnl_socket_setsockopt(nf_sock, NETLINK_ADD_MEMBERSHIP,
|
|
Packit |
c5a612 |
&group, sizeof(int)) < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (monhandler->monitor_flags & ~(1 << NFT_MSG_TRACE)) {
|
|
Packit |
c5a612 |
group = NFNLGRP_NFTABLES;
|
|
Packit |
c5a612 |
if (mnl_socket_setsockopt(nf_sock, NETLINK_ADD_MEMBERSHIP,
|
|
Packit |
c5a612 |
&group, sizeof(int)) < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return mnl_nft_event_listener(nf_sock, monhandler->ctx->nft->debug_mask,
|
|
Packit |
c5a612 |
&monhandler->ctx->nft->output,
|
|
Packit |
c5a612 |
netlink_events_cb, monhandler);
|
|
Packit |
c5a612 |
}
|