Home | History | Annotate | Download | only in iptables
      1 /*
      2  * (C) 2012 by Pablo Neira Ayuso <pablo (at) netfilter.org>
      3  *
      4  * This program is free software; you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published
      6  * by the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
     10  */
     11 
     12 #include <unistd.h>
     13 #include <fcntl.h>
     14 #include <sys/types.h>
     15 #include <sys/socket.h>
     16 #include <stdbool.h>
     17 #include <errno.h>
     18 #include <netdb.h>	/* getprotobynumber */
     19 #include <time.h>
     20 #include <stdarg.h>
     21 #include <inttypes.h>
     22 
     23 #include <xtables.h>
     24 #include <libiptc/libxtc.h>
     25 #include <libiptc/xtcshared.h>
     26 
     27 #include <stdlib.h>
     28 #include <string.h>
     29 
     30 #include <linux/netfilter/x_tables.h>
     31 #include <linux/netfilter_ipv4/ip_tables.h>
     32 #include <linux/netfilter_ipv6/ip6_tables.h>
     33 #include <netinet/ip6.h>
     34 
     35 #include <linux/netlink.h>
     36 #include <linux/netfilter/nfnetlink.h>
     37 #include <linux/netfilter/nf_tables.h>
     38 #include <linux/netfilter/nf_tables_compat.h>
     39 
     40 #include <libmnl/libmnl.h>
     41 #include <libnftnl/table.h>
     42 #include <libnftnl/chain.h>
     43 #include <libnftnl/rule.h>
     44 #include <libnftnl/expr.h>
     45 #include <libnftnl/set.h>
     46 #include <libnftnl/udata.h>
     47 
     48 #include <netinet/in.h>	/* inet_ntoa */
     49 #include <arpa/inet.h>
     50 
     51 #include "nft.h"
     52 #include "xshared.h" /* proto_to_name */
     53 #include "nft-shared.h"
     54 #include "xtables-config-parser.h"
     55 
     56 static void *nft_fn;
     57 
     58 int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
     59 	     int (*cb)(const struct nlmsghdr *nlh, void *data),
     60 	     void *data)
     61 {
     62 	int ret;
     63 	char buf[MNL_SOCKET_BUFFER_SIZE];
     64 
     65 	if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
     66 		return -1;
     67 
     68 	ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
     69 	while (ret > 0) {
     70 		ret = mnl_cb_run(buf, ret, h->seq, h->portid, cb, data);
     71 		if (ret <= 0)
     72 			break;
     73 
     74 		ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
     75 	}
     76 	if (ret == -1) {
     77 		return -1;
     78 	}
     79 
     80 	return 0;
     81 }
     82 
     83 static LIST_HEAD(batch_page_list);
     84 static int batch_num_pages;
     85 
     86 struct batch_page {
     87 	struct list_head	head;
     88 	struct mnl_nlmsg_batch	*batch;
     89 };
     90 
     91 /* selected batch page is 256 Kbytes long to load ruleset of
     92  * half a million rules without hitting -EMSGSIZE due to large
     93  * iovec.
     94  */
     95 #define BATCH_PAGE_SIZE getpagesize() * 32
     96 
     97 static struct mnl_nlmsg_batch *mnl_nftnl_batch_alloc(void)
     98 {
     99 	static char *buf;
    100 
    101 	/* libmnl needs higher buffer to handle batch overflows */
    102 	buf = malloc(BATCH_PAGE_SIZE + getpagesize());
    103 	if (buf == NULL)
    104 		return NULL;
    105 
    106 	return mnl_nlmsg_batch_start(buf, BATCH_PAGE_SIZE);
    107 }
    108 
    109 static struct mnl_nlmsg_batch *
    110 mnl_nftnl_batch_page_add(struct mnl_nlmsg_batch *batch)
    111 {
    112 	struct batch_page *batch_page;
    113 
    114 	batch_page = malloc(sizeof(struct batch_page));
    115 	if (batch_page == NULL)
    116 		return NULL;
    117 
    118 	batch_page->batch = batch;
    119 	list_add_tail(&batch_page->head, &batch_page_list);
    120 	batch_num_pages++;
    121 
    122 	return mnl_nftnl_batch_alloc();
    123 }
    124 
    125 static int nlbuffsiz;
    126 
    127 static void mnl_nft_set_sndbuffer(const struct mnl_socket *nl)
    128 {
    129 	int newbuffsiz;
    130 
    131 	if (batch_num_pages * BATCH_PAGE_SIZE <= nlbuffsiz)
    132 		return;
    133 
    134 	newbuffsiz = batch_num_pages * BATCH_PAGE_SIZE;
    135 
    136 	/* Rise sender buffer length to avoid hitting -EMSGSIZE */
    137 	if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE,
    138 		       &newbuffsiz, sizeof(socklen_t)) < 0)
    139 		return;
    140 
    141 	nlbuffsiz = newbuffsiz;
    142 }
    143 
    144 static void mnl_nftnl_batch_reset(void)
    145 {
    146 	struct batch_page *batch_page, *next;
    147 
    148 	list_for_each_entry_safe(batch_page, next, &batch_page_list, head) {
    149 		list_del(&batch_page->head);
    150 		free(batch_page->batch);
    151 		free(batch_page);
    152 		batch_num_pages--;
    153 	}
    154 }
    155 
    156 static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl)
    157 {
    158 	static const struct sockaddr_nl snl = {
    159 		.nl_family = AF_NETLINK
    160 	};
    161 	struct iovec iov[batch_num_pages];
    162 	struct msghdr msg = {
    163 		.msg_name	= (struct sockaddr *) &snl,
    164 		.msg_namelen	= sizeof(snl),
    165 		.msg_iov	= iov,
    166 		.msg_iovlen	= batch_num_pages,
    167 	};
    168 	struct batch_page *batch_page;
    169 	int i = 0, ret;
    170 
    171 	mnl_nft_set_sndbuffer(nl);
    172 
    173 	list_for_each_entry(batch_page, &batch_page_list, head) {
    174 		iov[i].iov_base = mnl_nlmsg_batch_head(batch_page->batch);
    175 		iov[i].iov_len = mnl_nlmsg_batch_size(batch_page->batch);
    176 		i++;
    177 #ifdef NL_DEBUG
    178 		mnl_nlmsg_fprintf(stdout,
    179 				  mnl_nlmsg_batch_head(batch_page->batch),
    180 				  mnl_nlmsg_batch_size(batch_page->batch),
    181 				  sizeof(struct nfgenmsg));
    182 #endif
    183 	}
    184 
    185 	ret = sendmsg(mnl_socket_get_fd(nl), &msg, 0);
    186 	mnl_nftnl_batch_reset();
    187 
    188 	return ret;
    189 }
    190 
    191 static int mnl_nftnl_batch_talk(struct nft_handle *h)
    192 {
    193 	int ret, fd = mnl_socket_get_fd(h->nl);
    194 	char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
    195 	fd_set readfds;
    196 	struct timeval tv = {
    197 		.tv_sec		= 0,
    198 		.tv_usec	= 0
    199 	};
    200 	int err = 0;
    201 
    202 	ret = mnl_nft_socket_sendmsg(h->nl);
    203 	if (ret == -1)
    204 		return -1;
    205 
    206 	FD_ZERO(&readfds);
    207 	FD_SET(fd, &readfds);
    208 
    209 	/* receive and digest all the acknowledgments from the kernel. */
    210 	ret = select(fd+1, &readfds, NULL, NULL, &tv);
    211 	if (ret == -1)
    212 		return -1;
    213 
    214 	while (ret > 0 && FD_ISSET(fd, &readfds)) {
    215 		ret = mnl_socket_recvfrom(h->nl, rcv_buf, sizeof(rcv_buf));
    216 		if (ret == -1)
    217 			return -1;
    218 
    219 		ret = mnl_cb_run(rcv_buf, ret, 0, h->portid, NULL, NULL);
    220 		/* Annotate first error and continue, make sure we get all
    221 		 * acknoledgments.
    222 		 */
    223 		if (!err && ret == -1)
    224 			err = errno;
    225 
    226 		ret = select(fd+1, &readfds, NULL, NULL, &tv);
    227 		if (ret == -1)
    228 			return -1;
    229 
    230 		FD_ZERO(&readfds);
    231 		FD_SET(fd, &readfds);
    232 	}
    233 	errno = err;
    234 	return err ? -1 : 0;
    235 }
    236 
    237 static void mnl_nftnl_batch_begin(struct mnl_nlmsg_batch *batch, uint32_t seq)
    238 {
    239 	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq);
    240 	if (!mnl_nlmsg_batch_next(batch))
    241 		mnl_nftnl_batch_page_add(batch);
    242 }
    243 
    244 static void mnl_nftnl_batch_end(struct mnl_nlmsg_batch *batch, uint32_t seq)
    245 {
    246 	nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq);
    247 	if (!mnl_nlmsg_batch_next(batch))
    248 		mnl_nftnl_batch_page_add(batch);
    249 }
    250 
    251 enum obj_update_type {
    252 	NFT_COMPAT_TABLE_ADD,
    253 	NFT_COMPAT_CHAIN_ADD,
    254 	NFT_COMPAT_CHAIN_USER_ADD,
    255 	NFT_COMPAT_CHAIN_USER_DEL,
    256 	NFT_COMPAT_CHAIN_UPDATE,
    257 	NFT_COMPAT_CHAIN_RENAME,
    258 	NFT_COMPAT_RULE_APPEND,
    259 	NFT_COMPAT_RULE_INSERT,
    260 	NFT_COMPAT_RULE_REPLACE,
    261 	NFT_COMPAT_RULE_DELETE,
    262 	NFT_COMPAT_RULE_FLUSH,
    263 };
    264 
    265 enum obj_action {
    266 	NFT_COMPAT_COMMIT,
    267 	NFT_COMPAT_ABORT,
    268 };
    269 
    270 struct obj_update {
    271 	struct list_head	head;
    272 	enum obj_update_type	type;
    273 	union {
    274 		struct nftnl_table	*table;
    275 		struct nftnl_chain	*chain;
    276 		struct nftnl_rule		*rule;
    277 		void			*ptr;
    278 	};
    279 };
    280 
    281 static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
    282 {
    283 	struct obj_update *obj;
    284 
    285 	obj = calloc(1, sizeof(struct obj_update));
    286 	if (obj == NULL)
    287 		return -1;
    288 
    289 	obj->ptr = ptr;
    290 	obj->type = type;
    291 	list_add_tail(&obj->head, &h->obj_list);
    292 	h->obj_list_num++;
    293 
    294 	return 0;
    295 }
    296 
    297 static int batch_table_add(struct nft_handle *h, enum obj_update_type type,
    298 			   struct nftnl_table *t)
    299 {
    300 	return batch_add(h, type, t);
    301 }
    302 
    303 static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
    304 			   struct nftnl_chain *c)
    305 {
    306 	return batch_add(h, type, c);
    307 }
    308 
    309 static int batch_rule_add(struct nft_handle *h, enum obj_update_type type,
    310 			  struct nftnl_rule *r)
    311 {
    312 	return batch_add(h, type, r);
    313 }
    314 
    315 struct builtin_table xtables_ipv4[TABLES_MAX] = {
    316 	[RAW] = {
    317 		.name	= "raw",
    318 		.chains = {
    319 			{
    320 				.name	= "PREROUTING",
    321 				.type	= "filter",
    322 				.prio	= -300,	/* NF_IP_PRI_RAW */
    323 				.hook	= NF_INET_PRE_ROUTING,
    324 			},
    325 			{
    326 				.name	= "OUTPUT",
    327 				.type	= "filter",
    328 				.prio	= -300,	/* NF_IP_PRI_RAW */
    329 				.hook	= NF_INET_LOCAL_OUT,
    330 			},
    331 		},
    332 	},
    333 	[MANGLE] = {
    334 		.name	= "mangle",
    335 		.chains = {
    336 			{
    337 				.name	= "PREROUTING",
    338 				.type	= "filter",
    339 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
    340 				.hook	= NF_INET_PRE_ROUTING,
    341 			},
    342 			{
    343 				.name	= "INPUT",
    344 				.type	= "filter",
    345 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
    346 				.hook	= NF_INET_LOCAL_IN,
    347 			},
    348 			{
    349 				.name	= "FORWARD",
    350 				.type	= "filter",
    351 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
    352 				.hook	= NF_INET_FORWARD,
    353 			},
    354 			{
    355 				.name	= "OUTPUT",
    356 				.type	= "route",
    357 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
    358 				.hook	= NF_INET_LOCAL_OUT,
    359 			},
    360 			{
    361 				.name	= "POSTROUTING",
    362 				.type	= "filter",
    363 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
    364 				.hook	= NF_INET_POST_ROUTING,
    365 			},
    366 		},
    367 	},
    368 	[FILTER] = {
    369 		.name	= "filter",
    370 		.chains = {
    371 			{
    372 				.name	= "INPUT",
    373 				.type	= "filter",
    374 				.prio	= 0,	/* NF_IP_PRI_FILTER */
    375 				.hook	= NF_INET_LOCAL_IN,
    376 			},
    377 			{
    378 				.name	= "FORWARD",
    379 				.type	= "filter",
    380 				.prio	= 0,	/* NF_IP_PRI_FILTER */
    381 				.hook	= NF_INET_FORWARD,
    382 			},
    383 			{
    384 				.name	= "OUTPUT",
    385 				.type	= "filter",
    386 				.prio	= 0,	/* NF_IP_PRI_FILTER */
    387 				.hook	= NF_INET_LOCAL_OUT,
    388 			},
    389 		},
    390 	},
    391 	[SECURITY] = {
    392 		.name	= "security",
    393 		.chains = {
    394 			{
    395 				.name	= "INPUT",
    396 				.type	= "filter",
    397 				.prio	= 150,	/* NF_IP_PRI_SECURITY */
    398 				.hook	= NF_INET_LOCAL_IN,
    399 			},
    400 			{
    401 				.name	= "FORWARD",
    402 				.type	= "filter",
    403 				.prio	= 150,	/* NF_IP_PRI_SECURITY */
    404 				.hook	= NF_INET_FORWARD,
    405 			},
    406 			{
    407 				.name	= "OUTPUT",
    408 				.type	= "filter",
    409 				.prio	= 150,	/* NF_IP_PRI_SECURITY */
    410 				.hook	= NF_INET_LOCAL_OUT,
    411 			},
    412 		},
    413 	},
    414 	[NAT] = {
    415 		.name	= "nat",
    416 		.chains = {
    417 			{
    418 				.name	= "PREROUTING",
    419 				.type	= "nat",
    420 				.prio	= -100, /* NF_IP_PRI_NAT_DST */
    421 				.hook	= NF_INET_PRE_ROUTING,
    422 			},
    423 			{
    424 				.name	= "INPUT",
    425 				.type	= "nat",
    426 				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
    427 				.hook	= NF_INET_LOCAL_IN,
    428 			},
    429 			{
    430 				.name	= "POSTROUTING",
    431 				.type	= "nat",
    432 				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
    433 				.hook	= NF_INET_POST_ROUTING,
    434 			},
    435 			{
    436 				.name	= "OUTPUT",
    437 				.type	= "nat",
    438 				.prio	= -100, /* NF_IP_PRI_NAT_DST */
    439 				.hook	= NF_INET_LOCAL_OUT,
    440 			},
    441 		},
    442 	},
    443 };
    444 
    445 #include <linux/netfilter_arp.h>
    446 
    447 struct builtin_table xtables_arp[TABLES_MAX] = {
    448 	[FILTER] = {
    449 	.name   = "filter",
    450 	.chains = {
    451 			{
    452 				.name   = "INPUT",
    453 				.type   = "filter",
    454 				.prio   = NF_IP_PRI_FILTER,
    455 				.hook   = NF_ARP_IN,
    456 			},
    457 			{
    458 				.name   = "FORWARD",
    459 				.type   = "filter",
    460 				.prio   = NF_IP_PRI_FILTER,
    461 				.hook   = NF_ARP_FORWARD,
    462 			},
    463 			{
    464 				.name   = "OUTPUT",
    465 				.type   = "filter",
    466 				.prio   = NF_IP_PRI_FILTER,
    467 				.hook   = NF_ARP_OUT,
    468 			},
    469 		},
    470 	},
    471 };
    472 
    473 #include <linux/netfilter_bridge.h>
    474 
    475 struct builtin_table xtables_bridge[TABLES_MAX] = {
    476 	[FILTER] = {
    477 		.name = "filter",
    478 		.chains = {
    479 			{
    480 				.name   = "INPUT",
    481 				.type   = "filter",
    482 				.prio   = NF_BR_PRI_FILTER_BRIDGED,
    483 				.hook   = NF_BR_LOCAL_IN,
    484 			},
    485 			{
    486 				.name   = "FORWARD",
    487 				.type   = "filter",
    488 				.prio   = NF_BR_PRI_FILTER_BRIDGED,
    489 				.hook   = NF_BR_FORWARD,
    490 			},
    491 			{
    492 				.name   = "OUTPUT",
    493 				.type   = "filter",
    494 				.prio   = NF_BR_PRI_FILTER_BRIDGED,
    495 				.hook   = NF_BR_LOCAL_OUT,
    496 			},
    497 		},
    498 	},
    499 	[NAT] = {
    500 		.name = "nat",
    501 		.chains = {
    502 			{
    503 				.name   = "PREROUTING",
    504 				.type   = "filter",
    505 				.prio   = NF_BR_PRI_NAT_DST_BRIDGED,
    506 				.hook   = NF_BR_PRE_ROUTING,
    507 			},
    508 			{
    509 				.name   = "OUTPUT",
    510 				.type   = "filter",
    511 				.prio   = NF_BR_PRI_NAT_DST_OTHER,
    512 				.hook   = NF_BR_LOCAL_OUT,
    513 			},
    514 			{
    515 				.name   = "POSTROUTING",
    516 				.type   = "filter",
    517 				.prio   = NF_BR_PRI_NAT_SRC,
    518 				.hook   = NF_BR_POST_ROUTING,
    519 			},
    520 		},
    521 	},
    522 };
    523 
    524 int nft_table_add(struct nft_handle *h, struct nftnl_table *t, uint16_t flags)
    525 {
    526 	char buf[MNL_SOCKET_BUFFER_SIZE];
    527 	struct nlmsghdr *nlh;
    528 	int ret;
    529 
    530 	nlh = nftnl_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, h->family,
    531 					NLM_F_ACK|flags, h->seq);
    532 	nftnl_table_nlmsg_build_payload(nlh, t);
    533 	nftnl_table_free(t);
    534 
    535 #ifdef NLDEBUG
    536 	char tmp[1024];
    537 
    538 	nft_table_snprintf(tmp, sizeof(tmp), t, 0, 0);
    539 	printf("DEBUG: table: %s\n", tmp);
    540 	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
    541 #endif
    542 
    543 	ret = mnl_talk(h, nlh, NULL, NULL);
    544 
    545 	return (ret == 0 || (ret == -1 && errno == EEXIST)) ? 0 : -1;
    546 }
    547 
    548 static int nft_table_builtin_add(struct nft_handle *h,
    549 				 struct builtin_table *_t)
    550 {
    551 	struct nftnl_table *t;
    552 	int ret;
    553 
    554 	if (_t->initialized)
    555 		return 0;
    556 
    557 	t = nftnl_table_alloc();
    558 	if (t == NULL)
    559 		return -1;
    560 
    561 	nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name);
    562 
    563 	if (h->batch_support)
    564 		ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t);
    565 	else
    566 		ret = nft_table_add(h, t, NLM_F_EXCL);
    567 
    568 	if (ret == 0)
    569 		_t->initialized = true;
    570 
    571 	return ret;
    572 }
    573 
    574 static struct nftnl_chain *
    575 nft_chain_builtin_alloc(struct builtin_table *table,
    576 			struct builtin_chain *chain, int policy)
    577 {
    578 	struct nftnl_chain *c;
    579 
    580 	c = nftnl_chain_alloc();
    581 	if (c == NULL)
    582 		return NULL;
    583 
    584 	nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table->name);
    585 	nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain->name);
    586 	nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
    587 	nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
    588 	nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
    589 	nftnl_chain_set(c, NFTNL_CHAIN_TYPE, (char *)chain->type);
    590 
    591 	return c;
    592 }
    593 
    594 int nft_chain_add(struct nft_handle *h, struct nftnl_chain *c, uint16_t flags)
    595 {
    596 	char buf[MNL_SOCKET_BUFFER_SIZE];
    597 	struct nlmsghdr *nlh;
    598 
    599 	/* NLM_F_CREATE requests module autoloading */
    600 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
    601 					NLM_F_ACK|flags|NLM_F_CREATE,
    602 					h->seq);
    603 	nftnl_chain_nlmsg_build_payload(nlh, c);
    604 	nftnl_chain_free(c);
    605 
    606 #ifdef NLDEBUG
    607 	char tmp[1024];
    608 
    609 	nft_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
    610 	printf("DEBUG: chain: %s\n", tmp);
    611 	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
    612 #endif
    613 
    614 	return mnl_talk(h, nlh, NULL, NULL);
    615 }
    616 
    617 static void nft_chain_builtin_add(struct nft_handle *h,
    618 				  struct builtin_table *table,
    619 				  struct builtin_chain *chain)
    620 {
    621 	struct nftnl_chain *c;
    622 
    623 	c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
    624 	if (c == NULL)
    625 		return;
    626 
    627 	if (h->batch_support)
    628 		batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
    629 	else
    630 		nft_chain_add(h, c, NLM_F_EXCL);
    631 }
    632 
    633 /* find if built-in table already exists */
    634 static struct builtin_table *
    635 nft_table_builtin_find(struct nft_handle *h, const char *table)
    636 {
    637 	int i;
    638 	bool found = false;
    639 
    640 	for (i=0; i<TABLES_MAX; i++) {
    641 		if (h->tables[i].name == NULL)
    642 			continue;
    643 
    644 		if (strcmp(h->tables[i].name, table) != 0)
    645 			continue;
    646 
    647 		found = true;
    648 		break;
    649 	}
    650 
    651 	return found ? &h->tables[i] : NULL;
    652 }
    653 
    654 /* find if built-in chain already exists */
    655 static struct builtin_chain *
    656 nft_chain_builtin_find(struct builtin_table *t, const char *chain)
    657 {
    658 	int i;
    659 	bool found = false;
    660 
    661 	for (i=0; i<NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
    662 		if (strcmp(t->chains[i].name, chain) != 0)
    663 			continue;
    664 
    665 		found = true;
    666 		break;
    667 	}
    668 	return found ? &t->chains[i] : NULL;
    669 }
    670 
    671 static void nft_chain_builtin_init(struct nft_handle *h,
    672 				   struct builtin_table *table)
    673 {
    674 	int i;
    675 	struct nftnl_chain_list *list = nft_chain_dump(h);
    676 	struct nftnl_chain *c;
    677 
    678 	/* Initialize built-in chains if they don't exist yet */
    679 	for (i=0; i<NF_IP_NUMHOOKS && table->chains[i].name != NULL; i++) {
    680 
    681 		c = nft_chain_list_find(list, table->name,
    682 					table->chains[i].name);
    683 		if (c != NULL)
    684 			continue;
    685 
    686 		nft_chain_builtin_add(h, table, &table->chains[i]);
    687 	}
    688 
    689 	nftnl_chain_list_free(list);
    690 }
    691 
    692 static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
    693 {
    694 	int ret = 0;
    695 	struct builtin_table *t;
    696 
    697 	t = nft_table_builtin_find(h, table);
    698 	if (t == NULL) {
    699 		ret = -1;
    700 		goto out;
    701 	}
    702 	if (nft_table_builtin_add(h, t) < 0) {
    703 		/* Built-in table already initialized, skip. */
    704 		if (errno == EEXIST)
    705 			goto out;
    706 	}
    707 	nft_chain_builtin_init(h, t);
    708 out:
    709 	return ret;
    710 }
    711 
    712 static bool nft_chain_builtin(struct nftnl_chain *c)
    713 {
    714 	/* Check if this chain has hook number, in that case is built-in.
    715 	 * Should we better export the flags to user-space via nf_tables?
    716 	 */
    717 	return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
    718 }
    719 
    720 static bool mnl_batch_supported(struct nft_handle *h)
    721 {
    722 	char buf[MNL_SOCKET_BUFFER_SIZE];
    723 	uint32_t seq = 1;
    724 	int ret;
    725 
    726 	mnl_nftnl_batch_begin(h->batch, seq++);
    727 
    728 	nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch),
    729 				NFT_MSG_NEWSET, AF_INET,
    730 				NLM_F_ACK, seq++);
    731 	mnl_nlmsg_batch_next(h->batch);
    732 
    733 	mnl_nftnl_batch_end(h->batch, seq++);
    734 
    735 	ret = mnl_socket_sendto(h->nl, mnl_nlmsg_batch_head(h->batch),
    736 				mnl_nlmsg_batch_size(h->batch));
    737 	if (ret < 0)
    738 		goto err;
    739 
    740 	mnl_nlmsg_batch_reset(h->batch);
    741 
    742 	ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
    743 	while (ret > 0) {
    744 		ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(h->nl),
    745 				 NULL, NULL);
    746 		if (ret <= 0)
    747 			break;
    748 
    749 		ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
    750 	}
    751 
    752 	/* We're sending an incomplete message to see if the kernel supports
    753 	 * set messages in batches. EINVAL means that we sent an incomplete
    754 	 * message with missing attributes. The kernel just ignores messages
    755 	 * that we cannot include in the batch.
    756 	 */
    757 	return (ret == -1 && errno == EINVAL) ? true : false;
    758 err:
    759 	mnl_nlmsg_batch_reset(h->batch);
    760 	return ret;
    761 }
    762 
    763 int nft_init(struct nft_handle *h, struct builtin_table *t)
    764 {
    765 	h->nl = mnl_socket_open(NETLINK_NETFILTER);
    766 	if (h->nl == NULL)
    767 		return -1;
    768 
    769 	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
    770 		return -1;
    771 
    772 	h->portid = mnl_socket_get_portid(h->nl);
    773 	h->tables = t;
    774 
    775 	INIT_LIST_HEAD(&h->obj_list);
    776 
    777 	h->batch = mnl_nftnl_batch_alloc();
    778 	h->batch_support = mnl_batch_supported(h);
    779 
    780 	return 0;
    781 }
    782 
    783 static void flush_rule_cache(struct nft_handle *h)
    784 {
    785 	if (!h->rule_cache)
    786 		return;
    787 
    788 	nftnl_rule_list_free(h->rule_cache);
    789 	h->rule_cache = NULL;
    790 }
    791 
    792 void nft_fini(struct nft_handle *h)
    793 {
    794 	flush_rule_cache(h);
    795 	mnl_socket_close(h->nl);
    796 	free(mnl_nlmsg_batch_head(h->batch));
    797 	mnl_nlmsg_batch_stop(h->batch);
    798 }
    799 
    800 static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
    801 {
    802 #ifdef NLDEBUG
    803 	char tmp[1024];
    804 
    805 	nft_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
    806 	printf("DEBUG: chain: %s\n", tmp);
    807 	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
    808 #endif
    809 }
    810 
    811 static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
    812 				       const char *table, const char *chain,
    813 				       int policy,
    814 				       const struct xt_counters *counters)
    815 {
    816 	struct nftnl_chain *c;
    817 	struct builtin_table *_t;
    818 	struct builtin_chain *_c;
    819 
    820 	_t = nft_table_builtin_find(h, table);
    821 	/* if this built-in table does not exists, create it */
    822 	if (_t != NULL)
    823 		nft_table_builtin_add(h, _t);
    824 
    825 	_c = nft_chain_builtin_find(_t, chain);
    826 	if (_c != NULL) {
    827 		/* This is a built-in chain */
    828 		c = nft_chain_builtin_alloc(_t, _c, policy);
    829 		if (c == NULL)
    830 			return NULL;
    831 	} else {
    832 		errno = ENOENT;
    833 		return NULL;
    834 	}
    835 
    836 	if (counters) {
    837 		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES,
    838 					counters->bcnt);
    839 		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS,
    840 					counters->pcnt);
    841 	}
    842 
    843 	return c;
    844 }
    845 
    846 int nft_chain_set(struct nft_handle *h, const char *table,
    847 		  const char *chain, const char *policy,
    848 		  const struct xt_counters *counters)
    849 {
    850 	struct nftnl_chain *c = NULL;
    851 	int ret;
    852 
    853 	nft_fn = nft_chain_set;
    854 
    855 	if (strcmp(policy, "DROP") == 0)
    856 		c = nft_chain_new(h, table, chain, NF_DROP, counters);
    857 	else if (strcmp(policy, "ACCEPT") == 0)
    858 		c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
    859 
    860 	if (c == NULL)
    861 		return 0;
    862 
    863 	if (h->batch_support)
    864 		ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c);
    865 	else
    866 		ret = nft_chain_add(h, c, 0);
    867 
    868 	/* the core expects 1 for success and 0 for error */
    869 	return ret == 0 ? 1 : 0;
    870 }
    871 
    872 static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
    873 {
    874 	void *info;
    875 
    876 	nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
    877 	nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
    878 
    879 	info = calloc(1, m->u.match_size);
    880 	if (info == NULL)
    881 		return -ENOMEM;
    882 
    883 	memcpy(info, m->data, m->u.match_size - sizeof(*m));
    884 	nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
    885 
    886 	return 0;
    887 }
    888 
    889 int add_match(struct nftnl_rule *r, struct xt_entry_match *m)
    890 {
    891 	struct nftnl_expr *expr;
    892 	int ret;
    893 
    894 	expr = nftnl_expr_alloc("match");
    895 	if (expr == NULL)
    896 		return -ENOMEM;
    897 
    898 	ret = __add_match(expr, m);
    899 	nftnl_rule_add_expr(r, expr);
    900 
    901 	return ret;
    902 }
    903 
    904 static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
    905 {
    906 	void *info;
    907 
    908 	nftnl_expr_set(e, NFTNL_EXPR_TG_NAME, t->u.user.name,
    909 			  strlen(t->u.user.name));
    910 	nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
    911 
    912 	info = calloc(1, t->u.target_size);
    913 	if (info == NULL)
    914 		return -ENOMEM;
    915 
    916 	memcpy(info, t->data, t->u.target_size - sizeof(*t));
    917 	nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
    918 
    919 	return 0;
    920 }
    921 
    922 int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
    923 {
    924 	struct nftnl_expr *expr;
    925 	int ret;
    926 
    927 	expr = nftnl_expr_alloc("target");
    928 	if (expr == NULL)
    929 		return -ENOMEM;
    930 
    931 	ret = __add_target(expr, t);
    932 	nftnl_rule_add_expr(r, expr);
    933 
    934 	return ret;
    935 }
    936 
    937 int add_jumpto(struct nftnl_rule *r, const char *name, int verdict)
    938 {
    939 	struct nftnl_expr *expr;
    940 
    941 	expr = nftnl_expr_alloc("immediate");
    942 	if (expr == NULL)
    943 		return -ENOMEM;
    944 
    945 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
    946 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
    947 	nftnl_expr_set_str(expr, NFTNL_EXPR_IMM_CHAIN, (char *)name);
    948 	nftnl_rule_add_expr(r, expr);
    949 
    950 	return 0;
    951 }
    952 
    953 int add_verdict(struct nftnl_rule *r, int verdict)
    954 {
    955 	struct nftnl_expr *expr;
    956 
    957 	expr = nftnl_expr_alloc("immediate");
    958 	if (expr == NULL)
    959 		return -ENOMEM;
    960 
    961 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
    962 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
    963 	nftnl_rule_add_expr(r, expr);
    964 
    965 	return 0;
    966 }
    967 
    968 int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
    969 	       bool goto_set)
    970 {
    971        int ret = 0;
    972 
    973        /* If no target at all, add nothing (default to continue) */
    974        if (cs->target != NULL) {
    975 	       /* Standard target? */
    976 	       if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
    977 		       ret = add_verdict(r, NF_ACCEPT);
    978 	       else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
    979 		       ret = add_verdict(r, NF_DROP);
    980 	       else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
    981 		       ret = add_verdict(r, NFT_RETURN);
    982 	       else
    983 		       ret = add_target(r, cs->target->t);
    984        } else if (strlen(cs->jumpto) > 0) {
    985 	       /* Not standard, then it's a go / jump to chain */
    986 	       if (goto_set)
    987 		       ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
    988 	       else
    989 		       ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
    990        }
    991        return ret;
    992 }
    993 
    994 static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
    995 {
    996 #ifdef NLDEBUG
    997 	char tmp[1024];
    998 
    999 	nft_rule_snprintf(tmp, sizeof(tmp), r, 0, 0);
   1000 	printf("DEBUG: rule: %s\n", tmp);
   1001 	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
   1002 #endif
   1003 }
   1004 
   1005 int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
   1006 {
   1007 	struct nftnl_expr *expr;
   1008 
   1009 	expr = nftnl_expr_alloc("counter");
   1010 	if (expr == NULL)
   1011 		return -ENOMEM;
   1012 
   1013 	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_PACKETS, packets);
   1014 	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_BYTES, bytes);
   1015 
   1016 	nftnl_rule_add_expr(r, expr);
   1017 
   1018 	return 0;
   1019 }
   1020 
   1021 enum udata_type {
   1022 	UDATA_TYPE_COMMENT,
   1023 	__UDATA_TYPE_MAX,
   1024 };
   1025 #define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
   1026 
   1027 int add_comment(struct nftnl_rule *r, const char *comment)
   1028 {
   1029 	struct nftnl_udata_buf *udata;
   1030 
   1031 	udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
   1032 	if (!udata)
   1033 		return -ENOMEM;
   1034 
   1035 	if (!nftnl_udata_put_strz(udata, UDATA_TYPE_COMMENT, comment))
   1036 		return -ENOMEM;
   1037 	nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
   1038 			    nftnl_udata_buf_data(udata),
   1039 			    nftnl_udata_buf_len(udata));
   1040 
   1041 	nftnl_udata_buf_free(udata);
   1042 
   1043 	return 0;
   1044 }
   1045 
   1046 static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
   1047 {
   1048 	unsigned char *value = nftnl_udata_get(attr);
   1049 	uint8_t type = nftnl_udata_type(attr);
   1050 	uint8_t len = nftnl_udata_len(attr);
   1051 	const struct nftnl_udata **tb = data;
   1052 
   1053 	switch (type) {
   1054 	case UDATA_TYPE_COMMENT:
   1055 		if (value[len - 1] != '\0')
   1056 			return -1;
   1057 		break;
   1058 	default:
   1059 		return 0;
   1060 	}
   1061 	tb[type] = attr;
   1062 	return 0;
   1063 }
   1064 
   1065 char *get_comment(const void *data, uint32_t data_len)
   1066 {
   1067 	const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
   1068 
   1069 	if (nftnl_udata_parse(data, data_len, parse_udata_cb, tb) < 0)
   1070 		return NULL;
   1071 
   1072 	if (!tb[UDATA_TYPE_COMMENT])
   1073 		return NULL;
   1074 
   1075 	return nftnl_udata_get(tb[UDATA_TYPE_COMMENT]);
   1076 }
   1077 
   1078 void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
   1079 {
   1080 	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, proto);
   1081 	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS,
   1082 			      inv ? NFT_RULE_COMPAT_F_INV : 0);
   1083 }
   1084 
   1085 static struct nftnl_rule *
   1086 nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
   1087 	     void *data)
   1088 {
   1089 	struct nftnl_rule *r;
   1090 
   1091 	r = nftnl_rule_alloc();
   1092 	if (r == NULL)
   1093 		return NULL;
   1094 
   1095 	nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
   1096 	nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
   1097 	nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
   1098 
   1099 	if (h->ops->add(r, data) < 0)
   1100 		goto err;
   1101 
   1102 	return r;
   1103 err:
   1104 	nftnl_rule_free(r);
   1105 	return NULL;
   1106 }
   1107 
   1108 int
   1109 nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
   1110 		void *data, uint64_t handle, bool verbose)
   1111 {
   1112 	struct nftnl_rule *r;
   1113 	int type;
   1114 
   1115 	/* If built-in chains don't exist for this table, create them */
   1116 	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
   1117 		nft_xt_builtin_init(h, table);
   1118 
   1119 	nft_fn = nft_rule_append;
   1120 
   1121 	r = nft_rule_new(h, chain, table, data);
   1122 	if (r == NULL)
   1123 		return 0;
   1124 
   1125 	if (handle > 0) {
   1126 		nftnl_rule_set(r, NFTNL_RULE_HANDLE, &handle);
   1127 		type = NFT_COMPAT_RULE_REPLACE;
   1128 	} else
   1129 		type = NFT_COMPAT_RULE_APPEND;
   1130 
   1131 	if (batch_rule_add(h, type, r) < 0)
   1132 		nftnl_rule_free(r);
   1133 
   1134 	flush_rule_cache(h);
   1135 	return 1;
   1136 }
   1137 
   1138 void
   1139 nft_rule_print_save(const void *data,
   1140 		    struct nftnl_rule *r, enum nft_rule_print type,
   1141 		    unsigned int format)
   1142 {
   1143 	const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
   1144 	int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
   1145 	struct nft_family_ops *ops;
   1146 
   1147 	ops = nft_family_ops_lookup(family);
   1148 
   1149 	if (!(format & FMT_NOCOUNTS) && ops->save_counters)
   1150 		ops->save_counters(data);
   1151 
   1152 	/* print chain name */
   1153 	switch(type) {
   1154 	case NFT_RULE_APPEND:
   1155 		printf("-A %s ", chain);
   1156 		break;
   1157 	case NFT_RULE_DEL:
   1158 		printf("-D %s ", chain);
   1159 		break;
   1160 	}
   1161 
   1162 	if (ops->save_firewall)
   1163 		ops->save_firewall(data, format);
   1164 
   1165 }
   1166 
   1167 static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
   1168 {
   1169 	struct nftnl_chain *c;
   1170 	struct nftnl_chain_list *list = data;
   1171 
   1172 	c = nftnl_chain_alloc();
   1173 	if (c == NULL)
   1174 		goto err;
   1175 
   1176 	if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
   1177 		goto out;
   1178 
   1179 	nftnl_chain_list_add_tail(c, list);
   1180 
   1181 	return MNL_CB_OK;
   1182 out:
   1183 	nftnl_chain_free(c);
   1184 err:
   1185 	return MNL_CB_OK;
   1186 }
   1187 
   1188 static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h)
   1189 {
   1190 	char buf[MNL_SOCKET_BUFFER_SIZE];
   1191 	struct nlmsghdr *nlh;
   1192 	struct nftnl_chain_list *list;
   1193 
   1194 	list = nftnl_chain_list_alloc();
   1195 	if (list == NULL) {
   1196 		errno = ENOMEM;
   1197 		return NULL;
   1198 	}
   1199 
   1200 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
   1201 					NLM_F_DUMP, h->seq);
   1202 
   1203 	mnl_talk(h, nlh, nftnl_chain_list_cb, list);
   1204 
   1205 	return list;
   1206 }
   1207 
   1208 struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h)
   1209 {
   1210 	return nftnl_chain_list_get(h);
   1211 }
   1212 
   1213 static const char *policy_name[NF_ACCEPT+1] = {
   1214 	[NF_DROP] = "DROP",
   1215 	[NF_ACCEPT] = "ACCEPT",
   1216 };
   1217 
   1218 static void nft_chain_print_save(struct nftnl_chain *c, bool basechain)
   1219 {
   1220 	const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   1221 	uint64_t pkts = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS);
   1222 	uint64_t bytes = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES);
   1223 
   1224 	/* print chain name */
   1225 	if (basechain) {
   1226 		uint32_t pol = NF_ACCEPT;
   1227 
   1228 		/* no default chain policy? don't crash, display accept */
   1229 		if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY))
   1230 			pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
   1231 
   1232 		printf(":%s %s [%"PRIu64":%"PRIu64"]\n", chain, policy_name[pol],
   1233 					     pkts, bytes);
   1234 	} else
   1235 		printf(":%s - [%"PRIu64":%"PRIu64"]\n", chain, pkts, bytes);
   1236 }
   1237 
   1238 int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
   1239 		   const char *table)
   1240 {
   1241 	struct nftnl_chain_list_iter *iter;
   1242 	struct nftnl_chain *c;
   1243 
   1244 	iter = nftnl_chain_list_iter_create(list);
   1245 	if (iter == NULL)
   1246 		return 0;
   1247 
   1248 	c = nftnl_chain_list_iter_next(iter);
   1249 	while (c != NULL) {
   1250 		const char *chain_table =
   1251 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   1252 		bool basechain = false;
   1253 
   1254 		if (strcmp(table, chain_table) != 0)
   1255 			goto next;
   1256 
   1257 		basechain = nft_chain_builtin(c);
   1258 		nft_chain_print_save(c, basechain);
   1259 next:
   1260 		c = nftnl_chain_list_iter_next(iter);
   1261 	}
   1262 
   1263 	nftnl_chain_list_iter_destroy(iter);
   1264 	nftnl_chain_list_free(list);
   1265 
   1266 	return 1;
   1267 }
   1268 
   1269 static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
   1270 {
   1271 	struct nftnl_rule *r;
   1272 	struct nftnl_rule_list *list = data;
   1273 
   1274 	r = nftnl_rule_alloc();
   1275 	if (r == NULL)
   1276 		goto err;
   1277 
   1278 	if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
   1279 		goto out;
   1280 
   1281 	nftnl_rule_list_add_tail(r, list);
   1282 
   1283 	return MNL_CB_OK;
   1284 out:
   1285 	nftnl_rule_free(r);
   1286 	nftnl_rule_list_free(list);
   1287 err:
   1288 	return MNL_CB_OK;
   1289 }
   1290 
   1291 static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
   1292 {
   1293 	char buf[MNL_SOCKET_BUFFER_SIZE];
   1294 	struct nlmsghdr *nlh;
   1295 	struct nftnl_rule_list *list;
   1296 	int ret;
   1297 
   1298 	if (h->rule_cache)
   1299 		return h->rule_cache;
   1300 
   1301 	list = nftnl_rule_list_alloc();
   1302 	if (list == NULL)
   1303 		return 0;
   1304 
   1305 	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
   1306 					NLM_F_DUMP, h->seq);
   1307 
   1308 	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list);
   1309 	if (ret < 0) {
   1310 		nftnl_rule_list_free(list);
   1311 		return NULL;
   1312 	}
   1313 
   1314 	h->rule_cache = list;
   1315 	return list;
   1316 }
   1317 
   1318 int nft_rule_save(struct nft_handle *h, const char *table, bool counters)
   1319 {
   1320 	struct nftnl_rule_list *list;
   1321 	struct nftnl_rule_list_iter *iter;
   1322 	struct nftnl_rule *r;
   1323 
   1324 	list = nft_rule_list_get(h);
   1325 	if (list == NULL)
   1326 		return 0;
   1327 
   1328 	iter = nftnl_rule_list_iter_create(list);
   1329 	if (iter == NULL)
   1330 		return 0;
   1331 
   1332 	r = nftnl_rule_list_iter_next(iter);
   1333 	while (r != NULL) {
   1334 		const char *rule_table =
   1335 			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
   1336 		struct iptables_command_state cs = {};
   1337 
   1338 		if (strcmp(table, rule_table) != 0)
   1339 			goto next;
   1340 
   1341 		nft_rule_to_iptables_command_state(r, &cs);
   1342 
   1343 		nft_rule_print_save(&cs, r, NFT_RULE_APPEND,
   1344 				    counters ? 0 : FMT_NOCOUNTS);
   1345 
   1346 next:
   1347 		r = nftnl_rule_list_iter_next(iter);
   1348 	}
   1349 
   1350 	nftnl_rule_list_iter_destroy(iter);
   1351 
   1352 	/* the core expects 1 for success and 0 for error */
   1353 	return 1;
   1354 }
   1355 
   1356 static void
   1357 __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
   1358 {
   1359 	struct nftnl_rule *r;
   1360 
   1361 	r = nftnl_rule_alloc();
   1362 	if (r == NULL)
   1363 		return;
   1364 
   1365 	nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table);
   1366 	nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain);
   1367 
   1368 	if (batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r) < 0)
   1369 		nftnl_rule_free(r);
   1370 }
   1371 
   1372 int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table)
   1373 {
   1374 	int ret;
   1375 	struct nftnl_chain_list *list;
   1376 	struct nftnl_chain_list_iter *iter;
   1377 	struct nftnl_chain *c;
   1378 
   1379 	nft_fn = nft_rule_flush;
   1380 
   1381 	list = nftnl_chain_list_get(h);
   1382 	if (list == NULL) {
   1383 		ret = 0;
   1384 		goto err;
   1385 	}
   1386 
   1387 	iter = nftnl_chain_list_iter_create(list);
   1388 	if (iter == NULL)
   1389 		goto err;
   1390 
   1391 	c = nftnl_chain_list_iter_next(iter);
   1392 	while (c != NULL) {
   1393 		const char *table_name =
   1394 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   1395 		const char *chain_name =
   1396 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   1397 
   1398 		if (strcmp(table, table_name) != 0)
   1399 			goto next;
   1400 
   1401 		if (chain != NULL && strcmp(chain, chain_name) != 0)
   1402 			goto next;
   1403 
   1404 		__nft_rule_flush(h, table_name, chain_name);
   1405 
   1406 		if (chain != NULL)
   1407 			break;
   1408 next:
   1409 		c = nftnl_chain_list_iter_next(iter);
   1410 	}
   1411 
   1412 	nftnl_chain_list_iter_destroy(iter);
   1413 	flush_rule_cache(h);
   1414 err:
   1415 	nftnl_chain_list_free(list);
   1416 
   1417 	/* the core expects 1 for success and 0 for error */
   1418 	return ret == 0 ? 1 : 0;
   1419 }
   1420 
   1421 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
   1422 {
   1423 	struct nftnl_chain *c;
   1424 	int ret;
   1425 
   1426 	nft_fn = nft_chain_user_add;
   1427 
   1428 	/* If built-in chains don't exist for this table, create them */
   1429 	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
   1430 		nft_xt_builtin_init(h, table);
   1431 
   1432 	c = nftnl_chain_alloc();
   1433 	if (c == NULL)
   1434 		return 0;
   1435 
   1436 	nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
   1437 	nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
   1438 
   1439 	if (h->batch_support) {
   1440 		ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
   1441 	} else {
   1442 		char buf[MNL_SOCKET_BUFFER_SIZE];
   1443 		struct nlmsghdr *nlh;
   1444 
   1445 		nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
   1446 						h->family,
   1447 						NLM_F_ACK|NLM_F_EXCL, h->seq);
   1448 		nftnl_chain_nlmsg_build_payload(nlh, c);
   1449 		nftnl_chain_free(c);
   1450 		ret = mnl_talk(h, nlh, NULL, NULL);
   1451 	}
   1452 
   1453 	/* the core expects 1 for success and 0 for error */
   1454 	return ret == 0 ? 1 : 0;
   1455 }
   1456 
   1457 static int __nft_chain_del(struct nft_handle *h, struct nftnl_chain *c)
   1458 {
   1459 	char buf[MNL_SOCKET_BUFFER_SIZE];
   1460 	struct nlmsghdr *nlh;
   1461 
   1462 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN, h->family,
   1463 					NLM_F_ACK, h->seq);
   1464 	nftnl_chain_nlmsg_build_payload(nlh, c);
   1465 
   1466 	return mnl_talk(h, nlh, NULL, NULL);
   1467 }
   1468 
   1469 int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table)
   1470 {
   1471 	struct nftnl_chain_list *list;
   1472 	struct nftnl_chain_list_iter *iter;
   1473 	struct nftnl_chain *c;
   1474 	int ret = 0;
   1475 	int deleted_ctr = 0;
   1476 
   1477 	list = nftnl_chain_list_get(h);
   1478 	if (list == NULL)
   1479 		goto err;
   1480 
   1481 	iter = nftnl_chain_list_iter_create(list);
   1482 	if (iter == NULL)
   1483 		goto err;
   1484 
   1485 	c = nftnl_chain_list_iter_next(iter);
   1486 	while (c != NULL) {
   1487 		const char *table_name =
   1488 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   1489 		const char *chain_name =
   1490 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   1491 
   1492 		/* don't delete built-in chain */
   1493 		if (nft_chain_builtin(c))
   1494 			goto next;
   1495 
   1496 		if (strcmp(table, table_name) != 0)
   1497 			goto next;
   1498 
   1499 		if (chain != NULL && strcmp(chain, chain_name) != 0)
   1500 			goto next;
   1501 
   1502 		if (h->batch_support)
   1503 			ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
   1504 		else
   1505 			ret = __nft_chain_del(h, c);
   1506 
   1507 		if (ret < 0)
   1508 			break;
   1509 
   1510 		deleted_ctr++;
   1511 
   1512 		if (chain != NULL)
   1513 			break;
   1514 next:
   1515 		c = nftnl_chain_list_iter_next(iter);
   1516 	}
   1517 
   1518 	nftnl_chain_list_iter_destroy(iter);
   1519 err:
   1520 	if (!h->batch_support)
   1521 		nftnl_chain_list_free(list);
   1522 
   1523 	/* chain not found */
   1524 	if (deleted_ctr == 0) {
   1525 		ret = -1;
   1526 		errno = ENOENT;
   1527 	}
   1528 
   1529 	/* the core expects 1 for success and 0 for error */
   1530 	return ret == 0 ? 1 : 0;
   1531 }
   1532 
   1533 struct nftnl_chain *
   1534 nft_chain_list_find(struct nftnl_chain_list *list,
   1535 		    const char *table, const char *chain)
   1536 {
   1537 	struct nftnl_chain_list_iter *iter;
   1538 	struct nftnl_chain *c;
   1539 
   1540 	iter = nftnl_chain_list_iter_create(list);
   1541 	if (iter == NULL)
   1542 		return NULL;
   1543 
   1544 	c = nftnl_chain_list_iter_next(iter);
   1545 	while (c != NULL) {
   1546 		const char *table_name =
   1547 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   1548 		const char *chain_name =
   1549 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   1550 
   1551 		if (strcmp(table, table_name) != 0)
   1552 			goto next;
   1553 
   1554 		if (strcmp(chain, chain_name) != 0)
   1555 			goto next;
   1556 
   1557 		nftnl_chain_list_iter_destroy(iter);
   1558 		return c;
   1559 next:
   1560 		c = nftnl_chain_list_iter_next(iter);
   1561 	}
   1562 	nftnl_chain_list_iter_destroy(iter);
   1563 	return NULL;
   1564 }
   1565 
   1566 static struct nftnl_chain *
   1567 nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
   1568 {
   1569 	struct nftnl_chain_list *list;
   1570 
   1571 	list = nftnl_chain_list_get(h);
   1572 	if (list == NULL)
   1573 		return NULL;
   1574 
   1575 	return nft_chain_list_find(list, table, chain);
   1576 }
   1577 
   1578 int nft_chain_user_rename(struct nft_handle *h,const char *chain,
   1579 			  const char *table, const char *newname)
   1580 {
   1581 	struct nftnl_chain *c;
   1582 	uint64_t handle;
   1583 	int ret;
   1584 
   1585 	nft_fn = nft_chain_user_add;
   1586 
   1587 	/* If built-in chains don't exist for this table, create them */
   1588 	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
   1589 		nft_xt_builtin_init(h, table);
   1590 
   1591 	/* Config load changed errno. Ensure genuine info for our callers. */
   1592 	errno = 0;
   1593 
   1594 	/* Find the old chain to be renamed */
   1595 	c = nft_chain_find(h, table, chain);
   1596 	if (c == NULL) {
   1597 		errno = ENOENT;
   1598 		return -1;
   1599 	}
   1600 	handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE);
   1601 
   1602 	/* Now prepare the new name for the chain */
   1603 	c = nftnl_chain_alloc();
   1604 	if (c == NULL)
   1605 		return -1;
   1606 
   1607 	nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
   1608 	nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)newname);
   1609 	nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
   1610 
   1611 	if (h->batch_support) {
   1612 		ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
   1613 	} else {
   1614 		char buf[MNL_SOCKET_BUFFER_SIZE];
   1615 		struct nlmsghdr *nlh;
   1616 
   1617 		nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
   1618 						h->family, NLM_F_ACK, h->seq);
   1619 		nftnl_chain_nlmsg_build_payload(nlh, c);
   1620 		nftnl_chain_free(c);
   1621 
   1622 		ret = mnl_talk(h, nlh, NULL, NULL);
   1623 	}
   1624 
   1625 	/* the core expects 1 for success and 0 for error */
   1626 	return ret == 0 ? 1 : 0;
   1627 }
   1628 
   1629 static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
   1630 {
   1631 	struct nftnl_table *t;
   1632 	struct nftnl_table_list *list = data;
   1633 
   1634 	t = nftnl_table_alloc();
   1635 	if (t == NULL)
   1636 		goto err;
   1637 
   1638 	if (nftnl_table_nlmsg_parse(nlh, t) < 0)
   1639 		goto out;
   1640 
   1641 	nftnl_table_list_add_tail(t, list);
   1642 
   1643 	return MNL_CB_OK;
   1644 out:
   1645 	nftnl_table_free(t);
   1646 err:
   1647 	return MNL_CB_OK;
   1648 }
   1649 
   1650 static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
   1651 {
   1652 	char buf[MNL_SOCKET_BUFFER_SIZE];
   1653 	struct nlmsghdr *nlh;
   1654 	struct nftnl_table_list *list;
   1655 
   1656 	list = nftnl_table_list_alloc();
   1657 	if (list == NULL)
   1658 		return 0;
   1659 
   1660 	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
   1661 					NLM_F_DUMP, h->seq);
   1662 
   1663 	mnl_talk(h, nlh, nftnl_table_list_cb, list);
   1664 
   1665 	return list;
   1666 }
   1667 
   1668 bool nft_table_find(struct nft_handle *h, const char *tablename)
   1669 {
   1670 	struct nftnl_table_list *list;
   1671 	struct nftnl_table_list_iter *iter;
   1672 	struct nftnl_table *t;
   1673 	bool ret = false;
   1674 
   1675 	list = nftnl_table_list_get(h);
   1676 	if (list == NULL)
   1677 		goto err;
   1678 
   1679 	iter = nftnl_table_list_iter_create(list);
   1680 	if (iter == NULL)
   1681 		goto err;
   1682 
   1683 	t = nftnl_table_list_iter_next(iter);
   1684 	while (t != NULL) {
   1685 		const char *this_tablename =
   1686 			nftnl_table_get(t, NFTNL_TABLE_NAME);
   1687 
   1688 		if (strcmp(tablename, this_tablename) == 0)
   1689 			return true;
   1690 
   1691 		t = nftnl_table_list_iter_next(iter);
   1692 	}
   1693 
   1694 	nftnl_table_list_free(list);
   1695 
   1696 err:
   1697 	return ret;
   1698 }
   1699 
   1700 int nft_for_each_table(struct nft_handle *h,
   1701 		       int (*func)(struct nft_handle *h, const char *tablename, bool counters),
   1702 		       bool counters)
   1703 {
   1704 	int ret = 1;
   1705 	struct nftnl_table_list *list;
   1706 	struct nftnl_table_list_iter *iter;
   1707 	struct nftnl_table *t;
   1708 
   1709 	list = nftnl_table_list_get(h);
   1710 	if (list == NULL) {
   1711 		ret = 0;
   1712 		goto err;
   1713 	}
   1714 
   1715 	iter = nftnl_table_list_iter_create(list);
   1716 	if (iter == NULL)
   1717 		return 0;
   1718 
   1719 	t = nftnl_table_list_iter_next(iter);
   1720 	while (t != NULL) {
   1721 		const char *tablename =
   1722 			nftnl_table_get(t, NFTNL_TABLE_NAME);
   1723 
   1724 		func(h, tablename, counters);
   1725 
   1726 		t = nftnl_table_list_iter_next(iter);
   1727 	}
   1728 
   1729 	nftnl_table_list_free(list);
   1730 
   1731 err:
   1732 	/* the core expects 1 for success and 0 for error */
   1733 	return ret == 0 ? 1 : 0;
   1734 }
   1735 
   1736 int nft_table_purge_chains(struct nft_handle *h, const char *this_table,
   1737 			   struct nftnl_chain_list *chain_list)
   1738 {
   1739 	struct nftnl_chain_list_iter *iter;
   1740 	struct nftnl_chain *chain_obj;
   1741 
   1742 	iter = nftnl_chain_list_iter_create(chain_list);
   1743 	if (iter == NULL)
   1744 		return 0;
   1745 
   1746 	chain_obj = nftnl_chain_list_iter_next(iter);
   1747 	while (chain_obj != NULL) {
   1748 		const char *table =
   1749 			nftnl_chain_get_str(chain_obj, NFTNL_CHAIN_TABLE);
   1750 
   1751 		if (strcmp(this_table, table) != 0)
   1752 			goto next;
   1753 
   1754 		if (nft_chain_builtin(chain_obj))
   1755 			goto next;
   1756 
   1757 		if ( __nft_chain_del(h, chain_obj) < 0) {
   1758 			if (errno != EBUSY)
   1759 				return -1;
   1760 		}
   1761 next:
   1762 		chain_obj = nftnl_chain_list_iter_next(iter);
   1763 	}
   1764 	nftnl_chain_list_iter_destroy(iter);
   1765 
   1766 	return 0;
   1767 }
   1768 
   1769 static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list,
   1770 			  struct nftnl_rule *r)
   1771 {
   1772 	int ret;
   1773 
   1774 	nftnl_rule_list_del(r);
   1775 
   1776 	ret = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
   1777 	if (ret < 0) {
   1778 		nftnl_rule_free(r);
   1779 		return -1;
   1780 	}
   1781 	return 1;
   1782 }
   1783 
   1784 static struct nftnl_rule *
   1785 nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list,
   1786 	      const char *chain, const char *table, void *data, int rulenum)
   1787 {
   1788 	struct nftnl_rule *r;
   1789 	struct nftnl_rule_list_iter *iter;
   1790 	int rule_ctr = 0;
   1791 	bool found = false;
   1792 
   1793 	iter = nftnl_rule_list_iter_create(list);
   1794 	if (iter == NULL)
   1795 		return 0;
   1796 
   1797 	r = nftnl_rule_list_iter_next(iter);
   1798 	while (r != NULL) {
   1799 		const char *rule_table =
   1800 			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
   1801 		const char *rule_chain =
   1802 			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
   1803 
   1804 		if (strcmp(table, rule_table) != 0 ||
   1805 		    strcmp(chain, rule_chain) != 0) {
   1806 			DEBUGP("different chain / table\n");
   1807 			goto next;
   1808 		}
   1809 
   1810 		if (rulenum >= 0) {
   1811 			/* Delete by rule number case */
   1812 			if (rule_ctr == rulenum) {
   1813 			    found = true;
   1814 			    break;
   1815 			}
   1816 		} else {
   1817 			found = h->ops->rule_find(h->ops, r, data);
   1818 			if (found)
   1819 				break;
   1820 		}
   1821 		rule_ctr++;
   1822 next:
   1823 		r = nftnl_rule_list_iter_next(iter);
   1824 	}
   1825 
   1826 	nftnl_rule_list_iter_destroy(iter);
   1827 
   1828 	return found ? r : NULL;
   1829 }
   1830 
   1831 int nft_rule_check(struct nft_handle *h, const char *chain,
   1832 		   const char *table, void *data, bool verbose)
   1833 {
   1834 	struct nftnl_rule_list *list;
   1835 	int ret;
   1836 
   1837 	nft_fn = nft_rule_check;
   1838 
   1839 	list = nft_rule_list_get(h);
   1840 	if (list == NULL)
   1841 		return 0;
   1842 
   1843 	ret = nft_rule_find(h, list, chain, table, data, -1) ? 1 : 0;
   1844 	if (ret == 0)
   1845 		errno = ENOENT;
   1846 
   1847 	return ret;
   1848 }
   1849 
   1850 int nft_rule_delete(struct nft_handle *h, const char *chain,
   1851 		    const char *table, void *data, bool verbose)
   1852 {
   1853 	int ret = 0;
   1854 	struct nftnl_rule *r;
   1855 	struct nftnl_rule_list *list;
   1856 
   1857 	nft_fn = nft_rule_delete;
   1858 
   1859 	list = nft_rule_list_get(h);
   1860 	if (list == NULL)
   1861 		return 0;
   1862 
   1863 	r = nft_rule_find(h, list, chain, table, data, -1);
   1864 	if (r != NULL) {
   1865 		ret =__nft_rule_del(h, list, r);
   1866 		if (ret < 0)
   1867 			errno = ENOMEM;
   1868 	} else
   1869 		errno = ENOENT;
   1870 
   1871 	flush_rule_cache(h);
   1872 
   1873 	return ret;
   1874 }
   1875 
   1876 static int
   1877 nft_rule_add(struct nft_handle *h, const char *chain,
   1878 	     const char *table, struct iptables_command_state *cs,
   1879 	     uint64_t handle, bool verbose)
   1880 {
   1881 	struct nftnl_rule *r;
   1882 
   1883 	r = nft_rule_new(h, chain, table, cs);
   1884 	if (r == NULL)
   1885 		return 0;
   1886 
   1887 	if (handle > 0)
   1888 		nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
   1889 
   1890 	if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) {
   1891 		nftnl_rule_free(r);
   1892 		return 0;
   1893 	}
   1894 
   1895 	flush_rule_cache(h);
   1896 	return 1;
   1897 }
   1898 
   1899 int nft_rule_insert(struct nft_handle *h, const char *chain,
   1900 		    const char *table, void *data, int rulenum, bool verbose)
   1901 {
   1902 	struct nftnl_rule_list *list;
   1903 	struct nftnl_rule *r;
   1904 	uint64_t handle = 0;
   1905 
   1906 	/* If built-in chains don't exist for this table, create them */
   1907 	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
   1908 		nft_xt_builtin_init(h, table);
   1909 
   1910 	nft_fn = nft_rule_insert;
   1911 
   1912 	if (rulenum > 0) {
   1913 		list = nft_rule_list_get(h);
   1914 		if (list == NULL)
   1915 			goto err;
   1916 
   1917 		r = nft_rule_find(h, list, chain, table, data, rulenum);
   1918 		if (r == NULL) {
   1919 			/* special case: iptables allows to insert into
   1920 			 * rule_count + 1 position.
   1921 			 */
   1922 			r = nft_rule_find(h, list, chain, table, data,
   1923 					  rulenum - 1);
   1924 			if (r != NULL) {
   1925 				flush_rule_cache(h);
   1926 				return nft_rule_append(h, chain, table, data,
   1927 						       0, verbose);
   1928 			}
   1929 
   1930 			errno = ENOENT;
   1931 			goto err;
   1932 		}
   1933 
   1934 		handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE);
   1935 		DEBUGP("adding after rule handle %"PRIu64"\n", handle);
   1936 
   1937 		flush_rule_cache(h);
   1938 	}
   1939 
   1940 	return nft_rule_add(h, chain, table, data, handle, verbose);
   1941 err:
   1942 	flush_rule_cache(h);
   1943 	return 0;
   1944 }
   1945 
   1946 int nft_rule_delete_num(struct nft_handle *h, const char *chain,
   1947 			const char *table, int rulenum, bool verbose)
   1948 {
   1949 	int ret = 0;
   1950 	struct nftnl_rule *r;
   1951 	struct nftnl_rule_list *list;
   1952 
   1953 	nft_fn = nft_rule_delete_num;
   1954 
   1955 	list = nft_rule_list_get(h);
   1956 	if (list == NULL)
   1957 		return 0;
   1958 
   1959 	r = nft_rule_find(h, list, chain, table, NULL, rulenum);
   1960 	if (r != NULL) {
   1961 		ret = 1;
   1962 
   1963 		DEBUGP("deleting rule by number %d\n", rulenum);
   1964 		ret = __nft_rule_del(h, list, r);
   1965 		if (ret < 0)
   1966 			errno = ENOMEM;
   1967 	} else
   1968 		errno = ENOENT;
   1969 
   1970 	flush_rule_cache(h);
   1971 
   1972 	return ret;
   1973 }
   1974 
   1975 int nft_rule_replace(struct nft_handle *h, const char *chain,
   1976 		     const char *table, void *data, int rulenum, bool verbose)
   1977 {
   1978 	int ret = 0;
   1979 	struct nftnl_rule *r;
   1980 	struct nftnl_rule_list *list;
   1981 
   1982 	nft_fn = nft_rule_replace;
   1983 
   1984 	list = nft_rule_list_get(h);
   1985 	if (list == NULL)
   1986 		return 0;
   1987 
   1988 	r = nft_rule_find(h, list, chain, table, data, rulenum);
   1989 	if (r != NULL) {
   1990 		DEBUGP("replacing rule with handle=%llu\n",
   1991 			(unsigned long long)
   1992 			nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
   1993 
   1994 		ret = nft_rule_append(h, chain, table, data,
   1995 				      nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
   1996 				      verbose);
   1997 	} else
   1998 		errno = ENOENT;
   1999 
   2000 	flush_rule_cache(h);
   2001 
   2002 	return ret;
   2003 }
   2004 
   2005 static int
   2006 __nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
   2007 		int rulenum, unsigned int format,
   2008 		void (*cb)(struct nftnl_rule *r, unsigned int num,
   2009 			   unsigned int format))
   2010 {
   2011 	struct nftnl_rule_list *list;
   2012 	struct nftnl_rule_list_iter *iter;
   2013 	struct nftnl_rule *r;
   2014 	int rule_ctr = 0, ret = 0;
   2015 
   2016 	list = nft_rule_list_get(h);
   2017 	if (list == NULL)
   2018 		return 0;
   2019 
   2020 	iter = nftnl_rule_list_iter_create(list);
   2021 	if (iter == NULL)
   2022 		goto err;
   2023 
   2024 	r = nftnl_rule_list_iter_next(iter);
   2025 	while (r != NULL) {
   2026 		const char *rule_table =
   2027 			nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
   2028 		const char *rule_chain =
   2029 			nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
   2030 
   2031 		if (strcmp(table, rule_table) != 0 ||
   2032 		    strcmp(chain, rule_chain) != 0)
   2033 			goto next;
   2034 
   2035 		rule_ctr++;
   2036 
   2037 		if (rulenum > 0 && rule_ctr != rulenum) {
   2038 			/* List by rule number case */
   2039 			goto next;
   2040 		}
   2041 
   2042 		cb(r, rule_ctr, format);
   2043 		if (rulenum > 0 && rule_ctr == rulenum) {
   2044 			ret = 1;
   2045 			break;
   2046 		}
   2047 
   2048 next:
   2049 		r = nftnl_rule_list_iter_next(iter);
   2050 	}
   2051 
   2052 	nftnl_rule_list_iter_destroy(iter);
   2053 err:
   2054 	if (ret == 0)
   2055 		errno = ENOENT;
   2056 
   2057 	return ret;
   2058 }
   2059 
   2060 int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
   2061 		  int rulenum, unsigned int format)
   2062 {
   2063 	const struct nft_family_ops *ops;
   2064 	struct nftnl_chain_list *list;
   2065 	struct nftnl_chain_list_iter *iter;
   2066 	struct nftnl_chain *c;
   2067 	bool found = false;
   2068 
   2069 	/* If built-in chains don't exist for this table, create them */
   2070 	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) {
   2071 		nft_xt_builtin_init(h, table);
   2072 		/* Force table and chain creation, otherwise first iptables -L
   2073 		 * lists no table/chains.
   2074 		 */
   2075 		if (!list_empty(&h->obj_list))
   2076 			nft_commit(h);
   2077 	}
   2078 
   2079 	ops = nft_family_ops_lookup(h->family);
   2080 
   2081 	if (chain && rulenum) {
   2082 		__nft_rule_list(h, chain, table,
   2083 				rulenum, format, ops->print_firewall);
   2084 		return 1;
   2085 	}
   2086 
   2087 	list = nft_chain_dump(h);
   2088 
   2089 	iter = nftnl_chain_list_iter_create(list);
   2090 	if (iter == NULL)
   2091 		goto err;
   2092 
   2093 	if (ops->print_table_header)
   2094 		ops->print_table_header(table);
   2095 
   2096 	c = nftnl_chain_list_iter_next(iter);
   2097 	while (c != NULL) {
   2098 		const char *chain_table =
   2099 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   2100 		const char *chain_name =
   2101 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   2102 		uint32_t policy =
   2103 			nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
   2104 		uint32_t refs =
   2105 			nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
   2106 		struct xt_counters ctrs = {
   2107 			.pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
   2108 			.bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
   2109 		};
   2110 		bool basechain = false;
   2111 
   2112 		if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
   2113 			basechain = true;
   2114 
   2115 		if (strcmp(table, chain_table) != 0)
   2116 			goto next;
   2117 		if (chain && strcmp(chain, chain_name) != 0)
   2118 			goto next;
   2119 
   2120 		if (found)
   2121 			printf("\n");
   2122 
   2123 		ops->print_header(format, chain_name, policy_name[policy],
   2124 				  &ctrs, basechain, refs);
   2125 
   2126 		__nft_rule_list(h, chain_name, table,
   2127 				rulenum, format, ops->print_firewall);
   2128 
   2129 		/* we printed the chain we wanted, stop processing. */
   2130 		if (chain)
   2131 			break;
   2132 
   2133 		found = true;
   2134 
   2135 next:
   2136 		c = nftnl_chain_list_iter_next(iter);
   2137 	}
   2138 
   2139 	nftnl_chain_list_iter_destroy(iter);
   2140 err:
   2141 	nftnl_chain_list_free(list);
   2142 
   2143 	return 1;
   2144 }
   2145 
   2146 static void
   2147 list_save(struct nftnl_rule *r, unsigned int num, unsigned int format)
   2148 {
   2149 	struct iptables_command_state cs = {};
   2150 
   2151 	nft_rule_to_iptables_command_state(r, &cs);
   2152 
   2153 	nft_rule_print_save(&cs, r, NFT_RULE_APPEND, !(format & FMT_NOCOUNTS));
   2154 }
   2155 
   2156 static int
   2157 nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain,
   2158 			 const char *table, struct nftnl_chain_list *list,
   2159 			 int counters)
   2160 {
   2161 	struct nftnl_chain_list_iter *iter;
   2162 	struct nftnl_chain *c;
   2163 
   2164 	iter = nftnl_chain_list_iter_create(list);
   2165 	if (iter == NULL)
   2166 		return 0;
   2167 
   2168 	c = nftnl_chain_list_iter_next(iter);
   2169 	while (c != NULL) {
   2170 		const char *chain_table =
   2171 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   2172 		const char *chain_name =
   2173 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   2174 		uint32_t policy =
   2175 			nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
   2176 
   2177 		if (strcmp(table, chain_table) != 0 ||
   2178 		    (chain && strcmp(chain, chain_name) != 0))
   2179 			goto next;
   2180 
   2181 		/* this is a base chain */
   2182 		if (nft_chain_builtin(c)) {
   2183 			printf("-P %s %s", chain_name, policy_name[policy]);
   2184 
   2185 			if (counters) {
   2186 				printf(" -c %"PRIu64" %"PRIu64"\n",
   2187 					nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
   2188 					nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
   2189 			} else
   2190 				printf("\n");
   2191 		} else {
   2192 			printf("-N %s\n", chain_name);
   2193 		}
   2194 next:
   2195 		c = nftnl_chain_list_iter_next(iter);
   2196 	}
   2197 
   2198 	nftnl_chain_list_iter_destroy(iter);
   2199 
   2200 	return 1;
   2201 }
   2202 
   2203 int nft_rule_list_save(struct nft_handle *h, const char *chain,
   2204 		       const char *table, int rulenum, int counters)
   2205 {
   2206 	struct nftnl_chain_list *list;
   2207 	struct nftnl_chain_list_iter *iter;
   2208 	struct nftnl_chain *c;
   2209 	int ret = 1;
   2210 
   2211 	list = nft_chain_dump(h);
   2212 
   2213 	/* Dump policies and custom chains first */
   2214 	if (!rulenum)
   2215 		nftnl_rule_list_chain_save(h, chain, table, list, counters);
   2216 
   2217 	/* Now dump out rules in this table */
   2218 	iter = nftnl_chain_list_iter_create(list);
   2219 	if (iter == NULL)
   2220 		goto err;
   2221 
   2222 	c = nftnl_chain_list_iter_next(iter);
   2223 	while (c != NULL) {
   2224 		const char *chain_table =
   2225 			nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
   2226 		const char *chain_name =
   2227 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
   2228 
   2229 		if (strcmp(table, chain_table) != 0)
   2230 			goto next;
   2231 		if (chain && strcmp(chain, chain_name) != 0)
   2232 			goto next;
   2233 
   2234 		ret = __nft_rule_list(h, chain_name, table, rulenum,
   2235 				      counters ? 0 : FMT_NOCOUNTS, list_save);
   2236 
   2237 		/* we printed the chain we wanted, stop processing. */
   2238 		if (chain)
   2239 			break;
   2240 next:
   2241 		c = nftnl_chain_list_iter_next(iter);
   2242 	}
   2243 
   2244 	nftnl_chain_list_iter_destroy(iter);
   2245 err:
   2246 	nftnl_chain_list_free(list);
   2247 
   2248 	return ret;
   2249 }
   2250 
   2251 int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
   2252 			   const char *table, int rulenum)
   2253 {
   2254 	struct iptables_command_state cs = {};
   2255 	struct nftnl_rule_list *list;
   2256 	struct nftnl_rule *r;
   2257 	int ret = 0;
   2258 
   2259 	nft_fn = nft_rule_delete;
   2260 
   2261 	list = nft_rule_list_get(h);
   2262 	if (list == NULL)
   2263 		return 0;
   2264 
   2265 	r = nft_rule_find(h, list, chain, table, NULL, rulenum);
   2266 	if (r == NULL) {
   2267 		errno = ENOENT;
   2268 		ret = 1;
   2269 		goto error;
   2270 	}
   2271 
   2272 	nft_rule_to_iptables_command_state(r, &cs);
   2273 
   2274 	cs.counters.pcnt = cs.counters.bcnt = 0;
   2275 
   2276 	ret =  nft_rule_append(h, chain, table, &cs,
   2277 			       nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE),
   2278 			       false);
   2279 
   2280 error:
   2281 	flush_rule_cache(h);
   2282 
   2283 	return ret;
   2284 }
   2285 
   2286 static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
   2287 				       uint16_t flags, uint32_t seq,
   2288 				       struct nftnl_table *table)
   2289 {
   2290 	struct nlmsghdr *nlh;
   2291 
   2292 	nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch),
   2293 					type, h->family, flags, seq);
   2294 	nftnl_table_nlmsg_build_payload(nlh, table);
   2295 	nftnl_table_free(table);
   2296 }
   2297 
   2298 static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
   2299 				       uint16_t flags, uint32_t seq,
   2300 				       struct nftnl_chain *chain)
   2301 {
   2302 	struct nlmsghdr *nlh;
   2303 
   2304 	nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch),
   2305 					type, h->family, flags, seq);
   2306 	nftnl_chain_nlmsg_build_payload(nlh, chain);
   2307 	nft_chain_print_debug(chain, nlh);
   2308 	nftnl_chain_free(chain);
   2309 }
   2310 
   2311 static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
   2312 				      uint16_t flags, uint32_t seq,
   2313 				      struct nftnl_rule *rule)
   2314 {
   2315 	struct nlmsghdr *nlh;
   2316 
   2317 	nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch),
   2318 				       type, h->family, flags, seq);
   2319 	nftnl_rule_nlmsg_build_payload(nlh, rule);
   2320 	nft_rule_print_debug(rule, nlh);
   2321 	nftnl_rule_free(rule);
   2322 }
   2323 
   2324 static int nft_action(struct nft_handle *h, int action)
   2325 {
   2326 	struct obj_update *n, *tmp;
   2327 	uint32_t seq = 1;
   2328 	int ret = 0;
   2329 
   2330 	mnl_nftnl_batch_begin(h->batch, seq++);
   2331 
   2332 	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
   2333 		switch (n->type) {
   2334 		case NFT_COMPAT_TABLE_ADD:
   2335 			nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE,
   2336 						   NLM_F_CREATE, seq++,
   2337 						   n->table);
   2338 			break;
   2339 		case NFT_COMPAT_CHAIN_ADD:
   2340 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
   2341 						   NLM_F_CREATE, seq++,
   2342 						   n->chain);
   2343 			break;
   2344 		case NFT_COMPAT_CHAIN_USER_ADD:
   2345 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
   2346 						   NLM_F_EXCL, seq++,
   2347 						   n->chain);
   2348 			break;
   2349 		case NFT_COMPAT_CHAIN_USER_DEL:
   2350 			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
   2351 						   0, seq++, n->chain);
   2352 			break;
   2353 		case NFT_COMPAT_CHAIN_UPDATE:
   2354 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
   2355 						   h->restore ?
   2356 						     NLM_F_CREATE : 0,
   2357 						   seq++, n->chain);
   2358 			break;
   2359 		case NFT_COMPAT_CHAIN_RENAME:
   2360 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0,
   2361 						   seq++, n->chain);
   2362 			break;
   2363 		case NFT_COMPAT_RULE_APPEND:
   2364 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
   2365 						  NLM_F_CREATE | NLM_F_APPEND,
   2366 						  seq++, n->rule);
   2367 			break;
   2368 		case NFT_COMPAT_RULE_INSERT:
   2369 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
   2370 						  NLM_F_CREATE, seq++,
   2371 						  n->rule);
   2372 			break;
   2373 		case NFT_COMPAT_RULE_REPLACE:
   2374 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
   2375 						  NLM_F_CREATE | NLM_F_REPLACE,
   2376 						  seq++, n->rule);
   2377 			break;
   2378 		case NFT_COMPAT_RULE_DELETE:
   2379 		case NFT_COMPAT_RULE_FLUSH:
   2380 			nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
   2381 						  seq++, n->rule);
   2382 			break;
   2383 		}
   2384 
   2385 		h->obj_list_num--;
   2386 		list_del(&n->head);
   2387 		free(n);
   2388 
   2389 		if (!mnl_nlmsg_batch_next(h->batch))
   2390 			h->batch = mnl_nftnl_batch_page_add(h->batch);
   2391 	}
   2392 
   2393 	switch (action) {
   2394 	case NFT_COMPAT_COMMIT:
   2395 		mnl_nftnl_batch_end(h->batch, seq++);
   2396 		break;
   2397 	case NFT_COMPAT_ABORT:
   2398 		break;
   2399 	}
   2400 
   2401 	if (!mnl_nlmsg_batch_is_empty(h->batch))
   2402 		h->batch = mnl_nftnl_batch_page_add(h->batch);
   2403 
   2404 	ret = mnl_nftnl_batch_talk(h);
   2405 
   2406 	mnl_nlmsg_batch_reset(h->batch);
   2407 
   2408 	return ret == 0 ? 1 : 0;
   2409 }
   2410 
   2411 int nft_commit(struct nft_handle *h)
   2412 {
   2413 	return nft_action(h, NFT_COMPAT_COMMIT);
   2414 }
   2415 
   2416 int nft_abort(struct nft_handle *h)
   2417 {
   2418 	return nft_action(h, NFT_COMPAT_ABORT);
   2419 }
   2420 
   2421 int nft_compatible_revision(const char *name, uint8_t rev, int opt)
   2422 {
   2423 	struct mnl_socket *nl;
   2424 	char buf[MNL_SOCKET_BUFFER_SIZE];
   2425 	struct nlmsghdr *nlh;
   2426 	uint32_t portid, seq, type;
   2427 	int ret = 0;
   2428 
   2429 	if (opt == IPT_SO_GET_REVISION_MATCH ||
   2430 	    opt == IP6T_SO_GET_REVISION_MATCH)
   2431 		type = 0;
   2432 	else
   2433 		type = 1;
   2434 
   2435 	nlh = mnl_nlmsg_put_header(buf);
   2436 	nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
   2437 	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
   2438 	nlh->nlmsg_seq = seq = time(NULL);
   2439 
   2440 	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
   2441 	nfg->nfgen_family = AF_INET;
   2442 	nfg->version = NFNETLINK_V0;
   2443 	nfg->res_id = 0;
   2444 
   2445 	mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
   2446 	mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
   2447 	mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
   2448 
   2449 	DEBUGP("requesting `%s' rev=%d type=%d via nft_compat\n",
   2450 		name, rev, type);
   2451 
   2452 	nl = mnl_socket_open(NETLINK_NETFILTER);
   2453 	if (nl == NULL)
   2454 		return 0;
   2455 
   2456 	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
   2457 		goto err;
   2458 
   2459 	portid = mnl_socket_get_portid(nl);
   2460 
   2461 	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
   2462 		goto err;
   2463 
   2464 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
   2465 	if (ret == -1)
   2466 		goto err;
   2467 
   2468 	ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
   2469 	if (ret == -1)
   2470 		goto err;
   2471 
   2472 err:
   2473 	mnl_socket_close(nl);
   2474 
   2475 	return ret < 0 ? 0 : 1;
   2476 }
   2477 
   2478 /* Translates errno numbers into more human-readable form than strerror. */
   2479 const char *nft_strerror(int err)
   2480 {
   2481 	unsigned int i;
   2482 	static struct table_struct {
   2483 		void *fn;
   2484 		int err;
   2485 		const char *message;
   2486 	} table[] =
   2487 	  {
   2488 	    { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
   2489 	    { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
   2490 	    { nft_chain_user_del, EBUSY, "Directory not empty" },
   2491 	    { nft_chain_user_del, EMLINK,
   2492 	      "Can't delete chain with references left" },
   2493 	    { nft_chain_user_add, EEXIST, "Chain already exists" },
   2494 	    { nft_rule_add, E2BIG, "Index of insertion too big" },
   2495 	    { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
   2496 	    { nft_rule_replace, ENOENT, "Index of replacement too big" },
   2497 	    { nft_rule_delete_num, E2BIG, "Index of deletion too big" },
   2498 /*	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
   2499 	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
   2500 	    { nft_rule_add, ELOOP, "Loop found in table" },
   2501 	    { nft_rule_add, EINVAL, "Target problem" },
   2502 	    /* ENOENT for DELETE probably means no matching rule */
   2503 	    { nft_rule_delete, ENOENT,
   2504 	      "Bad rule (does a matching rule exist in that chain?)" },
   2505 	    { nft_chain_set, ENOENT, "Bad built-in chain name" },
   2506 	    { nft_chain_set, EINVAL, "Bad policy name" },
   2507 	    { NULL, EPERM, "Permission denied (you must be root)" },
   2508 	    { NULL, 0, "Incompatible with this kernel" },
   2509 	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
   2510 	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
   2511 	    { NULL, ENOMEM, "Memory allocation problem" },
   2512 	    { NULL, ENOENT, "No chain/target/match by that name" },
   2513 	  };
   2514 
   2515 	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
   2516 		if ((!table[i].fn || table[i].fn == nft_fn)
   2517 		    && table[i].err == err)
   2518 			return table[i].message;
   2519 	}
   2520 
   2521 	return strerror(err);
   2522 }
   2523 
   2524 static void xtables_config_perror(uint32_t flags, const char *fmt, ...)
   2525 {
   2526 	va_list args;
   2527 
   2528 	va_start(args, fmt);
   2529 
   2530 	if (flags & NFT_LOAD_VERBOSE)
   2531 		vfprintf(stderr, fmt, args);
   2532 
   2533 	va_end(args);
   2534 }
   2535 
   2536 int nft_xtables_config_load(struct nft_handle *h, const char *filename,
   2537 			    uint32_t flags)
   2538 {
   2539 	struct nftnl_table_list *table_list = nftnl_table_list_alloc();
   2540 	struct nftnl_chain_list *chain_list = nftnl_chain_list_alloc();
   2541 	struct nftnl_table_list_iter *titer = NULL;
   2542 	struct nftnl_chain_list_iter *citer = NULL;
   2543 	struct nftnl_table *table;
   2544 	struct nftnl_chain *chain;
   2545 	uint32_t table_family, chain_family;
   2546 	bool found = false;
   2547 
   2548 	if (h->restore)
   2549 		return 0;
   2550 
   2551 	if (xtables_config_parse(filename, table_list, chain_list) < 0) {
   2552 		if (errno == ENOENT) {
   2553 			xtables_config_perror(flags,
   2554 				"configuration file `%s' does not exists\n",
   2555 				filename);
   2556 		} else {
   2557 			xtables_config_perror(flags,
   2558 				"Fatal error parsing config file: %s\n",
   2559 				 strerror(errno));
   2560 		}
   2561 		goto err;
   2562 	}
   2563 
   2564 	/* Stage 1) create tables */
   2565 	titer = nftnl_table_list_iter_create(table_list);
   2566 	while ((table = nftnl_table_list_iter_next(titer)) != NULL) {
   2567 		table_family = nftnl_table_get_u32(table,
   2568 						      NFTNL_TABLE_FAMILY);
   2569 		if (h->family != table_family)
   2570 			continue;
   2571 
   2572 		found = true;
   2573 
   2574 		if (batch_table_add(h, NFT_COMPAT_TABLE_ADD, table) < 0) {
   2575 			if (errno == EEXIST) {
   2576 				xtables_config_perror(flags,
   2577 					"table `%s' already exists, skipping\n",
   2578 					(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
   2579 			} else {
   2580 				xtables_config_perror(flags,
   2581 					"table `%s' cannot be create, reason `%s'. Exitting\n",
   2582 					(char *)nftnl_table_get(table, NFTNL_TABLE_NAME),
   2583 					strerror(errno));
   2584 				goto err;
   2585 			}
   2586 			continue;
   2587 		}
   2588 		xtables_config_perror(flags, "table `%s' has been created\n",
   2589 			(char *)nftnl_table_get(table, NFTNL_TABLE_NAME));
   2590 	}
   2591 	nftnl_table_list_iter_destroy(titer);
   2592 	nftnl_table_list_free(table_list);
   2593 
   2594 	if (!found)
   2595 		goto err;
   2596 
   2597 	/* Stage 2) create chains */
   2598 	citer = nftnl_chain_list_iter_create(chain_list);
   2599 	while ((chain = nftnl_chain_list_iter_next(citer)) != NULL) {
   2600 		chain_family = nftnl_chain_get_u32(chain,
   2601 						      NFTNL_CHAIN_TABLE);
   2602 		if (h->family != chain_family)
   2603 			continue;
   2604 
   2605 		if (batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, chain) < 0) {
   2606 			if (errno == EEXIST) {
   2607 				xtables_config_perror(flags,
   2608 					"chain `%s' already exists in table `%s', skipping\n",
   2609 					(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
   2610 					(char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
   2611 			} else {
   2612 				xtables_config_perror(flags,
   2613 					"chain `%s' cannot be create, reason `%s'. Exitting\n",
   2614 					(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
   2615 					strerror(errno));
   2616 				goto err;
   2617 			}
   2618 			continue;
   2619 		}
   2620 
   2621 		xtables_config_perror(flags,
   2622 			"chain `%s' in table `%s' has been created\n",
   2623 			(char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME),
   2624 			(char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE));
   2625 	}
   2626 	nftnl_chain_list_iter_destroy(citer);
   2627 	nftnl_chain_list_free(chain_list);
   2628 
   2629 	return 0;
   2630 
   2631 err:
   2632 	nftnl_table_list_free(table_list);
   2633 	nftnl_chain_list_free(chain_list);
   2634 
   2635 	if (titer != NULL)
   2636 		nftnl_table_list_iter_destroy(titer);
   2637 	if (citer != NULL)
   2638 		nftnl_chain_list_iter_destroy(citer);
   2639 
   2640 	return -1;
   2641 }
   2642 
   2643 int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
   2644 			    const char *table)
   2645 {
   2646 	struct nftnl_chain_list *list;
   2647 	struct nftnl_chain_list_iter *iter;
   2648 	struct nftnl_chain *c;
   2649 	int ret = 0;
   2650 
   2651 	list = nftnl_chain_list_get(h);
   2652 	if (list == NULL)
   2653 		goto err;
   2654 
   2655 	iter = nftnl_chain_list_iter_create(list);
   2656 	if (iter == NULL)
   2657 		goto err;
   2658 
   2659 	c = nftnl_chain_list_iter_next(iter);
   2660 	while (c != NULL) {
   2661 		const char *chain_name =
   2662 			nftnl_chain_get(c, NFTNL_CHAIN_NAME);
   2663 		const char *chain_table =
   2664 			nftnl_chain_get(c, NFTNL_CHAIN_TABLE);
   2665 
   2666 		if (strcmp(table, chain_table) != 0)
   2667 			goto next;
   2668 
   2669 		if (chain != NULL && strcmp(chain, chain_name) != 0)
   2670 			goto next;
   2671 
   2672 		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
   2673 		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
   2674 
   2675 		nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
   2676 
   2677 		if (h->batch_support) {
   2678 			ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
   2679 		} else {
   2680 			struct nlmsghdr *nlh;
   2681 			char buf[MNL_SOCKET_BUFFER_SIZE];
   2682 
   2683 			nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
   2684 							h->family, NLM_F_ACK,
   2685 							h->seq);
   2686 			nftnl_chain_nlmsg_build_payload(nlh, c);
   2687 			ret = mnl_talk(h, nlh, NULL, NULL);
   2688 		}
   2689 
   2690 		if (chain != NULL)
   2691 			break;
   2692 next:
   2693 		c = nftnl_chain_list_iter_next(iter);
   2694 	}
   2695 
   2696 	if (!h->batch_support)
   2697 		nftnl_chain_list_free(list);
   2698 
   2699 	nftnl_chain_list_iter_destroy(iter);
   2700 
   2701 err:
   2702 	/* the core expects 1 for success and 0 for error */
   2703 	return ret == 0 ? 1 : 0;
   2704 }
   2705 
   2706 uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
   2707 {
   2708 	if (invflags & flag)
   2709 		return NFT_CMP_NEQ;
   2710 
   2711 	return NFT_CMP_EQ;
   2712 }
   2713 
   2714 #define NFT_COMPAT_EXPR_MAX     8
   2715 
   2716 static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
   2717 	"match",
   2718 	"target",
   2719 	"payload",
   2720 	"meta",
   2721 	"cmp",
   2722 	"bitwise",
   2723 	"counter",
   2724 	"immediate"
   2725 };
   2726 
   2727 
   2728 static int nft_is_expr_compatible(const char *name)
   2729 {
   2730 	int i;
   2731 
   2732 	for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) {
   2733 		if (strcmp(supported_exprs[i], name) == 0)
   2734 			return 0;
   2735 	}
   2736 
   2737 	return 1;
   2738 }
   2739 
   2740 static int nft_is_rule_compatible(struct nftnl_rule *rule)
   2741 {
   2742 	struct nftnl_expr_iter *iter;
   2743 	struct nftnl_expr *expr;
   2744 	int ret = 0;
   2745 
   2746 	iter = nftnl_expr_iter_create(rule);
   2747 	if (iter == NULL)
   2748 		return -1;
   2749 
   2750 	expr = nftnl_expr_iter_next(iter);
   2751 	while (expr != NULL) {
   2752 		const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
   2753 
   2754 		if (nft_is_expr_compatible(name) == 0) {
   2755 			expr = nftnl_expr_iter_next(iter);
   2756 			continue;
   2757 		}
   2758 
   2759 		ret = 1;
   2760 		break;
   2761 	}
   2762 
   2763 	nftnl_expr_iter_destroy(iter);
   2764 	return ret;
   2765 }
   2766 
   2767 static int nft_is_chain_compatible(const char *table, const char *chain)
   2768 {
   2769 	const char *cur_table;
   2770 	struct builtin_chain *chains;
   2771 	int i, j;
   2772 
   2773 	for (i = 0; i < TABLES_MAX; i++) {
   2774 		cur_table = xtables_ipv4[i].name;
   2775 		chains = xtables_ipv4[i].chains;
   2776 
   2777 		if (strcmp(table, cur_table) != 0)
   2778 			continue;
   2779 
   2780 		for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) {
   2781 			if (strcmp(chain, chains[j].name) == 0)
   2782 				return 0;
   2783 		}
   2784 	}
   2785 
   2786 	return 1;
   2787 }
   2788 
   2789 static int nft_are_chains_compatible(struct nft_handle *h)
   2790 {
   2791 	struct nftnl_chain_list *list;
   2792 	struct nftnl_chain_list_iter *iter;
   2793 	struct nftnl_chain *chain;
   2794 	int ret = 0;
   2795 
   2796 	list = nftnl_chain_list_get(h);
   2797 	if (list == NULL)
   2798 		return -1;
   2799 
   2800 	iter = nftnl_chain_list_iter_create(list);
   2801 	if (iter == NULL)
   2802 		return -1;
   2803 
   2804 	chain = nftnl_chain_list_iter_next(iter);
   2805 	while (chain != NULL) {
   2806 		if (!nft_chain_builtin(chain))
   2807 			goto next;
   2808 
   2809 		const char *table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE);
   2810 		const char *name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME);
   2811 
   2812 		if (nft_is_chain_compatible(table, name) == 1) {
   2813 			ret = 1;
   2814 			break;
   2815 		}
   2816 
   2817 next:
   2818 		chain = nftnl_chain_list_iter_next(iter);
   2819 	}
   2820 
   2821 	nftnl_chain_list_iter_destroy(iter);
   2822 	nftnl_chain_list_free(list);
   2823 	return ret;
   2824 }
   2825 
   2826 static int nft_is_table_compatible(const char *name)
   2827 {
   2828 	int i;
   2829 
   2830 	for (i = 0; i < TABLES_MAX; i++) {
   2831 		if (strcmp(xtables_ipv4[i].name, name) == 0)
   2832 			return 0;
   2833 	}
   2834 
   2835 	return 1;
   2836 }
   2837 
   2838 static int nft_are_tables_compatible(struct nft_handle *h)
   2839 {
   2840 	struct nftnl_table_list *list;
   2841 	struct nftnl_table_list_iter *iter;
   2842 	struct nftnl_table *table;
   2843 	int ret = 0;
   2844 
   2845 	list = nftnl_table_list_get(h);
   2846 	if (list == NULL)
   2847 		return -1;
   2848 
   2849 	iter = nftnl_table_list_iter_create(list);
   2850 	if (iter == NULL)
   2851 		return -1;
   2852 
   2853 	table = nftnl_table_list_iter_next(iter);
   2854 	while (table != NULL) {
   2855 		const char *name = nftnl_table_get(table, NFTNL_TABLE_NAME);
   2856 
   2857 		if (nft_is_table_compatible(name) == 0) {
   2858 			table = nftnl_table_list_iter_next(iter);
   2859 			continue;
   2860 		}
   2861 
   2862 		ret = 1;
   2863 		break;
   2864 	}
   2865 
   2866 	nftnl_table_list_iter_destroy(iter);
   2867 	nftnl_table_list_free(list);
   2868 	return ret;
   2869 }
   2870 
   2871 int nft_is_ruleset_compatible(struct nft_handle *h)
   2872 {
   2873 
   2874 	struct nftnl_rule_list *list;
   2875 	struct nftnl_rule_list_iter *iter;
   2876 	struct nftnl_rule *rule;
   2877 	int ret = 0;
   2878 
   2879 	ret = nft_are_tables_compatible(h);
   2880 	if (ret != 0)
   2881 		return ret;
   2882 
   2883 	ret = nft_are_chains_compatible(h);
   2884 	if (ret != 0)
   2885 		return ret;
   2886 
   2887 	list = nft_rule_list_get(h);
   2888 	if (list == NULL)
   2889 		return -1;
   2890 
   2891 	iter = nftnl_rule_list_iter_create(list);
   2892 	if (iter == NULL)
   2893 		return -1;
   2894 
   2895 	rule = nftnl_rule_list_iter_next(iter);
   2896 	while (rule != NULL) {
   2897 		ret = nft_is_rule_compatible(rule);
   2898 		if (ret != 0)
   2899 			break;
   2900 
   2901 		rule = nftnl_rule_list_iter_next(iter);
   2902 	}
   2903 
   2904 	nftnl_rule_list_iter_destroy(iter);
   2905 	return ret;
   2906 }
   2907