Blame bootstrap_ver/iptables/nft.c

Packit Service 1ec7f4
/*
Packit Service 1ec7f4
 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
Packit Service 1ec7f4
 *
Packit Service 1ec7f4
 * This program is free software; you can redistribute it and/or modify
Packit Service 1ec7f4
 * it under the terms of the GNU General Public License as published
Packit Service 1ec7f4
 * by the Free Software Foundation; either version 2 of the License, or
Packit Service 1ec7f4
 * (at your option) any later version.
Packit Service 1ec7f4
 *
Packit Service 1ec7f4
 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
Packit Service 1ec7f4
 */
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <unistd.h>
Packit Service 1ec7f4
#include <fcntl.h>
Packit Service 1ec7f4
#include <sys/types.h>
Packit Service 1ec7f4
#include <sys/socket.h>
Packit Service 1ec7f4
#include <stdbool.h>
Packit Service 1ec7f4
#include <errno.h>
Packit Service 1ec7f4
#include <netdb.h>	/* getprotobynumber */
Packit Service 1ec7f4
#include <time.h>
Packit Service 1ec7f4
#include <stdarg.h>
Packit Service 1ec7f4
#include <inttypes.h>
Packit Service 1ec7f4
#include <assert.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <xtables.h>
Packit Service 1ec7f4
#include <libiptc/libxtc.h>
Packit Service 1ec7f4
#include <libiptc/xtcshared.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <stdlib.h>
Packit Service 1ec7f4
#include <string.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <linux/netfilter/x_tables.h>
Packit Service 1ec7f4
#include <linux/netfilter_ipv4/ip_tables.h>
Packit Service 1ec7f4
#include <linux/netfilter_ipv6/ip6_tables.h>
Packit Service 1ec7f4
#include <netinet/ip6.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <linux/netlink.h>
Packit Service 1ec7f4
#include <linux/netfilter/nfnetlink.h>
Packit Service 1ec7f4
#include <linux/netfilter/nf_tables.h>
Packit Service 1ec7f4
#include <linux/netfilter/nf_tables_compat.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <linux/netfilter/xt_limit.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <libmnl/libmnl.h>
Packit Service 1ec7f4
#include <libnftnl/table.h>
Packit Service 1ec7f4
#include <libnftnl/chain.h>
Packit Service 1ec7f4
#include <libnftnl/rule.h>
Packit Service 1ec7f4
#include <libnftnl/expr.h>
Packit Service 1ec7f4
#include <libnftnl/set.h>
Packit Service 1ec7f4
#include <libnftnl/udata.h>
Packit Service 1ec7f4
#include <libnftnl/batch.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <netinet/in.h>	/* inet_ntoa */
Packit Service 1ec7f4
#include <arpa/inet.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
#include "nft.h"
Packit Service 1ec7f4
#include "xshared.h" /* proto_to_name */
Packit Service 1ec7f4
#include "nft-shared.h"
Packit Service 1ec7f4
#include "xtables-config-parser.h"
Packit Service 1ec7f4
Packit Service 1ec7f4
static void *nft_fn;
Packit Service 1ec7f4
Packit Service 1ec7f4
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
Packit Service 1ec7f4
	     int (*cb)(const struct nlmsghdr *nlh, void *data),
Packit Service 1ec7f4
	     void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
	char buf[16536];
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
Packit Service 1ec7f4
	while (ret > 0) {
Packit Service 1ec7f4
		ret = mnl_cb_run(buf, ret, h->seq, h->portid, cb, data);
Packit Service 1ec7f4
		if (ret <= 0)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	if (ret == -1) {
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
Packit Service 1ec7f4
Packit Service 1ec7f4
/* selected batch page is 256 Kbytes long to load ruleset of
Packit Service 1ec7f4
 * half a million rules without hitting -EMSGSIZE due to large
Packit Service 1ec7f4
 * iovec.
Packit Service 1ec7f4
 */
Packit Service 1ec7f4
#define BATCH_PAGE_SIZE getpagesize() * 32
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_batch *mnl_batch_init(void)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_batch *batch;
Packit Service 1ec7f4
Packit Service 1ec7f4
	batch = nftnl_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE);
Packit Service 1ec7f4
	if (batch == NULL)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return batch;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void mnl_nft_batch_continue(struct nftnl_batch *batch)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	assert(nftnl_batch_update(batch) >= 0);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t seqnum)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
Packit Service 1ec7f4
	mnl_nft_batch_continue(batch);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return seqnum;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	nftnl_batch_end(nftnl_batch_buffer(batch), seqnum);
Packit Service 1ec7f4
	mnl_nft_batch_continue(batch);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void mnl_batch_reset(struct nftnl_batch *batch)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	nftnl_batch_free(batch);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
struct mnl_err {
Packit Service 1ec7f4
	struct list_head	head;
Packit Service 1ec7f4
	int			err;
Packit Service 1ec7f4
	uint32_t		seqnum;
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static void mnl_err_list_node_add(struct list_head *err_list, int error,
Packit Service 1ec7f4
				  int seqnum)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct mnl_err *err = malloc(sizeof(struct mnl_err));
Packit Service 1ec7f4
Packit Service 1ec7f4
	err->seqnum = seqnum;
Packit Service 1ec7f4
	err->err = error;
Packit Service 1ec7f4
	list_add_tail(&err->head, err_list);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void mnl_err_list_free(struct mnl_err *err)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	list_del(&err->head);
Packit Service 1ec7f4
	free(err);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nlbuffsiz;
Packit Service 1ec7f4
Packit Service 1ec7f4
static void mnl_set_sndbuffer(const struct mnl_socket *nl,
Packit Service 1ec7f4
			      struct nftnl_batch *batch)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int newbuffsiz;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE <= nlbuffsiz)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	newbuffsiz = nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Rise sender buffer length to avoid hitting -EMSGSIZE */
Packit Service 1ec7f4
	if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE,
Packit Service 1ec7f4
		       &newbuffsiz, sizeof(socklen_t)) < 0)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlbuffsiz = newbuffsiz;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nf_sock,
