Blame iptables/nft.c

Packit Service d1fe03
/*
Packit Service d1fe03
 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
Packit Service d1fe03
 *
Packit Service d1fe03
 * This program is free software; you can redistribute it and/or modify
Packit Service d1fe03
 * it under the terms of the GNU General Public License as published
Packit Service d1fe03
 * by the Free Software Foundation; either version 2 of the License, or
Packit Service d1fe03
 * (at your option) any later version.
Packit Service d1fe03
 *
Packit Service d1fe03
 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
Packit Service d1fe03
 */
Packit Service d1fe03
Packit Service d1fe03
#include <unistd.h>
Packit Service d1fe03
#include <fcntl.h>
Packit Service d1fe03
#include <sys/types.h>
Packit Service d1fe03
#include <sys/socket.h>
Packit Service d1fe03
#include <stdbool.h>
Packit Service d1fe03
#include <errno.h>
Packit Service d1fe03
#include <netdb.h>	/* getprotobynumber */
Packit Service d1fe03
#include <time.h>
Packit Service d1fe03
#include <stdarg.h>
Packit Service d1fe03
#include <inttypes.h>
Packit Service d1fe03
#include <assert.h>
Packit Service d1fe03
Packit Service d1fe03
#include <xtables.h>
Packit Service d1fe03
#include <libiptc/libxtc.h>
Packit Service d1fe03
#include <libiptc/xtcshared.h>
Packit Service d1fe03
Packit Service d1fe03
#include <stdlib.h>
Packit Service d1fe03
#include <string.h>
Packit Service d1fe03
Packit Service d1fe03
#include <linux/netfilter/x_tables.h>
Packit Service d1fe03
#include <linux/netfilter_ipv4/ip_tables.h>
Packit Service d1fe03
#include <linux/netfilter_ipv6/ip6_tables.h>
Packit Service d1fe03
#include <netinet/ip6.h>
Packit Service d1fe03
Packit Service d1fe03
#include <linux/netlink.h>
Packit Service d1fe03
#include <linux/netfilter/nfnetlink.h>
Packit Service d1fe03
#include <linux/netfilter/nf_tables.h>
Packit Service d1fe03
#include <linux/netfilter/nf_tables_compat.h>
Packit Service d1fe03
Packit Service d1fe03
#include <linux/netfilter/xt_limit.h>
Packit Service d1fe03
Packit Service d1fe03
#include <libmnl/libmnl.h>
Packit Service d1fe03
#include <libnftnl/gen.h>
Packit Service d1fe03
#include <libnftnl/table.h>
Packit Service d1fe03
#include <libnftnl/chain.h>
Packit Service d1fe03
#include <libnftnl/rule.h>
Packit Service d1fe03
#include <libnftnl/expr.h>
Packit Service d1fe03
#include <libnftnl/set.h>
Packit Service d1fe03
#include <libnftnl/udata.h>
Packit Service d1fe03
#include <libnftnl/batch.h>
Packit Service d1fe03
Packit Service d1fe03
#include <netinet/in.h>	/* inet_ntoa */
Packit Service d1fe03
#include <arpa/inet.h>
Packit Service d1fe03
Packit Service d1fe03
#include "nft.h"
Packit Service d1fe03
#include "xshared.h" /* proto_to_name */
Packit Service d1fe03
#include "nft-cache.h"
Packit Service d1fe03
#include "nft-shared.h"
Packit Service d1fe03
#include "nft-bridge.h" /* EBT_NOPROTO */
Packit Service d1fe03
Packit Service d1fe03
static void *nft_fn;
Packit Service d1fe03
Packit Service d1fe03
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
Packit Service d1fe03
	     int (*cb)(const struct nlmsghdr *nlh, void *data),
Packit Service d1fe03
	     void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	int ret;
Packit Service d1fe03
	char buf[32768];
Packit Service d1fe03
Packit Service d1fe03
	if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
Packit Service d1fe03
	while (ret > 0) {
Packit Service d1fe03
		ret = mnl_cb_run(buf, ret, h->seq, h->portid, cb, data);
Packit Service d1fe03
		if (ret <= 0)
Packit Service d1fe03
			break;
Packit Service d1fe03
Packit Service d1fe03
		ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
Packit Service d1fe03
	}
Packit Service d1fe03
	if (ret == -1) {
Packit Service d1fe03
		return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
Packit Service d1fe03
Packit Service d1fe03
/* selected batch page is 256 Kbytes long to load ruleset of
Packit Service d1fe03
 * half a million rules without hitting -EMSGSIZE due to large
Packit Service d1fe03
 * iovec.
Packit Service d1fe03
 */
Packit Service d1fe03
#define BATCH_PAGE_SIZE getpagesize() * 32
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_batch *mnl_batch_init(void)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_batch *batch;
Packit Service d1fe03
Packit Service d1fe03
	batch = nftnl_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE);
Packit Service d1fe03
	if (batch == NULL)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	return batch;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void mnl_nft_batch_continue(struct nftnl_batch *batch)
Packit Service d1fe03
{
Packit Service d1fe03
	assert(nftnl_batch_update(batch) >= 0);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
Packit Service d1fe03
	nlh = nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
Packit Service d1fe03
Packit Service d1fe03
	mnl_attr_put_u32(nlh, NFTA_GEN_ID, htonl(genid));
Packit Service d1fe03
Packit Service d1fe03
	mnl_nft_batch_continue(batch);
Packit Service d1fe03
Packit Service d1fe03
	return seqnum;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum)
