Blame iptables/nft.c

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