Packit Service 1ec7f4
				      struct nftnl_batch *batch)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	static const struct sockaddr_nl snl = {
Packit Service 1ec7f4
		.nl_family = AF_NETLINK
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
	uint32_t iov_len = nftnl_batch_iovec_len(batch);
Packit Service 1ec7f4
	struct iovec iov[iov_len];
Packit Service 1ec7f4
	struct msghdr msg = {
Packit Service 1ec7f4
		.msg_name	= (struct sockaddr *) &snl,
Packit Service 1ec7f4
		.msg_namelen	= sizeof(snl),
Packit Service 1ec7f4
		.msg_iov	= iov,
Packit Service 1ec7f4
		.msg_iovlen	= iov_len,
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
Packit Service 1ec7f4
	mnl_set_sndbuffer(nf_sock, batch);
Packit Service 1ec7f4
	nftnl_batch_iovec(batch, iov, iov_len);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return sendmsg(mnl_socket_get_fd(nf_sock), &msg, 0);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int mnl_batch_talk(const struct mnl_socket *nf_sock,
Packit Service 1ec7f4
			  struct nftnl_batch *batch, struct list_head *err_list)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct mnl_socket *nl = nf_sock;
Packit Service 1ec7f4
	int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
Packit Service 1ec7f4
	char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
Packit Service 1ec7f4
	fd_set readfds;
Packit Service 1ec7f4
	struct timeval tv = {
Packit Service 1ec7f4
		.tv_sec		= 0,
Packit Service 1ec7f4
		.tv_usec	= 0
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
	int err = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_nft_socket_sendmsg(nf_sock, batch);
Packit Service 1ec7f4
	if (ret == -1)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	FD_ZERO(&readfds);
Packit Service 1ec7f4
	FD_SET(fd, &readfds);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* receive and digest all the acknowledgments from the kernel. */
Packit Service 1ec7f4
	ret = select(fd+1, &readfds, NULL, NULL, &tv;;
Packit Service 1ec7f4
	if (ret == -1)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	while (ret > 0 && FD_ISSET(fd, &readfds)) {
Packit Service 1ec7f4
		struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
Packit Service 1ec7f4
		if (ret == -1)
Packit Service 1ec7f4
			return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL);
Packit Service 1ec7f4
		/* Continue on error, make sure we get all acknowledgments */
Packit Service 1ec7f4
		if (ret == -1) {
Packit Service 1ec7f4
			mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq);
Packit Service 1ec7f4
			err = -1;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = select(fd+1, &readfds, NULL, NULL, &tv;;
Packit Service 1ec7f4
		if (ret == -1)
Packit Service 1ec7f4
			return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
		FD_ZERO(&readfds);
Packit Service 1ec7f4
		FD_SET(fd, &readfds);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	return err;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
enum obj_update_type {
Packit Service 1ec7f4
	NFT_COMPAT_TABLE_ADD,
Packit Service 1ec7f4
	NFT_COMPAT_TABLE_FLUSH,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_ADD,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_USER_ADD,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_USER_DEL,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_USER_FLUSH,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_UPDATE,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_RENAME,
Packit Service 1ec7f4
	NFT_COMPAT_CHAIN_ZERO,
Packit Service 1ec7f4
	NFT_COMPAT_RULE_APPEND,
Packit Service 1ec7f4
	NFT_COMPAT_RULE_INSERT,
Packit Service 1ec7f4
	NFT_COMPAT_RULE_REPLACE,
Packit Service 1ec7f4
	NFT_COMPAT_RULE_DELETE,
Packit Service 1ec7f4
	NFT_COMPAT_RULE_FLUSH,
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
enum obj_action {
Packit Service 1ec7f4
	NFT_COMPAT_COMMIT,
Packit Service 1ec7f4
	NFT_COMPAT_ABORT,
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
struct obj_update {
Packit Service 1ec7f4
	struct list_head	head;
Packit Service 1ec7f4
	enum obj_update_type	type;
Packit Service 1ec7f4
	unsigned int		seq;
Packit Service 1ec7f4
	union {
Packit Service 1ec7f4
		struct nftnl_table	*table;
Packit Service 1ec7f4
		struct nftnl_chain	*chain;
Packit Service 1ec7f4
		struct nftnl_rule	*rule;
Packit Service 1ec7f4
		void			*ptr;
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
	struct {
Packit Service 1ec7f4
		unsigned int		lineno;
Packit Service 1ec7f4
	} error;
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static int mnl_append_error(const struct nft_handle *h,
Packit Service 1ec7f4
			    const struct obj_update *o,
Packit Service 1ec7f4
			    const struct mnl_err *err,
Packit Service 1ec7f4
			    char *buf, unsigned int len)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	static const char *type_name[] = {
Packit Service 1ec7f4
		[NFT_COMPAT_TABLE_ADD] = "TABLE_ADD",
Packit Service 1ec7f4
		[NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
Packit Service 1ec7f4
		[NFT_COMPAT_CHAIN_ZERO] = "CHAIN_ZERO",
Packit Service 1ec7f4
		[NFT_COMPAT_RULE_APPEND] = "RULE_APPEND",
Packit Service 1ec7f4
		[NFT_COMPAT_RULE_INSERT] = "RULE_INSERT",
Packit Service 1ec7f4
		[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
Packit Service 1ec7f4
		[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
Packit Service 1ec7f4
		[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
	char errmsg[256];
Packit Service 1ec7f4
	char tcr[128];
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (o->error.lineno)
Packit Service 1ec7f4
		snprintf(errmsg, sizeof(errmsg), "\nline %u: %s failed (%s)",
Packit Service 1ec7f4
			 o->error.lineno, type_name[o->type], strerror(err->err));
Packit Service 1ec7f4
	else
Packit Service 1ec7f4
		snprintf(errmsg, sizeof(errmsg), " %s failed (%s)",
Packit Service 1ec7f4
			 type_name[o->type], strerror(err->err));
Packit Service 1ec7f4
Packit Service 1ec7f4
	switch (o->type) {
Packit Service 1ec7f4
	case NFT_COMPAT_TABLE_ADD:
Packit Service 1ec7f4
	case NFT_COMPAT_TABLE_FLUSH:
Packit Service 1ec7f4
		snprintf(tcr, sizeof(tcr), "table %s",
Packit Service 1ec7f4
			 nftnl_table_get_str(o->table, NFTNL_TABLE_NAME));
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_ADD:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_ZERO:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_UPDATE:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_RENAME:
Packit Service 1ec7f4
		snprintf(tcr, sizeof(tcr), "chain %s",
Packit Service 1ec7f4
			 nftnl_chain_get_str(o->chain, NFTNL_CHAIN_NAME));
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_APPEND:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_INSERT:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_REPLACE:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_DELETE:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_FLUSH:
Packit Service 1ec7f4
		snprintf(tcr, sizeof(tcr), "rule in chain %s",
Packit Service 1ec7f4
			 nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
Packit Service 1ec7f4
#if 0
Packit Service 1ec7f4
		{
Packit Service 1ec7f4
			nft_rule_print_save(o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
#endif
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return snprintf(buf, len, "%s: %s", errmsg, tcr);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct obj_update *obj;
Packit Service 1ec7f4
Packit Service 1ec7f4
	obj = calloc(1, sizeof(struct obj_update));
Packit Service 1ec7f4
	if (obj == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	obj->ptr = ptr;
Packit Service 1ec7f4
	obj->error.lineno = h->error.lineno;
Packit Service 1ec7f4
	obj->type = type;
Packit Service 1ec7f4
	list_add_tail(&obj->head, &h->obj_list);
Packit Service 1ec7f4
	h->obj_list_num++;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int batch_table_add(struct nft_handle *h, enum obj_update_type type,
Packit Service 1ec7f4
			   struct nftnl_table *t)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	return batch_add(h, type, t);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
Packit Service 1ec7f4
			   struct nftnl_chain *c)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	return batch_add(h, type, c);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int batch_rule_add(struct nft_handle *h, enum obj_update_type type,
Packit Service 1ec7f4
			  struct nftnl_rule *r)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	return batch_add(h, type, r);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
Packit Service 1ec7f4
	[NFT_TABLE_RAW] = {
Packit Service 1ec7f4
		.name	= "raw",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "PREROUTING",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= -300,	/* NF_IP_PRI_RAW */
Packit Service 1ec7f4
				.hook	= NF_INET_PRE_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "OUTPUT",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= -300,	/* NF_IP_PRI_RAW */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
	[NFT_TABLE_MANGLE] = {
Packit Service 1ec7f4
		.name	= "mangle",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "PREROUTING",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service 1ec7f4
				.hook	= NF_INET_PRE_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "INPUT",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_IN,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "FORWARD",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service 1ec7f4
				.hook	= NF_INET_FORWARD,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "OUTPUT",
Packit Service 1ec7f4
				.type	= "route",
Packit Service 1ec7f4
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "POSTROUTING",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= -150,	/* NF_IP_PRI_MANGLE */
Packit Service 1ec7f4
				.hook	= NF_INET_POST_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
	[NFT_TABLE_FILTER] = {
Packit Service 1ec7f4
		.name	= "filter",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "INPUT",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= 0,	/* NF_IP_PRI_FILTER */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_IN,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "FORWARD",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= 0,	/* NF_IP_PRI_FILTER */
Packit Service 1ec7f4
				.hook	= NF_INET_FORWARD,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "OUTPUT",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= 0,	/* NF_IP_PRI_FILTER */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
	[NFT_TABLE_SECURITY] = {
Packit Service 1ec7f4
		.name	= "security",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "INPUT",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= 150,	/* NF_IP_PRI_SECURITY */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_IN,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "FORWARD",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= 150,	/* NF_IP_PRI_SECURITY */
Packit Service 1ec7f4
				.hook	= NF_INET_FORWARD,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "OUTPUT",
Packit Service 1ec7f4
				.type	= "filter",
Packit Service 1ec7f4
				.prio	= 150,	/* NF_IP_PRI_SECURITY */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
	[NFT_TABLE_NAT] = {
Packit Service 1ec7f4
		.name	= "nat",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "PREROUTING",
Packit Service 1ec7f4
				.type	= "nat",
Packit Service 1ec7f4
				.prio	= -100, /* NF_IP_PRI_NAT_DST */
Packit Service 1ec7f4
				.hook	= NF_INET_PRE_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "INPUT",
Packit Service 1ec7f4
				.type	= "nat",
Packit Service 1ec7f4
				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_IN,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "POSTROUTING",
Packit Service 1ec7f4
				.type	= "nat",
Packit Service 1ec7f4
				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
Packit Service 1ec7f4
				.hook	= NF_INET_POST_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name	= "OUTPUT",
Packit Service 1ec7f4
				.type	= "nat",
Packit Service 1ec7f4
				.prio	= -100, /* NF_IP_PRI_NAT_DST */
Packit Service 1ec7f4
				.hook	= NF_INET_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <linux/netfilter_arp.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
Packit Service 1ec7f4
	[NFT_TABLE_FILTER] = {
Packit Service 1ec7f4
	.name   = "filter",
Packit Service 1ec7f4
	.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "INPUT",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_IP_PRI_FILTER,
Packit Service 1ec7f4
				.hook   = NF_ARP_IN,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "OUTPUT",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_IP_PRI_FILTER,
Packit Service 1ec7f4
				.hook   = NF_ARP_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
#include <linux/netfilter_bridge.h>
Packit Service 1ec7f4
Packit Service 1ec7f4
struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
Packit Service 1ec7f4
	[NFT_TABLE_FILTER] = {
Packit Service 1ec7f4
		.name = "filter",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "INPUT",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_BR_PRI_FILTER_BRIDGED,
Packit Service 1ec7f4
				.hook   = NF_BR_LOCAL_IN,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "FORWARD",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_BR_PRI_FILTER_BRIDGED,
Packit Service 1ec7f4
				.hook   = NF_BR_FORWARD,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "OUTPUT",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_BR_PRI_FILTER_BRIDGED,
Packit Service 1ec7f4
				.hook   = NF_BR_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
	[NFT_TABLE_NAT] = {
Packit Service 1ec7f4
		.name = "nat",
Packit Service 1ec7f4
		.chains = {
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "PREROUTING",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_BR_PRI_NAT_DST_BRIDGED,
Packit Service 1ec7f4
				.hook   = NF_BR_PRE_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "OUTPUT",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_BR_PRI_NAT_DST_OTHER,
Packit Service 1ec7f4
				.hook   = NF_BR_LOCAL_OUT,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
			{
Packit Service 1ec7f4
				.name   = "POSTROUTING",
Packit Service 1ec7f4
				.type   = "filter",
Packit Service 1ec7f4
				.prio   = NF_BR_PRI_NAT_SRC,
Packit Service 1ec7f4
				.hook   = NF_BR_POST_ROUTING,
Packit Service 1ec7f4
			},
Packit Service 1ec7f4
		},
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_table_builtin_add(struct nft_handle *h,
Packit Service 1ec7f4
				 struct builtin_table *_t)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_table *t;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (_t->initialized)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nftnl_table_alloc();
Packit Service 1ec7f4
	if (t == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_chain *
Packit Service 1ec7f4
nft_chain_builtin_alloc(struct builtin_table *table,
Packit Service 1ec7f4
			struct builtin_chain *chain, int policy)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_alloc();
Packit Service 1ec7f4
	if (c == NULL)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table->name);
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain->name);
Packit Service 1ec7f4
	nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
Packit Service 1ec7f4
	nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
Packit Service 1ec7f4
	nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_TYPE, (char *)chain->type);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return c;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_chain_builtin_add(struct nft_handle *h,
Packit Service 1ec7f4
				  struct builtin_table *table,
Packit Service 1ec7f4
				  struct builtin_chain *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
Packit Service 1ec7f4
	if (c == NULL)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
/* find if built-in table already exists */
Packit Service 1ec7f4
struct builtin_table *
Packit Service 1ec7f4
nft_table_builtin_find(struct nft_handle *h, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int i;
Packit Service 1ec7f4
	bool found = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 0; i < NFT_TABLE_MAX; i++) {
Packit Service 1ec7f4
		if (h->tables[i].name == NULL)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(h->tables[i].name, table) != 0)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		found = true;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return found ? &h->tables[i] : NULL;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
/* find if built-in chain already exists */
Packit Service 1ec7f4
struct builtin_chain *
Packit Service 1ec7f4
nft_chain_builtin_find(struct builtin_table *t, const char *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int i;
Packit Service 1ec7f4
	bool found = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i=0; i<NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
Packit Service 1ec7f4
		if (strcmp(t->chains[i].name, chain) != 0)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		found = true;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	return found ? &t->chains[i] : NULL;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_chain_builtin_init(struct nft_handle *h,
Packit Service 1ec7f4
				   struct builtin_table *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list *list = nft_chain_list_get(h);
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	int i;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Initialize built-in chains if they don't exist yet */
Packit Service 1ec7f4
	for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
Packit Service 1ec7f4
Packit Service 1ec7f4
		c = nft_chain_list_find(list, table->name,
Packit Service 1ec7f4
					table->chains[i].name);
Packit Service 1ec7f4
		if (c != NULL)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		nft_chain_builtin_add(h, table, &table->chains[i]);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct builtin_table *t;
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nft_table_builtin_find(h, table);
Packit Service 1ec7f4
	if (t == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (t->initialized)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nft_table_builtin_add(h, t) < 0)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_chain_builtin_init(h, t);
Packit Service 1ec7f4
Packit Service 1ec7f4
	t->initialized = true;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static bool nft_chain_builtin(struct nftnl_chain *c)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	/* Check if this chain has hook number, in that case is built-in.
Packit Service 1ec7f4
	 * Should we better export the flags to user-space via nf_tables?
Packit Service 1ec7f4
	 */
Packit Service 1ec7f4
	return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_restart(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	mnl_socket_close(h->nl);
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->nl = mnl_socket_open(NETLINK_NETFILTER);
Packit Service 1ec7f4
	if (h->nl == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->portid = mnl_socket_get_portid(h->nl);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_init(struct nft_handle *h, struct builtin_table *t)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	h->nl = mnl_socket_open(NETLINK_NETFILTER);
Packit Service 1ec7f4
	if (h->nl == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
Packit Service 1ec7f4
		mnl_socket_close(h->nl);
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->portid = mnl_socket_get_portid(h->nl);
Packit Service 1ec7f4
	h->tables = t;
Packit Service 1ec7f4
Packit Service 1ec7f4
	INIT_LIST_HEAD(&h->obj_list);
Packit Service 1ec7f4
	INIT_LIST_HEAD(&h->err_list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __flush_rule_cache(struct nftnl_rule *r, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *tablename = data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!strcmp(nftnl_rule_get_str(r, NFTNL_RULE_TABLE), tablename)) {
Packit Service 1ec7f4
		nftnl_rule_list_del(r);
Packit Service 1ec7f4
		nftnl_rule_free(r);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void flush_rule_cache(struct nft_handle *h, const char *tablename)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	if (!h->rule_cache)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (tablename) {
Packit Service 1ec7f4
		nftnl_rule_list_foreach(h->rule_cache, __flush_rule_cache,
Packit Service 1ec7f4
					(void *)tablename);
Packit Service 1ec7f4
	} else {
Packit Service 1ec7f4
		nftnl_rule_list_free(h->rule_cache);
Packit Service 1ec7f4
		h->rule_cache = NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __flush_chain_cache(struct nftnl_chain *c, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *tablename = data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!strcmp(nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), tablename)) {
Packit Service 1ec7f4
		nftnl_chain_list_del(c);
Packit Service 1ec7f4
		nftnl_chain_free(c);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void flush_chain_cache(struct nft_handle *h, const char *tablename)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	if (!h->chain_cache)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (tablename) {
Packit Service 1ec7f4
		nftnl_chain_list_foreach(h->chain_cache, __flush_chain_cache,
Packit Service 1ec7f4
					 (void *)tablename);
Packit Service 1ec7f4
	} else {
Packit Service 1ec7f4
		nftnl_chain_list_free(h->chain_cache);
Packit Service 1ec7f4
		h->chain_cache = NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
void nft_fini(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	flush_chain_cache(h, NULL);
Packit Service 1ec7f4
	flush_rule_cache(h, NULL);
Packit Service 1ec7f4
	mnl_socket_close(h->nl);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
#ifdef NLDEBUG
Packit Service 1ec7f4
	char tmp[1024];
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
Packit Service 1ec7f4
	printf("DEBUG: chain: %s\n", tmp);
Packit Service 1ec7f4
	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
Packit Service 1ec7f4
#endif
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
Packit Service 1ec7f4
				       const char *table, const char *chain,
Packit Service 1ec7f4
				       int policy,
Packit Service 1ec7f4
				       const struct xt_counters *counters)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	struct builtin_table *_t;
Packit Service 1ec7f4
	struct builtin_chain *_c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	_t = nft_table_builtin_find(h, table);
Packit Service 1ec7f4
	if (!_t) {
Packit Service 1ec7f4
		errno = ENXIO;
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* if this built-in table does not exists, create it */
Packit Service 1ec7f4
	nft_table_builtin_add(h, _t);
Packit Service 1ec7f4
Packit Service 1ec7f4
	_c = nft_chain_builtin_find(_t, chain);
Packit Service 1ec7f4
	if (_c != NULL) {
Packit Service 1ec7f4
		/* This is a built-in chain */
Packit Service 1ec7f4
		c = nft_chain_builtin_alloc(_t, _c, policy);
Packit Service 1ec7f4
		if (c == NULL)
Packit Service 1ec7f4
			return NULL;
Packit Service 1ec7f4
	} else {
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (counters) {
Packit Service 1ec7f4
		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES,
Packit Service 1ec7f4
					counters->bcnt);
Packit Service 1ec7f4
		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS,
Packit Service 1ec7f4
					counters->pcnt);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return c;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_set(struct nft_handle *h, const char *table,
Packit Service 1ec7f4
		  const char *chain, const char *policy,
Packit Service 1ec7f4
		  const struct xt_counters *counters)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c = NULL;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_chain_set;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (strcmp(policy, "DROP") == 0)
Packit Service 1ec7f4
		c = nft_chain_new(h, table, chain, NF_DROP, counters);
Packit Service 1ec7f4
	else if (strcmp(policy, "ACCEPT") == 0)
Packit Service 1ec7f4
		c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
Packit Service 1ec7f4
	else
Packit Service 1ec7f4
		errno = EINVAL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (c == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	void *info;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
Packit Service 1ec7f4
	nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
Packit Service 1ec7f4
Packit Service 1ec7f4
	info = calloc(1, m->u.match_size);
Packit Service 1ec7f4
	if (info == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	memcpy(info, m->data, m->u.match_size - sizeof(*m));
Packit Service 1ec7f4
	nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct xt_rateinfo *rinfo = (void *)m->data;
Packit Service 1ec7f4
	static const uint32_t mult[] = {
Packit Service 1ec7f4
		XT_LIMIT_SCALE*24*60*60,	/* day */
Packit Service 1ec7f4
		XT_LIMIT_SCALE*60*60,		/* hour */
Packit Service 1ec7f4
		XT_LIMIT_SCALE*60,		/* min */
Packit Service 1ec7f4
		XT_LIMIT_SCALE,			/* sec */
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
	int i;
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("limit");
Packit Service 1ec7f4
	if (!expr)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 1; i < ARRAY_SIZE(mult); i++) {
Packit Service 1ec7f4
		if (rinfo->avg > mult[i] ||
Packit Service 1ec7f4
		    mult[i] / rinfo->avg < mult[i] % rinfo->avg)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_TYPE, NFT_LIMIT_PKTS);
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_FLAGS, 0);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_RATE,
Packit Service 1ec7f4
			   mult[i - 1] / rinfo->avg);
Packit Service 1ec7f4
        nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_UNIT,
Packit Service 1ec7f4
			   mult[i - 1] / XT_LIMIT_SCALE);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_BURST, rinfo->burst);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_match(struct nftnl_rule *r, struct xt_entry_match *m)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!strcmp(m->u.user.name, "limit"))
Packit Service 1ec7f4
		return add_nft_limit(r, m);
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("match");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = __add_match(expr, m);
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	void *info;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set(e, NFTNL_EXPR_TG_NAME, t->u.user.name,
Packit Service 1ec7f4
			  strlen(t->u.user.name));
Packit Service 1ec7f4
	nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
Packit Service 1ec7f4
Packit Service 1ec7f4
	info = calloc(1, t->u.target_size);
Packit Service 1ec7f4
	if (info == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	memcpy(info, t->data, t->u.target_size - sizeof(*t));
Packit Service 1ec7f4
	nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int add_meta_nftrace(struct nftnl_rule *r)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("immediate");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
Packit Service 1ec7f4
	nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("meta");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_NFTRACE);
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (strcmp(t->u.user.name, "TRACE") == 0)
Packit Service 1ec7f4
		return add_meta_nftrace(r);
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("target");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = __add_target(expr, t);
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("immediate");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
Packit Service 1ec7f4
	nftnl_expr_set_str(expr, NFTNL_EXPR_IMM_CHAIN, (char *)name);
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_verdict(struct nftnl_rule *r, int verdict)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("immediate");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
Packit Service 1ec7f4
	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
Packit Service 1ec7f4
	       bool goto_set)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
       int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
       /* If no target at all, add nothing (default to continue) */
Packit Service 1ec7f4
       if (cs->target != NULL) {
Packit Service 1ec7f4
	       /* Standard target? */
Packit Service 1ec7f4
	       if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
Packit Service 1ec7f4
		       ret = add_verdict(r, NF_ACCEPT);
Packit Service 1ec7f4
	       else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
Packit Service 1ec7f4
		       ret = add_verdict(r, NF_DROP);
Packit Service 1ec7f4
	       else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
Packit Service 1ec7f4
		       ret = add_verdict(r, NFT_RETURN);
Packit Service 1ec7f4
	       else
Packit Service 1ec7f4
		       ret = add_target(r, cs->target->t);
Packit Service 1ec7f4
       } else if (strlen(cs->jumpto) > 0) {
Packit Service 1ec7f4
	       /* Not standard, then it's a go / jump to chain */
Packit Service 1ec7f4
	       if (goto_set)
Packit Service 1ec7f4
		       ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
Packit Service 1ec7f4
	       else
Packit Service 1ec7f4
		       ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
Packit Service 1ec7f4
       }
Packit Service 1ec7f4
       return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
#ifdef NLDEBUG
Packit Service 1ec7f4
	char tmp[1024];
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_snprintf(tmp, sizeof(tmp), r, 0, 0);
Packit Service 1ec7f4
	printf("DEBUG: rule: %s\n", tmp);
Packit Service 1ec7f4
	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
Packit Service 1ec7f4
#endif
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_alloc("counter");
Packit Service 1ec7f4
	if (expr == NULL)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_PACKETS, packets);
Packit Service 1ec7f4
	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_BYTES, bytes);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_add_expr(r, expr);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
enum udata_type {
Packit Service 1ec7f4
	UDATA_TYPE_COMMENT,
Packit Service 1ec7f4
	__UDATA_TYPE_MAX,
Packit Service 1ec7f4
};
Packit Service 1ec7f4
#define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
Packit Service 1ec7f4
Packit Service 1ec7f4
int add_comment(struct nftnl_rule *r, const char *comment)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_udata_buf *udata;
Packit Service 1ec7f4
	uint32_t len;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len))
Packit Service 1ec7f4
		return -EALREADY;
Packit Service 1ec7f4
Packit Service 1ec7f4
	udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
Packit Service 1ec7f4
	if (!udata)
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (strnlen(comment, 255) == 255)
Packit Service 1ec7f4
		return -ENOSPC;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!nftnl_udata_put_strz(udata, UDATA_TYPE_COMMENT, comment))
Packit Service 1ec7f4
		return -ENOMEM;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
Packit Service 1ec7f4
			    nftnl_udata_buf_data(udata),
Packit Service 1ec7f4
			    nftnl_udata_buf_len(udata));
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_udata_buf_free(udata);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	unsigned char *value = nftnl_udata_get(attr);
Packit Service 1ec7f4
	uint8_t type = nftnl_udata_type(attr);
Packit Service 1ec7f4
	uint8_t len = nftnl_udata_len(attr);
Packit Service 1ec7f4
	const struct nftnl_udata **tb = data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	switch (type) {
Packit Service 1ec7f4
	case UDATA_TYPE_COMMENT:
Packit Service 1ec7f4
		if (value[len - 1] != '\0')
Packit Service 1ec7f4
			return -1;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	default:
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	tb[type] = attr;
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
char *get_comment(const void *data, uint32_t data_len)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nftnl_udata_parse(data, data_len, parse_udata_cb, tb) < 0)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!tb[UDATA_TYPE_COMMENT])
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return nftnl_udata_get(tb[UDATA_TYPE_COMMENT]);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, proto);
Packit Service 1ec7f4
	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS,
Packit Service 1ec7f4
			      inv ? NFT_RULE_COMPAT_F_INV : 0);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_rule *
Packit Service 1ec7f4
nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
Packit Service 1ec7f4
	     void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_alloc();
Packit Service 1ec7f4
	if (r == NULL)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
Packit Service 1ec7f4
	nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
Packit Service 1ec7f4
	nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (h->ops->add(r, data) < 0)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return r;
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	nftnl_rule_free(r);
Packit Service 1ec7f4
	return NULL;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h);
Packit Service 1ec7f4
Packit Service 1ec7f4
int
Packit Service 1ec7f4
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
Packit Service 1ec7f4
		void *data, uint64_t handle, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	int type;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* If built-in chains don't exist for this table, create them */
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_append;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_new(h, chain, table, data);
Packit Service 1ec7f4
	if (r == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (handle > 0) {
Packit Service 1ec7f4
		nftnl_rule_set(r, NFTNL_RULE_HANDLE, &handle);
Packit Service 1ec7f4
		type = NFT_COMPAT_RULE_REPLACE;
Packit Service 1ec7f4
	} else
Packit Service 1ec7f4
		type = NFT_COMPAT_RULE_APPEND;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (batch_rule_add(h, type, r) < 0) {
Packit Service 1ec7f4
		nftnl_rule_free(r);
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (verbose)
Packit Service 1ec7f4
		h->ops->print_rule(r, 0, FMT_PRINT_RULE);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!nft_rule_list_get(h))
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_add_tail(r, h->rule_cache);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
void
Packit Service 1ec7f4
nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type,
Packit Service 1ec7f4
		    unsigned int format)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
Packit Service 1ec7f4
	int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
Packit Service 1ec7f4
	struct iptables_command_state cs = {};
Packit Service 1ec7f4
	struct nft_family_ops *ops;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ops = nft_family_ops_lookup(family);
Packit Service 1ec7f4
	ops->rule_to_cs(r, &cs);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
Packit Service 1ec7f4
		ops->save_counters(&cs);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* print chain name */
Packit Service 1ec7f4
	switch(type) {
Packit Service 1ec7f4
	case NFT_RULE_APPEND:
Packit Service 1ec7f4
		printf("-A %s ", chain);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_RULE_DEL:
Packit Service 1ec7f4
		printf("-D %s ", chain);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (ops->save_rule)
Packit Service 1ec7f4
		ops->save_rule(&cs, format);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (ops->clear_cs)
Packit Service 1ec7f4
		ops->clear_cs(&cs);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	struct nftnl_chain_list *list = data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_alloc();
Packit Service 1ec7f4
	if (c == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
Packit Service 1ec7f4
		goto out;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_add_tail(c, list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return MNL_CB_OK;
Packit Service 1ec7f4
out:
Packit Service 1ec7f4
	nftnl_chain_free(c);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	return MNL_CB_OK;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	char buf[16536];
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (h->chain_cache)
Packit Service 1ec7f4
		return h->chain_cache;
Packit Service 1ec7f4
retry:
Packit Service 1ec7f4
	list = nftnl_chain_list_alloc();
Packit Service 1ec7f4
	if (list == NULL) {
Packit Service 1ec7f4
		errno = ENOMEM;
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
Packit Service 1ec7f4
					NLM_F_DUMP, h->seq);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list);
Packit Service 1ec7f4
	if (ret < 0 && errno == EINTR) {
Packit Service 1ec7f4
		assert(nft_restart(h) >= 0);
Packit Service 1ec7f4
		nftnl_chain_list_free(list);
Packit Service 1ec7f4
		goto retry;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->chain_cache = list;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return list;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static const char *policy_name[NF_ACCEPT+1] = {
Packit Service 1ec7f4
	[NF_DROP] = "DROP",
Packit Service 1ec7f4
	[NF_ACCEPT] = "ACCEPT",
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
Packit Service 1ec7f4
		   const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nft_family_ops *ops;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ops = nft_family_ops_lookup(h->family);
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *chain_table =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *policy = NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, chain_table) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (nft_chain_builtin(c)) {
Packit Service 1ec7f4
			uint32_t pol = NF_ACCEPT;
Packit Service 1ec7f4
Packit Service 1ec7f4
			if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY))
Packit Service 1ec7f4
				pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service 1ec7f4
			policy = policy_name[pol];
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (ops->save_chain)
Packit Service 1ec7f4
			ops->save_chain(c, policy);
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	struct nftnl_rule_list *list = data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_alloc();
Packit Service 1ec7f4
	if (r == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
Packit Service 1ec7f4
		goto out;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_add_tail(r, list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return MNL_CB_OK;
Packit Service 1ec7f4
out:
Packit Service 1ec7f4
	nftnl_rule_free(r);
Packit Service 1ec7f4
	nftnl_rule_list_free(list);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	return MNL_CB_OK;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	char buf[16536];
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (h->rule_cache)
Packit Service 1ec7f4
		return h->rule_cache;
Packit Service 1ec7f4
Packit Service 1ec7f4
retry:
Packit Service 1ec7f4
	list = nftnl_rule_list_alloc();
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
Packit Service 1ec7f4
					NLM_F_DUMP, h->seq);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list);
Packit Service 1ec7f4
	if (ret < 0) {
Packit Service 1ec7f4
		if (errno == EINTR) {
Packit Service 1ec7f4
			assert(nft_restart(h) >= 0);
Packit Service 1ec7f4
			nftnl_rule_list_free(list);
Packit Service 1ec7f4
			goto retry;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		nftnl_rule_list_free(list);
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->rule_cache = list;
Packit Service 1ec7f4
	return list;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	struct nftnl_rule_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_rule_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	while (r != NULL) {
Packit Service 1ec7f4
		const char *rule_table =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, rule_table) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		nft_rule_print_save(r, NFT_RULE_APPEND, format);
Packit Service 1ec7f4
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_iter_destroy(iter);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void
Packit Service 1ec7f4
__nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_alloc();
Packit Service 1ec7f4
	if (r == NULL)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
Packit Service 1ec7f4
	nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r) < 0)
Packit Service 1ec7f4
		nftnl_rule_free(r);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
struct chain_user_flush_data {
Packit Service 1ec7f4
	struct nft_handle	*handle;
Packit Service 1ec7f4
	const char		*table;
Packit Service 1ec7f4
	const char		*chain;
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __nft_chain_user_flush(struct nftnl_chain *c, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
	const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
	struct chain_user_flush_data *d = data;
Packit Service 1ec7f4
	struct nft_handle *h = d->handle;
Packit Service 1ec7f4
	const char *table = d->table;
Packit Service 1ec7f4
	const char *chain = d->chain;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (strcmp(table, table_name) != 0)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM))
Packit Service 1ec7f4
		__nft_rule_flush(h, table, chain);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list,
Packit Service 1ec7f4
			 const char *table, const char *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct chain_user_flush_data d = {
Packit Service 1ec7f4
		.handle = h,
Packit Service 1ec7f4
		.table	= table,
Packit Service 1ec7f4
		.chain  = chain,
Packit Service 1ec7f4
	};
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_chain_user_flush;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_foreach(list, __nft_chain_user_flush, &d);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
Packit Service 1ec7f4
		   bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_flush;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
	if (list == NULL) {
Packit Service 1ec7f4
		ret = 1;
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL) {
Packit Service 1ec7f4
		ret = 1;
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *table_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, table_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (chain != NULL && strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (verbose)
Packit Service 1ec7f4
			fprintf(stdout, "Flushing chain `%s'\n", chain_name);
Packit Service 1ec7f4
Packit Service 1ec7f4
		__nft_rule_flush(h, table_name, chain_name);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (chain != NULL)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
	flush_rule_cache(h, table);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_chain_user_add;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* If built-in chains don't exist for this table, create them */
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_alloc();
Packit Service 1ec7f4
	if (c == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_chain_list_get(h);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_add(c, h->chain_cache);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
/* From linux/netlink.h */
Packit Service 1ec7f4
#ifndef NLM_F_NONREC
Packit Service 1ec7f4
#define NLM_F_NONREC	0x100	/* Do not delete recursively    */
Packit Service 1ec7f4
#endif
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_user_del(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
		       const char *table, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
	int deleted_ctr = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_chain_user_del;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *table_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		/* don't delete built-in chain */
Packit Service 1ec7f4
		if (nft_chain_builtin(c))
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, table_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (chain != NULL && strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (verbose)
Packit Service 1ec7f4
			fprintf(stdout, "Deleting chain `%s'\n", chain);
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (ret < 0)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
		deleted_ctr++;
Packit Service 1ec7f4
		nftnl_chain_list_del(c);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (chain != NULL)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* chain not found */
Packit Service 1ec7f4
	if (chain != NULL && deleted_ctr == 0) {
Packit Service 1ec7f4
		ret = -1;
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
struct nftnl_chain *
Packit Service 1ec7f4
nft_chain_list_find(struct nftnl_chain_list *list,
Packit Service 1ec7f4
		    const char *table, const char *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *table_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, table_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
		return c;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
	return NULL;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_chain *
Packit Service 1ec7f4
nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return nft_chain_list_find(list, table, chain);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
bool nft_chain_exists(struct nft_handle *h,
Packit Service 1ec7f4
		      const char *table, const char *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct builtin_table *t = nft_table_builtin_find(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* xtables does not support custom tables */
Packit Service 1ec7f4
	if (!t)
Packit Service 1ec7f4
		return false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nft_chain_builtin_find(t, chain))
Packit Service 1ec7f4
		return true;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return !!nft_chain_find(h, table, chain);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_user_rename(struct nft_handle *h,const char *chain,
Packit Service 1ec7f4
			  const char *table, const char *newname)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	uint64_t handle;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_chain_user_add;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* If built-in chains don't exist for this table, create them */
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Config load changed errno. Ensure genuine info for our callers. */
Packit Service 1ec7f4
	errno = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Find the old chain to be renamed */
Packit Service 1ec7f4
	c = nft_chain_find(h, table, chain);
Packit Service 1ec7f4
	if (c == NULL) {
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Now prepare the new name for the chain */
Packit Service 1ec7f4
	c = nftnl_chain_alloc();
Packit Service 1ec7f4
	if (c == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
Packit Service 1ec7f4
	nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)newname);
Packit Service 1ec7f4
	nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_table *t;
Packit Service 1ec7f4
	struct nftnl_table_list *list = data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nftnl_table_alloc();
Packit Service 1ec7f4
	if (t == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (nftnl_table_nlmsg_parse(nlh, t) < 0)
Packit Service 1ec7f4
		goto out;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_table_list_add_tail(t, list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return MNL_CB_OK;
Packit Service 1ec7f4
out:
Packit Service 1ec7f4
	nftnl_table_free(t);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	return MNL_CB_OK;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	char buf[16536];
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
	struct nftnl_table_list *list;
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
retry:
Packit Service 1ec7f4
	list = nftnl_table_list_alloc();
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
Packit Service 1ec7f4
					NLM_F_DUMP, h->seq);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
Packit Service 1ec7f4
	if (ret < 0 && errno == EINTR) {
Packit Service 1ec7f4
		assert(nft_restart(h) >= 0);
Packit Service 1ec7f4
		nftnl_table_list_free(list);
Packit Service 1ec7f4
		goto retry;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return list;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
bool nft_table_find(struct nft_handle *h, const char *tablename)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_table_list *list;
Packit Service 1ec7f4
	struct nftnl_table_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_table *t;
Packit Service 1ec7f4
	bool ret = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nftnl_table_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_table_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nftnl_table_list_iter_next(iter);
Packit Service 1ec7f4
	while (t != NULL) {
Packit Service 1ec7f4
		const char *this_tablename =
Packit Service 1ec7f4
			nftnl_table_get(t, NFTNL_TABLE_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(tablename, this_tablename) == 0) {
Packit Service 1ec7f4
			ret = true;
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		t = nftnl_table_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_table_list_iter_destroy(iter);
Packit Service 1ec7f4
	nftnl_table_list_free(list);
Packit Service 1ec7f4
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_for_each_table(struct nft_handle *h,
Packit Service 1ec7f4
		       int (*func)(struct nft_handle *h, const char *tablename, bool counters),
Packit Service 1ec7f4
		       bool counters)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_table_list *list;
Packit Service 1ec7f4
	struct nftnl_table_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_table *t;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nftnl_table_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_table_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nftnl_table_list_iter_next(iter);
Packit Service 1ec7f4
	while (t != NULL) {
Packit Service 1ec7f4
		const char *tablename =
Packit Service 1ec7f4
			nftnl_table_get(t, NFTNL_TABLE_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		func(h, tablename, counters);
Packit Service 1ec7f4
Packit Service 1ec7f4
		t = nftnl_table_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_table_list_iter_destroy(iter);
Packit Service 1ec7f4
	nftnl_table_list_free(list);
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __nft_table_flush(struct nft_handle *h, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct builtin_table *_t;
Packit Service 1ec7f4
	struct nftnl_table *t;
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nftnl_table_alloc();
Packit Service 1ec7f4
	if (t == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
Packit Service 1ec7f4
Packit Service 1ec7f4
	_t = nft_table_builtin_find(h, table);
Packit Service 1ec7f4
	assert(_t);
Packit Service 1ec7f4
	_t->initialized = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	flush_chain_cache(h, table);
Packit Service 1ec7f4
	flush_rule_cache(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_table_flush(struct nft_handle *h, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_table_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_table_list *list;
Packit Service 1ec7f4
	struct nftnl_table *t;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_table_flush;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nftnl_table_list_get(h);
Packit Service 1ec7f4
	if (list == NULL) {
Packit Service 1ec7f4
		ret = -1;
Packit Service 1ec7f4
		goto err_out;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_table_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL) {
Packit Service 1ec7f4
		ret = -1;
Packit Service 1ec7f4
		goto err_table_list;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	t = nftnl_table_list_iter_next(iter);
Packit Service 1ec7f4
	while (t != NULL) {
Packit Service 1ec7f4
		const char *table_name =
Packit Service 1ec7f4
			nftnl_table_get_str(t, NFTNL_TABLE_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table_name, table) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = __nft_table_flush(h, table);
Packit Service 1ec7f4
		if (ret < 0)
Packit Service 1ec7f4
			goto err_table_iter;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		t = nftnl_table_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!h->rule_cache) {
Packit Service 1ec7f4
		h->rule_cache = nftnl_rule_list_alloc();
Packit Service 1ec7f4
		if (h->rule_cache == NULL)
Packit Service 1ec7f4
			return -1;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
err_table_iter:
Packit Service 1ec7f4
	nftnl_table_list_iter_destroy(iter);
Packit Service 1ec7f4
err_table_list:
Packit Service 1ec7f4
	nftnl_table_list_free(list);
Packit Service 1ec7f4
err_out:
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
void nft_table_new(struct nft_handle *h, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list,
Packit Service 1ec7f4
			  struct nftnl_rule *r)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int ret;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_del(r);
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
Packit Service 1ec7f4
	if (ret < 0) {
Packit Service 1ec7f4
		nftnl_rule_free(r);
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_rule *
Packit Service 1ec7f4
nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list,
Packit Service 1ec7f4
	      const char *chain, const char *table, void *data, int rulenum)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	struct nftnl_rule_list_iter *iter;
Packit Service 1ec7f4
	int rule_ctr = 0;
Packit Service 1ec7f4
	bool found = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_rule_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	while (r != NULL) {
Packit Service 1ec7f4
		const char *rule_table =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
Packit Service 1ec7f4
		const char *rule_chain =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, rule_table) != 0 ||
Packit Service 1ec7f4
		    strcmp(chain, rule_chain) != 0) {
Packit Service 1ec7f4
			DEBUGP("different chain / table\n");
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (rulenum >= 0) {
Packit Service 1ec7f4
			/* Delete by rule number case */
Packit Service 1ec7f4
			if (rule_ctr == rulenum) {
Packit Service 1ec7f4
			    found = true;
Packit Service 1ec7f4
			    break;
Packit Service 1ec7f4
			}
Packit Service 1ec7f4
		} else {
Packit Service 1ec7f4
			found = h->ops->rule_find(h->ops, r, data);
Packit Service 1ec7f4
			if (found)
Packit Service 1ec7f4
				break;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
		rule_ctr++;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_iter_destroy(iter);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return found ? r : NULL;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_check(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
		   const char *table, void *data, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_check;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_find(h, list, chain, table, data, -1);
Packit Service 1ec7f4
	if (r == NULL) {
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	if (verbose)
Packit Service 1ec7f4
		h->ops->print_rule(r, 0, FMT_PRINT_RULE);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_delete(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
		    const char *table, void *data, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_delete;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_find(h, list, chain, table, data, -1);
Packit Service 1ec7f4
	if (r != NULL) {
Packit Service 1ec7f4
		ret =__nft_rule_del(h, list, r);
Packit Service 1ec7f4
		if (ret < 0)
Packit Service 1ec7f4
			errno = ENOMEM;
Packit Service 1ec7f4
		if (verbose)
Packit Service 1ec7f4
			h->ops->print_rule(r, 0, FMT_PRINT_RULE);
Packit Service 1ec7f4
	} else
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct nftnl_rule *
Packit Service 1ec7f4
nft_rule_add(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
	     const char *table, struct iptables_command_state *cs,
Packit Service 1ec7f4
	     uint64_t handle, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_new(h, chain, table, cs);
Packit Service 1ec7f4
	if (r == NULL)
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (handle > 0)
Packit Service 1ec7f4
		nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) {
Packit Service 1ec7f4
		nftnl_rule_free(r);
Packit Service 1ec7f4
		return NULL;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (verbose)
Packit Service 1ec7f4
		h->ops->print_rule(r, 0, FMT_PRINT_RULE);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return r;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_insert(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
		    const char *table, void *data, int rulenum, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule *r, *new_rule;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	uint64_t handle = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* If built-in chains don't exist for this table, create them */
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_insert;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (rulenum > 0) {
Packit Service 1ec7f4
		list = nft_rule_list_get(h);
Packit Service 1ec7f4
		if (list == NULL)
Packit Service 1ec7f4
			goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
		r = nft_rule_find(h, list, chain, table, data, rulenum);
Packit Service 1ec7f4
		if (r == NULL) {
Packit Service 1ec7f4
			/* special case: iptables allows to insert into
Packit Service 1ec7f4
			 * rule_count + 1 position.
Packit Service 1ec7f4
			 */
Packit Service 1ec7f4
			r = nft_rule_find(h, list, chain, table, data,
Packit Service 1ec7f4
					  rulenum - 1);
Packit Service 1ec7f4
			if (r != NULL)
Packit Service 1ec7f4
				return nft_rule_append(h, chain, table, data,
Packit Service 1ec7f4
						       0, verbose);
Packit Service 1ec7f4
Packit Service 1ec7f4
			errno = ENOENT;
Packit Service 1ec7f4
			goto err;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE);
Packit Service 1ec7f4
		DEBUGP("adding after rule handle %"PRIu64"\n", handle);
Packit Service 1ec7f4
	} else {
Packit Service 1ec7f4
		nft_rule_list_get(h);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	new_rule = nft_rule_add(h, chain, table, data, handle, verbose);
Packit Service 1ec7f4
	if (!new_rule)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (handle)
Packit Service 1ec7f4
		nftnl_rule_list_insert_at(new_rule, r);
Packit Service 1ec7f4
	else
Packit Service 1ec7f4
		nftnl_rule_list_add(new_rule, h->rule_cache);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_delete_num(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
			const char *table, int rulenum, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_delete_num;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_find(h, list, chain, table, NULL, rulenum);
Packit Service 1ec7f4
	if (r != NULL) {
Packit Service 1ec7f4
		DEBUGP("deleting rule by number %d\n", rulenum);
Packit Service 1ec7f4
		ret = __nft_rule_del(h, list, r);
Packit Service 1ec7f4
		if (ret < 0)
Packit Service 1ec7f4
			errno = ENOMEM;
Packit Service 1ec7f4
	} else
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_replace(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
		     const char *table, void *data, int rulenum, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_replace;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_find(h, list, chain, table, data, rulenum);
Packit Service 1ec7f4
	if (r != NULL) {
Packit Service 1ec7f4
		DEBUGP("replacing rule with handle=%llu\n",
Packit Service 1ec7f4
			(unsigned long long)
Packit Service 1ec7f4
			nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
Packit Service 1ec7f4
Packit Service 1ec7f4
		nftnl_rule_list_del(r);
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = nft_rule_append(h, chain, table, data,
Packit Service 1ec7f4
				      nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
Packit Service 1ec7f4
				      verbose);
Packit Service 1ec7f4
	} else
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int
Packit Service 1ec7f4
__nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
Packit Service 1ec7f4
		int rulenum, unsigned int format,
Packit Service 1ec7f4
		void (*cb)(struct nftnl_rule *r, unsigned int num,
Packit Service 1ec7f4
			   unsigned int format))
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	struct nftnl_rule_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	int rule_ctr = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_rule_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	while (r != NULL) {
Packit Service 1ec7f4
		const char *rule_table =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
Packit Service 1ec7f4
		const char *rule_chain =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, rule_table) != 0 ||
Packit Service 1ec7f4
		    strcmp(chain, rule_chain) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		rule_ctr++;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (rulenum > 0 && rule_ctr != rulenum) {
Packit Service 1ec7f4
			/* List by rule number case */
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		cb(r, rule_ctr, format);
Packit Service 1ec7f4
		if (rulenum > 0)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_iter_destroy(iter);
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_rule_count(struct nft_handle *h,
Packit Service 1ec7f4
			  const char *chain, const char *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	int rule_ctr = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_rule_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	while (r != NULL) {
Packit Service 1ec7f4
		const char *rule_table =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
Packit Service 1ec7f4
		const char *rule_chain =
Packit Service 1ec7f4
			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, rule_table) != 0 ||
Packit Service 1ec7f4
		    strcmp(chain, rule_chain) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		rule_ctr++;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_iter_destroy(iter);
Packit Service 1ec7f4
	return rule_ctr;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
Packit Service 1ec7f4
		  int rulenum, unsigned int format)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct nft_family_ops *ops;
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	bool found = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* If built-in chains don't exist for this table, create them */
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) {
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
		/* Force table and chain creation, otherwise first iptables -L
Packit Service 1ec7f4
		 * lists no table/chains.
Packit Service 1ec7f4
		 */
Packit Service 1ec7f4
		if (!list_empty(&h->obj_list)) {
Packit Service 1ec7f4
			nft_commit(h);
Packit Service 1ec7f4
			flush_chain_cache(h, NULL);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	ops = nft_family_ops_lookup(h->family);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!nft_is_table_compatible(h, table)) {
Packit Service 1ec7f4
		xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (chain && rulenum) {
Packit Service 1ec7f4
		__nft_rule_list(h, chain, table,
Packit Service 1ec7f4
				rulenum, format, ops->print_rule);
Packit Service 1ec7f4
		return 1;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!chain && ops->print_table_header)
Packit Service 1ec7f4
		ops->print_table_header(table);
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *chain_table =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
		uint32_t policy =
Packit Service 1ec7f4
			nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service 1ec7f4
		uint32_t refs =
Packit Service 1ec7f4
			nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
Packit Service 1ec7f4
		struct xt_counters ctrs = {
Packit Service 1ec7f4
			.pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
Packit Service 1ec7f4
			.bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
Packit Service 1ec7f4
		};
Packit Service 1ec7f4
		bool basechain = false;
Packit Service 1ec7f4
		uint32_t entries;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
Packit Service 1ec7f4
			basechain = true;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, chain_table) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
		if (chain) {
Packit Service 1ec7f4
			if (strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
				goto next;
Packit Service 1ec7f4
			else if (ops->print_table_header)
Packit Service 1ec7f4
				ops->print_table_header(table);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (found)
Packit Service 1ec7f4
			printf("\n");
Packit Service 1ec7f4
Packit Service 1ec7f4
		entries = nft_rule_count(h, chain_name, table);
Packit Service 1ec7f4
		ops->print_header(format, chain_name, policy_name[policy],
Packit Service 1ec7f4
				  &ctrs, basechain, refs - entries, entries);
Packit Service 1ec7f4
Packit Service 1ec7f4
		__nft_rule_list(h, chain_name, table,
Packit Service 1ec7f4
				rulenum, format, ops->print_rule);
Packit Service 1ec7f4
Packit Service 1ec7f4
		found = true;
Packit Service 1ec7f4
Packit Service 1ec7f4
		/* we printed the chain we wanted, stop processing. */
Packit Service 1ec7f4
		if (chain)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	if (chain && !found)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void
Packit Service 1ec7f4
list_save(struct nftnl_rule *r, unsigned int num, unsigned int format)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	nft_rule_print_save(r, NFT_RULE_APPEND, format);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int
Packit Service 1ec7f4
nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
			 const char *table, struct nftnl_chain_list *list,
Packit Service 1ec7f4
			 int counters)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *chain_table =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
		uint32_t policy =
Packit Service 1ec7f4
			nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, chain_table) != 0 ||
Packit Service 1ec7f4
		    (chain && strcmp(chain, chain_name) != 0))
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		/* this is a base chain */
Packit Service 1ec7f4
		if (nft_chain_builtin(c)) {
Packit Service 1ec7f4
			printf("-P %s %s", chain_name, policy_name[policy]);
Packit Service 1ec7f4
Packit Service 1ec7f4
			if (counters) {
Packit Service 1ec7f4
				printf(" -c %"PRIu64" %"PRIu64"\n",
Packit Service 1ec7f4
					nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
Packit Service 1ec7f4
					nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
Packit Service 1ec7f4
			} else
Packit Service 1ec7f4
				printf("\n");
Packit Service 1ec7f4
		} else {
Packit Service 1ec7f4
			printf("-N %s\n", chain_name);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_list_save(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
		       const char *table, int rulenum, int counters)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	unsigned int format = 0;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* If built-in chains don't exist for this table, create them */
Packit Service 1ec7f4
	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) {
Packit Service 1ec7f4
		nft_xt_builtin_init(h, table);
Packit Service 1ec7f4
		/* Force table and chain creation, otherwise first iptables -L
Packit Service 1ec7f4
		 * lists no table/chains.
Packit Service 1ec7f4
		 */
Packit Service 1ec7f4
		if (!list_empty(&h->obj_list)) {
Packit Service 1ec7f4
			nft_commit(h);
Packit Service 1ec7f4
			flush_chain_cache(h, NULL);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!nft_is_table_compatible(h, table)) {
Packit Service 1ec7f4
		xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table);
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Dump policies and custom chains first */
Packit Service 1ec7f4
	if (!rulenum)
Packit Service 1ec7f4
		nftnl_rule_list_chain_save(h, chain, table, list, counters);
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Now dump out rules in this table */
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (counters < 0)
Packit Service 1ec7f4
		format = FMT_C_COUNTS;
Packit Service 1ec7f4
	else if (counters == 0)
Packit Service 1ec7f4
		format = FMT_NOCOUNTS;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *chain_table =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, chain_table) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
		if (chain && strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = __nft_rule_list(h, chain_name, table, rulenum,
Packit Service 1ec7f4
				      format, list_save);
Packit Service 1ec7f4
Packit Service 1ec7f4
		/* we printed the chain we wanted, stop processing. */
Packit Service 1ec7f4
		if (chain)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
			   const char *table, int rulenum)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct iptables_command_state cs = {};
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_fn = nft_rule_delete;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nft_rule_find(h, list, chain, table, NULL, rulenum);
Packit Service 1ec7f4
	if (r == NULL) {
Packit Service 1ec7f4
		errno = ENOENT;
Packit Service 1ec7f4
		ret = 1;
Packit Service 1ec7f4
		goto error;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nft_rule_to_iptables_command_state(r, &cs);
Packit Service 1ec7f4
Packit Service 1ec7f4
	cs.counters.pcnt = cs.counters.bcnt = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret =  nft_rule_append(h, chain, table, &cs,
Packit Service 1ec7f4
			       nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
Packit Service 1ec7f4
			       false);
Packit Service 1ec7f4
Packit Service 1ec7f4
error:
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
Packit Service 1ec7f4
				       uint16_t flags, uint32_t seq,
Packit Service 1ec7f4
				       struct nftnl_table *table)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service 1ec7f4
					type, h->family, flags, seq);
Packit Service 1ec7f4
	nftnl_table_nlmsg_build_payload(nlh, table);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
Packit Service 1ec7f4
				       uint16_t flags, uint32_t seq,
Packit Service 1ec7f4
				       struct nftnl_chain *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service 1ec7f4
					type, h->family, flags, seq);
Packit Service 1ec7f4
	nftnl_chain_nlmsg_build_payload(nlh, chain);
Packit Service 1ec7f4
	nft_chain_print_debug(chain, nlh);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
Packit Service 1ec7f4
				      uint16_t flags, uint32_t seq,
Packit Service 1ec7f4
				      struct nftnl_rule *rule)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
Packit Service 1ec7f4
				       type, h->family, flags, seq);
Packit Service 1ec7f4
	nftnl_rule_nlmsg_build_payload(nlh, rule);
Packit Service 1ec7f4
	nft_rule_print_debug(rule, nlh);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	switch (o->type) {
Packit Service 1ec7f4
	case NFT_COMPAT_TABLE_ADD:
Packit Service 1ec7f4
	case NFT_COMPAT_TABLE_FLUSH:
Packit Service 1ec7f4
		nftnl_table_free(o->table);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_ZERO:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_ADD:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_UPDATE:
Packit Service 1ec7f4
	case NFT_COMPAT_CHAIN_RENAME:
Packit Service 1ec7f4
		nftnl_chain_free(o->chain);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_APPEND:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_INSERT:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_REPLACE:
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_DELETE:
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_RULE_FLUSH:
Packit Service 1ec7f4
		nftnl_rule_free(o->rule);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	h->obj_list_num--;
Packit Service 1ec7f4
	list_del(&o->head);
Packit Service 1ec7f4
	free(o);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_action(struct nft_handle *h, int action)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct obj_update *n, *tmp;
Packit Service 1ec7f4
	struct mnl_err *err, *ne;
Packit Service 1ec7f4
	unsigned int buflen, i, len;
Packit Service 1ec7f4
	bool show_errors = true;
Packit Service 1ec7f4
	char errmsg[1024];
Packit Service 1ec7f4
	uint32_t seq = 1;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->batch = mnl_batch_init();
Packit Service 1ec7f4
Packit Service 1ec7f4
	mnl_batch_begin(h->batch, seq++);
Packit Service 1ec7f4
Packit Service 1ec7f4
	list_for_each_entry(n, &h->obj_list, head) {
Packit Service 1ec7f4
		n->seq = seq++;
Packit Service 1ec7f4
		switch (n->type) {
Packit Service 1ec7f4
		case NFT_COMPAT_TABLE_ADD:
Packit Service 1ec7f4
			nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE,
Packit Service 1ec7f4
						   NLM_F_CREATE, n->seq,
Packit Service 1ec7f4
						   n->table);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_TABLE_FLUSH:
Packit Service 1ec7f4
			nft_compat_table_batch_add(h, NFT_MSG_DELTABLE,
Packit Service 1ec7f4
						   0,
Packit Service 1ec7f4
						   n->seq, n->table);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_ADD:
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_ZERO:
Packit Service 1ec7f4
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
Packit Service 1ec7f4
						   NLM_F_CREATE, n->seq,
Packit Service 1ec7f4
						   n->chain);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_USER_ADD:
Packit Service 1ec7f4
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
Packit Service 1ec7f4
						   NLM_F_EXCL, n->seq,
Packit Service 1ec7f4
						   n->chain);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_USER_DEL:
Packit Service 1ec7f4
			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
Packit Service 1ec7f4
						   NLM_F_NONREC, n->seq,
Packit Service 1ec7f4
						   n->chain);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_USER_FLUSH:
Packit Service 1ec7f4
			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
Packit Service 1ec7f4
						   0, n->seq,
Packit Service 1ec7f4
						   n->chain);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_UPDATE:
Packit Service 1ec7f4
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
Packit Service 1ec7f4
						   h->restore ?
Packit Service 1ec7f4
						     NLM_F_CREATE : 0,
Packit Service 1ec7f4
						   n->seq, n->chain);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_CHAIN_RENAME:
Packit Service 1ec7f4
			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0,
Packit Service 1ec7f4
						   n->seq, n->chain);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_RULE_APPEND:
Packit Service 1ec7f4
			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
Packit Service 1ec7f4
						  NLM_F_CREATE | NLM_F_APPEND,
Packit Service 1ec7f4
						  n->seq, n->rule);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_RULE_INSERT:
Packit Service 1ec7f4
			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
Packit Service 1ec7f4
						  NLM_F_CREATE, n->seq,
Packit Service 1ec7f4
						  n->rule);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_RULE_REPLACE:
Packit Service 1ec7f4
			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
Packit Service 1ec7f4
						  NLM_F_CREATE | NLM_F_REPLACE,
Packit Service 1ec7f4
						  n->seq, n->rule);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		case NFT_COMPAT_RULE_DELETE:
Packit Service 1ec7f4
		case NFT_COMPAT_RULE_FLUSH:
Packit Service 1ec7f4
			nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
Packit Service 1ec7f4
						  n->seq, n->rule);
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		mnl_nft_batch_continue(h->batch);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	switch (action) {
Packit Service 1ec7f4
	case NFT_COMPAT_COMMIT:
Packit Service 1ec7f4
		mnl_batch_end(h->batch, seq++);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case NFT_COMPAT_ABORT:
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_batch_talk(h->nl, h->batch, &h->err_list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	i = 0;
Packit Service 1ec7f4
	buflen = sizeof(errmsg);
Packit Service 1ec7f4
Packit Service 1ec7f4
	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
Packit Service 1ec7f4
		list_for_each_entry_safe(err, ne, &h->err_list, head) {
Packit Service 1ec7f4
			if (err->seqnum > n->seq)
Packit Service 1ec7f4
				break;
Packit Service 1ec7f4
Packit Service 1ec7f4
			if (err->seqnum == n->seq && show_errors) {
Packit Service 1ec7f4
				if (n->error.lineno == 0)
Packit Service 1ec7f4
					show_errors = false;
Packit Service 1ec7f4
				len = mnl_append_error(h, n, err, errmsg + i, buflen);
Packit Service 1ec7f4
				if (len > 0 && len <= buflen) {
Packit Service 1ec7f4
					buflen -= len;
Packit Service 1ec7f4
					i += len;
Packit Service 1ec7f4
				}
Packit Service 1ec7f4
			}
Packit Service 1ec7f4
			mnl_err_list_free(err);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
		batch_obj_del(h, n);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	mnl_batch_reset(h->batch);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (i)
Packit Service 1ec7f4
		xtables_error(RESOURCE_PROBLEM, "%s", errmsg);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_commit(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	return nft_action(h, NFT_COMPAT_COMMIT);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_abort(struct nft_handle *h)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	return nft_action(h, NFT_COMPAT_ABORT);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct mnl_socket *nl;
Packit Service 1ec7f4
	char buf[16536];
Packit Service 1ec7f4
	struct nlmsghdr *nlh;
Packit Service 1ec7f4
	uint32_t portid, seq, type = 0;
Packit Service 1ec7f4
	uint32_t pf = AF_INET;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	switch (opt) {
Packit Service 1ec7f4
	case IPT_SO_GET_REVISION_MATCH:
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case IP6T_SO_GET_REVISION_MATCH:
Packit Service 1ec7f4
		pf = AF_INET6;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case IPT_SO_GET_REVISION_TARGET:
Packit Service 1ec7f4
		type = 1;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case IP6T_SO_GET_REVISION_TARGET:
Packit Service 1ec7f4
		type = 1;
Packit Service 1ec7f4
		pf = AF_INET6;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	default:
Packit Service 1ec7f4
		/* No revision support (arp, ebtables), assume latest version ok */
Packit Service 1ec7f4
		return 1;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nlh = mnl_nlmsg_put_header(buf);
Packit Service 1ec7f4
	nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
Packit Service 1ec7f4
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
Packit Service 1ec7f4
	nlh->nlmsg_seq = seq = time(NULL);
Packit Service 1ec7f4
Packit Service 1ec7f4
	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
Packit Service 1ec7f4
	nfg->nfgen_family = pf;
Packit Service 1ec7f4
	nfg->version = NFNETLINK_V0;
Packit Service 1ec7f4
	nfg->res_id = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
Packit Service 1ec7f4
	mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
Packit Service 1ec7f4
	mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
Packit Service 1ec7f4
Packit Service 1ec7f4
	DEBUGP("requesting `%s' rev=%d type=%d via nft_compat\n",
Packit Service 1ec7f4
		name, rev, type);
Packit Service 1ec7f4
Packit Service 1ec7f4
	nl = mnl_socket_open(NETLINK_NETFILTER);
Packit Service 1ec7f4
	if (nl == NULL)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	portid = mnl_socket_get_portid(nl);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
Packit Service 1ec7f4
	if (ret == -1)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
Packit Service 1ec7f4
	if (ret == -1)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	mnl_socket_close(nl);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret < 0 ? 0 : 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
/* Translates errno numbers into more human-readable form than strerror. */
Packit Service 1ec7f4
const char *nft_strerror(int err)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	unsigned int i;
Packit Service 1ec7f4
	static struct table_struct {
Packit Service 1ec7f4
		void *fn;
Packit Service 1ec7f4
		int err;
Packit Service 1ec7f4
		const char *message;
Packit Service 1ec7f4
	} table[] =
Packit Service 1ec7f4
	  {
Packit Service 1ec7f4
	    { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
Packit Service 1ec7f4
	    { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
Packit Service 1ec7f4
	    { nft_chain_user_del, EBUSY, "Directory not empty" },
Packit Service 1ec7f4
	    { nft_chain_user_del, EMLINK,
Packit Service 1ec7f4
	      "Can't delete chain with references left" },
Packit Service 1ec7f4
	    { nft_chain_user_add, EEXIST, "Chain already exists" },
Packit Service 1ec7f4
	    { nft_rule_insert, ENOENT, "Index of insertion too big" },
Packit Service 1ec7f4
	    { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
Packit Service 1ec7f4
	    { nft_rule_replace, ENOENT, "Index of replacement too big" },
Packit Service 1ec7f4
	    { nft_rule_delete_num, ENOENT, "Index of deletion too big" },
Packit Service 1ec7f4
/*	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
Packit Service 1ec7f4
	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
Packit Service 1ec7f4
	    /* ENOENT for DELETE probably means no matching rule */
Packit Service 1ec7f4
	    { nft_rule_delete, ENOENT,
Packit Service 1ec7f4
	      "Bad rule (does a matching rule exist in that chain?)" },
Packit Service 1ec7f4
	    { nft_chain_set, ENOENT, "Bad built-in chain name" },
Packit Service 1ec7f4
	    { nft_chain_set, EINVAL, "Bad policy name" },
Packit Service 1ec7f4
	    { nft_chain_set, ENXIO, "Bad table name" },
Packit Service 1ec7f4
	    { NULL, ELOOP, "Loop found in table" },
Packit Service 1ec7f4
	    { NULL, EPERM, "Permission denied (you must be root)" },
Packit Service 1ec7f4
	    { NULL, 0, "Incompatible with this kernel" },
Packit Service 1ec7f4
	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
Packit Service 1ec7f4
	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
Packit Service 1ec7f4
	    { NULL, ENOMEM, "Memory allocation problem" },
Packit Service 1ec7f4
	    { NULL, ENOENT, "No chain/target/match by that name" },
Packit Service 1ec7f4
	  };
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
Packit Service 1ec7f4
		if ((!table[i].fn || table[i].fn == nft_fn)
Packit Service 1ec7f4
		    && table[i].err == err)
Packit Service 1ec7f4
			return table[i].message;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return strerror(err);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void xtables_config_perror(uint32_t flags, const char *fmt, ...)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	va_list args;
Packit Service 1ec7f4
Packit Service 1ec7f4
	va_start(args, fmt);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (flags & NFT_LOAD_VERBOSE)
Packit Service 1ec7f4
		vfprintf(stderr, fmt, args);
Packit Service 1ec7f4
Packit Service 1ec7f4
	va_end(args);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int __nft_xtables_config_load(struct nft_handle *h, const char *filename,
Packit Service 1ec7f4
				     uint32_t flags)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_table_list *table_list = NULL;
Packit Service 1ec7f4
	struct nftnl_chain_list *chain_list = NULL;
Packit Service 1ec7f4
	struct nftnl_table_list_iter *titer = NULL;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *citer = NULL;
Packit Service 1ec7f4
	struct nftnl_table *table;
Packit Service 1ec7f4
	struct nftnl_chain *chain;
Packit Service 1ec7f4
	uint32_t table_family, chain_family;
Packit Service 1ec7f4
	bool found = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	table_list = nftnl_table_list_alloc();
Packit Service 1ec7f4
	chain_list = nftnl_chain_list_alloc();
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (xtables_config_parse(filename, table_list, chain_list) < 0) {
Packit Service 1ec7f4
		if (errno == ENOENT) {
Packit Service 1ec7f4
			xtables_config_perror(flags,
Packit Service 1ec7f4
				"configuration file `%s' does not exists\n",
Packit Service 1ec7f4
				filename);
Packit Service 1ec7f4
		} else {
Packit Service 1ec7f4
			xtables_config_perror(flags,
Packit Service 1ec7f4
				"Fatal error parsing config file: %s\n",
Packit Service 1ec7f4
				 strerror(errno));
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Stage 1) create tables */
Packit Service 1ec7f4
	titer = nftnl_table_list_iter_create(table_list);
Packit Service 1ec7f4
	while ((table = nftnl_table_list_iter_next(titer)) != NULL) {
Packit Service 1ec7f4
		table_family = nftnl_table_get_u32(table,
Packit Service 1ec7f4
						      NFTNL_TABLE_FAMILY);
Packit Service 1ec7f4
		if (h->family != table_family)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		found = true;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (batch_table_add(h, NFT_COMPAT_TABLE_ADD, table) < 0) {
Packit Service 1ec7f4
			if (errno == EEXIST) {
Packit Service 1ec7f4
				xtables_config_perror(flags,
Packit Service 1ec7f4
					"table `%s' already exists, skipping\n",
Packit Service 1ec7f4
					(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
Packit Service 1ec7f4
			} else {
Packit Service 1ec7f4
				xtables_config_perror(flags,
Packit Service 1ec7f4
					"table `%s' cannot be create, reason `%s'. Exitting\n",
Packit Service 1ec7f4
					(char *)nftnl_table_get(table, NFTNL_TABLE_NAME),
Packit Service 1ec7f4
					strerror(errno));
Packit Service 1ec7f4
				goto err;
Packit Service 1ec7f4
			}
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
		xtables_config_perror(flags, "table `%s' has been created\n",
Packit Service 1ec7f4
			(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	nftnl_table_list_iter_destroy(titer);
Packit Service 1ec7f4
	nftnl_table_list_free(table_list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!found)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	/* Stage 2) create chains */
Packit Service 1ec7f4
	citer = nftnl_chain_list_iter_create(chain_list);
Packit Service 1ec7f4
	while ((chain = nftnl_chain_list_iter_next(citer)) != NULL) {
Packit Service 1ec7f4
		chain_family = nftnl_chain_get_u32(chain,
Packit Service 1ec7f4
						      NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
		if (h->family != chain_family)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, chain) < 0) {
Packit Service 1ec7f4
			if (errno == EEXIST) {
Packit Service 1ec7f4
				xtables_config_perror(flags,
Packit Service 1ec7f4
					"chain `%s' already exists in table `%s', skipping\n",
Packit Service 1ec7f4
					(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
Packit Service 1ec7f4
					(char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
Packit Service 1ec7f4
			} else {
Packit Service 1ec7f4
				xtables_config_perror(flags,
Packit Service 1ec7f4
					"chain `%s' cannot be create, reason `%s'. Exitting\n",
Packit Service 1ec7f4
					(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
Packit Service 1ec7f4
					strerror(errno));
Packit Service 1ec7f4
				goto err;
Packit Service 1ec7f4
			}
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		xtables_config_perror(flags,
Packit Service 1ec7f4
			"chain `%s' in table `%s' has been created\n",
Packit Service 1ec7f4
			(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
Packit Service 1ec7f4
			(char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(citer);
Packit Service 1ec7f4
	nftnl_chain_list_free(chain_list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->config_done = 1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	nftnl_table_list_free(table_list);
Packit Service 1ec7f4
	nftnl_chain_list_free(chain_list);
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (titer != NULL)
Packit Service 1ec7f4
		nftnl_table_list_iter_destroy(titer);
Packit Service 1ec7f4
	if (citer != NULL)
Packit Service 1ec7f4
		nftnl_chain_list_iter_destroy(citer);
Packit Service 1ec7f4
Packit Service 1ec7f4
	h->config_done = -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return -1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_xtables_config_load(struct nft_handle *h, const char *filename,
Packit Service 1ec7f4
			    uint32_t flags)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	if (!h->config_done)
Packit Service 1ec7f4
		return __nft_xtables_config_load(h, filename, flags);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return h->config_done;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void nft_chain_zero_rule_counters(struct nft_handle *h,
Packit Service 1ec7f4
					 struct nftnl_chain *c)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	const char *table_name;
Packit Service 1ec7f4
	const char *chain_name;
Packit Service 1ec7f4
	struct nftnl_rule *r;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
	iter = nftnl_rule_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
Packit Service 1ec7f4
	table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
	chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
	r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	while (r != NULL) {
Packit Service 1ec7f4
		struct nftnl_expr_iter *ei;
Packit Service 1ec7f4
		const char *table_chain;
Packit Service 1ec7f4
		const char *rule_chain;
Packit Service 1ec7f4
		struct nftnl_expr *e;
Packit Service 1ec7f4
		bool zero_needed;
Packit Service 1ec7f4
Packit Service 1ec7f4
		table_chain = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
Packit Service 1ec7f4
		if (strcmp(table_chain, table_name))
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		rule_chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
Packit Service 1ec7f4
		if (strcmp(rule_chain, chain_name))
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ei = nftnl_expr_iter_create(r);
Packit Service 1ec7f4
		if (!ei)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
		e = nftnl_expr_iter_next(ei);
Packit Service 1ec7f4
	        zero_needed = false;
Packit Service 1ec7f4
		while (e != NULL) {
Packit Service 1ec7f4
			const char *en = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
Packit Service 1ec7f4
Packit Service 1ec7f4
			if (strcmp(en, "counter") == 0 && (
Packit Service 1ec7f4
			    nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS) ||
Packit Service 1ec7f4
			    nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES))) {
Packit Service 1ec7f4
				nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_PACKETS, 0);
Packit Service 1ec7f4
				nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_BYTES, 0);
Packit Service 1ec7f4
				zero_needed = true;
Packit Service 1ec7f4
			}
Packit Service 1ec7f4
Packit Service 1ec7f4
			e = nftnl_expr_iter_next(ei);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		nftnl_expr_iter_destroy(ei);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (zero_needed) {
Packit Service 1ec7f4
			/*
Packit Service 1ec7f4
			 * Unset RULE_POSITION for older kernels, we want to replace
Packit Service 1ec7f4
			 * rule based on its handle only.
Packit Service 1ec7f4
			 */
Packit Service 1ec7f4
			nftnl_rule_unset(r, NFTNL_RULE_POSITION);
Packit Service 1ec7f4
			batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		r = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_iter_destroy(iter);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
Packit Service 1ec7f4
			    const char *table, bool verbose)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *c;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		goto err;
Packit Service 1ec7f4
Packit Service 1ec7f4
	c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (c != NULL) {
Packit Service 1ec7f4
		const char *chain_name =
Packit Service 1ec7f4
			nftnl_chain_get(c, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
		const char *chain_table =
Packit Service 1ec7f4
			nftnl_chain_get(c, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, chain_table) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (chain != NULL && strcmp(chain, chain_name) != 0)
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (verbose)
Packit Service 1ec7f4
			fprintf(stdout, "Zeroing chain `%s'\n", chain_name);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
Packit Service 1ec7f4
			/* zero base chain counters. */
Packit Service 1ec7f4
			nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
Packit Service 1ec7f4
			nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		nft_chain_zero_rule_counters(h, c);
Packit Service 1ec7f4
Packit Service 1ec7f4
		nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (chain != NULL)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		c = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
Packit Service 1ec7f4
err:
Packit Service 1ec7f4
	/* the core expects 1 for success and 0 for error */
Packit Service 1ec7f4
	return ret == 0 ? 1 : 0;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	if (invflags & flag)
Packit Service 1ec7f4
		return NFT_CMP_NEQ;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return NFT_CMP_EQ;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
#define NFT_COMPAT_EXPR_MAX     8
Packit Service 1ec7f4
Packit Service 1ec7f4
static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
Packit Service 1ec7f4
	"match",
Packit Service 1ec7f4
	"target",
Packit Service 1ec7f4
	"payload",
Packit Service 1ec7f4
	"meta",
Packit Service 1ec7f4
	"cmp",
Packit Service 1ec7f4
	"bitwise",
Packit Service 1ec7f4
	"counter",
Packit Service 1ec7f4
	"immediate"
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_is_expr_compatible(const struct nftnl_expr *expr)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
Packit Service 1ec7f4
	int i;
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) {
Packit Service 1ec7f4
		if (strcmp(supported_exprs[i], name) == 0)
Packit Service 1ec7f4
			return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!strcmp(name, "limit") &&
Packit Service 1ec7f4
	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_TYPE) == NFT_LIMIT_PKTS &&
Packit Service 1ec7f4
	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static bool nft_is_rule_compatible(struct nftnl_rule *rule)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_expr_iter *iter;
Packit Service 1ec7f4
	struct nftnl_expr *expr;
Packit Service 1ec7f4
	bool compatible = false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_expr_iter_create(rule);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	expr = nftnl_expr_iter_next(iter);
Packit Service 1ec7f4
	while (expr != NULL) {
Packit Service 1ec7f4
		if (nft_is_expr_compatible(expr) == 0) {
Packit Service 1ec7f4
			expr = nftnl_expr_iter_next(iter);
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
Packit Service 1ec7f4
		compatible = true;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_expr_iter_destroy(iter);
Packit Service 1ec7f4
	return compatible;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_is_chain_compatible(const struct nft_handle *h,
Packit Service 1ec7f4
				   const struct nftnl_chain *chain)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *table, *name, *type, *cur_table;
Packit Service 1ec7f4
	struct builtin_chain *chains;
Packit Service 1ec7f4
	int i, j, prio;
Packit Service 1ec7f4
	enum nf_inet_hooks hook;
Packit Service 1ec7f4
Packit Service 1ec7f4
	table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
	name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME);
Packit Service 1ec7f4
	type = nftnl_chain_get(chain, NFTNL_CHAIN_TYPE);
Packit Service 1ec7f4
	prio = nftnl_chain_get_u32(chain, NFTNL_CHAIN_PRIO);
Packit Service 1ec7f4
	hook = nftnl_chain_get_u32(chain, NFTNL_CHAIN_HOOKNUM);
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 0; i < NFT_TABLE_MAX; i++) {
Packit Service 1ec7f4
		cur_table = h->tables[i].name;
Packit Service 1ec7f4
		chains = h->tables[i].chains;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (!cur_table || strcmp(table, cur_table) != 0)
Packit Service 1ec7f4
			continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
		for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) {
Packit Service 1ec7f4
			if (strcmp(name, chains[j].name) != 0)
Packit Service 1ec7f4
				continue;
Packit Service 1ec7f4
Packit Service 1ec7f4
			if (strcmp(type, chains[j].type) == 0 &&
Packit Service 1ec7f4
			    prio == chains[j].prio &&
Packit Service 1ec7f4
			    hook == chains[j].hook)
Packit Service 1ec7f4
				return 0;
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
		}
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_chain_list *list;
Packit Service 1ec7f4
	struct nftnl_chain_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_chain *chain;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_chain_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_chain_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return -1;
Packit Service 1ec7f4
Packit Service 1ec7f4
	chain = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	while (chain != NULL) {
Packit Service 1ec7f4
		const char *chain_table;
Packit Service 1ec7f4
Packit Service 1ec7f4
		chain_table = nftnl_chain_get_str(chain, NFTNL_CHAIN_TABLE);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(chain_table, tablename) ||
Packit Service 1ec7f4
		    !nft_chain_builtin(chain))
Packit Service 1ec7f4
			goto next;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = nft_is_chain_compatible(h, chain);
Packit Service 1ec7f4
		if (ret != 0)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
next:
Packit Service 1ec7f4
		chain = nftnl_chain_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_chain_list_iter_destroy(iter);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return ret;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
bool nft_is_table_compatible(struct nft_handle *h, const char *tablename)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct nftnl_rule_list *list;
Packit Service 1ec7f4
	struct nftnl_rule_list_iter *iter;
Packit Service 1ec7f4
	struct nftnl_rule *rule;
Packit Service 1ec7f4
	int ret = 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (!nft_table_builtin_find(h, tablename))
Packit Service 1ec7f4
		return false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	ret = nft_are_chains_compatible(h, tablename);
Packit Service 1ec7f4
	if (ret != 0)
Packit Service 1ec7f4
		return false;
Packit Service 1ec7f4
Packit Service 1ec7f4
	list = nft_rule_list_get(h);
Packit Service 1ec7f4
	if (list == NULL)
Packit Service 1ec7f4
		return true;
Packit Service 1ec7f4
Packit Service 1ec7f4
	iter = nftnl_rule_list_iter_create(list);
Packit Service 1ec7f4
	if (iter == NULL)
Packit Service 1ec7f4
		return true;
Packit Service 1ec7f4
Packit Service 1ec7f4
	rule = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	while (rule != NULL) {
Packit Service 1ec7f4
		const char *table = nftnl_rule_get_str(rule, NFTNL_RULE_TABLE);
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strcmp(table, tablename))
Packit Service 1ec7f4
			goto next_rule;
Packit Service 1ec7f4
Packit Service 1ec7f4
		ret = nft_is_rule_compatible(rule);
Packit Service 1ec7f4
		if (ret != 0)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
next_rule:
Packit Service 1ec7f4
		rule = nftnl_rule_list_iter_next(iter);
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	nftnl_rule_list_iter_destroy(iter);
Packit Service 1ec7f4
	return ret == 0;
Packit Service 1ec7f4
}