|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2013-2017 Pablo Neira Ayuso <pablo@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 |
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <libmnl/libmnl.h>
|
|
Packit |
c5a612 |
#include <libnftnl/common.h>
|
|
Packit |
c5a612 |
#include <libnftnl/ruleset.h>
|
|
Packit |
c5a612 |
#include <libnftnl/table.h>
|
|
Packit |
c5a612 |
#include <libnftnl/chain.h>
|
|
Packit |
c5a612 |
#include <libnftnl/rule.h>
|
|
Packit |
c5a612 |
#include <libnftnl/expr.h>
|
|
Packit |
c5a612 |
#include <libnftnl/set.h>
|
|
Packit |
c5a612 |
#include <libnftnl/object.h>
|
|
Packit |
c5a612 |
#include <libnftnl/flowtable.h>
|
|
Packit |
c5a612 |
#include <libnftnl/batch.h>
|
|
Packit |
c5a612 |
#include <libnftnl/udata.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <linux/netfilter/nfnetlink.h>
|
|
Packit |
c5a612 |
#include <linux/netfilter/nf_tables.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <mnl.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
#include <sys/socket.h>
|
|
Packit |
c5a612 |
#include <arpa/inet.h>
|
|
Packit |
c5a612 |
#include <fcntl.h>
|
|
Packit |
c5a612 |
#include <errno.h>
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <nftables.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct mnl_socket *nft_mnl_socket_open(void)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct mnl_socket *nf_sock;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nf_sock = mnl_socket_open(NETLINK_NETFILTER);
|
|
Packit |
c5a612 |
if (!nf_sock)
|
|
Packit |
c5a612 |
netlink_init_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK))
|
|
Packit |
c5a612 |
netlink_init_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nf_sock;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct mnl_socket *nft_mnl_socket_reopen(struct mnl_socket *nf_sock)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
mnl_socket_close(nf_sock);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nft_mnl_socket_open();
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
uint32_t mnl_seqnum_alloc(unsigned int *seqnum)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return (*seqnum)++;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* The largest nf_tables netlink message is the set element message, which
|
|
Packit |
c5a612 |
* contains the NFTA_SET_ELEM_LIST_ELEMENTS attribute. This attribute is
|
|
Packit |
c5a612 |
* a nest that describes the set elements. Given that the netlink attribute
|
|
Packit |
c5a612 |
* length (nla_len) is 16 bits, the largest message is a bit larger than
|
|
Packit |
c5a612 |
* 64 KBytes.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int
|
|
Packit |
c5a612 |
nft_mnl_recv(struct netlink_ctx *ctx, uint32_t portid,
|
|
Packit |
c5a612 |
int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[NFT_NLMSG_MAXSIZE];
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_socket_recvfrom(ctx->nft->nf_sock, buf, sizeof(buf));
|
|
Packit |
c5a612 |
while (ret > 0) {
|
|
Packit |
c5a612 |
ret = mnl_cb_run(buf, ret, ctx->seqnum, portid, cb, cb_data);
|
|
Packit |
c5a612 |
if (ret <= 0)
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_socket_recvfrom(ctx->nft->nf_sock, buf, sizeof(buf));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
if (ret < 0 && errno == EAGAIN)
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return ret;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int
|
|
Packit |
c5a612 |
nft_mnl_talk(struct netlink_ctx *ctx, const void *data, unsigned int len,
|
|
Packit |
c5a612 |
int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint32_t portid = mnl_socket_get_portid(ctx->nft->nf_sock);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (ctx->nft->debug_mask & NFT_DEBUG_MNL)
|
|
Packit |
c5a612 |
mnl_nlmsg_fprintf(ctx->nft->output.output_fp, data, len,
|
|
Packit |
c5a612 |
sizeof(struct nfgenmsg));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (mnl_socket_sendto(ctx->nft->nf_sock, data, len) < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nft_mnl_recv(ctx, portid, cb, cb_data);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Rule-set consistency check across several netlink dumps
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
static uint32_t nft_genid;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int genid_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nft_genid = ntohs(nfh->res_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
uint32_t mnl_genid_get(struct netlink_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, AF_UNSPEC, 0, ctx->seqnum);
|
|
Packit |
c5a612 |
/* Skip error checking, old kernels sets res_id field to zero. */
|
|
Packit |
c5a612 |
nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, genid_cb, NULL);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nft_genid;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static uint16_t nft_genid_u16(uint32_t genid)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return genid & 0xffff;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int check_genid(const struct nlmsghdr *nlh)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_genid_u16(nft_genid) != ntohs(nfh->res_id)) {
|
|
Packit |
c5a612 |
errno = EINTR;
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Batching
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* selected batch page is 256 Kbytes long to load ruleset of
|
|
Packit |
c5a612 |
* half a million rules without hitting -EMSGSIZE due to large
|
|
Packit |
c5a612 |
* iovec.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
#define BATCH_PAGE_SIZE getpagesize() * 32
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_batch *mnl_batch_init(void)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_batch *batch;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
batch = nftnl_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE);
|
|
Packit |
c5a612 |
if (batch == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return batch;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void mnl_nft_batch_continue(struct nftnl_batch *batch)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (nftnl_batch_update(batch) < 0)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t seqnum)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return seqnum;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nftnl_batch_end(nftnl_batch_buffer(batch), seqnum);
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(batch);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
bool mnl_batch_ready(struct nftnl_batch *batch)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
/* Check if the batch only contains the initial and trailing batch
|
|
Packit |
c5a612 |
* messages. In that case, the batch is empty.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
return nftnl_batch_buffer_len(batch) !=
|
|
Packit |
c5a612 |
(NLMSG_HDRLEN + sizeof(struct nfgenmsg)) * 2;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void mnl_batch_reset(struct nftnl_batch *batch)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
nftnl_batch_free(batch);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void mnl_err_list_node_add(struct list_head *err_list, int error,
|
|
Packit |
c5a612 |
int seqnum)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct mnl_err *err = xmalloc(sizeof(struct mnl_err));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err->seqnum = seqnum;
|
|
Packit |
c5a612 |
err->err = error;
|
|
Packit |
c5a612 |
list_add_tail(&err->head, err_list);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
void mnl_err_list_free(struct mnl_err *err)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
list_del(&err->head);
|
|
Packit |
c5a612 |
xfree(err);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void mnl_set_sndbuffer(const struct mnl_socket *nl,
|
|
Packit |
c5a612 |
struct nftnl_batch *batch)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
socklen_t len = sizeof(int);
|
|
Packit |
c5a612 |
int sndnlbuffsiz = 0;
|
|
Packit |
c5a612 |
int newbuffsiz;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
getsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUF,
|
|
Packit |
c5a612 |
&sndnlbuffsiz, &len;;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
newbuffsiz = nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE;
|
|
Packit |
c5a612 |
if (newbuffsiz <= sndnlbuffsiz)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* Rise sender buffer length to avoid hitting -EMSGSIZE */
|
|
Packit |
c5a612 |
if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE,
|
|
Packit |
c5a612 |
&newbuffsiz, sizeof(socklen_t)) < 0)
|
|
Packit |
c5a612 |
return;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static unsigned int nlsndbufsiz;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int mnl_set_rcvbuffer(const struct mnl_socket *nl, socklen_t bufsiz)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
socklen_t len = sizeof(nlsndbufsiz);
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!nlsndbufsiz) {
|
|
Packit |
c5a612 |
getsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUF,
|
|
Packit |
c5a612 |
&nlsndbufsiz, &len;;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nlsndbufsiz >= bufsiz)
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUFFORCE,
|
|
Packit |
c5a612 |
&bufsiz, sizeof(socklen_t));
|
|
Packit |
c5a612 |
if (ret < 0) {
|
|
Packit |
c5a612 |
/* If this doesn't work, try to reach the system wide maximum
|
|
Packit |
c5a612 |
* (or whatever the user requested).
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
ret = setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUF,
|
|
Packit |
c5a612 |
&bufsiz, sizeof(socklen_t));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return ret;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static size_t mnl_nft_batch_to_msg(struct netlink_ctx *ctx, struct msghdr *msg,
|
|
Packit |
c5a612 |
const struct sockaddr_nl *snl,
|
|
Packit |
c5a612 |
struct iovec *iov, unsigned int iov_len)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int i;
|
|
Packit |
c5a612 |
size_t len = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
msg->msg_name = (struct sockaddr_nl *)snl;
|
|
Packit |
c5a612 |
msg->msg_namelen = sizeof(*snl);
|
|
Packit |
c5a612 |
msg->msg_iov = iov;
|
|
Packit |
c5a612 |
msg->msg_iovlen = iov_len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_batch_iovec(ctx->batch, iov, iov_len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
for (i = 0; i < iov_len; i++)
|
|
Packit |
c5a612 |
len += msg->msg_iov[i].iov_len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return len;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static ssize_t mnl_nft_socket_sendmsg(struct netlink_ctx *ctx,
|
|
Packit |
c5a612 |
const struct msghdr *msg)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint32_t iov_len = msg->msg_iovlen;
|
|
Packit |
c5a612 |
struct iovec *iov = msg->msg_iov;
|
|
Packit |
c5a612 |
unsigned int i;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (ctx->nft->debug_mask & NFT_DEBUG_MNL) {
|
|
Packit |
c5a612 |
for (i = 0; i < iov_len; i++) {
|
|
Packit |
c5a612 |
mnl_nlmsg_fprintf(ctx->nft->output.output_fp,
|
|
Packit |
c5a612 |
iov[i].iov_base, iov[i].iov_len,
|
|
Packit |
c5a612 |
sizeof(struct nfgenmsg));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return sendmsg(mnl_socket_get_fd(ctx->nft->nf_sock), msg, 0);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#define NFT_MNL_ECHO_RCVBUFF_DEFAULT (MNL_SOCKET_BUFFER_SIZE * 1024)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
|
|
Packit |
c5a612 |
uint32_t num_cmds)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct mnl_socket *nl = ctx->nft->nf_sock;
|
|
Packit |
c5a612 |
int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
|
|
Packit |
c5a612 |
uint32_t iov_len = nftnl_batch_iovec_len(ctx->batch);
|
|
Packit |
c5a612 |
char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
const struct sockaddr_nl snl = {
|
|
Packit |
c5a612 |
.nl_family = AF_NETLINK
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
struct timeval tv = {
|
|
Packit |
c5a612 |
.tv_sec = 0,
|
|
Packit |
c5a612 |
.tv_usec = 0
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
struct iovec iov[iov_len];
|
|
Packit |
c5a612 |
struct msghdr msg = {};
|
|
Packit |
c5a612 |
unsigned int rcvbufsiz;
|
|
Packit |
c5a612 |
size_t batch_size;
|
|
Packit |
c5a612 |
fd_set readfds;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_set_sndbuffer(ctx->nft->nf_sock, ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
batch_size = mnl_nft_batch_to_msg(ctx, &msg, &snl, iov, iov_len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_echo(&ctx->nft->output)) {
|
|
Packit |
c5a612 |
rcvbufsiz = num_cmds * 1024;
|
|
Packit |
c5a612 |
if (rcvbufsiz < NFT_MNL_ECHO_RCVBUFF_DEFAULT)
|
|
Packit |
c5a612 |
rcvbufsiz = NFT_MNL_ECHO_RCVBUFF_DEFAULT;
|
|
Packit |
c5a612 |
} else {
|
|
Packit |
c5a612 |
rcvbufsiz = num_cmds * div_round_up(batch_size, num_cmds) * 4;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_set_rcvbuffer(ctx->nft->nf_sock, rcvbufsiz);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_nft_socket_sendmsg(ctx, &msg;;
|
|
Packit |
c5a612 |
if (ret == -1)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* receive and digest all the acknowledgments from the kernel. */
|
|
Packit |
c5a612 |
while (true) {
|
|
Packit |
c5a612 |
FD_ZERO(&readfds);
|
|
Packit |
c5a612 |
FD_SET(fd, &readfds);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = select(fd + 1, &readfds, NULL, NULL, &tv;;
|
|
Packit |
c5a612 |
if (ret == -1)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!FD_ISSET(fd, &readfds))
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
|
|
Packit |
c5a612 |
if (ret == -1)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_cb_run(rcv_buf, ret, 0, portid, &netlink_echo_callback, ctx);
|
|
Packit |
c5a612 |
/* Continue on error, make sure we get all acknowledgments */
|
|
Packit |
c5a612 |
if (ret == -1) {
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct rule *rule = cmd->rule;
|
|
Packit |
c5a612 |
struct handle *h = &rule->handle;
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr = nftnl_rule_alloc();
|
|
Packit |
c5a612 |
if (!nlr)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
|
|
Packit |
c5a612 |
nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
|
|
Packit |
c5a612 |
if (h->position.id)
|
|
Packit |
c5a612 |
nftnl_rule_set_u64(nlr, NFTNL_RULE_POSITION, h->position.id);
|
|
Packit |
c5a612 |
if (h->rule_id)
|
|
Packit |
c5a612 |
nftnl_rule_set_u32(nlr, NFTNL_RULE_ID, h->rule_id);
|
|
Packit |
c5a612 |
if (h->position_id)
|
|
Packit |
c5a612 |
nftnl_rule_set_u32(nlr, NFTNL_RULE_POSITION_ID, h->position_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_linearize_rule(ctx, nlr, rule);
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWRULE,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
NLM_F_CREATE | flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_rule_nlmsg_build_payload(nlh, nlr);
|
|
Packit |
c5a612 |
nftnl_rule_free(nlr);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct rule *rule = cmd->rule;
|
|
Packit |
c5a612 |
struct handle *h = &rule->handle;
|
|
Packit |
c5a612 |
unsigned int flags = 0;
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_echo(&ctx->nft->output))
|
|
Packit |
c5a612 |
flags |= NLM_F_ECHO;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr = nftnl_rule_alloc();
|
|
Packit |
c5a612 |
if (!nlr)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
|
|
Packit |
c5a612 |
nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
|
|
Packit |
c5a612 |
nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, h->handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_linearize_rule(ctx, nlr, rule);
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWRULE,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
NLM_F_REPLACE | flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_rule_nlmsg_build_payload(nlh, nlr);
|
|
Packit |
c5a612 |
nftnl_rule_free(nlr);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct handle *h = &cmd->handle;
|
|
Packit |
c5a612 |
struct nftnl_rule *nlr;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr = nftnl_rule_alloc();
|
|
Packit |
c5a612 |
if (!nlr)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
|
|
Packit |
c5a612 |
if (h->chain.name)
|
|
Packit |
c5a612 |
nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
|
|
Packit |
c5a612 |
if (h->handle.id)
|
|
Packit |
c5a612 |
nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, h->handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELRULE,
|
|
Packit |
c5a612 |
nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY),
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_rule_nlmsg_build_payload(nlh, nlr);
|
|
Packit |
c5a612 |
nftnl_rule_free(nlr);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Rule
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int rule_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_rule_list *nlr_list = data;
|
|
Packit |
c5a612 |
struct nftnl_rule *r;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
r = nftnl_rule_alloc();
|
|
Packit |
c5a612 |
if (r == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
|
|
Packit |
c5a612 |
goto err_free;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_rule_list_add_tail(r, nlr_list);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err_free:
|
|
Packit |
c5a612 |
nftnl_rule_free(r);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
|
|
Packit |
c5a612 |
int family)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nftnl_rule_list *nlr_list;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlr_list = nftnl_rule_list_alloc();
|
|
Packit |
c5a612 |
if (nlr_list == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
|
|
Packit |
c5a612 |
NLM_F_DUMP, ctx->seqnum);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, rule_cb, nlr_list);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlr_list;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
nftnl_rule_list_free(nlr_list);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Chain
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int priority, policy, i = 0;
|
|
Packit |
c5a612 |
struct nftnl_chain *nlc;
|
|
Packit |
c5a612 |
const char **dev_array;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
struct expr *expr;
|
|
Packit |
c5a612 |
int dev_array_len;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlc = nftnl_chain_alloc();
|
|
Packit |
c5a612 |
if (nlc == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, cmd->handle.chain.name);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (cmd->chain) {
|
|
Packit |
c5a612 |
if (cmd->chain->flags & CHAIN_F_BASECHAIN) {
|
|
Packit |
c5a612 |
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_HOOKNUM,
|
|
Packit |
c5a612 |
cmd->chain->hooknum);
|
|
Packit |
c5a612 |
mpz_export_data(&priority,
|
|
Packit |
c5a612 |
cmd->chain->priority.expr->value,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN, sizeof(int));
|
|
Packit |
c5a612 |
nftnl_chain_set_s32(nlc, NFTNL_CHAIN_PRIO, priority);
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_TYPE,
|
|
Packit |
c5a612 |
cmd->chain->type);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (cmd->chain->policy) {
|
|
Packit |
c5a612 |
mpz_export_data(&policy, cmd->chain->policy->value,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN, sizeof(int));
|
|
Packit |
c5a612 |
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (cmd->chain->dev_expr) {
|
|
Packit |
c5a612 |
dev_array = xmalloc(sizeof(char *) * 8);
|
|
Packit |
c5a612 |
dev_array_len = 8;
|
|
Packit |
c5a612 |
list_for_each_entry(expr, &cmd->chain->dev_expr->expressions, list) {
|
|
Packit |
c5a612 |
dev_array[i++] = expr->identifier;
|
|
Packit |
c5a612 |
if (i == dev_array_len) {
|
|
Packit |
c5a612 |
dev_array_len *= 2;
|
|
Packit |
c5a612 |
dev_array = xrealloc(dev_array,
|
|
Packit |
c5a612 |
dev_array_len * sizeof(char *));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dev_array[i] = NULL;
|
|
Packit |
c5a612 |
if (i == 1)
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV, dev_array[0]);
|
|
Packit |
c5a612 |
else if (i > 1)
|
|
Packit |
c5a612 |
nftnl_chain_set_data(nlc, NFTNL_CHAIN_DEVICES, dev_array,
|
|
Packit |
c5a612 |
sizeof(char *) * dev_array_len);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
xfree(dev_array);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
netlink_dump_chain(nlc, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWCHAIN,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
NLM_F_CREATE | flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_chain_nlmsg_build_payload(nlh, nlc);
|
|
Packit |
c5a612 |
nftnl_chain_free(nlc);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
const struct chain *chain)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const char *name = cmd->arg;
|
|
Packit |
c5a612 |
struct nftnl_chain *nlc;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlc = nftnl_chain_alloc();
|
|
Packit |
c5a612 |
if (nlc == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
|
|
Packit |
c5a612 |
nftnl_chain_set_u64(nlc, NFTNL_CHAIN_HANDLE, chain->handle.handle.id);
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, name);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_dump_chain(nlc, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWCHAIN,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_chain_nlmsg_build_payload(nlh, nlc);
|
|
Packit |
c5a612 |
nftnl_chain_free(nlc);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_chain *nlc;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlc = nftnl_chain_alloc();
|
|
Packit |
c5a612 |
if (nlc == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
|
|
Packit |
c5a612 |
if (cmd->handle.chain.name)
|
|
Packit |
c5a612 |
nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME,
|
|
Packit |
c5a612 |
cmd->handle.chain.name);
|
|
Packit |
c5a612 |
else if (cmd->handle.handle.id)
|
|
Packit |
c5a612 |
nftnl_chain_set_u64(nlc, NFTNL_CHAIN_HANDLE,
|
|
Packit |
c5a612 |
cmd->handle.handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELCHAIN,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_chain_nlmsg_build_payload(nlh, nlc);
|
|
Packit |
c5a612 |
nftnl_chain_free(nlc);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int chain_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_chain_list *nlc_list = data;
|
|
Packit |
c5a612 |
struct nftnl_chain *c;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
c = nftnl_chain_alloc();
|
|
Packit |
c5a612 |
if (c == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
|
|
Packit |
c5a612 |
goto err_free;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_chain_list_add_tail(c, nlc_list);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err_free:
|
|
Packit |
c5a612 |
nftnl_chain_free(c);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
|
|
Packit |
c5a612 |
int family)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nftnl_chain_list *nlc_list;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlc_list = nftnl_chain_list_alloc();
|
|
Packit |
c5a612 |
if (nlc_list == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
|
|
Packit |
c5a612 |
NLM_F_DUMP, ctx->seqnum);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlc_list;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
nftnl_chain_list_free(nlc_list);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Table
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table *nlt;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt = nftnl_table_alloc();
|
|
Packit |
c5a612 |
if (nlt == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_table_set_str(nlt, NFTNL_TABLE_NAME, cmd->handle.table.name);
|
|
Packit |
c5a612 |
if (cmd->table)
|
|
Packit |
c5a612 |
nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, cmd->table->flags);
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, 0);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWTABLE,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_table_nlmsg_build_payload(nlh, nlt);
|
|
Packit |
c5a612 |
nftnl_table_free(nlt);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table *nlt;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt = nftnl_table_alloc();
|
|
Packit |
c5a612 |
if (nlt == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
if (cmd->handle.table.name)
|
|
Packit |
c5a612 |
nftnl_table_set_str(nlt, NFTNL_TABLE_NAME,
|
|
Packit |
c5a612 |
cmd->handle.table.name);
|
|
Packit |
c5a612 |
else if (cmd->handle.handle.id)
|
|
Packit |
c5a612 |
nftnl_table_set_u64(nlt, NFTNL_TABLE_HANDLE,
|
|
Packit |
c5a612 |
cmd->handle.handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELTABLE,
|
|
Packit |
c5a612 |
cmd->handle.family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_table_nlmsg_build_payload(nlh, nlt);
|
|
Packit |
c5a612 |
nftnl_table_free(nlt);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int table_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_table_list *nlt_list = data;
|
|
Packit |
c5a612 |
struct nftnl_table *t;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
t = nftnl_table_alloc();
|
|
Packit |
c5a612 |
if (t == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_table_nlmsg_parse(nlh, t) < 0)
|
|
Packit |
c5a612 |
goto err_free;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_table_list_add_tail(t, nlt_list);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err_free:
|
|
Packit |
c5a612 |
nftnl_table_free(t);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
|
|
Packit |
c5a612 |
int family)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nftnl_table_list *nlt_list;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlt_list = nftnl_table_list_alloc();
|
|
Packit |
c5a612 |
if (nlt_list == NULL)
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
|
|
Packit |
c5a612 |
NLM_F_DUMP, ctx->seqnum);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, table_cb, nlt_list);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nlt_list;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
nftnl_table_list_free(nlt_list);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Set
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct handle *h = &cmd->handle;
|
|
Packit |
c5a612 |
struct nftnl_udata_buf *udbuf;
|
|
Packit |
c5a612 |
struct set *set = cmd->set;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (!nls)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_ID, h->set_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_FLAGS, set->flags);
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_KEY_TYPE,
|
|
Packit |
c5a612 |
dtype_map_to_kernel(set->key->dtype));
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_KEY_LEN,
|
|
Packit |
c5a612 |
div_round_up(set->key->len, BITS_PER_BYTE));
|
|
Packit |
c5a612 |
if (set_is_datamap(set->flags)) {
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
|
|
Packit |
c5a612 |
dtype_map_to_kernel(set->datatype));
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_DATA_LEN,
|
|
Packit |
c5a612 |
set->datalen / BITS_PER_BYTE);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (set_is_objmap(set->flags))
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_OBJ_TYPE, set->objtype);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (set->timeout)
|
|
Packit |
c5a612 |
nftnl_set_set_u64(nls, NFTNL_SET_TIMEOUT, set->timeout);
|
|
Packit |
c5a612 |
if (set->gc_int)
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_GC_INTERVAL, set->gc_int);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_ID, set->handle.set_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!(set->flags & NFT_SET_CONSTANT)) {
|
|
Packit |
c5a612 |
if (set->policy != NFT_SET_POL_PERFORMANCE)
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_POLICY, set->policy);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (set->desc.size != 0)
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_DESC_SIZE,
|
|
Packit |
c5a612 |
set->desc.size);
|
|
Packit |
c5a612 |
} else if (set->init) {
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_DESC_SIZE, set->init->size);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
|
|
Packit |
c5a612 |
if (!udbuf)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEYBYTEORDER,
|
|
Packit |
c5a612 |
set->key->byteorder))
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (set_is_datamap(set->flags) &&
|
|
Packit |
c5a612 |
!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATABYTEORDER,
|
|
Packit |
c5a612 |
set->datatype->byteorder))
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (set->automerge &&
|
|
Packit |
c5a612 |
!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_MERGE_ELEMENTS,
|
|
Packit |
c5a612 |
set->automerge))
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf),
|
|
Packit |
c5a612 |
nftnl_udata_buf_len(udbuf));
|
|
Packit |
c5a612 |
nftnl_udata_buf_free(udbuf);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_dump_set(nls, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWSET,
|
|
Packit |
c5a612 |
h->family,
|
|
Packit |
c5a612 |
NLM_F_CREATE | flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_nlmsg_build_payload(nlh, nls);
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct handle *h = &cmd->handle;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (!nls)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
|
|
Packit |
c5a612 |
if (h->set.name)
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
|
|
Packit |
c5a612 |
else if (h->handle.id)
|
|
Packit |
c5a612 |
nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELSET,
|
|
Packit |
c5a612 |
h->family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_nlmsg_build_payload(nlh, nls);
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int set_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_set_list *nls_list = data;
|
|
Packit |
c5a612 |
struct nftnl_set *s;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
s = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (s == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_set_nlmsg_parse(nlh, s) < 0)
|
|
Packit |
c5a612 |
goto err_free;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_list_add_tail(s, nls_list);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err_free:
|
|
Packit |
c5a612 |
nftnl_set_free(s);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_set_list *
|
|
Packit |
c5a612 |
mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nftnl_set_list *nls_list;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
struct nftnl_set *s;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
s = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (s == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
|
|
Packit |
c5a612 |
NLM_F_DUMP, ctx->seqnum);
|
|
Packit |
c5a612 |
if (table != NULL)
|
|
Packit |
c5a612 |
nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
|
|
Packit |
c5a612 |
nftnl_set_nlmsg_build_payload(nlh, s);
|
|
Packit |
c5a612 |
nftnl_set_free(s);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls_list = nftnl_set_list_alloc();
|
|
Packit |
c5a612 |
if (nls_list == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_cb, nls_list);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nls_list;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
nftnl_set_list_free(nls_list);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct obj *obj = cmd->object;
|
|
Packit |
c5a612 |
struct nftnl_obj *nlo;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlo = nftnl_obj_alloc();
|
|
Packit |
c5a612 |
if (!nlo)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
|
|
Packit |
c5a612 |
nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, obj->type);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
switch (obj->type) {
|
|
Packit |
c5a612 |
case NFT_OBJECT_COUNTER:
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_PKTS,
|
|
Packit |
c5a612 |
obj->counter.packets);
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_BYTES,
|
|
Packit |
c5a612 |
obj->counter.bytes);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_QUOTA:
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_BYTES,
|
|
Packit |
c5a612 |
obj->quota.bytes);
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED,
|
|
Packit |
c5a612 |
obj->quota.used);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS,
|
|
Packit |
c5a612 |
obj->quota.flags);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_LIMIT:
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_RATE, obj->limit.rate);
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_UNIT, obj->limit.unit);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_BURST, obj->limit.burst);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_TYPE, obj->limit.type);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS, obj->limit.flags);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_CT_HELPER:
|
|
Packit |
c5a612 |
nftnl_obj_set_str(nlo, NFTNL_OBJ_CT_HELPER_NAME,
|
|
Packit |
c5a612 |
obj->ct_helper.name);
|
|
Packit |
c5a612 |
nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO,
|
|
Packit |
c5a612 |
obj->ct_helper.l4proto);
|
|
Packit |
c5a612 |
if (obj->ct_helper.l3proto)
|
|
Packit |
c5a612 |
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO,
|
|
Packit |
c5a612 |
obj->ct_helper.l3proto);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_CT_TIMEOUT:
|
|
Packit |
c5a612 |
nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO,
|
|
Packit |
c5a612 |
obj->ct_timeout.l4proto);
|
|
Packit |
c5a612 |
if (obj->ct_timeout.l3proto)
|
|
Packit |
c5a612 |
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO,
|
|
Packit |
c5a612 |
obj->ct_timeout.l3proto);
|
|
Packit |
c5a612 |
nftnl_obj_set_data(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY,
|
|
Packit |
c5a612 |
obj->ct_timeout.timeout,
|
|
Packit |
c5a612 |
sizeof(obj->ct_timeout.timeout));
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_CT_EXPECT:
|
|
Packit |
c5a612 |
if (obj->ct_expect.l3proto)
|
|
Packit |
c5a612 |
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO,
|
|
Packit |
c5a612 |
obj->ct_expect.l3proto);
|
|
Packit |
c5a612 |
nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO,
|
|
Packit |
c5a612 |
obj->ct_expect.l4proto);
|
|
Packit |
c5a612 |
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT,
|
|
Packit |
c5a612 |
obj->ct_expect.dport);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT,
|
|
Packit |
c5a612 |
obj->ct_expect.timeout);
|
|
Packit |
c5a612 |
nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE,
|
|
Packit |
c5a612 |
obj->ct_expect.size);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_SECMARK:
|
|
Packit |
c5a612 |
nftnl_obj_set_str(nlo, NFTNL_OBJ_SECMARK_CTX,
|
|
Packit |
c5a612 |
obj->secmark.ctx);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
case NFT_OBJECT_SYNPROXY:
|
|
Packit |
c5a612 |
nftnl_obj_set_u16(nlo, NFTNL_OBJ_SYNPROXY_MSS,
|
|
Packit |
c5a612 |
obj->synproxy.mss);
|
|
Packit |
c5a612 |
nftnl_obj_set_u8(nlo, NFTNL_OBJ_SYNPROXY_WSCALE,
|
|
Packit |
c5a612 |
obj->synproxy.wscale);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS,
|
|
Packit |
c5a612 |
obj->synproxy.flags);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
default:
|
|
Packit |
c5a612 |
BUG("Unknown type %d\n", obj->type);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
netlink_dump_obj(nlo, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWOBJ, cmd->handle.family,
|
|
Packit |
c5a612 |
NLM_F_CREATE | flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_obj_nlmsg_build_payload(nlh, nlo);
|
|
Packit |
c5a612 |
nftnl_obj_free(nlo);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_obj *nlo;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlo = nftnl_obj_alloc();
|
|
Packit |
c5a612 |
if (!nlo)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
|
|
Packit |
c5a612 |
if (cmd->handle.obj.name)
|
|
Packit |
c5a612 |
nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
|
|
Packit |
c5a612 |
else if (cmd->handle.handle.id)
|
|
Packit |
c5a612 |
nftnl_obj_set_u64(nlo, NFTNL_OBJ_HANDLE, cmd->handle.handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELOBJ, cmd->handle.family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_obj_nlmsg_build_payload(nlh, nlo);
|
|
Packit |
c5a612 |
nftnl_obj_free(nlo);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int obj_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_obj_list *nln_list = data;
|
|
Packit |
c5a612 |
struct nftnl_obj *n;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = nftnl_obj_alloc();
|
|
Packit |
c5a612 |
if (n == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_obj_nlmsg_parse(nlh, n) < 0)
|
|
Packit |
c5a612 |
goto err_free;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_obj_list_add_tail(n, nln_list);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err_free:
|
|
Packit |
c5a612 |
nftnl_obj_free(n);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_obj_list *
|
|
Packit |
c5a612 |
mnl_nft_obj_dump(struct netlink_ctx *ctx, int family,
|
|
Packit |
c5a612 |
const char *table, const char *name, uint32_t type, bool dump,
|
|
Packit |
c5a612 |
bool reset)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint16_t nl_flags = dump ? NLM_F_DUMP : NLM_F_ACK;
|
|
Packit |
c5a612 |
struct nftnl_obj_list *nln_list;
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
struct nftnl_obj *n;
|
|
Packit |
c5a612 |
int msg_type, ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (reset)
|
|
Packit |
c5a612 |
msg_type = NFT_MSG_GETOBJ_RESET;
|
|
Packit |
c5a612 |
else
|
|
Packit |
c5a612 |
msg_type = NFT_MSG_GETOBJ;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = nftnl_obj_alloc();
|
|
Packit |
c5a612 |
if (n == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
|
|
Packit |
c5a612 |
nl_flags, ctx->seqnum);
|
|
Packit |
c5a612 |
if (table != NULL)
|
|
Packit |
c5a612 |
nftnl_obj_set_str(n, NFTNL_OBJ_TABLE, table);
|
|
Packit |
c5a612 |
if (name != NULL)
|
|
Packit |
c5a612 |
nftnl_obj_set_str(n, NFTNL_OBJ_NAME, name);
|
|
Packit |
c5a612 |
if (type != NFT_OBJECT_UNSPEC)
|
|
Packit |
c5a612 |
nftnl_obj_set_u32(n, NFTNL_OBJ_TYPE, type);
|
|
Packit |
c5a612 |
nftnl_obj_nlmsg_build_payload(nlh, n);
|
|
Packit |
c5a612 |
nftnl_obj_free(n);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nln_list = nftnl_obj_list_alloc();
|
|
Packit |
c5a612 |
if (nln_list == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, obj_cb, nln_list);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nln_list;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
nftnl_obj_list_free(nln_list);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Set elements
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_elems_nlmsg_parse(nlh, data);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int mnl_nft_setelem_batch(struct nftnl_set *nls,
|
|
Packit |
c5a612 |
struct nftnl_batch *batch,
|
|
Packit |
c5a612 |
enum nf_tables_msg_types cmd,
|
|
Packit |
c5a612 |
unsigned int flags, uint32_t seqnum)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
struct nftnl_set_elems_iter *iter;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
iter = nftnl_set_elems_iter_create(nls);
|
|
Packit |
c5a612 |
if (iter == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (cmd == NFT_MSG_NEWSETELEM)
|
|
Packit |
c5a612 |
flags |= NLM_F_CREATE;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (nftnl_set_elems_iter_cur(iter)) {
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), cmd,
|
|
Packit |
c5a612 |
nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
|
|
Packit |
c5a612 |
flags, seqnum);
|
|
Packit |
c5a612 |
ret = nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter);
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(batch);
|
|
Packit |
c5a612 |
if (ret <= 0)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_elems_iter_destroy(iter);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
|
|
Packit |
c5a612 |
const struct expr *expr, unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct handle *h = &set->handle;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (nls == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
|
|
Packit |
c5a612 |
if (h->set_id)
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_ID, h->set_id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
alloc_setelem_cache(expr, nls);
|
|
Packit |
c5a612 |
netlink_dump_set(nls, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_NEWSETELEM, flags,
|
|
Packit |
c5a612 |
ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return err;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_setelem_flush(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct handle *h = &cmd->handle;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (nls == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
|
|
Packit |
c5a612 |
if (h->handle.id)
|
|
Packit |
c5a612 |
nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_dump_set(nls, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELSETELEM,
|
|
Packit |
c5a612 |
h->family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_elems_nlmsg_build_payload(nlh, nls);
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
const struct handle *h = &cmd->handle;
|
|
Packit |
c5a612 |
struct nftnl_set *nls;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (nls == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
|
|
Packit |
c5a612 |
if (h->set.name)
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
|
|
Packit |
c5a612 |
else if (h->handle.id)
|
|
Packit |
c5a612 |
nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (cmd->expr)
|
|
Packit |
c5a612 |
alloc_setelem_cache(cmd->expr, nls);
|
|
Packit |
c5a612 |
netlink_dump_set(nls, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_DELSETELEM, 0,
|
|
Packit |
c5a612 |
ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_free(nls);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return err;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_set *mnl_nft_setelem_get_one(struct netlink_ctx *ctx,
|
|
Packit |
c5a612 |
struct nftnl_set *nls_in)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nftnl_set *nls_out;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
int err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM,
|
|
Packit |
c5a612 |
nftnl_set_get_u32(nls_in, NFTNL_SET_FAMILY),
|
|
Packit |
c5a612 |
NLM_F_ACK, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_elems_nlmsg_build_payload(nlh, nls_in);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nls_out = nftnl_set_alloc();
|
|
Packit |
c5a612 |
if (!nls_out)
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls_out, NFTNL_SET_TABLE,
|
|
Packit |
c5a612 |
nftnl_set_get_str(nls_in, NFTNL_SET_TABLE));
|
|
Packit |
c5a612 |
nftnl_set_set_str(nls_out, NFTNL_SET_NAME,
|
|
Packit |
c5a612 |
nftnl_set_get_str(nls_in, NFTNL_SET_NAME));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_elem_cb, nls_out);
|
|
Packit |
c5a612 |
if (err < 0) {
|
|
Packit |
c5a612 |
nftnl_set_free(nls_out);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nls_out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_setelem_get(struct netlink_ctx *ctx, struct nftnl_set *nls)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM,
|
|
Packit |
c5a612 |
nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
|
|
Packit |
c5a612 |
NLM_F_DUMP, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_set_elems_nlmsg_build_payload(nlh, nls);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_elem_cb, nls);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int flowtable_cb(const struct nlmsghdr *nlh, void *data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_flowtable_list *nln_list = data;
|
|
Packit |
c5a612 |
struct nftnl_flowtable *n;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (check_genid(nlh) < 0)
|
|
Packit |
c5a612 |
return MNL_CB_ERROR;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = nftnl_flowtable_alloc();
|
|
Packit |
c5a612 |
if (n == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nftnl_flowtable_nlmsg_parse(nlh, n) < 0)
|
|
Packit |
c5a612 |
goto err_free;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_flowtable_list_add_tail(n, nln_list);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
err_free:
|
|
Packit |
c5a612 |
nftnl_flowtable_free(n);
|
|
Packit |
c5a612 |
return MNL_CB_OK;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
struct nftnl_flowtable_list *
|
|
Packit |
c5a612 |
mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_flowtable_list *nln_list;
|
|
Packit |
c5a612 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
Packit |
c5a612 |
struct nftnl_flowtable *n;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
n = nftnl_flowtable_alloc();
|
|
Packit |
c5a612 |
if (n == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
|
|
Packit |
c5a612 |
NLM_F_DUMP, ctx->seqnum);
|
|
Packit |
c5a612 |
if (table != NULL)
|
|
Packit |
c5a612 |
nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_TABLE, table);
|
|
Packit |
c5a612 |
nftnl_flowtable_nlmsg_build_payload(nlh, n);
|
|
Packit |
c5a612 |
nftnl_flowtable_free(n);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nln_list = nftnl_flowtable_list_alloc();
|
|
Packit |
c5a612 |
if (nln_list == NULL)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return nln_list;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
nftnl_flowtable_list_free(nln_list);
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
|
|
Packit |
c5a612 |
unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_flowtable *flo;
|
|
Packit |
c5a612 |
const char **dev_array;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
int i = 0, len = 1;
|
|
Packit |
c5a612 |
struct expr *expr;
|
|
Packit |
c5a612 |
int priority;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
flo = nftnl_flowtable_alloc();
|
|
Packit |
c5a612 |
if (!flo)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
|
|
Packit |
c5a612 |
cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
|
|
Packit |
c5a612 |
cmd->handle.table.name);
|
|
Packit |
c5a612 |
nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
|
|
Packit |
c5a612 |
cmd->handle.flowtable.name);
|
|
Packit |
c5a612 |
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM,
|
|
Packit |
c5a612 |
cmd->flowtable->hooknum);
|
|
Packit |
c5a612 |
mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
|
|
Packit |
c5a612 |
BYTEORDER_HOST_ENDIAN, sizeof(int));
|
|
Packit |
c5a612 |
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, priority);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
|
|
Packit |
c5a612 |
len++;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dev_array = calloc(len, sizeof(char *));
|
|
Packit |
c5a612 |
list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
|
|
Packit |
c5a612 |
dev_array[i++] = expr->identifier;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
dev_array[i] = NULL;
|
|
Packit |
c5a612 |
nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
|
|
Packit |
c5a612 |
dev_array, sizeof(char *) * len);
|
|
Packit |
c5a612 |
free(dev_array);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
netlink_dump_flowtable(flo, ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_NEWFLOWTABLE, cmd->handle.family,
|
|
Packit |
c5a612 |
NLM_F_CREATE | flags, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_flowtable_nlmsg_build_payload(nlh, flo);
|
|
Packit |
c5a612 |
nftnl_flowtable_free(flo);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct nftnl_flowtable *flo;
|
|
Packit |
c5a612 |
struct nlmsghdr *nlh;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
flo = nftnl_flowtable_alloc();
|
|
Packit |
c5a612 |
if (!flo)
|
|
Packit |
c5a612 |
memory_allocation_error();
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
|
|
Packit |
c5a612 |
cmd->handle.family);
|
|
Packit |
c5a612 |
nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
|
|
Packit |
c5a612 |
cmd->handle.table.name);
|
|
Packit |
c5a612 |
if (cmd->handle.flowtable.name)
|
|
Packit |
c5a612 |
nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
|
|
Packit |
c5a612 |
cmd->handle.flowtable.name);
|
|
Packit |
c5a612 |
else if (cmd->handle.handle.id)
|
|
Packit |
c5a612 |
nftnl_flowtable_set_u64(flo, NFTNL_FLOWTABLE_HANDLE,
|
|
Packit |
c5a612 |
cmd->handle.handle.id);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
|
|
Packit |
c5a612 |
NFT_MSG_DELFLOWTABLE, cmd->handle.family,
|
|
Packit |
c5a612 |
0, ctx->seqnum);
|
|
Packit |
c5a612 |
nftnl_flowtable_nlmsg_build_payload(nlh, flo);
|
|
Packit |
c5a612 |
nftnl_flowtable_free(flo);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
mnl_nft_batch_continue(ctx->batch);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* events
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
#define NFTABLES_NLEVENT_BUFSIZ (1 << 24)
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
|
|
Packit |
c5a612 |
struct output_ctx *octx,
|
|
Packit |
c5a612 |
int (*cb)(const struct nlmsghdr *nlh, void *data),
|
|
Packit |
c5a612 |
void *cb_data)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
/* Set netlink socket buffer size to 16 Mbytes to reduce chances of
|
|
Packit |
c5a612 |
* message loss due to ENOBUFS.
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ;
|
|
Packit |
c5a612 |
int fd = mnl_socket_get_fd(nf_sock);
|
|
Packit |
c5a612 |
char buf[NFT_NLMSG_MAXSIZE];
|
|
Packit |
c5a612 |
fd_set readfds;
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_set_rcvbuffer(nf_sock, bufsiz);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
nft_print(octx, "# Cannot set up netlink receive socket buffer size to %u bytes, falling back to %u bytes\n",
|
|
Packit |
c5a612 |
NFTABLES_NLEVENT_BUFSIZ, bufsiz);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (1) {
|
|
Packit |
c5a612 |
FD_ZERO(&readfds);
|
|
Packit |
c5a612 |
FD_SET(fd, &readfds);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = select(fd + 1, &readfds, NULL, NULL, NULL);
|
|
Packit |
c5a612 |
if (ret < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (FD_ISSET(fd, &readfds)) {
|
|
Packit |
c5a612 |
ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
|
|
Packit |
c5a612 |
if (ret < 0) {
|
|
Packit |
c5a612 |
if (errno == ENOBUFS) {
|
|
Packit |
c5a612 |
nft_print(octx, "# ERROR: We lost some netlink events!\n");
|
|
Packit |
c5a612 |
continue;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
nft_print(octx, "# ERROR: %s\n",
|
|
Packit |
c5a612 |
strerror(errno));
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (debug_mask & NFT_DEBUG_MNL) {
|
|
Packit |
c5a612 |
mnl_nlmsg_fprintf(octx->output_fp, buf, sizeof(buf),
|
|
Packit |
c5a612 |
sizeof(struct nfgenmsg));
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
ret = mnl_cb_run(buf, ret, 0, 0, cb, cb_data);
|
|
Packit |
c5a612 |
if (ret <= 0)
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return ret;
|
|
Packit |
c5a612 |
}
|