Packit Service d1fe03
{
Packit Service d1fe03
	nftnl_batch_end(nftnl_batch_buffer(batch), seqnum);
Packit Service d1fe03
	mnl_nft_batch_continue(batch);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void mnl_batch_reset(struct nftnl_batch *batch)
Packit Service d1fe03
{
Packit Service d1fe03
	nftnl_batch_free(batch);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
struct mnl_err {
Packit Service d1fe03
	struct list_head	head;
Packit Service d1fe03
	int			err;
Packit Service d1fe03
	uint32_t		seqnum;
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
static void mnl_err_list_node_add(struct list_head *err_list, int error,
Packit Service d1fe03
				  int seqnum)
Packit Service d1fe03
{
Packit Service d1fe03
	struct mnl_err *err = malloc(sizeof(struct mnl_err));
Packit Service d1fe03
Packit Service d1fe03
	err->seqnum = seqnum;
Packit Service d1fe03
	err->err = error;
Packit Service d1fe03
	list_add_tail(&err->head, err_list);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void mnl_err_list_free(struct mnl_err *err)
Packit Service d1fe03
{
Packit Service d1fe03
	list_del(&err->head);
Packit Service d1fe03
	free(err);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void mnl_set_sndbuffer(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	int newbuffsiz = nftnl_batch_iovec_len(h->batch) * BATCH_PAGE_SIZE;
Packit Service d1fe03
Packit Service d1fe03
	if (newbuffsiz <= h->nlsndbuffsiz)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	/* Rise sender buffer length to avoid hitting -EMSGSIZE */
Packit Service d1fe03
	if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_SNDBUFFORCE,
Packit Service d1fe03
		       &newbuffsiz, sizeof(socklen_t)) < 0)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	h->nlsndbuffsiz = newbuffsiz;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void mnl_set_rcvbuffer(struct nft_handle *h, int numcmds)
Packit Service d1fe03
{
Packit Service d1fe03
	int newbuffsiz = getpagesize() * numcmds;
Packit Service d1fe03
Packit Service d1fe03
	if (newbuffsiz <= h->nlrcvbuffsiz)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	/* Rise receiver buffer length to avoid hitting -ENOBUFS */
Packit Service d1fe03
	if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_RCVBUFFORCE,
Packit Service d1fe03
		       &newbuffsiz, sizeof(socklen_t)) < 0)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	h->nlrcvbuffsiz = newbuffsiz;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static ssize_t mnl_nft_socket_sendmsg(struct nft_handle *h, int numcmds)
Packit Service d1fe03
{
Packit Service d1fe03
	static const struct sockaddr_nl snl = {
Packit Service d1fe03
		.nl_family = AF_NETLINK
Packit Service d1fe03
	};
Packit Service d1fe03
	uint32_t iov_len = nftnl_batch_iovec_len(h->batch);
Packit Service d1fe03
	struct iovec iov[iov_len];
Packit Service d1fe03
	struct msghdr msg = {
Packit Service d1fe03
		.msg_name	= (struct sockaddr *) &snl,
Packit Service d1fe03
		.msg_namelen	= sizeof(snl),
Packit Service d1fe03
		.msg_iov	= iov,
Packit Service d1fe03
		.msg_iovlen	= iov_len,
Packit Service d1fe03
	};
Packit Service d1fe03
Packit Service d1fe03
	mnl_set_sndbuffer(h);
Packit Service d1fe03
	mnl_set_rcvbuffer(h, numcmds);
Packit Service d1fe03
	nftnl_batch_iovec(h->batch, iov, iov_len);
Packit Service d1fe03
Packit Service d1fe03
	return sendmsg(mnl_socket_get_fd(h->nl), &msg, 0);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int mnl_batch_talk(struct nft_handle *h, int numcmds)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct mnl_socket *nl = h->nl;
Packit Service d1fe03
	int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
Packit Service d1fe03
	char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
Packit Service d1fe03
	fd_set readfds;
Packit Service d1fe03
	struct timeval tv = {
Packit Service d1fe03
		.tv_sec		= 0,
Packit Service d1fe03
		.tv_usec	= 0
Packit Service d1fe03
	};
Packit Service d1fe03
	int err = 0;
Packit Service d1fe03
Packit Service d1fe03
	ret = mnl_nft_socket_sendmsg(h, numcmds);
Packit Service d1fe03
	if (ret == -1)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	FD_ZERO(&readfds);
Packit Service d1fe03
	FD_SET(fd, &readfds);
Packit Service d1fe03
Packit Service d1fe03
	/* receive and digest all the acknowledgments from the kernel. */
Packit Service d1fe03
	ret = select(fd+1, &readfds, NULL, NULL, &tv;;
Packit Service d1fe03
	if (ret == -1)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	while (ret > 0 && FD_ISSET(fd, &readfds)) {
Packit Service d1fe03
		struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
Packit Service d1fe03
Packit Service d1fe03
		ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
Packit Service d1fe03
		if (ret == -1)
Packit Service d1fe03
			return -1;
Packit Service d1fe03
Packit Service d1fe03
		ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL);
Packit Service d1fe03
		/* Continue on error, make sure we get all acknowledgments */
Packit Service d1fe03
		if (ret == -1) {
Packit Service d1fe03
			mnl_err_list_node_add(&h->err_list, errno,
Packit Service d1fe03
					      nlh->nlmsg_seq);
Packit Service d1fe03
			err = -1;
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		ret = select(fd+1, &readfds, NULL, NULL, &tv;;
Packit Service d1fe03
		if (ret == -1)
Packit Service d1fe03
			return -1;
Packit Service d1fe03
Packit Service d1fe03
		FD_ZERO(&readfds);
Packit Service d1fe03
		FD_SET(fd, &readfds);
Packit Service d1fe03
	}
Packit Service d1fe03
	return err;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
enum obj_update_type {
Packit Service d1fe03
	NFT_COMPAT_TABLE_ADD,
Packit Service d1fe03
	NFT_COMPAT_TABLE_FLUSH,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_ADD,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_USER_ADD,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_USER_DEL,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_USER_FLUSH,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_UPDATE,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_RENAME,
Packit Service d1fe03
	NFT_COMPAT_CHAIN_ZERO,
Packit Service d1fe03
	NFT_COMPAT_RULE_APPEND,
Packit Service d1fe03
	NFT_COMPAT_RULE_INSERT,
Packit Service d1fe03
	NFT_COMPAT_RULE_REPLACE,
Packit Service d1fe03
	NFT_COMPAT_RULE_DELETE,
Packit Service d1fe03
	NFT_COMPAT_RULE_FLUSH,
Packit Service d1fe03
	NFT_COMPAT_SET_ADD,
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
enum obj_action {
Packit Service d1fe03
	NFT_COMPAT_COMMIT,
Packit Service d1fe03
	NFT_COMPAT_ABORT,
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
struct obj_update {
Packit Service d1fe03
	struct list_head	head;
Packit Service d1fe03
	enum obj_update_type	type:8;
Packit Service d1fe03
	uint8_t			skip:1;
Packit Service d1fe03
	uint8_t			implicit:1;
Packit Service d1fe03
	unsigned int		seq;
Packit Service d1fe03
	union {
Packit Service d1fe03
		struct nftnl_table	*table;
Packit Service d1fe03
		struct nftnl_chain	*chain;
Packit Service d1fe03
		struct nftnl_rule	*rule;
Packit Service d1fe03
		struct nftnl_set	*set;
Packit Service d1fe03
		void			*ptr;
Packit Service d1fe03
	};
Packit Service d1fe03
	struct {
Packit Service d1fe03
		unsigned int		lineno;
Packit Service d1fe03
	} error;
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
static int mnl_append_error(const struct nft_handle *h,
Packit Service d1fe03
			    const struct obj_update *o,
Packit Service d1fe03
			    const struct mnl_err *err,
Packit Service d1fe03
			    char *buf, unsigned int len)
Packit Service d1fe03
{
Packit Service d1fe03
	static const char *type_name[] = {
Packit Service d1fe03
		[NFT_COMPAT_TABLE_ADD] = "TABLE_ADD",
Packit Service d1fe03
		[NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
Packit Service d1fe03
		[NFT_COMPAT_CHAIN_ZERO] = "CHAIN_ZERO",
Packit Service d1fe03
		[NFT_COMPAT_RULE_APPEND] = "RULE_APPEND",
Packit Service d1fe03
		[NFT_COMPAT_RULE_INSERT] = "RULE_INSERT",
Packit Service d1fe03
		[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
Packit Service d1fe03
		[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
Packit Service d1fe03
		[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
Packit Service d1fe03
		[NFT_COMPAT_SET_ADD] = "SET_ADD",
Packit Service d1fe03
	};
Packit Service d1fe03
	char errmsg[256];
Packit Service d1fe03
	char tcr[128];
Packit Service d1fe03
Packit Service d1fe03
	if (o->error.lineno)
Packit Service d1fe03
		snprintf(errmsg, sizeof(errmsg), "\nline %u: %s failed (%s)",
Packit Service d1fe03
			 o->error.lineno, type_name[o->type], strerror(err->err));
Packit Service d1fe03
	else
Packit Service d1fe03
		snprintf(errmsg, sizeof(errmsg), " %s failed (%s)",
Packit Service d1fe03
			 type_name[o->type], strerror(err->err));
Packit Service d1fe03
Packit Service d1fe03
	switch (o->type) {
Packit Service d1fe03
	case NFT_COMPAT_TABLE_ADD:
Packit Service d1fe03
	case NFT_COMPAT_TABLE_FLUSH:
Packit Service d1fe03
		snprintf(tcr, sizeof(tcr), "table %s",
Packit Service d1fe03
			 nftnl_table_get_str(o->table, NFTNL_TABLE_NAME));
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_ADD:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_ZERO:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_UPDATE:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_RENAME:
Packit Service d1fe03
		snprintf(tcr, sizeof(tcr), "chain %s",
Packit Service d1fe03
			 nftnl_chain_get_str(o->chain, NFTNL_CHAIN_NAME));
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_RULE_APPEND:
Packit Service d1fe03
	case NFT_COMPAT_RULE_INSERT:
Packit Service d1fe03
	case NFT_COMPAT_RULE_REPLACE:
Packit Service d1fe03
	case NFT_COMPAT_RULE_DELETE:
Packit Service d1fe03
	case NFT_COMPAT_RULE_FLUSH:
Packit Service d1fe03
		snprintf(tcr, sizeof(tcr), "rule in chain %s",
Packit Service d1fe03
			 nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
Packit Service d1fe03
#if 0
Packit Service d1fe03
		{
Packit Service d1fe03
			nft_rule_print_save(h, o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
Packit Service d1fe03
		}
Packit Service d1fe03
#endif
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_SET_ADD:
Packit Service d1fe03
		snprintf(tcr, sizeof(tcr), "set %s",
Packit Service d1fe03
			 nftnl_set_get_str(o->set, NFTNL_SET_NAME));
Packit Service d1fe03
		break;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return snprintf(buf, len, "%s: %s", errmsg, tcr);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
Packit Service d1fe03
{
Packit Service d1fe03
	struct obj_update *obj;
Packit Service d1fe03
Packit Service d1fe03
	obj = calloc(1, sizeof(struct obj_update));
Packit Service d1fe03
	if (obj == NULL)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	obj->ptr = ptr;
Packit Service d1fe03
	obj->error.lineno = h->error.lineno;
Packit Service d1fe03
	obj->type = type;
Packit Service d1fe03
	list_add_tail(&obj->head, &h->obj_list);
Packit Service d1fe03
	h->obj_list_num++;
Packit Service d1fe03
Packit Service d1fe03
	return obj;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct obj_update *
Packit Service d1fe03
batch_table_add(struct nft_handle *h, enum obj_update_type type,
Packit Service d1fe03
		struct nftnl_table *t)
Packit Service d1fe03
{
Packit Service d1fe03
	return batch_add(h, type, t);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct obj_update *
Packit Service d1fe03
batch_set_add(struct nft_handle *h, enum obj_update_type type,
Packit Service d1fe03
	      struct nftnl_set *s)
Packit Service d1fe03
{
Packit Service d1fe03
	return batch_add(h, type, s);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
Packit Service d1fe03
			   struct nftnl_chain *c)
Packit Service d1fe03
{
Packit Service d1fe03
	return batch_add(h, type, c) ? 0 : -1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct obj_update *
Packit Service d1fe03
batch_rule_add(struct nft_handle *h, enum obj_update_type type,
Packit Service d1fe03
			  struct nftnl_rule *r)
Packit Service d1fe03
{
Packit Service d1fe03
	return batch_add(h, type, r);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
Packit Service d1fe03
	[NFT_TABLE_RAW] = {
Packit Service d1fe03
		.name	= "raw",
Packit Service d1fe03
		.type	= NFT_TABLE_RAW,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "PREROUTING",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= -300,	/* NF_IP_PRI_RAW */
Packit Service d1fe03
				.hook	= NF_INET_PRE_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "OUTPUT",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= -300,	/* NF_IP_PRI_RAW */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
	[NFT_TABLE_MANGLE] = {
Packit Service d1fe03
		.name	= "mangle",
Packit Service d1fe03
		.type	= NFT_TABLE_MANGLE,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "PREROUTING",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service d1fe03
				.hook	= NF_INET_PRE_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "INPUT",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_IN,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "FORWARD",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service d1fe03
				.hook	= NF_INET_FORWARD,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "OUTPUT",
Packit Service d1fe03
				.type	= "route",
Packit Service d1fe03
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "POSTROUTING",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service d1fe03
				.hook	= NF_INET_POST_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
	[NFT_TABLE_FILTER] = {
Packit Service d1fe03
		.name	= "filter",
Packit Service d1fe03
		.type	= NFT_TABLE_FILTER,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "INPUT",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= 0,	/* NF_IP_PRI_FILTER */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_IN,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "FORWARD",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= 0,	/* NF_IP_PRI_FILTER */
Packit Service d1fe03
				.hook	= NF_INET_FORWARD,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "OUTPUT",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= 0,	/* NF_IP_PRI_FILTER */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
	[NFT_TABLE_SECURITY] = {
Packit Service d1fe03
		.name	= "security",
Packit Service d1fe03
		.type	= NFT_TABLE_SECURITY,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "INPUT",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= 150,	/* NF_IP_PRI_SECURITY */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_IN,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "FORWARD",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= 150,	/* NF_IP_PRI_SECURITY */
Packit Service d1fe03
				.hook	= NF_INET_FORWARD,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "OUTPUT",
Packit Service d1fe03
				.type	= "filter",
Packit Service d1fe03
				.prio	= 150,	/* NF_IP_PRI_SECURITY */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
	[NFT_TABLE_NAT] = {
Packit Service d1fe03
		.name	= "nat",
Packit Service d1fe03
		.type	= NFT_TABLE_NAT,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "PREROUTING",
Packit Service d1fe03
				.type	= "nat",
Packit Service d1fe03
				.prio	= -100, /* NF_IP_PRI_NAT_DST */
Packit Service d1fe03
				.hook	= NF_INET_PRE_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "INPUT",
Packit Service d1fe03
				.type	= "nat",
Packit Service d1fe03
				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_IN,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "POSTROUTING",
Packit Service d1fe03
				.type	= "nat",
Packit Service d1fe03
				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
Packit Service d1fe03
				.hook	= NF_INET_POST_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name	= "OUTPUT",
Packit Service d1fe03
				.type	= "nat",
Packit Service d1fe03
				.prio	= -100, /* NF_IP_PRI_NAT_DST */
Packit Service d1fe03
				.hook	= NF_INET_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
#include <linux/netfilter_arp.h>
Packit Service d1fe03
Packit Service d1fe03
const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
Packit Service d1fe03
	[NFT_TABLE_FILTER] = {
Packit Service d1fe03
	.name   = "filter",
Packit Service d1fe03
	.type	= NFT_TABLE_FILTER,
Packit Service d1fe03
	.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "INPUT",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_IP_PRI_FILTER,
Packit Service d1fe03
				.hook   = NF_ARP_IN,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "OUTPUT",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_IP_PRI_FILTER,
Packit Service d1fe03
				.hook   = NF_ARP_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
#include <linux/netfilter_bridge.h>
Packit Service d1fe03
Packit Service d1fe03
const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
Packit Service d1fe03
	[NFT_TABLE_FILTER] = {
Packit Service d1fe03
		.name = "filter",
Packit Service d1fe03
		.type	= NFT_TABLE_FILTER,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "INPUT",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_BR_PRI_FILTER_BRIDGED,
Packit Service d1fe03
				.hook   = NF_BR_LOCAL_IN,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "FORWARD",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_BR_PRI_FILTER_BRIDGED,
Packit Service d1fe03
				.hook   = NF_BR_FORWARD,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "OUTPUT",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_BR_PRI_FILTER_BRIDGED,
Packit Service d1fe03
				.hook   = NF_BR_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
	[NFT_TABLE_NAT] = {
Packit Service d1fe03
		.name = "nat",
Packit Service d1fe03
		.type	= NFT_TABLE_NAT,
Packit Service d1fe03
		.chains = {
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "PREROUTING",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_BR_PRI_NAT_DST_BRIDGED,
Packit Service d1fe03
				.hook   = NF_BR_PRE_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "OUTPUT",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_BR_PRI_NAT_DST_OTHER,
Packit Service d1fe03
				.hook   = NF_BR_LOCAL_OUT,
Packit Service d1fe03
			},
Packit Service d1fe03
			{
Packit Service d1fe03
				.name   = "POSTROUTING",
Packit Service d1fe03
				.type   = "filter",
Packit Service d1fe03
				.prio   = NF_BR_PRI_NAT_SRC,
Packit Service d1fe03
				.hook   = NF_BR_POST_ROUTING,
Packit Service d1fe03
			},
Packit Service d1fe03
		},
Packit Service d1fe03
	},
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
static bool nft_table_initialized(const struct nft_handle *h,
Packit Service d1fe03
				  enum nft_table_type type)
Packit Service d1fe03
{
Packit Service d1fe03
	return h->cache->table[type].initialized;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_table_builtin_add(struct nft_handle *h,
Packit Service d1fe03
				 const struct builtin_table *_t)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_table *t;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	if (nft_table_initialized(h, _t->type))
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	t = nftnl_table_alloc();
Packit Service d1fe03
	if (t == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
Packit Service d1fe03
Packit Service d1fe03
	ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_chain *
Packit Service d1fe03
nft_chain_builtin_alloc(const struct builtin_table *table,
Packit Service d1fe03
			const struct builtin_chain *chain, int policy)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_alloc();
Packit Service d1fe03
	if (c == NULL)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name);
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
Packit Service d1fe03
	nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
Packit Service d1fe03
	nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
Packit Service d1fe03
	nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
Packit Service d1fe03
Packit Service d1fe03
	return c;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_chain_builtin_add(struct nft_handle *h,
Packit Service d1fe03
				  const struct builtin_table *table,
Packit Service d1fe03
				  const struct builtin_chain *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
Packit Service d1fe03
	if (c == NULL)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
Packit Service d1fe03
	nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
/* find if built-in table already exists */
Packit Service d1fe03
const struct builtin_table *
Packit Service d1fe03
nft_table_builtin_find(struct nft_handle *h, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	int i;
Packit Service d1fe03
	bool found = false;
Packit Service d1fe03
Packit Service d1fe03
	for (i = 0; i < NFT_TABLE_MAX; i++) {
Packit Service d1fe03
		if (h->tables[i].name == NULL)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		if (strcmp(h->tables[i].name, table) != 0)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		found = true;
Packit Service d1fe03
		break;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return found ? &h->tables[i] : NULL;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
/* find if built-in chain already exists */
Packit Service d1fe03
const struct builtin_chain *
Packit Service d1fe03
nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	int i;
Packit Service d1fe03
	bool found = false;
Packit Service d1fe03
Packit Service d1fe03
	for (i=0; i<NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
Packit Service d1fe03
		if (strcmp(t->chains[i].name, chain) != 0)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		found = true;
Packit Service d1fe03
		break;
Packit Service d1fe03
	}
Packit Service d1fe03
	return found ? &t->chains[i] : NULL;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_chain_builtin_init(struct nft_handle *h,
Packit Service d1fe03
				   const struct builtin_table *table)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	int i;
Packit Service d1fe03
Packit Service d1fe03
	/* Initialize built-in chains if they don't exist yet */
Packit Service d1fe03
	for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
Packit Service d1fe03
		list = nft_chain_list_get(h, table->name,
Packit Service d1fe03
					  table->chains[i].name);
Packit Service d1fe03
		if (!list)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, table->chains[i].name);
Packit Service d1fe03
		if (c != NULL)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		nft_chain_builtin_add(h, table, &table->chains[i]);
Packit Service d1fe03
	}
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct builtin_table *t;
Packit Service d1fe03
Packit Service d1fe03
	t = nft_table_builtin_find(h, table);
Packit Service d1fe03
	if (t == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	if (nft_table_initialized(h, t->type))
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (nft_table_builtin_add(h, t) < 0)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	nft_chain_builtin_init(h, t);
Packit Service d1fe03
Packit Service d1fe03
	h->cache->table[t->type].initialized = true;
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static bool nft_chain_builtin(struct nftnl_chain *c)
Packit Service d1fe03
{
Packit Service d1fe03
	/* Check if this chain has hook number, in that case is built-in.
Packit Service d1fe03
	 * Should we better export the flags to user-space via nf_tables?
Packit Service d1fe03
	 */
Packit Service d1fe03
	return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_restart(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	mnl_socket_close(h->nl);
Packit Service d1fe03
Packit Service d1fe03
	h->nl = mnl_socket_open(NETLINK_NETFILTER);
Packit Service d1fe03
	if (h->nl == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	h->portid = mnl_socket_get_portid(h->nl);
Packit Service d1fe03
	h->nlsndbuffsiz = 0;
Packit Service d1fe03
	h->nlrcvbuffsiz = 0;
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service ae2aec
int nft_init(struct nft_handle *h, const struct builtin_table *t)
Packit Service d1fe03
{
Packit Service d1fe03
	h->nl = mnl_socket_open(NETLINK_NETFILTER);
Packit Service d1fe03
	if (h->nl == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
Packit Service d1fe03
		mnl_socket_close(h->nl);
Packit Service d1fe03
		return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	h->portid = mnl_socket_get_portid(h->nl);
Packit Service d1fe03
	h->tables = t;
Packit Service d1fe03
	h->cache = &h->__cache[0];
Packit Service d1fe03
Packit Service d1fe03
	INIT_LIST_HEAD(&h->obj_list);
Packit Service d1fe03
	INIT_LIST_HEAD(&h->err_list);
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
void nft_fini(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	flush_chain_cache(h, NULL);
Packit Service d1fe03
	mnl_socket_close(h->nl);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
Packit Service d1fe03
{
Packit Service d1fe03
#ifdef NLDEBUG
Packit Service d1fe03
	char tmp[1024];
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
Packit Service d1fe03
	printf("DEBUG: chain: %s\n", tmp);
Packit Service d1fe03
	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
Packit Service d1fe03
#endif
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
Packit Service d1fe03
				       const char *table, const char *chain,
Packit Service d1fe03
				       int policy,
Packit Service d1fe03
				       const struct xt_counters *counters)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	const struct builtin_table *_t;
Packit Service d1fe03
	const struct builtin_chain *_c;
Packit Service d1fe03
Packit Service d1fe03
	_t = nft_table_builtin_find(h, table);
Packit Service d1fe03
	if (!_t) {
Packit Service d1fe03
		errno = ENXIO;
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	/* if this built-in table does not exists, create it */
Packit Service d1fe03
	nft_table_builtin_add(h, _t);
Packit Service d1fe03
Packit Service d1fe03
	_c = nft_chain_builtin_find(_t, chain);
Packit Service d1fe03
	if (_c != NULL) {
Packit Service d1fe03
		/* This is a built-in chain */
Packit Service d1fe03
		c = nft_chain_builtin_alloc(_t, _c, policy);
Packit Service d1fe03
		if (c == NULL)
Packit Service d1fe03
			return NULL;
Packit Service d1fe03
	} else {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (counters) {
Packit Service d1fe03
		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES,
Packit Service d1fe03
					counters->bcnt);
Packit Service d1fe03
		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS,
Packit Service d1fe03
					counters->pcnt);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return c;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_set(struct nft_handle *h, const char *table,
Packit Service d1fe03
		  const char *chain, const char *policy,
Packit Service d1fe03
		  const struct xt_counters *counters)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c = NULL;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_chain_set;
Packit Service d1fe03
Packit Service d1fe03
	if (strcmp(policy, "DROP") == 0)
Packit Service d1fe03
		c = nft_chain_new(h, table, chain, NF_DROP, counters);
Packit Service d1fe03
	else if (strcmp(policy, "ACCEPT") == 0)
Packit Service d1fe03
		c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
Packit Service d1fe03
	else
Packit Service d1fe03
		errno = EINVAL;
Packit Service d1fe03
Packit Service d1fe03
	if (c == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c);
Packit Service d1fe03
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
Packit Service d1fe03
{
Packit Service d1fe03
	void *info;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
Packit Service d1fe03
Packit Service d1fe03
	info = calloc(1, m->u.match_size);
Packit Service d1fe03
	if (info == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	memcpy(info, m->data, m->u.match_size - sizeof(*m));
Packit Service d1fe03
	nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
Packit Service d1fe03
{
Packit Service d1fe03
	struct xt_rateinfo *rinfo = (void *)m->data;
Packit Service d1fe03
	static const uint32_t mult[] = {
Packit Service d1fe03
		XT_LIMIT_SCALE*24*60*60,	/* day */
Packit Service d1fe03
		XT_LIMIT_SCALE*60*60,		/* hour */
Packit Service d1fe03
		XT_LIMIT_SCALE*60,		/* min */
Packit Service d1fe03
		XT_LIMIT_SCALE,			/* sec */
Packit Service d1fe03
	};
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
	int i;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("limit");
Packit Service d1fe03
	if (!expr)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	for (i = 1; i < ARRAY_SIZE(mult); i++) {
Packit Service d1fe03
		if (rinfo->avg > mult[i] ||
Packit Service d1fe03
		    mult[i] / rinfo->avg < mult[i] % rinfo->avg)
Packit Service d1fe03
			break;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_TYPE, NFT_LIMIT_PKTS);
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_FLAGS, 0);
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_RATE,
Packit Service d1fe03
			   mult[i - 1] / rinfo->avg);
Packit Service d1fe03
        nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_UNIT,
Packit Service d1fe03
			   mult[i - 1] / XT_LIMIT_SCALE);
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_BURST, rinfo->burst);
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
Packit Service d1fe03
				      uint32_t flags, uint32_t key_type,
Packit Service d1fe03
				      uint32_t key_len, uint32_t size)
Packit Service d1fe03
{
Packit Service d1fe03
	static uint32_t set_id = 0;
Packit Service d1fe03
	struct nftnl_set *s;
Packit Service d1fe03
Packit Service d1fe03
	s = nftnl_set_alloc();
Packit Service d1fe03
	if (!s)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_set_set_u32(s, NFTNL_SET_FAMILY, h->family);
Packit Service d1fe03
	nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
Packit Service d1fe03
	nftnl_set_set_str(s, NFTNL_SET_NAME, "__set%d");
Packit Service d1fe03
	nftnl_set_set_u32(s, NFTNL_SET_ID, ++set_id);
Packit Service d1fe03
	nftnl_set_set_u32(s, NFTNL_SET_FLAGS,
Packit Service d1fe03
			  NFT_SET_ANONYMOUS | NFT_SET_CONSTANT | flags);
Packit Service d1fe03
	nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, key_type);
Packit Service d1fe03
	nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
Packit Service d1fe03
	nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
Packit Service d1fe03
Packit Service d1fe03
	return batch_set_add(h, NFT_COMPAT_SET_ADD, s) ? s : NULL;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_expr *
Packit Service d1fe03
gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *e = nftnl_expr_alloc("payload");
Packit Service d1fe03
Packit Service d1fe03
	if (!e)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
Packit Service d1fe03
	return e;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_expr *
Packit Service d1fe03
gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *e = nftnl_expr_alloc("lookup");
Packit Service d1fe03
Packit Service d1fe03
	if (!e)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
Packit Service d1fe03
	nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SET_ID, set_id);
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_FLAGS, flags);
Packit Service d1fe03
	return e;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
/* simplified nftables:include/netlink.h, netlink_padded_len() */
Packit Service d1fe03
#define NETLINK_ALIGN		4
Packit Service d1fe03
Packit Service d1fe03
/* from nftables:include/datatype.h, TYPE_BITS */
Packit Service d1fe03
#define CONCAT_TYPE_BITS	6
Packit Service d1fe03
Packit Service d1fe03
/* from nftables:include/datatype.h, enum datatypes */
Packit Service d1fe03
#define NFT_DATATYPE_IPADDR	7
Packit Service d1fe03
#define NFT_DATATYPE_ETHERADDR	9
Packit Service d1fe03
Packit Service d1fe03
static int __add_nft_among(struct nft_handle *h, const char *table,
Packit Service d1fe03
			   struct nftnl_rule *r, struct nft_among_pair *pairs,
Packit Service d1fe03
			   int cnt, bool dst, bool inv, bool ip)
Packit Service d1fe03
{
Packit Service d1fe03
	uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN;
Packit Service d1fe03
	/* { !dst, dst } */
Packit Service d1fe03
	static const int eth_addr_off[] = {
Packit Service d1fe03
		offsetof(struct ether_header, ether_shost),
Packit Service d1fe03
		offsetof(struct ether_header, ether_dhost)
Packit Service d1fe03
	};
Packit Service d1fe03
	static const int ip_addr_off[] = {
Packit Service d1fe03
		offsetof(struct iphdr, saddr),
Packit Service d1fe03
		offsetof(struct iphdr, daddr)
Packit Service d1fe03
	};
Packit Service d1fe03
	struct nftnl_expr *e;
Packit Service d1fe03
	struct nftnl_set *s;
Packit Service d1fe03
	int idx = 0;
Packit Service d1fe03
Packit Service d1fe03
	if (ip) {
Packit Service d1fe03
		type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
Packit Service d1fe03
		len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
Packit Service d1fe03
		len &= ~(NETLINK_ALIGN - 1);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service ae2aec
	s = add_anon_set(h, table, 0, type, len, cnt);
Packit Service d1fe03
	if (!s)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
	set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
Packit Service d1fe03
Packit Service d1fe03
	for (idx = 0; idx < cnt; idx++) {
Packit Service d1fe03
		struct nftnl_set_elem *elem = nftnl_set_elem_alloc();
Packit Service d1fe03
Packit Service d1fe03
		if (!elem)
Packit Service d1fe03
			return -ENOMEM;
Packit Service d1fe03
		nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY,
Packit Service d1fe03
				   &pairs[idx], len);
Packit Service d1fe03
		nftnl_set_elem_add(s, elem);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	e = gen_payload(NFT_PAYLOAD_LL_HEADER,
Packit Service d1fe03
			eth_addr_off[dst], ETH_ALEN, NFT_REG_1);
Packit Service d1fe03
	if (!e)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
	nftnl_rule_add_expr(r, e);
Packit Service d1fe03
Packit Service d1fe03
	if (ip) {
Packit Service d1fe03
		e = gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
Packit Service d1fe03
				sizeof(struct in_addr), NFT_REG32_02);
Packit Service d1fe03
		if (!e)
Packit Service d1fe03
			return -ENOMEM;
Packit Service d1fe03
		nftnl_rule_add_expr(r, e);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv);
Packit Service d1fe03
	if (!e)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
	nftnl_rule_add_expr(r, e);
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int add_nft_among(struct nft_handle *h,
Packit Service d1fe03
			 struct nftnl_rule *r, struct xt_entry_match *m)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nft_among_data *data = (struct nft_among_data *)m->data;
Packit Service d1fe03
	const char *table = nftnl_rule_get(r, NFTNL_RULE_TABLE);
Packit Service d1fe03
Packit Service d1fe03
	if ((data->src.cnt && data->src.ip) ||
Packit Service d1fe03
	    (data->dst.cnt && data->dst.ip)) {
Packit Service d1fe03
		uint16_t eth_p_ip = htons(ETH_P_IP);
Packit Service d1fe03
Packit Service d1fe03
		add_meta(r, NFT_META_PROTOCOL);
Packit Service d1fe03
		add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (data->src.cnt)
Packit Service d1fe03
		__add_nft_among(h, table, r, data->pairs, data->src.cnt,
Packit Service d1fe03
				false, data->src.inv, data->src.ip);
Packit Service d1fe03
	if (data->dst.cnt)
Packit Service d1fe03
		__add_nft_among(h, table, r, data->pairs + data->src.cnt,
Packit Service d1fe03
				data->dst.cnt, true, data->dst.inv,
Packit Service d1fe03
				data->dst.ip);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int add_match(struct nft_handle *h,
Packit Service d1fe03
	      struct nftnl_rule *r, struct xt_entry_match *m)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	if (!strcmp(m->u.user.name, "limit"))
Packit Service d1fe03
		return add_nft_limit(r, m);
Packit Service d1fe03
	else if (!strcmp(m->u.user.name, "among"))
Packit Service d1fe03
		return add_nft_among(h, r, m);
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("match");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	ret = __add_match(expr, m);
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
Packit Service d1fe03
{
Packit Service d1fe03
	void *info;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set(e, NFTNL_EXPR_TG_NAME, t->u.user.name,
Packit Service d1fe03
			  strlen(t->u.user.name));
Packit Service d1fe03
	nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
Packit Service d1fe03
Packit Service d1fe03
	info = calloc(1, t->u.target_size);
Packit Service d1fe03
	if (info == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	memcpy(info, t->data, t->u.target_size - sizeof(*t));
Packit Service d1fe03
	nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int add_meta_nftrace(struct nftnl_rule *r)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("immediate");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
Packit Service d1fe03
	nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("meta");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_NFTRACE);
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	if (strcmp(t->u.user.name, "TRACE") == 0)
Packit Service d1fe03
		return add_meta_nftrace(r);
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("target");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	ret = __add_target(expr, t);
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("immediate");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
Packit Service d1fe03
	nftnl_expr_set_str(expr, NFTNL_EXPR_IMM_CHAIN, (char *)name);
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int add_verdict(struct nftnl_rule *r, int verdict)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("immediate");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
Packit Service d1fe03
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
Packit Service d1fe03
	       bool goto_set)
Packit Service d1fe03
{
Packit Service d1fe03
       int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
       /* If no target at all, add nothing (default to continue) */
Packit Service d1fe03
       if (cs->target != NULL) {
Packit Service d1fe03
	       /* Standard target? */
Packit Service d1fe03
	       if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
Packit Service d1fe03
		       ret = add_verdict(r, NF_ACCEPT);
Packit Service d1fe03
	       else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
Packit Service d1fe03
		       ret = add_verdict(r, NF_DROP);
Packit Service d1fe03
	       else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
Packit Service d1fe03
		       ret = add_verdict(r, NFT_RETURN);
Packit Service d1fe03
	       else
Packit Service d1fe03
		       ret = add_target(r, cs->target->t);
Packit Service d1fe03
       } else if (strlen(cs->jumpto) > 0) {
Packit Service d1fe03
	       /* Not standard, then it's a go / jump to chain */
Packit Service d1fe03
	       if (goto_set)
Packit Service d1fe03
		       ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
Packit Service d1fe03
	       else
Packit Service d1fe03
		       ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
Packit Service d1fe03
       }
Packit Service d1fe03
       return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
Packit Service d1fe03
{
Packit Service d1fe03
#ifdef NLDEBUG
Packit Service d1fe03
	char tmp[1024];
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_snprintf(tmp, sizeof(tmp), r, 0, 0);
Packit Service d1fe03
	printf("DEBUG: rule: %s\n", tmp);
Packit Service d1fe03
	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
Packit Service d1fe03
#endif
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_alloc("counter");
Packit Service d1fe03
	if (expr == NULL)
Packit Service d1fe03
		return -ENOMEM;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_PACKETS, packets);
Packit Service d1fe03
	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_BYTES, bytes);
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_add_expr(r, expr);
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
enum udata_type {
Packit Service d1fe03
	UDATA_TYPE_COMMENT,
Packit Service d1fe03
	UDATA_TYPE_EBTABLES_POLICY,
Packit Service d1fe03
	__UDATA_TYPE_MAX,
Packit Service d1fe03
};
Packit Service d1fe03
#define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
Packit Service d1fe03
Packit Service d1fe03
static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	unsigned char *value = nftnl_udata_get(attr);
Packit Service d1fe03
	uint8_t type = nftnl_udata_type(attr);
Packit Service d1fe03
	uint8_t len = nftnl_udata_len(attr);
Packit Service d1fe03
	const struct nftnl_udata **tb = data;
Packit Service d1fe03
Packit Service d1fe03
	switch (type) {
Packit Service d1fe03
	case UDATA_TYPE_COMMENT:
Packit Service d1fe03
		if (value[len - 1] != '\0')
Packit Service d1fe03
			return -1;
Packit Service d1fe03
		break;
Packit Service d1fe03
	case UDATA_TYPE_EBTABLES_POLICY:
Packit Service d1fe03
		break;
Packit Service d1fe03
	default:
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
	tb[type] = attr;
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
char *get_comment(const void *data, uint32_t data_len)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
Packit Service d1fe03
Packit Service d1fe03
	if (nftnl_udata_parse(data, data_len, parse_udata_cb, tb) < 0)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	if (!tb[UDATA_TYPE_COMMENT])
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	return nftnl_udata_get(tb[UDATA_TYPE_COMMENT]);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
Packit Service d1fe03
{
Packit Service d1fe03
	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, proto);
Packit Service d1fe03
	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS,
Packit Service d1fe03
			      inv ? NFT_RULE_COMPAT_F_INV : 0);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_rule *
Packit Service d1fe03
nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
Packit Service d1fe03
	     void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_alloc();
Packit Service d1fe03
	if (r == NULL)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
Packit Service d1fe03
	nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
Packit Service d1fe03
	nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
Packit Service d1fe03
Packit Service d1fe03
	if (h->ops->add(h, r, data) < 0)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	return r;
Packit Service d1fe03
err:
Packit Service d1fe03
	nftnl_rule_free(r);
Packit Service d1fe03
	return NULL;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_chain *
Packit Service d1fe03
nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
Packit Service d1fe03
Packit Service d1fe03
int
Packit Service d1fe03
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
Packit Service d1fe03
		void *data, struct nftnl_rule *ref, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	int type;
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
Packit Service d1fe03
	/* Since ebtables user-defined chain policies are implemented as last
Packit Service d1fe03
	 * rule in nftables, rule cache is required here to treat them right. */
Packit Service d1fe03
	if (h->family == NFPROTO_BRIDGE) {
Packit Service d1fe03
		c = nft_chain_find(h, table, chain);
Packit Service d1fe03
		if (c && !nft_chain_builtin(c))
Packit Service d1fe03
			nft_build_cache(h, c);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_append;
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_new(h, chain, table, data);
Packit Service d1fe03
	if (r == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (ref) {
Packit Service d1fe03
		nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
Packit Service d1fe03
				   nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
Packit Service d1fe03
		type = NFT_COMPAT_RULE_REPLACE;
Packit Service d1fe03
	} else
Packit Service d1fe03
		type = NFT_COMPAT_RULE_APPEND;
Packit Service d1fe03
Packit Service d1fe03
	if (batch_rule_add(h, type, r) == NULL) {
Packit Service d1fe03
		nftnl_rule_free(r);
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (verbose)
Packit Service d1fe03
		h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
Packit Service d1fe03
Packit Service d1fe03
	if (ref) {
Packit Service d1fe03
		nftnl_chain_rule_insert_at(r, ref);
Packit Service d1fe03
		nftnl_chain_rule_del(r);
Packit Service d1fe03
	} else {
Packit Service d1fe03
		c = nft_chain_find(h, table, chain);
Packit Service d1fe03
		if (!c) {
Packit Service d1fe03
			errno = ENOENT;
Packit Service d1fe03
			return 0;
Packit Service d1fe03
		}
Packit Service d1fe03
		nftnl_chain_rule_add_tail(r, c);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
void
Packit Service d1fe03
nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
Packit Service d1fe03
		    enum nft_rule_print type, unsigned int format)
Packit Service d1fe03
{
Packit Service d1fe03
	const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
Packit Service d1fe03
	struct iptables_command_state cs = {};
Packit Service d1fe03
	struct nft_family_ops *ops = h->ops;
Packit Service d1fe03
Packit Service d1fe03
	ops->rule_to_cs(h, r, &cs);
Packit Service d1fe03
Packit Service d1fe03
	if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
Packit Service d1fe03
		ops->save_counters(&cs);
Packit Service d1fe03
Packit Service d1fe03
	/* print chain name */
Packit Service d1fe03
	switch(type) {
Packit Service d1fe03
	case NFT_RULE_APPEND:
Packit Service d1fe03
		printf("-A %s ", chain);
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_RULE_DEL:
Packit Service d1fe03
		printf("-D %s ", chain);
Packit Service d1fe03
		break;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (ops->save_rule)
Packit Service d1fe03
		ops->save_rule(&cs, format);
Packit Service d1fe03
Packit Service d1fe03
	if (ops->clear_cs)
Packit Service d1fe03
		ops->clear_cs(&cs);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
Packit Service d1fe03
	const void *data;
Packit Service d1fe03
	uint32_t len;
Packit Service d1fe03
Packit Service d1fe03
	if (!nftnl_rule_is_set(r, NFTNL_RULE_USERDATA))
Packit Service d1fe03
		return false;
Packit Service d1fe03
Packit Service d1fe03
	data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len;;
Packit Service d1fe03
	if (nftnl_udata_parse(data, len, parse_udata_cb, tb) < 0)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	if (!tb[UDATA_TYPE_EBTABLES_POLICY] ||
Packit Service d1fe03
	    nftnl_udata_get_u32(tb[UDATA_TYPE_EBTABLES_POLICY]) != 1)
Packit Service d1fe03
		return false;
Packit Service d1fe03
Packit Service d1fe03
	return true;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule *r = NULL, *last;
Packit Service d1fe03
	struct nftnl_rule_iter *iter;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_rule_iter_create(c);
Packit Service d1fe03
	if (!iter)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	do {
Packit Service d1fe03
		last = r;
Packit Service d1fe03
		r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	} while (r);
Packit Service d1fe03
	nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
Packit Service d1fe03
	return last;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
void nft_bridge_chain_postprocess(struct nft_handle *h,
Packit Service d1fe03
				  struct nftnl_chain *c)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule *last = nft_chain_last_rule(c);
Packit Service d1fe03
	struct nftnl_expr_iter *iter;
Packit Service d1fe03
	struct nftnl_expr *expr;
Packit Service d1fe03
	int verdict;
Packit Service d1fe03
Packit Service d1fe03
	if (!last || !nft_rule_is_policy_rule(last))
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_expr_iter_create(last);
Packit Service d1fe03
	if (!iter)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_iter_next(iter);
Packit Service d1fe03
	if (!expr ||
Packit Service d1fe03
	    strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)))
Packit Service d1fe03
		goto out_iter;
Packit Service d1fe03
Packit Service d1fe03
	expr = nftnl_expr_iter_next(iter);
Packit Service d1fe03
	if (!expr ||
Packit Service d1fe03
	    strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) ||
Packit Service d1fe03
	    !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT))
Packit Service d1fe03
		goto out_iter;
Packit Service d1fe03
Packit Service d1fe03
	verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
Packit Service d1fe03
	switch (verdict) {
Packit Service d1fe03
	case NF_ACCEPT:
Packit Service d1fe03
	case NF_DROP:
Packit Service d1fe03
		break;
Packit Service d1fe03
	default:
Packit Service d1fe03
		goto out_iter;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
Packit Service d1fe03
	if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL)
Packit Service d1fe03
		fprintf(stderr, "Failed to delete old policy rule\n");
Packit Service d1fe03
	nftnl_chain_rule_del(last);
Packit Service d1fe03
out_iter:
Packit Service d1fe03
	nftnl_expr_iter_destroy(iter);
Packit Service d1fe03
}
Packit Service d1fe03
static const char *policy_name[NF_ACCEPT+1] = {
Packit Service d1fe03
	[NF_DROP] = "DROP",
Packit Service d1fe03
	[NF_ACCEPT] = "ACCEPT",
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nft_family_ops *ops = h->ops;
Packit Service d1fe03
	struct nftnl_chain_list_iter *iter;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_chain_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	while (c != NULL) {
Packit Service d1fe03
		const char *policy = NULL;
Packit Service d1fe03
Packit Service d1fe03
		if (nft_chain_builtin(c)) {
Packit Service d1fe03
			uint32_t pol = NF_ACCEPT;
Packit Service d1fe03
Packit Service d1fe03
			if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY))
Packit Service d1fe03
				pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service d1fe03
			policy = policy_name[pol];
Packit Service d1fe03
		} else if (h->family == NFPROTO_BRIDGE) {
Packit Service d1fe03
			if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) {
Packit Service d1fe03
				uint32_t pol;
Packit Service d1fe03
Packit Service d1fe03
				pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service d1fe03
				policy = policy_name[pol];
Packit Service d1fe03
			} else {
Packit Service d1fe03
				policy = "RETURN";
Packit Service d1fe03
			}
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		if (ops->save_chain)
Packit Service d1fe03
			ops->save_chain(c, policy);
Packit Service d1fe03
Packit Service d1fe03
		c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_list_iter_destroy(iter);
Packit Service d1fe03
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_chain_save_rules(struct nft_handle *h,
Packit Service d1fe03
				struct nftnl_chain *c, unsigned int format)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule_iter *iter;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_rule_iter_create(c);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 1;
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	while (r != NULL) {
Packit Service d1fe03
		nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
Packit Service d1fe03
		r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list_iter *iter;
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, NULL);
Packit Service d1fe03
	if (!list)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_chain_list_iter_create(list);
Packit Service d1fe03
	if (!iter)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	while (c) {
Packit Service d1fe03
		nft_build_cache(h, c);
Packit Service d1fe03
		ret = nft_chain_save_rules(h, c, format);
Packit Service d1fe03
		if (ret != 0)
Packit Service d1fe03
			break;
Packit Service d1fe03
Packit Service d1fe03
		c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_list_iter_destroy(iter);
Packit Service d1fe03
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void
Packit Service d1fe03
__nft_rule_flush(struct nft_handle *h, const char *table,
Packit Service d1fe03
		 const char *chain, bool verbose, bool implicit)
Packit Service d1fe03
{
Packit Service d1fe03
	struct obj_update *obj;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	if (verbose && chain)
Packit Service d1fe03
		fprintf(stdout, "Flushing chain `%s'\n", chain);
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_alloc();
Packit Service d1fe03
	if (r == NULL)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
Packit Service d1fe03
	if (chain)
Packit Service d1fe03
		nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
Packit Service d1fe03
Packit Service d1fe03
	obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
Packit Service d1fe03
	if (!obj) {
Packit Service d1fe03
		nftnl_rule_free(r);
Packit Service d1fe03
		return;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	obj->implicit = implicit;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
Packit Service d1fe03
		   bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list_iter *iter;
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain *c = NULL;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_flush;
Packit Service d1fe03
Packit Service d1fe03
	if (chain || verbose) {
Packit Service d1fe03
		list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
		if (list == NULL) {
Packit Service d1fe03
			ret = 1;
Packit Service d1fe03
			goto err;
Packit Service d1fe03
		}
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
		if (!c) {
Packit Service d1fe03
			errno = ENOENT;
Packit Service d1fe03
			return 0;
Packit Service d1fe03
		}
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (chain || !verbose) {
Packit Service d1fe03
		__nft_rule_flush(h, table, chain, verbose, false);
Packit Service d1fe03
		flush_rule_cache(h, table, c);
Packit Service d1fe03
		return 1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_chain_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL) {
Packit Service d1fe03
		ret = 1;
Packit Service d1fe03
		goto err;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	while (c != NULL) {
Packit Service d1fe03
		chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service d1fe03
Packit Service d1fe03
		__nft_rule_flush(h, table, chain, verbose, false);
Packit Service d1fe03
		flush_rule_cache(h, table, c);
Packit Service d1fe03
		c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
	nftnl_chain_list_iter_destroy(iter);
Packit Service d1fe03
err:
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_chain_user_add;
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
Packit Service d1fe03
	if (nft_chain_exists(h, table, chain)) {
Packit Service d1fe03
		errno = EEXIST;
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_alloc();
Packit Service d1fe03
	if (c == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
Packit Service d1fe03
	if (h->family == NFPROTO_BRIDGE)
Packit Service d1fe03
		nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
Packit Service d1fe03
Packit Service d1fe03
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (list)
Packit Service d1fe03
		nftnl_chain_list_add(c, list);
Packit Service d1fe03
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	bool created = false;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (c) {
Packit Service d1fe03
		/* Apparently -n still flushes existing user defined
Packit Service d1fe03
		 * chains that are redefined.
Packit Service d1fe03
		 */
Packit Service d1fe03
		if (h->noflush)
Packit Service d1fe03
			__nft_rule_flush(h, table, chain, false, true);
Packit Service d1fe03
	} else {
Packit Service d1fe03
		c = nftnl_chain_alloc();
Packit Service d1fe03
		if (!c)
Packit Service d1fe03
			return -1;
Packit Service d1fe03
Packit Service d1fe03
		nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
Packit Service d1fe03
		nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
Packit Service d1fe03
		created = true;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (h->family == NFPROTO_BRIDGE)
Packit Service d1fe03
		nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
Packit Service d1fe03
Packit Service d1fe03
	if (!created)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (list)
Packit Service d1fe03
		nftnl_chain_list_add(c, list);
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
/* From linux/netlink.h */
Packit Service d1fe03
#ifndef NLM_F_NONREC
Packit Service d1fe03
#define NLM_F_NONREC	0x100	/* Do not delete recursively    */
Packit Service d1fe03
#endif
Packit Service d1fe03
Packit Service d1fe03
struct chain_user_del_data {
Packit Service d1fe03
	struct nft_handle	*handle;
Packit Service d1fe03
	bool			verbose;
Packit Service d1fe03
	int			builtin_err;
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	struct chain_user_del_data *d = data;
Packit Service d1fe03
	struct nft_handle *h = d->handle;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	/* don't delete built-in chain */
Packit Service d1fe03
	if (nft_chain_builtin(c))
Packit Service d1fe03
		return d->builtin_err;
Packit Service d1fe03
Packit Service d1fe03
	if (d->verbose)
Packit Service d1fe03
		fprintf(stdout, "Deleting chain `%s'\n",
Packit Service d1fe03
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
Packit Service d1fe03
Packit Service d1fe03
	/* This triggers required policy rule deletion. */
Packit Service d1fe03
	if (h->family == NFPROTO_BRIDGE)
Packit Service d1fe03
		nft_build_cache(h, c);
Packit Service d1fe03
Packit Service d1fe03
	/* XXX This triggers a fast lookup from the kernel. */
Packit Service d1fe03
	nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
Packit Service d1fe03
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
Packit Service d1fe03
	if (ret)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_list_del(c);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_user_del(struct nft_handle *h, const char *chain,
Packit Service d1fe03
		       const char *table, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct chain_user_del_data d = {
Packit Service d1fe03
		.handle = h,
Packit Service d1fe03
		.verbose = verbose,
Packit Service d1fe03
	};
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_chain_user_del;
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (list == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
		if (!c) {
Packit Service d1fe03
			errno = ENOENT;
Packit Service d1fe03
			return 0;
Packit Service d1fe03
		}
Packit Service d1fe03
		d.builtin_err = -2;
Packit Service d1fe03
		ret = __nft_chain_user_del(c, &d);
Packit Service d1fe03
		if (ret == -2)
Packit Service d1fe03
			errno = EINVAL;
Packit Service d1fe03
		goto out;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d);
Packit Service d1fe03
out:
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_chain *
Packit Service d1fe03
nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (list == NULL)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	return nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
bool nft_chain_exists(struct nft_handle *h,
Packit Service d1fe03
		      const char *table, const char *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct builtin_table *t = nft_table_builtin_find(h, table);
Packit Service d1fe03
Packit Service d1fe03
	/* xtables does not support custom tables */
Packit Service d1fe03
	if (!t)
Packit Service d1fe03
		return false;
Packit Service d1fe03
Packit Service d1fe03
	if (nft_chain_builtin_find(t, chain))
Packit Service d1fe03
		return true;
Packit Service d1fe03
Packit Service d1fe03
	return !!nft_chain_find(h, table, chain);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_user_rename(struct nft_handle *h,const char *chain,
Packit Service d1fe03
			  const char *table, const char *newname)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	uint64_t handle;
Packit Service d1fe03
	int ret;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_chain_user_rename;
Packit Service d1fe03
Packit Service d1fe03
	if (nft_chain_exists(h, table, newname)) {
Packit Service d1fe03
		errno = EEXIST;
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
Packit Service d1fe03
	/* Config load changed errno. Ensure genuine info for our callers. */
Packit Service d1fe03
	errno = 0;
Packit Service d1fe03
Packit Service d1fe03
	/* Find the old chain to be renamed */
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (c == NULL) {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
	handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE);
Packit Service d1fe03
Packit Service d1fe03
	/* Now prepare the new name for the chain */
Packit Service d1fe03
	c = nftnl_chain_alloc();
Packit Service d1fe03
	if (c == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
Packit Service d1fe03
	nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
Packit Service d1fe03
	nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
Packit Service d1fe03
Packit Service d1fe03
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
Packit Service d1fe03
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
bool nft_table_find(struct nft_handle *h, const char *tablename)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_table_list_iter *iter;
Packit Service d1fe03
	struct nftnl_table_list *list;
Packit Service d1fe03
	struct nftnl_table *t;
Packit Service d1fe03
	bool ret = false;
Packit Service d1fe03
Packit Service d1fe03
	list = nftnl_table_list_get(h);
Packit Service d1fe03
	if (list == NULL)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_table_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	t = nftnl_table_list_iter_next(iter);
Packit Service d1fe03
	while (t != NULL) {
Packit Service d1fe03
		const char *this_tablename =
Packit Service d1fe03
			nftnl_table_get(t, NFTNL_TABLE_NAME);
Packit Service d1fe03
Packit Service d1fe03
		if (strcmp(tablename, this_tablename) == 0) {
Packit Service d1fe03
			ret = true;
Packit Service d1fe03
			break;
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		t = nftnl_table_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_table_list_iter_destroy(iter);
Packit Service d1fe03
Packit Service d1fe03
err:
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_for_each_table(struct nft_handle *h,
Packit Service d1fe03
		       int (*func)(struct nft_handle *h, const char *tablename, void *data),
Packit Service d1fe03
		       void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_table_list *list;
Packit Service d1fe03
	struct nftnl_table_list_iter *iter;
Packit Service d1fe03
	struct nftnl_table *t;
Packit Service d1fe03
Packit Service d1fe03
	list = nftnl_table_list_get(h);
Packit Service d1fe03
	if (list == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_table_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	t = nftnl_table_list_iter_next(iter);
Packit Service d1fe03
	while (t != NULL) {
Packit Service d1fe03
		const char *tablename =
Packit Service d1fe03
			nftnl_table_get(t, NFTNL_TABLE_NAME);
Packit Service d1fe03
Packit Service d1fe03
		func(h, tablename, data);
Packit Service d1fe03
Packit Service d1fe03
		t = nftnl_table_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_table_list_iter_destroy(iter);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int __nft_table_flush(struct nft_handle *h, const char *table, bool exists)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct builtin_table *_t;
Packit Service d1fe03
	struct obj_update *obj;
Packit Service d1fe03
	struct nftnl_table *t;
Packit Service d1fe03
Packit Service d1fe03
	t = nftnl_table_alloc();
Packit Service d1fe03
	if (t == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
Packit Service d1fe03
Packit Service d1fe03
	obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
Packit Service d1fe03
	if (!obj) {
Packit Service d1fe03
		nftnl_table_free(t);
Packit Service d1fe03
		return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (!exists)
Packit Service d1fe03
		obj->skip = 1;
Packit Service d1fe03
Packit Service d1fe03
	_t = nft_table_builtin_find(h, table);
Packit Service d1fe03
	assert(_t);
Packit Service d1fe03
	h->cache->table[_t->type].initialized = false;
Packit Service d1fe03
Packit Service d1fe03
	flush_chain_cache(h, table);
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_table_flush(struct nft_handle *h, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_table_list_iter *iter;
Packit Service d1fe03
	struct nftnl_table_list *list;
Packit Service d1fe03
	struct nftnl_table *t;
Packit Service d1fe03
	bool exists = false;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_table_flush;
Packit Service d1fe03
Packit Service d1fe03
	list = nftnl_table_list_get(h);
Packit Service d1fe03
	if (list == NULL) {
Packit Service d1fe03
		ret = -1;
Packit Service d1fe03
		goto err_out;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_table_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL) {
Packit Service d1fe03
		ret = -1;
Packit Service d1fe03
		goto err_table_list;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	t = nftnl_table_list_iter_next(iter);
Packit Service d1fe03
	while (t != NULL) {
Packit Service d1fe03
		const char *table_name =
Packit Service d1fe03
			nftnl_table_get_str(t, NFTNL_TABLE_NAME);
Packit Service d1fe03
Packit Service d1fe03
		if (strcmp(table_name, table) == 0) {
Packit Service d1fe03
			exists = true;
Packit Service d1fe03
			break;
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		t = nftnl_table_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	ret = __nft_table_flush(h, table, exists);
Packit Service d1fe03
	nftnl_table_list_iter_destroy(iter);
Packit Service d1fe03
err_table_list:
Packit Service d1fe03
err_out:
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
void nft_table_new(struct nft_handle *h, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
Packit Service d1fe03
{
Packit Service d1fe03
	struct obj_update *obj;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_list_del(r);
Packit Service d1fe03
Packit Service d1fe03
	if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE))
Packit Service d1fe03
		nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id);
Packit Service d1fe03
Packit Service d1fe03
	obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
Packit Service d1fe03
	if (!obj) {
Packit Service d1fe03
		nftnl_rule_free(r);
Packit Service d1fe03
		return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_rule *
Packit Service d1fe03
nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	struct nftnl_rule_iter *iter;
Packit Service d1fe03
	bool found = false;
Packit Service d1fe03
Packit Service d1fe03
	nft_build_cache(h, c);
Packit Service d1fe03
Packit Service d1fe03
	if (rulenum >= 0)
Packit Service d1fe03
		/* Delete by rule number case */
Packit Service d1fe03
		return nftnl_rule_lookup_byindex(c, rulenum);
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_rule_iter_create(c);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	while (r != NULL) {
Packit Service d1fe03
		found = h->ops->rule_find(h, r, data);
Packit Service d1fe03
		if (found)
Packit Service d1fe03
			break;
Packit Service d1fe03
		r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
Packit Service d1fe03
	return found ? r : NULL;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_check(struct nft_handle *h, const char *chain,
Packit Service d1fe03
		   const char *table, void *data, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_check;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (!c)
Packit Service d1fe03
		goto fail_enoent;
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_find(h, c, data, -1);
Packit Service d1fe03
	if (r == NULL)
Packit Service d1fe03
		goto fail_enoent;
Packit Service d1fe03
Packit Service d1fe03
	if (verbose)
Packit Service d1fe03
		h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
Packit Service d1fe03
Packit Service d1fe03
	return 1;
Packit Service d1fe03
fail_enoent:
Packit Service d1fe03
	errno = ENOENT;
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_delete(struct nft_handle *h, const char *chain,
Packit Service d1fe03
		    const char *table, void *data, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_delete;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (!c) {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_find(h, c, data, -1);
Packit Service d1fe03
	if (r != NULL) {
Packit Service d1fe03
		ret =__nft_rule_del(h, r);
Packit Service d1fe03
		if (ret < 0)
Packit Service d1fe03
			errno = ENOMEM;
Packit Service d1fe03
		if (verbose)
Packit Service d1fe03
			h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
Packit Service d1fe03
	} else
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static struct nftnl_rule *
Packit Service d1fe03
nft_rule_add(struct nft_handle *h, const char *chain,
Packit Service d1fe03
	     const char *table, struct iptables_command_state *cs,
Packit Service d1fe03
	     struct nftnl_rule *ref, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	uint64_t ref_id;
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_new(h, chain, table, cs);
Packit Service d1fe03
	if (r == NULL)
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
Packit Service d1fe03
	if (ref) {
Packit Service d1fe03
		ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
Packit Service d1fe03
		if (ref_id > 0) {
Packit Service d1fe03
			nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, ref_id);
Packit Service d1fe03
			DEBUGP("adding after rule handle %"PRIu64"\n", ref_id);
Packit Service d1fe03
		} else {
Packit Service d1fe03
			ref_id = nftnl_rule_get_u32(ref, NFTNL_RULE_ID);
Packit Service d1fe03
			if (!ref_id) {
Packit Service d1fe03
				ref_id = ++h->rule_id;
Packit Service d1fe03
				nftnl_rule_set_u32(ref, NFTNL_RULE_ID, ref_id);
Packit Service d1fe03
			}
Packit Service d1fe03
			nftnl_rule_set_u32(r, NFTNL_RULE_POSITION_ID, ref_id);
Packit Service d1fe03
			DEBUGP("adding after rule ID %"PRIu64"\n", ref_id);
Packit Service d1fe03
		}
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) {
Packit Service d1fe03
		nftnl_rule_free(r);
Packit Service d1fe03
		return NULL;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (verbose)
Packit Service d1fe03
		h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
Packit Service d1fe03
Packit Service d1fe03
	return r;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_insert(struct nft_handle *h, const char *chain,
Packit Service d1fe03
		    const char *table, void *data, int rulenum, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule *r = NULL, *new_rule;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_insert;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (!c) {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		goto err;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (rulenum > 0) {
Packit Service d1fe03
		r = nft_rule_find(h, c, data, rulenum);
Packit Service d1fe03
		if (r == NULL) {
Packit Service d1fe03
			/* special case: iptables allows to insert into
Packit Service d1fe03
			 * rule_count + 1 position.
Packit Service d1fe03
			 */
Packit Service d1fe03
			r = nft_rule_find(h, c, data, rulenum - 1);
Packit Service d1fe03
			if (r != NULL)
Packit Service d1fe03
				return nft_rule_append(h, chain, table, data,
Packit Service d1fe03
						       NULL, verbose);
Packit Service d1fe03
Packit Service d1fe03
			errno = E2BIG;
Packit Service d1fe03
			goto err;
Packit Service d1fe03
		}
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	new_rule = nft_rule_add(h, chain, table, data, r, verbose);
Packit Service d1fe03
	if (!new_rule)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	if (r)
Packit Service d1fe03
		nftnl_chain_rule_insert_at(new_rule, r);
Packit Service d1fe03
	else
Packit Service d1fe03
		nftnl_chain_rule_add(new_rule, c);
Packit Service d1fe03
Packit Service d1fe03
	return 1;
Packit Service d1fe03
err:
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_delete_num(struct nft_handle *h, const char *chain,
Packit Service d1fe03
			const char *table, int rulenum, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_delete_num;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (!c) {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_find(h, c, NULL, rulenum);
Packit Service d1fe03
	if (r != NULL) {
Packit Service d1fe03
		DEBUGP("deleting rule by number %d\n", rulenum);
Packit Service d1fe03
		ret = __nft_rule_del(h, r);
Packit Service d1fe03
		if (ret < 0)
Packit Service d1fe03
			errno = ENOMEM;
Packit Service d1fe03
	} else
Packit Service d1fe03
		errno = E2BIG;
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_replace(struct nft_handle *h, const char *chain,
Packit Service d1fe03
		     const char *table, void *data, int rulenum, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_replace;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (!c) {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_find(h, c, data, rulenum);
Packit Service d1fe03
	if (r != NULL) {
Packit Service d1fe03
		DEBUGP("replacing rule with handle=%llu\n",
Packit Service d1fe03
			(unsigned long long)
Packit Service d1fe03
			nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
Packit Service d1fe03
Packit Service d1fe03
		ret = nft_rule_append(h, chain, table, data, r, verbose);
Packit Service d1fe03
	} else
Packit Service d1fe03
		errno = E2BIG;
Packit Service d1fe03
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int
Packit Service d1fe03
__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
Packit Service d1fe03
		int rulenum, unsigned int format,
Packit Service d1fe03
		void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
Packit Service d1fe03
			   unsigned int num, unsigned int format))
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule_iter *iter;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	int rule_ctr = 0;
Packit Service d1fe03
Packit Service d1fe03
	if (rulenum > 0) {
Packit Service d1fe03
		r = nftnl_rule_lookup_byindex(c, rulenum - 1);
Packit Service d1fe03
		if (!r)
Packit Service d1fe03
			/* iptables-legacy returns 0 when listing for
Packit Service d1fe03
			 * valid chain but invalid rule number
Packit Service d1fe03
			 */
Packit Service d1fe03
			return 1;
Packit Service d1fe03
		cb(h, r, rulenum, format);
Packit Service d1fe03
		return 1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_rule_iter_create(c);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	while (r != NULL) {
Packit Service d1fe03
		cb(h, r, ++rule_ctr, format);
Packit Service d1fe03
		r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_rule_iter *iter;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	int rule_ctr = 0;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_rule_iter_create(c);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	while (r != NULL) {
Packit Service d1fe03
		rule_ctr++;
Packit Service d1fe03
		r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
	return rule_ctr;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void __nft_print_header(struct nft_handle *h,
Packit Service d1fe03
			       struct nftnl_chain *c, unsigned int format)
Packit Service d1fe03
{
Packit Service d1fe03
	const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service d1fe03
	bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
Packit Service d1fe03
	uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
Packit Service d1fe03
	uint32_t entries = nft_rule_count(h, c);
Packit Service d1fe03
	struct xt_counters ctrs = {
Packit Service d1fe03
		.pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
Packit Service d1fe03
		.bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
Packit Service d1fe03
	};
Packit Service d1fe03
	const char *pname = NULL;
Packit Service d1fe03
Packit Service d1fe03
	if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
Packit Service d1fe03
		pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
Packit Service d1fe03
Packit Service d1fe03
	h->ops->print_header(format, chain_name, pname,
Packit Service d1fe03
			&ctrs, basechain, refs - entries, entries);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
Packit Service d1fe03
		  int rulenum, unsigned int format)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct nft_family_ops *ops = h->ops;
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain_list_iter *iter;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	bool found = false;
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
	nft_assert_table_compatible(h, table, chain);
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (!list)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
		if (!c)
Packit Service d1fe03
			return 0;
Packit Service d1fe03
Packit Service d1fe03
		if (!rulenum) {
Packit Service d1fe03
			if (ops->print_table_header)
Packit Service d1fe03
				ops->print_table_header(table);
Packit Service d1fe03
			__nft_print_header(h, c, format);
Packit Service d1fe03
		}
Packit Service d1fe03
		__nft_rule_list(h, c, rulenum, format, ops->print_rule);
Packit Service d1fe03
		return 1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_chain_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (ops->print_table_header)
Packit Service d1fe03
		ops->print_table_header(table);
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	while (c != NULL) {
Packit Service d1fe03
		if (found)
Packit Service d1fe03
			printf("\n");
Packit Service d1fe03
Packit Service d1fe03
		__nft_print_header(h, c, format);
Packit Service d1fe03
		__nft_rule_list(h, c, rulenum, format, ops->print_rule);
Packit Service d1fe03
Packit Service d1fe03
		found = true;
Packit Service d1fe03
		c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
	nftnl_chain_list_iter_destroy(iter);
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void
Packit Service d1fe03
list_save(struct nft_handle *h, struct nftnl_rule *r,
Packit Service d1fe03
	  unsigned int num, unsigned int format)
Packit Service d1fe03
{
Packit Service d1fe03
	nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service d1fe03
	uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service d1fe03
	int *counters = data;
Packit Service d1fe03
Packit Service d1fe03
	if (!nft_chain_builtin(c)) {
Packit Service d1fe03
		printf("-N %s\n", chain_name);
Packit Service d1fe03
		return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	/* this is a base chain */
Packit Service d1fe03
Packit Service d1fe03
	printf("-P %s %s", chain_name, policy_name[policy]);
Packit Service d1fe03
	if (*counters)
Packit Service d1fe03
		printf(" -c %"PRIu64" %"PRIu64,
Packit Service d1fe03
		       nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
Packit Service d1fe03
		       nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
Packit Service d1fe03
	printf("\n");
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int
Packit Service d1fe03
nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain,
Packit Service d1fe03
			   struct nftnl_chain_list *list, int counters)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
		if (!c)
Packit Service d1fe03
			return 0;
Packit Service d1fe03
Packit Service d1fe03
		__nftnl_rule_list_chain_save(c, &counters);
Packit Service d1fe03
		return 1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_list_foreach(list, __nftnl_rule_list_chain_save, &counters);
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_list_save(struct nft_handle *h, const char *chain,
Packit Service d1fe03
		       const char *table, int rulenum, int counters)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct nftnl_chain_list_iter *iter;
Packit Service d1fe03
	unsigned int format = 0;
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	nft_xt_builtin_init(h, table);
Packit Service d1fe03
	nft_assert_table_compatible(h, table, chain);
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (!list)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	/* Dump policies and custom chains first */
Packit Service d1fe03
	if (!rulenum)
Packit Service d1fe03
		nftnl_rule_list_chain_save(h, chain, list, counters);
Packit Service d1fe03
Packit Service d1fe03
	if (counters < 0)
Packit Service d1fe03
		format = FMT_C_COUNTS;
Packit Service d1fe03
	else if (counters == 0)
Packit Service d1fe03
		format = FMT_NOCOUNTS;
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
		if (!c)
Packit Service d1fe03
			return 0;
Packit Service d1fe03
Packit Service d1fe03
		return __nft_rule_list(h, c, rulenum, format, list_save);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	/* Now dump out rules in this table */
Packit Service d1fe03
	iter = nftnl_chain_list_iter_create(list);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	while (c != NULL) {
Packit Service d1fe03
		ret = __nft_rule_list(h, c, rulenum, format, list_save);
Packit Service d1fe03
		c = nftnl_chain_list_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
	nftnl_chain_list_iter_destroy(iter);
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
Packit Service d1fe03
			   const char *table, int rulenum)
Packit Service d1fe03
{
Packit Service d1fe03
	struct iptables_command_state cs = {};
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	nft_fn = nft_rule_delete;
Packit Service d1fe03
Packit Service d1fe03
	c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	if (!c)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_find(h, c, NULL, rulenum);
Packit Service d1fe03
	if (r == NULL) {
Packit Service d1fe03
		errno = ENOENT;
Packit Service d1fe03
		ret = 1;
Packit Service d1fe03
		goto error;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nft_rule_to_iptables_command_state(h, r, &cs);
Packit Service d1fe03
Packit Service d1fe03
	cs.counters.pcnt = cs.counters.bcnt = 0;
Packit Service d1fe03
Packit Service d1fe03
	ret =  nft_rule_append(h, chain, table, &cs, r, false);
Packit Service d1fe03
Packit Service d1fe03
error:
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
Packit Service d1fe03
				       uint16_t flags, uint32_t seq,
Packit Service d1fe03
				       struct nftnl_table *table)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
Packit Service d1fe03
	nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service d1fe03
					type, h->family, flags, seq);
Packit Service d1fe03
	nftnl_table_nlmsg_build_payload(nlh, table);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
Packit Service d1fe03
				     uint16_t flags, uint32_t seq,
Packit Service d1fe03
				     struct nftnl_set *set)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
Packit Service d1fe03
	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service d1fe03
					type, h->family, flags, seq);
Packit Service d1fe03
	nftnl_set_nlmsg_build_payload(nlh, set);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type,
Packit Service d1fe03
					 uint16_t flags, uint32_t *seq,
Packit Service d1fe03
					 struct nftnl_set *set)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_set_elems_iter *iter;
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_set_elems_iter_create(set);
Packit Service d1fe03
	if (!iter)
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	while (nftnl_set_elems_iter_cur(iter)) {
Packit Service d1fe03
		(*seq)++;
Packit Service d1fe03
		mnl_nft_batch_continue(h->batch);
Packit Service d1fe03
		nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service d1fe03
					    type, h->family, flags, *seq);
Packit Service d1fe03
		if (nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter) <= 0)
Packit Service d1fe03
			break;
Packit Service d1fe03
	}
Packit Service d1fe03
	nftnl_set_elems_iter_destroy(iter);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
Packit Service d1fe03
				       uint16_t flags, uint32_t seq,
Packit Service d1fe03
				       struct nftnl_chain *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
Packit Service d1fe03
	nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service d1fe03
					type, h->family, flags, seq);
Packit Service d1fe03
	nftnl_chain_nlmsg_build_payload(nlh, chain);
Packit Service d1fe03
	nft_chain_print_debug(chain, nlh);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
Packit Service d1fe03
				      uint16_t flags, uint32_t seq,
Packit Service d1fe03
				      struct nftnl_rule *rule)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
Packit Service d1fe03
	nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service d1fe03
				       type, h->family, flags, seq);
Packit Service d1fe03
	nftnl_rule_nlmsg_build_payload(nlh, rule);
Packit Service d1fe03
	nft_rule_print_debug(rule, nlh);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
Packit Service d1fe03
{
Packit Service d1fe03
	switch (o->type) {
Packit Service d1fe03
	case NFT_COMPAT_TABLE_ADD:
Packit Service d1fe03
	case NFT_COMPAT_TABLE_FLUSH:
Packit Service d1fe03
		nftnl_table_free(o->table);
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_ZERO:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_ADD:
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_UPDATE:
Packit Service d1fe03
	case NFT_COMPAT_CHAIN_RENAME:
Packit Service d1fe03
		nftnl_chain_free(o->chain);
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_RULE_APPEND:
Packit Service d1fe03
	case NFT_COMPAT_RULE_INSERT:
Packit Service d1fe03
	case NFT_COMPAT_RULE_REPLACE:
Packit Service d1fe03
	case NFT_COMPAT_RULE_DELETE:
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_RULE_FLUSH:
Packit Service d1fe03
		nftnl_rule_free(o->rule);
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_SET_ADD:
Packit Service d1fe03
		nftnl_set_free(o->set);
Packit Service d1fe03
		break;
Packit Service d1fe03
	}
Packit Service d1fe03
	h->obj_list_num--;
Packit Service d1fe03
	list_del(&o->head);
Packit Service d1fe03
	free(o);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_refresh_transaction(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	const char *tablename, *chainname;
Packit Service d1fe03
	const struct nftnl_chain *c;
Packit Service d1fe03
	struct obj_update *n, *tmp;
Packit Service d1fe03
	bool exists;
Packit Service d1fe03
Packit Service d1fe03
	h->error.lineno = 0;
Packit Service d1fe03
Packit Service d1fe03
	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
Packit Service d1fe03
		if (n->implicit) {
Packit Service d1fe03
			batch_obj_del(h, n);
Packit Service d1fe03
			continue;
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		switch (n->type) {
Packit Service d1fe03
		case NFT_COMPAT_TABLE_FLUSH:
Packit Service d1fe03
			tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME);
Packit Service d1fe03
			if (!tablename)
Packit Service d1fe03
				continue;
Packit Service d1fe03
			exists = nft_table_find(h, tablename);
Packit Service d1fe03
			if (exists)
Packit Service d1fe03
				n->skip = 0;
Packit Service d1fe03
			else
Packit Service d1fe03
				n->skip = 1;
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service d1fe03
			tablename = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_TABLE);
Packit Service d1fe03
			if (!tablename)
Packit Service d1fe03
				continue;
Packit Service d1fe03
Packit Service d1fe03
			chainname = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_NAME);
Packit Service d1fe03
			if (!chainname)
Packit Service d1fe03
				continue;
Packit Service d1fe03
Packit Service d1fe03
			if (!h->noflush)
Packit Service d1fe03
				break;
Packit Service d1fe03
Packit Service d1fe03
			c = nft_chain_find(h, tablename, chainname);
Packit Service d1fe03
			if (c) {
Packit Service d1fe03
				/* -restore -n flushes existing rules from redefined user-chain */
Packit Service d1fe03
				__nft_rule_flush(h, tablename,
Packit Service d1fe03
						 chainname, false, true);
Packit Service d1fe03
				n->skip = 1;
Packit Service d1fe03
			} else if (!c) {
Packit Service d1fe03
				n->skip = 0;
Packit Service d1fe03
			}
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_TABLE_ADD:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_ADD:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_ZERO:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_UPDATE:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_RENAME:
Packit Service d1fe03
		case NFT_COMPAT_RULE_APPEND:
Packit Service d1fe03
		case NFT_COMPAT_RULE_INSERT:
Packit Service d1fe03
		case NFT_COMPAT_RULE_REPLACE:
Packit Service d1fe03
		case NFT_COMPAT_RULE_DELETE:
Packit Service d1fe03
		case NFT_COMPAT_RULE_FLUSH:
Packit Service d1fe03
		case NFT_COMPAT_SET_ADD:
Packit Service d1fe03
			break;
Packit Service d1fe03
		}
Packit Service d1fe03
	}
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_action(struct nft_handle *h, int action)
Packit Service d1fe03
{
Packit Service d1fe03
	struct obj_update *n, *tmp;
Packit Service d1fe03
	struct mnl_err *err, *ne;
Packit Service d1fe03
	unsigned int buflen, i, len;
Packit Service d1fe03
	bool show_errors = true;
Packit Service d1fe03
	char errmsg[1024];
Packit Service d1fe03
	uint32_t seq;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
retry:
Packit Service d1fe03
	seq = 1;
Packit Service d1fe03
	h->batch = mnl_batch_init();
Packit Service d1fe03
Packit Service d1fe03
	mnl_batch_begin(h->batch, h->nft_genid, seq++);
Packit Service d1fe03
	h->nft_genid++;
Packit Service d1fe03
Packit Service d1fe03
	list_for_each_entry(n, &h->obj_list, head) {
Packit Service d1fe03
Packit Service d1fe03
		if (n->skip)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		n->seq = seq++;
Packit Service d1fe03
		switch (n->type) {
Packit Service d1fe03
		case NFT_COMPAT_TABLE_ADD:
Packit Service d1fe03
			nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE,
Packit Service d1fe03
						   NLM_F_CREATE, n->seq,
Packit Service d1fe03
						   n->table);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_TABLE_FLUSH:
Packit Service d1fe03
			nft_compat_table_batch_add(h, NFT_MSG_DELTABLE,
Packit Service d1fe03
						   0,
Packit Service d1fe03
						   n->seq, n->table);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_ADD:
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_ZERO:
Packit Service d1fe03
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
Packit Service d1fe03
						   NLM_F_CREATE, n->seq,
Packit Service d1fe03
						   n->chain);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service d1fe03
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
Packit Service d1fe03
						   NLM_F_EXCL, n->seq,
Packit Service d1fe03
						   n->chain);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service d1fe03
			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
Packit Service d1fe03
						   NLM_F_NONREC, n->seq,
Packit Service d1fe03
						   n->chain);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service d1fe03
			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
Packit Service d1fe03
						   0, n->seq,
Packit Service d1fe03
						   n->chain);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_UPDATE:
Packit Service d1fe03
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
Packit Service d1fe03
						   h->restore ?
Packit Service d1fe03
						     NLM_F_CREATE : 0,
Packit Service d1fe03
						   n->seq, n->chain);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_CHAIN_RENAME:
Packit Service d1fe03
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0,
Packit Service d1fe03
						   n->seq, n->chain);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_RULE_APPEND:
Packit Service d1fe03
			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
Packit Service d1fe03
						  NLM_F_CREATE | NLM_F_APPEND,
Packit Service d1fe03
						  n->seq, n->rule);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_RULE_INSERT:
Packit Service d1fe03
			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
Packit Service d1fe03
						  NLM_F_CREATE, n->seq,
Packit Service d1fe03
						  n->rule);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_RULE_REPLACE:
Packit Service d1fe03
			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
Packit Service d1fe03
						  NLM_F_CREATE | NLM_F_REPLACE,
Packit Service d1fe03
						  n->seq, n->rule);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_RULE_DELETE:
Packit Service d1fe03
		case NFT_COMPAT_RULE_FLUSH:
Packit Service d1fe03
			nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
Packit Service d1fe03
						  n->seq, n->rule);
Packit Service d1fe03
			break;
Packit Service d1fe03
		case NFT_COMPAT_SET_ADD:
Packit Service d1fe03
			nft_compat_set_batch_add(h, NFT_MSG_NEWSET,
Packit Service d1fe03
						 NLM_F_CREATE, n->seq, n->set);
Packit Service d1fe03
			nft_compat_setelem_batch_add(h, NFT_MSG_NEWSETELEM,
Packit Service d1fe03
						     NLM_F_CREATE, &n->seq, n->set);
Packit Service d1fe03
			seq = n->seq;
Packit Service d1fe03
			break;
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		mnl_nft_batch_continue(h->batch);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	switch (action) {
Packit Service d1fe03
	case NFT_COMPAT_COMMIT:
Packit Service d1fe03
		mnl_batch_end(h->batch, seq++);
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NFT_COMPAT_ABORT:
Packit Service d1fe03
		break;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	errno = 0;
Packit Service d1fe03
	ret = mnl_batch_talk(h, seq);
Packit Service d1fe03
	if (ret && errno == ERESTART) {
Packit Service d1fe03
		nft_rebuild_cache(h);
Packit Service d1fe03
Packit Service d1fe03
		nft_refresh_transaction(h);
Packit Service d1fe03
Packit Service d1fe03
		i=0;
Packit Service d1fe03
		list_for_each_entry_safe(err, ne, &h->err_list, head)
Packit Service d1fe03
			mnl_err_list_free(err);
Packit Service d1fe03
Packit Service d1fe03
		mnl_batch_reset(h->batch);
Packit Service d1fe03
		goto retry;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	i = 0;
Packit Service d1fe03
	buflen = sizeof(errmsg);
Packit Service d1fe03
Packit Service d1fe03
	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
Packit Service d1fe03
		list_for_each_entry_safe(err, ne, &h->err_list, head) {
Packit Service d1fe03
			if (err->seqnum > n->seq)
Packit Service d1fe03
				break;
Packit Service d1fe03
Packit Service d1fe03
			if (err->seqnum == n->seq && show_errors) {
Packit Service d1fe03
				if (n->error.lineno == 0)
Packit Service d1fe03
					show_errors = false;
Packit Service d1fe03
				len = mnl_append_error(h, n, err, errmsg + i, buflen);
Packit Service d1fe03
				if (len > 0 && len <= buflen) {
Packit Service d1fe03
					buflen -= len;
Packit Service d1fe03
					i += len;
Packit Service d1fe03
				}
Packit Service d1fe03
			}
Packit Service d1fe03
			mnl_err_list_free(err);
Packit Service d1fe03
		}
Packit Service d1fe03
		batch_obj_del(h, n);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nft_release_cache(h);
Packit Service d1fe03
	mnl_batch_reset(h->batch);
Packit Service d1fe03
Packit Service d1fe03
	if (i)
Packit Service d1fe03
		xtables_error(RESOURCE_PROBLEM, "%s", errmsg);
Packit Service d1fe03
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service d1fe03
	struct iptables_command_state cs = {
Packit Service d1fe03
		.eb.bitmask = EBT_NOPROTO,
Packit Service d1fe03
	};
Packit Service d1fe03
	struct nftnl_udata_buf *udata;
Packit Service d1fe03
	struct nft_handle *h = data;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
	const char *pname;
Packit Service d1fe03
Packit Service d1fe03
	if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
Packit Service d1fe03
		return 0; /* ignore base chains */
Packit Service d1fe03
Packit Service d1fe03
	if (!nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_unset(c, NFTNL_CHAIN_POLICY);
Packit Service d1fe03
Packit Service d1fe03
	switch (policy) {
Packit Service d1fe03
	case NFT_RETURN:
Packit Service d1fe03
		return 0; /* return policy is default for nft chains */
Packit Service d1fe03
	case NF_ACCEPT:
Packit Service d1fe03
		pname = "ACCEPT";
Packit Service d1fe03
		break;
Packit Service d1fe03
	case NF_DROP:
Packit Service d1fe03
		pname = "DROP";
Packit Service d1fe03
		break;
Packit Service d1fe03
	default:
Packit Service d1fe03
		return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	command_jump(&cs, pname);
Packit Service d1fe03
Packit Service d1fe03
	r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
Packit Service d1fe03
			 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
Packit Service d1fe03
	if (!r)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
Packit Service d1fe03
	if (!udata)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
Packit Service d1fe03
			    nftnl_udata_buf_data(udata),
Packit Service d1fe03
			    nftnl_udata_buf_len(udata));
Packit Service d1fe03
	nftnl_udata_buf_free(udata);
Packit Service d1fe03
Packit Service d1fe03
	if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) {
Packit Service d1fe03
		nftnl_rule_free(r);
Packit Service d1fe03
		return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
Packit Service d1fe03
			      const char *chain, const char *policy)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain *c = nft_chain_find(h, table, chain);
Packit Service d1fe03
	int pval;
Packit Service d1fe03
Packit Service d1fe03
	if (!c)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (!strcmp(policy, "DROP"))
Packit Service d1fe03
		pval = NF_DROP;
Packit Service d1fe03
	else if (!strcmp(policy, "ACCEPT"))
Packit Service d1fe03
		pval = NF_ACCEPT;
Packit Service d1fe03
	else if (!strcmp(policy, "RETURN"))
Packit Service d1fe03
		pval = NFT_RETURN;
Packit Service d1fe03
	else
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	nft_build_cache(h, c);
Packit Service d1fe03
Packit Service d1fe03
	nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
Packit Service d1fe03
	return 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static void nft_bridge_commit_prepare(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct builtin_table *t;
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	int i;
Packit Service d1fe03
Packit Service d1fe03
	for (i = 0; i < NFT_TABLE_MAX; i++) {
Packit Service d1fe03
		t = &h->tables[i];
Packit Service d1fe03
Packit Service d1fe03
		if (!t->name)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		list = h->cache->table[t->type].chains;
Packit Service d1fe03
		if (!list)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		nftnl_chain_list_foreach(list, ebt_add_policy_rule, h);
Packit Service d1fe03
	}
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_commit(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	return nft_action(h, NFT_COMPAT_COMMIT);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_bridge_commit(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	nft_bridge_commit_prepare(h);
Packit Service d1fe03
	return nft_commit(h);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_abort(struct nft_handle *h)
Packit Service d1fe03
{
Packit Service d1fe03
	return nft_action(h, NFT_COMPAT_ABORT);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_abort_policy_rule(struct nft_handle *h, const char *table)
Packit Service d1fe03
{
Packit Service d1fe03
	struct obj_update *n, *tmp;
Packit Service d1fe03
Packit Service d1fe03
	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
Packit Service d1fe03
		if (n->type != NFT_COMPAT_RULE_APPEND &&
Packit Service d1fe03
		    n->type != NFT_COMPAT_RULE_DELETE)
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		if (strcmp(table,
Packit Service d1fe03
			   nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		if (!nft_rule_is_policy_rule(n->rule))
Packit Service d1fe03
			continue;
Packit Service d1fe03
Packit Service d1fe03
		batch_obj_del(h, n);
Packit Service d1fe03
	}
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
Packit Service d1fe03
{
Packit Service d1fe03
	struct mnl_socket *nl;
Packit Service d1fe03
	char buf[16536];
Packit Service d1fe03
	struct nlmsghdr *nlh;
Packit Service d1fe03
	uint32_t portid, seq, type = 0;
Packit Service d1fe03
	uint32_t pf = AF_INET;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	switch (opt) {
Packit Service d1fe03
	case IPT_SO_GET_REVISION_MATCH:
Packit Service d1fe03
		break;
Packit Service d1fe03
	case IP6T_SO_GET_REVISION_MATCH:
Packit Service d1fe03
		pf = AF_INET6;
Packit Service d1fe03
		break;
Packit Service d1fe03
	case IPT_SO_GET_REVISION_TARGET:
Packit Service d1fe03
		type = 1;
Packit Service d1fe03
		break;
Packit Service d1fe03
	case IP6T_SO_GET_REVISION_TARGET:
Packit Service d1fe03
		type = 1;
Packit Service d1fe03
		pf = AF_INET6;
Packit Service d1fe03
		break;
Packit Service d1fe03
	default:
Packit Service d1fe03
		/* No revision support (arp, ebtables), assume latest version ok */
Packit Service d1fe03
		return 1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nlh = mnl_nlmsg_put_header(buf);
Packit Service d1fe03
	nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
Packit Service d1fe03
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
Packit Service d1fe03
	nlh->nlmsg_seq = seq = time(NULL);
Packit Service d1fe03
Packit Service d1fe03
	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
Packit Service d1fe03
	nfg->nfgen_family = pf;
Packit Service d1fe03
	nfg->version = NFNETLINK_V0;
Packit Service d1fe03
	nfg->res_id = 0;
Packit Service d1fe03
Packit Service d1fe03
	mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
Packit Service d1fe03
	mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
Packit Service d1fe03
	mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
Packit Service d1fe03
Packit Service d1fe03
	DEBUGP("requesting `%s' rev=%d type=%d via nft_compat\n",
Packit Service d1fe03
		name, rev, type);
Packit Service d1fe03
Packit Service d1fe03
	nl = mnl_socket_open(NETLINK_NETFILTER);
Packit Service d1fe03
	if (nl == NULL)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	portid = mnl_socket_get_portid(nl);
Packit Service d1fe03
Packit Service d1fe03
	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
Packit Service d1fe03
	if (ret == -1)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
Packit Service d1fe03
	if (ret == -1)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
err:
Packit Service d1fe03
	mnl_socket_close(nl);
Packit Service d1fe03
Packit Service d1fe03
	return ret < 0 ? 0 : 1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
/* Translates errno numbers into more human-readable form than strerror. */
Packit Service d1fe03
const char *nft_strerror(int err)
Packit Service d1fe03
{
Packit Service d1fe03
	unsigned int i;
Packit Service d1fe03
	static struct table_struct {
Packit Service d1fe03
		void *fn;
Packit Service d1fe03
		int err;
Packit Service d1fe03
		const char *message;
Packit Service d1fe03
	} table[] =
Packit Service d1fe03
	  {
Packit Service d1fe03
	    { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
Packit Service d1fe03
	    { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
Packit Service d1fe03
	    { nft_chain_user_del, EBUSY, "Directory not empty" },
Packit Service d1fe03
	    { nft_chain_user_del, EMLINK,
Packit Service d1fe03
	      "Can't delete chain with references left" },
Packit Service d1fe03
	    { nft_chain_user_add, EEXIST, "Chain already exists" },
Packit Service d1fe03
	    { nft_chain_user_rename, EEXIST, "File exists" },
Packit Service d1fe03
	    { nft_rule_insert, E2BIG, "Index of insertion too big" },
Packit Service d1fe03
	    { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
Packit Service d1fe03
	    { nft_rule_replace, E2BIG, "Index of replacement too big" },
Packit Service d1fe03
	    { nft_rule_delete_num, E2BIG, "Index of deletion too big" },
Packit Service d1fe03
/*	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
Packit Service d1fe03
	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
Packit Service d1fe03
	    /* ENOENT for DELETE probably means no matching rule */
Packit Service d1fe03
	    { nft_rule_delete, ENOENT,
Packit Service d1fe03
	      "Bad rule (does a matching rule exist in that chain?)" },
Packit Service d1fe03
	    { nft_chain_set, ENOENT, "Bad built-in chain name" },
Packit Service d1fe03
	    { nft_chain_set, EINVAL, "Bad policy name" },
Packit Service d1fe03
	    { nft_chain_set, ENXIO, "Bad table name" },
Packit Service d1fe03
	    { NULL, ELOOP, "Loop found in table" },
Packit Service d1fe03
	    { NULL, EPERM, "Permission denied (you must be root)" },
Packit Service d1fe03
	    { NULL, 0, "Incompatible with this kernel" },
Packit Service d1fe03
	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
Packit Service d1fe03
	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
Packit Service d1fe03
	    { NULL, ENOMEM, "Memory allocation problem" },
Packit Service d1fe03
	    { NULL, ENOENT, "No chain/target/match by that name" },
Packit Service d1fe03
	  };
Packit Service d1fe03
Packit Service d1fe03
	for (i = 0; i < ARRAY_SIZE(table); i++) {
Packit Service d1fe03
		if ((!table[i].fn || table[i].fn == nft_fn)
Packit Service d1fe03
		    && table[i].err == err)
Packit Service d1fe03
			return table[i].message;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	return strerror(err);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int recover_rule_compat(struct nftnl_rule *r)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_expr_iter *iter;
Packit Service d1fe03
	struct nftnl_expr *e;
Packit Service d1fe03
	uint32_t reg;
Packit Service d1fe03
	int ret = -1;
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_expr_iter_create(r);
Packit Service d1fe03
	if (!iter)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
next_expr:
Packit Service d1fe03
	e = nftnl_expr_iter_next(iter);
Packit Service d1fe03
	if (!e)
Packit Service d1fe03
		goto out;
Packit Service d1fe03
Packit Service d1fe03
	if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
Packit Service d1fe03
	    nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
Packit Service d1fe03
		goto next_expr;
Packit Service d1fe03
Packit Service d1fe03
	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
Packit Service d1fe03
Packit Service d1fe03
	e = nftnl_expr_iter_next(iter);
Packit Service d1fe03
	if (!e)
Packit Service d1fe03
		goto out;
Packit Service d1fe03
Packit Service d1fe03
	if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
Packit Service d1fe03
	    reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
Packit Service d1fe03
		goto next_expr;
Packit Service d1fe03
Packit Service d1fe03
	add_compat(r, nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA),
Packit Service d1fe03
		   nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ);
Packit Service d1fe03
	ret = 0;
Packit Service d1fe03
out:
Packit Service d1fe03
	nftnl_expr_iter_destroy(iter);
Packit Service d1fe03
	return ret;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
struct chain_zero_data {
Packit Service d1fe03
	struct nft_handle	*handle;
Packit Service d1fe03
	bool			verbose;
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	struct chain_zero_data *d = data;
Packit Service d1fe03
	struct nft_handle *h = d->handle;
Packit Service d1fe03
	struct nftnl_rule_iter *iter;
Packit Service d1fe03
	struct nftnl_rule *r;
Packit Service d1fe03
Packit Service d1fe03
	if (d->verbose)
Packit Service d1fe03
		fprintf(stdout, "Zeroing chain `%s'\n",
Packit Service d1fe03
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
Packit Service d1fe03
Packit Service d1fe03
	if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
Packit Service d1fe03
		/* zero base chain counters. */
Packit Service d1fe03
		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
Packit Service d1fe03
		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
Packit Service d1fe03
		nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
Packit Service d1fe03
		if (batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
Packit Service d1fe03
			return -1;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nft_build_cache(h, c);
Packit Service d1fe03
Packit Service d1fe03
	iter = nftnl_rule_iter_create(c);
Packit Service d1fe03
	if (iter == NULL)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	while (r != NULL) {
Packit Service d1fe03
		struct nftnl_expr_iter *ei;
Packit Service d1fe03
		struct nftnl_expr *e;
Packit Service d1fe03
		bool zero_needed;
Packit Service d1fe03
Packit Service d1fe03
		ei = nftnl_expr_iter_create(r);
Packit Service d1fe03
		if (!ei)
Packit Service d1fe03
			break;
Packit Service d1fe03
Packit Service d1fe03
		e = nftnl_expr_iter_next(ei);
Packit Service d1fe03
	        zero_needed = false;
Packit Service d1fe03
		while (e != NULL) {
Packit Service d1fe03
			const char *en = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
Packit Service d1fe03
Packit Service d1fe03
			if (strcmp(en, "counter") == 0 && (
Packit Service d1fe03
			    nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS) ||
Packit Service d1fe03
			    nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES))) {
Packit Service d1fe03
				nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_PACKETS, 0);
Packit Service d1fe03
				nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_BYTES, 0);
Packit Service d1fe03
				zero_needed = true;
Packit Service d1fe03
			}
Packit Service d1fe03
Packit Service d1fe03
			e = nftnl_expr_iter_next(ei);
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		nftnl_expr_iter_destroy(ei);
Packit Service d1fe03
Packit Service d1fe03
		if (zero_needed) {
Packit Service d1fe03
			/*
Packit Service d1fe03
			 * Unset RULE_POSITION for older kernels, we want to replace
Packit Service d1fe03
			 * rule based on its handle only.
Packit Service d1fe03
			 */
Packit Service d1fe03
			recover_rule_compat(r);
Packit Service d1fe03
			nftnl_rule_unset(r, NFTNL_RULE_POSITION);
Packit Service d1fe03
			if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
Packit Service d1fe03
				nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
				return -1;
Packit Service d1fe03
			}
Packit Service d1fe03
		}
Packit Service d1fe03
		r = nftnl_rule_iter_next(iter);
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	nftnl_rule_iter_destroy(iter);
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
Packit Service d1fe03
			    const char *table, bool verbose)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *list;
Packit Service d1fe03
	struct chain_zero_data d = {
Packit Service d1fe03
		.handle = h,
Packit Service d1fe03
		.verbose = verbose,
Packit Service d1fe03
	};
Packit Service d1fe03
	struct nftnl_chain *c;
Packit Service d1fe03
	int ret = 0;
Packit Service d1fe03
Packit Service d1fe03
	list = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (list == NULL)
Packit Service d1fe03
		goto err;
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		c = nftnl_chain_list_lookup_byname(list, chain);
Packit Service d1fe03
		if (!c) {
Packit Service d1fe03
			errno = ENOENT;
Packit Service d1fe03
			return 0;
Packit Service d1fe03
		}
Packit Service d1fe03
Packit Service d1fe03
		ret = __nft_chain_zero_counters(c, &d);
Packit Service d1fe03
		goto err;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d);
Packit Service d1fe03
err:
Packit Service d1fe03
	/* the core expects 1 for success and 0 for error */
Packit Service d1fe03
	return ret == 0 ? 1 : 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
Packit Service d1fe03
{
Packit Service d1fe03
	if (invflags & flag)
Packit Service d1fe03
		return NFT_CMP_NEQ;
Packit Service d1fe03
Packit Service d1fe03
	return NFT_CMP_EQ;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static const char *supported_exprs[] = {
Packit Service d1fe03
	"match",
Packit Service d1fe03
	"target",
Packit Service d1fe03
	"payload",
Packit Service d1fe03
	"meta",
Packit Service d1fe03
	"cmp",
Packit Service d1fe03
	"bitwise",
Packit Service d1fe03
	"counter",
Packit Service d1fe03
	"immediate",
Packit Service d1fe03
	"lookup",
Packit Service d1fe03
};
Packit Service d1fe03
Packit Service d1fe03
Packit Service d1fe03
static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
Packit Service d1fe03
	int i;
Packit Service d1fe03
Packit Service d1fe03
	for (i = 0; i < ARRAY_SIZE(supported_exprs); i++) {
Packit Service d1fe03
		if (strcmp(supported_exprs[i], name) == 0)
Packit Service d1fe03
			return 0;
Packit Service d1fe03
	}
Packit Service d1fe03
Packit Service d1fe03
	if (!strcmp(name, "limit") &&
Packit Service d1fe03
	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_TYPE) == NFT_LIMIT_PKTS &&
Packit Service d1fe03
	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	return -1;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
Packit Service d1fe03
{
Packit Service d1fe03
	const struct builtin_table *table;
Packit Service d1fe03
	const struct builtin_chain *chain;
Packit Service d1fe03
	const char *tname, *cname, *type;
Packit Service d1fe03
	struct nft_handle *h = data;
Packit Service d1fe03
	enum nf_inet_hooks hook;
Packit Service d1fe03
	int prio;
Packit Service d1fe03
Packit Service d1fe03
	nft_build_cache(h, c);
Packit Service d1fe03
Packit Service d1fe03
	if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	if (!nft_chain_builtin(c))
Packit Service d1fe03
		return 0;
Packit Service d1fe03
Packit Service d1fe03
	tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service d1fe03
	table = nft_table_builtin_find(h, tname);
Packit Service d1fe03
	if (!table)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service d1fe03
	chain = nft_chain_builtin_find(table, cname);
Packit Service d1fe03
	if (!chain)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	type = nftnl_chain_get_str(c, NFTNL_CHAIN_TYPE);
Packit Service d1fe03
	prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO);
Packit Service d1fe03
	hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
Packit Service d1fe03
	if (strcmp(type, chain->type) ||
Packit Service d1fe03
	    prio != chain->prio ||
Packit Service d1fe03
	    hook != chain->hook)
Packit Service d1fe03
		return -1;
Packit Service d1fe03
Packit Service d1fe03
	return 0;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
bool nft_is_table_compatible(struct nft_handle *h,
Packit Service d1fe03
			     const char *table, const char *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	struct nftnl_chain_list *clist;
Packit Service d1fe03
Packit Service d1fe03
	clist = nft_chain_list_get(h, table, chain);
Packit Service d1fe03
	if (clist == NULL)
Packit Service d1fe03
		return false;
Packit Service d1fe03
Packit Service d1fe03
	if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
Packit Service d1fe03
		return false;
Packit Service d1fe03
Packit Service d1fe03
	return true;
Packit Service d1fe03
}
Packit Service d1fe03
Packit Service d1fe03
void nft_assert_table_compatible(struct nft_handle *h,
Packit Service d1fe03
				 const char *table, const char *chain)
Packit Service d1fe03
{
Packit Service d1fe03
	const char *pfx = "", *sfx = "";
Packit Service d1fe03
Packit Service d1fe03
	if (nft_is_table_compatible(h, table, chain))
Packit Service d1fe03
		return;
Packit Service d1fe03
Packit Service d1fe03
	if (chain) {
Packit Service d1fe03
		pfx = "chain `";
Packit Service d1fe03
		sfx = "' in ";
Packit Service d1fe03
	} else {
Packit Service d1fe03
		chain = "";
Packit Service d1fe03
	}
Packit Service d1fe03
	xtables_error(OTHER_PROBLEM,
Packit Service d1fe03
		      "%s%s%stable `%s' is incompatible, use 'nft' tool.\n",
Packit Service d1fe03
		      pfx, chain, sfx, table);
Packit Service d1fe03
}