• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@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 #include <assert.h>
23 
24 #include <xtables.h>
25 #include <libiptc/libxtc.h>
26 #include <libiptc/xtcshared.h>
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <linux/netfilter/x_tables.h>
32 #include <linux/netfilter_ipv4/ip_tables.h>
33 #include <linux/netfilter_ipv6/ip6_tables.h>
34 #include <netinet/ip6.h>
35 
36 #include <linux/netlink.h>
37 #include <linux/netfilter/nfnetlink.h>
38 #include <linux/netfilter/nf_tables.h>
39 #include <linux/netfilter/nf_tables_compat.h>
40 
41 #include <linux/netfilter/xt_limit.h>
42 
43 #include <libmnl/libmnl.h>
44 #include <libnftnl/gen.h>
45 #include <libnftnl/table.h>
46 #include <libnftnl/chain.h>
47 #include <libnftnl/rule.h>
48 #include <libnftnl/expr.h>
49 #include <libnftnl/set.h>
50 #include <libnftnl/udata.h>
51 #include <libnftnl/batch.h>
52 
53 #include <netinet/in.h>	/* inet_ntoa */
54 #include <arpa/inet.h>
55 
56 #include "nft.h"
57 #include "xshared.h" /* proto_to_name */
58 #include "nft-cache.h"
59 #include "nft-shared.h"
60 #include "nft-bridge.h" /* EBT_NOPROTO */
61 
62 static void *nft_fn;
63 
mnl_talk(struct nft_handle * h,struct nlmsghdr * nlh,int (* cb)(const struct nlmsghdr * nlh,void * data),void * data)64 int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
65 	     int (*cb)(const struct nlmsghdr *nlh, void *data),
66 	     void *data)
67 {
68 	int ret;
69 	char buf[32768];
70 
71 	if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
72 		return -1;
73 
74 	ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
75 	while (ret > 0) {
76 		ret = mnl_cb_run(buf, ret, h->seq, h->portid, cb, data);
77 		if (ret <= 0)
78 			break;
79 
80 		ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
81 	}
82 	if (ret == -1) {
83 		return -1;
84 	}
85 
86 	return 0;
87 }
88 
89 #define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
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 
mnl_batch_init(void)97 static struct nftnl_batch *mnl_batch_init(void)
98 {
99 	struct nftnl_batch *batch;
100 
101 	batch = nftnl_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE);
102 	if (batch == NULL)
103 		return NULL;
104 
105 	return batch;
106 }
107 
mnl_nft_batch_continue(struct nftnl_batch * batch)108 static void mnl_nft_batch_continue(struct nftnl_batch *batch)
109 {
110 	assert(nftnl_batch_update(batch) >= 0);
111 }
112 
mnl_batch_begin(struct nftnl_batch * batch,uint32_t genid,uint32_t seqnum)113 static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum)
114 {
115 	struct nlmsghdr *nlh;
116 
117 	nlh = nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
118 
119 	mnl_attr_put_u32(nlh, NFTA_GEN_ID, htonl(genid));
120 
121 	mnl_nft_batch_continue(batch);
122 
123 	return seqnum;
124 }
125 
mnl_batch_end(struct nftnl_batch * batch,uint32_t seqnum)126 static void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum)
127 {
128 	nftnl_batch_end(nftnl_batch_buffer(batch), seqnum);
129 	mnl_nft_batch_continue(batch);
130 }
131 
mnl_batch_reset(struct nftnl_batch * batch)132 static void mnl_batch_reset(struct nftnl_batch *batch)
133 {
134 	nftnl_batch_free(batch);
135 }
136 
137 struct mnl_err {
138 	struct list_head	head;
139 	int			err;
140 	uint32_t		seqnum;
141 };
142 
mnl_err_list_node_add(struct list_head * err_list,int error,int seqnum)143 static void mnl_err_list_node_add(struct list_head *err_list, int error,
144 				  int seqnum)
145 {
146 	struct mnl_err *err = malloc(sizeof(struct mnl_err));
147 
148 	err->seqnum = seqnum;
149 	err->err = error;
150 	list_add_tail(&err->head, err_list);
151 }
152 
mnl_err_list_free(struct mnl_err * err)153 static void mnl_err_list_free(struct mnl_err *err)
154 {
155 	list_del(&err->head);
156 	free(err);
157 }
158 
mnl_set_sndbuffer(struct nft_handle * h)159 static void mnl_set_sndbuffer(struct nft_handle *h)
160 {
161 	int newbuffsiz = nftnl_batch_iovec_len(h->batch) * BATCH_PAGE_SIZE;
162 
163 	if (newbuffsiz <= h->nlsndbuffsiz)
164 		return;
165 
166 	/* Rise sender buffer length to avoid hitting -EMSGSIZE */
167 	if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_SNDBUFFORCE,
168 		       &newbuffsiz, sizeof(socklen_t)) < 0)
169 		return;
170 
171 	h->nlsndbuffsiz = newbuffsiz;
172 }
173 
mnl_set_rcvbuffer(struct nft_handle * h,int numcmds)174 static void mnl_set_rcvbuffer(struct nft_handle *h, int numcmds)
175 {
176 	int newbuffsiz = getpagesize() * numcmds;
177 
178 	if (newbuffsiz <= h->nlrcvbuffsiz)
179 		return;
180 
181 	/* Rise receiver buffer length to avoid hitting -ENOBUFS */
182 	if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_RCVBUFFORCE,
183 		       &newbuffsiz, sizeof(socklen_t)) < 0)
184 		return;
185 
186 	h->nlrcvbuffsiz = newbuffsiz;
187 }
188 
mnl_nft_socket_sendmsg(struct nft_handle * h,int numcmds)189 static ssize_t mnl_nft_socket_sendmsg(struct nft_handle *h, int numcmds)
190 {
191 	static const struct sockaddr_nl snl = {
192 		.nl_family = AF_NETLINK
193 	};
194 	uint32_t iov_len = nftnl_batch_iovec_len(h->batch);
195 	struct iovec iov[iov_len];
196 	struct msghdr msg = {
197 		.msg_name	= (struct sockaddr *) &snl,
198 		.msg_namelen	= sizeof(snl),
199 		.msg_iov	= iov,
200 		.msg_iovlen	= iov_len,
201 	};
202 
203 	mnl_set_sndbuffer(h);
204 	mnl_set_rcvbuffer(h, numcmds);
205 	nftnl_batch_iovec(h->batch, iov, iov_len);
206 
207 	return sendmsg(mnl_socket_get_fd(h->nl), &msg, 0);
208 }
209 
mnl_batch_talk(struct nft_handle * h,int numcmds)210 static int mnl_batch_talk(struct nft_handle *h, int numcmds)
211 {
212 	const struct mnl_socket *nl = h->nl;
213 	int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
214 	char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
215 	fd_set readfds;
216 	struct timeval tv = {
217 		.tv_sec		= 0,
218 		.tv_usec	= 0
219 	};
220 	int err = 0;
221 
222 	ret = mnl_nft_socket_sendmsg(h, numcmds);
223 	if (ret == -1)
224 		return -1;
225 
226 	FD_ZERO(&readfds);
227 	FD_SET(fd, &readfds);
228 
229 	/* receive and digest all the acknowledgments from the kernel. */
230 	ret = select(fd+1, &readfds, NULL, NULL, &tv);
231 	if (ret == -1)
232 		return -1;
233 
234 	while (ret > 0 && FD_ISSET(fd, &readfds)) {
235 		struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
236 
237 		ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
238 		if (ret == -1)
239 			return -1;
240 
241 		ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL);
242 		/* Continue on error, make sure we get all acknowledgments */
243 		if (ret == -1) {
244 			mnl_err_list_node_add(&h->err_list, errno,
245 					      nlh->nlmsg_seq);
246 			err = -1;
247 		}
248 
249 		ret = select(fd+1, &readfds, NULL, NULL, &tv);
250 		if (ret == -1)
251 			return -1;
252 
253 		FD_ZERO(&readfds);
254 		FD_SET(fd, &readfds);
255 	}
256 	return err;
257 }
258 
259 enum obj_action {
260 	NFT_COMPAT_COMMIT,
261 	NFT_COMPAT_ABORT,
262 };
263 
264 struct obj_update {
265 	struct list_head	head;
266 	enum obj_update_type	type:8;
267 	uint8_t			skip:1;
268 	unsigned int		seq;
269 	union {
270 		struct nftnl_table	*table;
271 		struct nftnl_chain	*chain;
272 		struct nftnl_rule	*rule;
273 		struct nftnl_set	*set;
274 		void			*ptr;
275 	};
276 	struct {
277 		unsigned int		lineno;
278 	} error;
279 };
280 
mnl_append_error(const struct nft_handle * h,const struct obj_update * o,const struct mnl_err * err,char * buf,unsigned int len)281 static int mnl_append_error(const struct nft_handle *h,
282 			    const struct obj_update *o,
283 			    const struct mnl_err *err,
284 			    char *buf, unsigned int len)
285 {
286 	static const char *type_name[] = {
287 		[NFT_COMPAT_TABLE_ADD] = "TABLE_ADD",
288 		[NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
289 		[NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
290 		[NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
291 		[NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
292 		[NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
293 		[NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
294 		[NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
295 		[NFT_COMPAT_CHAIN_ZERO] = "CHAIN_ZERO",
296 		[NFT_COMPAT_RULE_APPEND] = "RULE_APPEND",
297 		[NFT_COMPAT_RULE_INSERT] = "RULE_INSERT",
298 		[NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
299 		[NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
300 		[NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
301 		[NFT_COMPAT_SET_ADD] = "SET_ADD",
302 	};
303 	char errmsg[256];
304 	char tcr[128];
305 
306 	if (o->error.lineno)
307 		snprintf(errmsg, sizeof(errmsg), "\nline %u: %s failed (%s)",
308 			 o->error.lineno, type_name[o->type], strerror(err->err));
309 	else
310 		snprintf(errmsg, sizeof(errmsg), " %s failed (%s)",
311 			 type_name[o->type], strerror(err->err));
312 
313 	switch (o->type) {
314 	case NFT_COMPAT_TABLE_ADD:
315 	case NFT_COMPAT_TABLE_FLUSH:
316 		snprintf(tcr, sizeof(tcr), "table %s",
317 			 nftnl_table_get_str(o->table, NFTNL_TABLE_NAME));
318 		break;
319 	case NFT_COMPAT_CHAIN_ADD:
320 	case NFT_COMPAT_CHAIN_ZERO:
321 	case NFT_COMPAT_CHAIN_USER_ADD:
322 	case NFT_COMPAT_CHAIN_USER_DEL:
323 	case NFT_COMPAT_CHAIN_USER_FLUSH:
324 	case NFT_COMPAT_CHAIN_UPDATE:
325 	case NFT_COMPAT_CHAIN_RENAME:
326 		snprintf(tcr, sizeof(tcr), "chain %s",
327 			 nftnl_chain_get_str(o->chain, NFTNL_CHAIN_NAME));
328 		break;
329 	case NFT_COMPAT_RULE_APPEND:
330 	case NFT_COMPAT_RULE_INSERT:
331 	case NFT_COMPAT_RULE_REPLACE:
332 	case NFT_COMPAT_RULE_DELETE:
333 	case NFT_COMPAT_RULE_FLUSH:
334 		snprintf(tcr, sizeof(tcr), "rule in chain %s",
335 			 nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
336 #if 0
337 		{
338 			nft_rule_print_save(h, o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
339 		}
340 #endif
341 		break;
342 	case NFT_COMPAT_SET_ADD:
343 		snprintf(tcr, sizeof(tcr), "set %s",
344 			 nftnl_set_get_str(o->set, NFTNL_SET_NAME));
345 		break;
346 	case NFT_COMPAT_RULE_LIST:
347 	case NFT_COMPAT_RULE_CHECK:
348 	case NFT_COMPAT_CHAIN_RESTORE:
349 	case NFT_COMPAT_RULE_SAVE:
350 	case NFT_COMPAT_RULE_ZERO:
351 	case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
352 		assert(0);
353 		break;
354 	}
355 
356 	return snprintf(buf, len, "%s: %s", errmsg, tcr);
357 }
358 
batch_add(struct nft_handle * h,enum obj_update_type type,void * ptr)359 static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
360 {
361 	struct obj_update *obj;
362 
363 	obj = calloc(1, sizeof(struct obj_update));
364 	if (obj == NULL)
365 		return NULL;
366 
367 	obj->ptr = ptr;
368 	obj->error.lineno = h->error.lineno;
369 	obj->type = type;
370 	list_add_tail(&obj->head, &h->obj_list);
371 	h->obj_list_num++;
372 
373 	return obj;
374 }
375 
376 static struct obj_update *
batch_table_add(struct nft_handle * h,enum obj_update_type type,struct nftnl_table * t)377 batch_table_add(struct nft_handle *h, enum obj_update_type type,
378 		struct nftnl_table *t)
379 {
380 	return batch_add(h, type, t);
381 }
382 
383 static struct obj_update *
batch_set_add(struct nft_handle * h,enum obj_update_type type,struct nftnl_set * s)384 batch_set_add(struct nft_handle *h, enum obj_update_type type,
385 	      struct nftnl_set *s)
386 {
387 	return batch_add(h, type, s);
388 }
389 
390 static struct obj_update *
batch_chain_add(struct nft_handle * h,enum obj_update_type type,struct nftnl_chain * c)391 batch_chain_add(struct nft_handle *h, enum obj_update_type type,
392 			   struct nftnl_chain *c)
393 {
394 	return batch_add(h, type, c);
395 }
396 
397 static struct obj_update *
batch_rule_add(struct nft_handle * h,enum obj_update_type type,struct nftnl_rule * r)398 batch_rule_add(struct nft_handle *h, enum obj_update_type type,
399 			  struct nftnl_rule *r)
400 {
401 	return batch_add(h, type, r);
402 }
403 
404 static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
405 
batch_chain_flush(struct nft_handle * h,const char * table,const char * chain)406 static void batch_chain_flush(struct nft_handle *h,
407 			      const char *table, const char *chain)
408 {
409 	struct obj_update *obj, *tmp;
410 
411 	list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
412 		struct nftnl_rule *r = obj->ptr;
413 
414 		switch (obj->type) {
415 		case NFT_COMPAT_RULE_APPEND:
416 		case NFT_COMPAT_RULE_INSERT:
417 		case NFT_COMPAT_RULE_REPLACE:
418 		case NFT_COMPAT_RULE_DELETE:
419 			break;
420 		default:
421 			continue;
422 		}
423 
424 		if (table &&
425 		    strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
426 			continue;
427 
428 		if (chain &&
429 		    strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
430 			continue;
431 
432 		batch_obj_del(h, obj);
433 	}
434 }
435 
436 const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
437 	[NFT_TABLE_RAW] = {
438 		.name	= "raw",
439 		.type	= NFT_TABLE_RAW,
440 		.chains = {
441 			{
442 				.name	= "PREROUTING",
443 				.type	= "filter",
444 				.prio	= -300,	/* NF_IP_PRI_RAW */
445 				.hook	= NF_INET_PRE_ROUTING,
446 			},
447 			{
448 				.name	= "OUTPUT",
449 				.type	= "filter",
450 				.prio	= -300,	/* NF_IP_PRI_RAW */
451 				.hook	= NF_INET_LOCAL_OUT,
452 			},
453 		},
454 	},
455 	[NFT_TABLE_MANGLE] = {
456 		.name	= "mangle",
457 		.type	= NFT_TABLE_MANGLE,
458 		.chains = {
459 			{
460 				.name	= "PREROUTING",
461 				.type	= "filter",
462 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
463 				.hook	= NF_INET_PRE_ROUTING,
464 			},
465 			{
466 				.name	= "INPUT",
467 				.type	= "filter",
468 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
469 				.hook	= NF_INET_LOCAL_IN,
470 			},
471 			{
472 				.name	= "FORWARD",
473 				.type	= "filter",
474 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
475 				.hook	= NF_INET_FORWARD,
476 			},
477 			{
478 				.name	= "OUTPUT",
479 				.type	= "route",
480 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
481 				.hook	= NF_INET_LOCAL_OUT,
482 			},
483 			{
484 				.name	= "POSTROUTING",
485 				.type	= "filter",
486 				.prio	= -150,	/* NF_IP_PRI_MANGLE */
487 				.hook	= NF_INET_POST_ROUTING,
488 			},
489 		},
490 	},
491 	[NFT_TABLE_FILTER] = {
492 		.name	= "filter",
493 		.type	= NFT_TABLE_FILTER,
494 		.chains = {
495 			{
496 				.name	= "INPUT",
497 				.type	= "filter",
498 				.prio	= 0,	/* NF_IP_PRI_FILTER */
499 				.hook	= NF_INET_LOCAL_IN,
500 			},
501 			{
502 				.name	= "FORWARD",
503 				.type	= "filter",
504 				.prio	= 0,	/* NF_IP_PRI_FILTER */
505 				.hook	= NF_INET_FORWARD,
506 			},
507 			{
508 				.name	= "OUTPUT",
509 				.type	= "filter",
510 				.prio	= 0,	/* NF_IP_PRI_FILTER */
511 				.hook	= NF_INET_LOCAL_OUT,
512 			},
513 		},
514 	},
515 	[NFT_TABLE_SECURITY] = {
516 		.name	= "security",
517 		.type	= NFT_TABLE_SECURITY,
518 		.chains = {
519 			{
520 				.name	= "INPUT",
521 				.type	= "filter",
522 				.prio	= 150,	/* NF_IP_PRI_SECURITY */
523 				.hook	= NF_INET_LOCAL_IN,
524 			},
525 			{
526 				.name	= "FORWARD",
527 				.type	= "filter",
528 				.prio	= 150,	/* NF_IP_PRI_SECURITY */
529 				.hook	= NF_INET_FORWARD,
530 			},
531 			{
532 				.name	= "OUTPUT",
533 				.type	= "filter",
534 				.prio	= 150,	/* NF_IP_PRI_SECURITY */
535 				.hook	= NF_INET_LOCAL_OUT,
536 			},
537 		},
538 	},
539 	[NFT_TABLE_NAT] = {
540 		.name	= "nat",
541 		.type	= NFT_TABLE_NAT,
542 		.chains = {
543 			{
544 				.name	= "PREROUTING",
545 				.type	= "nat",
546 				.prio	= -100, /* NF_IP_PRI_NAT_DST */
547 				.hook	= NF_INET_PRE_ROUTING,
548 			},
549 			{
550 				.name	= "INPUT",
551 				.type	= "nat",
552 				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
553 				.hook	= NF_INET_LOCAL_IN,
554 			},
555 			{
556 				.name	= "POSTROUTING",
557 				.type	= "nat",
558 				.prio	= 100, /* NF_IP_PRI_NAT_SRC */
559 				.hook	= NF_INET_POST_ROUTING,
560 			},
561 			{
562 				.name	= "OUTPUT",
563 				.type	= "nat",
564 				.prio	= -100, /* NF_IP_PRI_NAT_DST */
565 				.hook	= NF_INET_LOCAL_OUT,
566 			},
567 		},
568 	},
569 };
570 
571 #include <linux/netfilter_arp.h>
572 
573 const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
574 	[NFT_TABLE_FILTER] = {
575 	.name   = "filter",
576 	.type	= NFT_TABLE_FILTER,
577 	.chains = {
578 			{
579 				.name   = "INPUT",
580 				.type   = "filter",
581 				.prio   = NF_IP_PRI_FILTER,
582 				.hook   = NF_ARP_IN,
583 			},
584 			{
585 				.name   = "OUTPUT",
586 				.type   = "filter",
587 				.prio   = NF_IP_PRI_FILTER,
588 				.hook   = NF_ARP_OUT,
589 			},
590 		},
591 	},
592 };
593 
594 #include <linux/netfilter_bridge.h>
595 
596 const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
597 	[NFT_TABLE_FILTER] = {
598 		.name = "filter",
599 		.type	= NFT_TABLE_FILTER,
600 		.chains = {
601 			{
602 				.name   = "INPUT",
603 				.type   = "filter",
604 				.prio   = NF_BR_PRI_FILTER_BRIDGED,
605 				.hook   = NF_BR_LOCAL_IN,
606 			},
607 			{
608 				.name   = "FORWARD",
609 				.type   = "filter",
610 				.prio   = NF_BR_PRI_FILTER_BRIDGED,
611 				.hook   = NF_BR_FORWARD,
612 			},
613 			{
614 				.name   = "OUTPUT",
615 				.type   = "filter",
616 				.prio   = NF_BR_PRI_FILTER_BRIDGED,
617 				.hook   = NF_BR_LOCAL_OUT,
618 			},
619 		},
620 	},
621 	[NFT_TABLE_NAT] = {
622 		.name = "nat",
623 		.type	= NFT_TABLE_NAT,
624 		.chains = {
625 			{
626 				.name   = "PREROUTING",
627 				.type   = "filter",
628 				.prio   = NF_BR_PRI_NAT_DST_BRIDGED,
629 				.hook   = NF_BR_PRE_ROUTING,
630 			},
631 			{
632 				.name   = "OUTPUT",
633 				.type   = "filter",
634 				.prio   = NF_BR_PRI_NAT_DST_OTHER,
635 				.hook   = NF_BR_LOCAL_OUT,
636 			},
637 			{
638 				.name   = "POSTROUTING",
639 				.type   = "filter",
640 				.prio   = NF_BR_PRI_NAT_SRC,
641 				.hook   = NF_BR_POST_ROUTING,
642 			},
643 		},
644 	},
645 };
646 
nft_table_builtin_add(struct nft_handle * h,const struct builtin_table * _t)647 static int nft_table_builtin_add(struct nft_handle *h,
648 				 const struct builtin_table *_t)
649 {
650 	struct nftnl_table *t;
651 	int ret;
652 
653 	if (h->cache->table[_t->type].exists)
654 		return 0;
655 
656 	t = nftnl_table_alloc();
657 	if (t == NULL)
658 		return -1;
659 
660 	nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
661 
662 	ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
663 
664 	return ret;
665 }
666 
667 static struct nftnl_chain *
nft_chain_builtin_alloc(const struct builtin_table * table,const struct builtin_chain * chain,int policy)668 nft_chain_builtin_alloc(const struct builtin_table *table,
669 			const struct builtin_chain *chain, int policy)
670 {
671 	struct nftnl_chain *c;
672 
673 	c = nftnl_chain_alloc();
674 	if (c == NULL)
675 		return NULL;
676 
677 	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name);
678 	nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
679 	nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
680 	nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
681 	if (policy >= 0)
682 		nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
683 
684 	nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
685 
686 	return c;
687 }
688 
nft_chain_builtin_add(struct nft_handle * h,const struct builtin_table * table,const struct builtin_chain * chain,bool fake)689 static void nft_chain_builtin_add(struct nft_handle *h,
690 				  const struct builtin_table *table,
691 				  const struct builtin_chain *chain,
692 				  bool fake)
693 {
694 	struct nftnl_chain *c;
695 
696 	c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
697 	if (c == NULL)
698 		return;
699 
700 	if (!fake)
701 		batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
702 	nft_cache_add_chain(h, table, c);
703 }
704 
705 /* find if built-in table already exists */
706 const struct builtin_table *
nft_table_builtin_find(struct nft_handle * h,const char * table)707 nft_table_builtin_find(struct nft_handle *h, const char *table)
708 {
709 	int i;
710 	bool found = false;
711 
712 	for (i = 0; i < NFT_TABLE_MAX; i++) {
713 		if (h->tables[i].name == NULL)
714 			continue;
715 
716 		if (strcmp(h->tables[i].name, table) != 0)
717 			continue;
718 
719 		found = true;
720 		break;
721 	}
722 
723 	return found ? &h->tables[i] : NULL;
724 }
725 
726 /* find if built-in chain already exists */
727 const struct builtin_chain *
nft_chain_builtin_find(const struct builtin_table * t,const char * chain)728 nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
729 {
730 	int i;
731 	bool found = false;
732 
733 	for (i=0; i<NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
734 		if (strcmp(t->chains[i].name, chain) != 0)
735 			continue;
736 
737 		found = true;
738 		break;
739 	}
740 	return found ? &t->chains[i] : NULL;
741 }
742 
nft_chain_builtin_init(struct nft_handle * h,const struct builtin_table * table)743 static void nft_chain_builtin_init(struct nft_handle *h,
744 				   const struct builtin_table *table)
745 {
746 	int i;
747 
748 	/* Initialize built-in chains if they don't exist yet */
749 	for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
750 		if (nft_chain_find(h, table->name, table->chains[i].name))
751 			continue;
752 
753 		nft_chain_builtin_add(h, table, &table->chains[i], false);
754 	}
755 }
756 
757 static const struct builtin_table *
nft_xt_builtin_table_init(struct nft_handle * h,const char * table)758 nft_xt_builtin_table_init(struct nft_handle *h, const char *table)
759 {
760 	const struct builtin_table *t;
761 
762 	if (!h->cache_init)
763 		return NULL;
764 
765 	t = nft_table_builtin_find(h, table);
766 	if (t == NULL)
767 		return NULL;
768 
769 	if (nft_table_builtin_add(h, t) < 0)
770 		return NULL;
771 
772 	return t;
773 }
774 
nft_xt_builtin_init(struct nft_handle * h,const char * table,const char * chain)775 static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
776 			       const char *chain)
777 {
778 	const struct builtin_table *t;
779 	const struct builtin_chain *c;
780 
781 	if (!h->cache_init)
782 		return 0;
783 
784 	t = nft_xt_builtin_table_init(h, table);
785 	if (!t)
786 		return -1;
787 
788 	if (h->cache_req.level < NFT_CL_CHAINS)
789 		return 0;
790 
791 	if (!chain) {
792 		nft_chain_builtin_init(h, t);
793 		return 0;
794 	}
795 
796 	c = nft_chain_builtin_find(t, chain);
797 	if (!c)
798 		return -1;
799 
800 	if (h->cache->table[t->type].base_chains[c->hook])
801 		return 0;
802 
803 	nft_chain_builtin_add(h, t, c, false);
804 	return 0;
805 }
806 
nft_chain_builtin(struct nftnl_chain * c)807 static bool nft_chain_builtin(struct nftnl_chain *c)
808 {
809 	/* Check if this chain has hook number, in that case is built-in.
810 	 * Should we better export the flags to user-space via nf_tables?
811 	 */
812 	return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
813 }
814 
__nft_xt_fake_builtin_chains(struct nft_handle * h,const char * table,void * data)815 static int __nft_xt_fake_builtin_chains(struct nft_handle *h,
816 				        const char *table, void *data)
817 {
818 	const char *chain = data ? *(const char **)data : NULL;
819 	const struct builtin_table *t;
820 	struct nft_chain **bcp;
821 	int i;
822 
823 	t = nft_table_builtin_find(h, table);
824 	if (!t)
825 		return -1;
826 
827 	bcp = h->cache->table[t->type].base_chains;
828 	for (i = 0; i < NF_INET_NUMHOOKS && t->chains[i].name; i++) {
829 		if (bcp[t->chains[i].hook])
830 			continue;
831 
832 		if (chain && strcmp(chain, t->chains[i].name))
833 			continue;
834 
835 		nft_chain_builtin_add(h, t, &t->chains[i], true);
836 	}
837 	return 0;
838 }
839 
nft_xt_fake_builtin_chains(struct nft_handle * h,const char * table,const char * chain)840 int nft_xt_fake_builtin_chains(struct nft_handle *h,
841 			       const char *table, const char *chain)
842 {
843 	if (table)
844 		return __nft_xt_fake_builtin_chains(h, table, &chain);
845 
846 	return nft_for_each_table(h, __nft_xt_fake_builtin_chains, &chain);
847 }
848 
nft_restart(struct nft_handle * h)849 int nft_restart(struct nft_handle *h)
850 {
851 	mnl_socket_close(h->nl);
852 
853 	h->nl = mnl_socket_open(NETLINK_NETFILTER);
854 	if (h->nl == NULL)
855 		return -1;
856 
857 	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
858 		return -1;
859 
860 	h->portid = mnl_socket_get_portid(h->nl);
861 	h->nlsndbuffsiz = 0;
862 	h->nlrcvbuffsiz = 0;
863 
864 	return 0;
865 }
866 
nft_init(struct nft_handle * h,int family,const struct builtin_table * t)867 int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
868 {
869 	memset(h, 0, sizeof(*h));
870 
871 	h->nl = mnl_socket_open(NETLINK_NETFILTER);
872 	if (h->nl == NULL)
873 		return -1;
874 
875 	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
876 		mnl_socket_close(h->nl);
877 		return -1;
878 	}
879 
880 	h->ops = nft_family_ops_lookup(family);
881 	if (!h->ops)
882 		xtables_error(PARAMETER_PROBLEM, "Unknown family");
883 
884 	h->portid = mnl_socket_get_portid(h->nl);
885 	h->tables = t;
886 	h->cache = &h->__cache[0];
887 	h->family = family;
888 
889 	INIT_LIST_HEAD(&h->obj_list);
890 	INIT_LIST_HEAD(&h->err_list);
891 	INIT_LIST_HEAD(&h->cmd_list);
892 	INIT_LIST_HEAD(&h->cache_req.chain_list);
893 
894 	return 0;
895 }
896 
nft_fini(struct nft_handle * h)897 void nft_fini(struct nft_handle *h)
898 {
899 	struct list_head *pos, *n;
900 
901 	list_for_each_safe(pos, n, &h->cmd_list)
902 		nft_cmd_free(list_entry(pos, struct nft_cmd, head));
903 
904 	list_for_each_safe(pos, n, &h->obj_list)
905 		batch_obj_del(h, list_entry(pos, struct obj_update, head));
906 
907 	list_for_each_safe(pos, n, &h->err_list)
908 		mnl_err_list_free(list_entry(pos, struct mnl_err, head));
909 
910 	nft_release_cache(h);
911 	mnl_socket_close(h->nl);
912 }
913 
nft_chain_print_debug(struct nftnl_chain * c,struct nlmsghdr * nlh)914 static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
915 {
916 #ifdef NLDEBUG
917 	char tmp[1024];
918 
919 	nftnl_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
920 	printf("DEBUG: chain: %s\n", tmp);
921 	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
922 #endif
923 }
924 
nft_chain_new(struct nft_handle * h,const char * table,const char * chain,int policy,const struct xt_counters * counters)925 static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
926 				       const char *table, const char *chain,
927 				       int policy,
928 				       const struct xt_counters *counters)
929 {
930 	struct nftnl_chain *c;
931 	const struct builtin_table *_t;
932 	const struct builtin_chain *_c;
933 
934 	_t = nft_table_builtin_find(h, table);
935 	if (!_t) {
936 		errno = ENXIO;
937 		return NULL;
938 	}
939 
940 	/* if this built-in table does not exists, create it */
941 	nft_xt_builtin_init(h, table, chain);
942 
943 	_c = nft_chain_builtin_find(_t, chain);
944 	if (_c != NULL) {
945 		/* This is a built-in chain */
946 		c = nft_chain_builtin_alloc(_t, _c, policy);
947 		if (c == NULL)
948 			return NULL;
949 	} else {
950 		errno = ENOENT;
951 		return NULL;
952 	}
953 
954 	if (counters) {
955 		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES,
956 					counters->bcnt);
957 		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS,
958 					counters->pcnt);
959 	}
960 
961 	return c;
962 }
963 
nft_chain_set(struct nft_handle * h,const char * table,const char * chain,const char * policy,const struct xt_counters * counters)964 int nft_chain_set(struct nft_handle *h, const char *table,
965 		  const char *chain, const char *policy,
966 		  const struct xt_counters *counters)
967 {
968 	struct nftnl_chain *c = NULL;
969 
970 	nft_fn = nft_chain_set;
971 
972 	if (strcmp(policy, "DROP") == 0)
973 		c = nft_chain_new(h, table, chain, NF_DROP, counters);
974 	else if (strcmp(policy, "ACCEPT") == 0)
975 		c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
976 	else if (strcmp(policy, "-") == 0)
977 		c = nft_chain_new(h, table, chain, -1, counters);
978 	else
979 		errno = EINVAL;
980 
981 	if (c == NULL)
982 		return 0;
983 
984 	if (!batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c))
985 		return 0;
986 
987 	/* the core expects 1 for success and 0 for error */
988 	return 1;
989 }
990 
__add_match(struct nftnl_expr * e,struct xt_entry_match * m)991 static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
992 {
993 	void *info;
994 
995 	nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
996 	nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
997 
998 	info = calloc(1, m->u.match_size);
999 	if (info == NULL)
1000 		return -ENOMEM;
1001 
1002 	memcpy(info, m->data, m->u.match_size - sizeof(*m));
1003 	nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
1004 
1005 	return 0;
1006 }
1007 
add_nft_limit(struct nftnl_rule * r,struct xt_entry_match * m)1008 static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
1009 {
1010 	struct xt_rateinfo *rinfo = (void *)m->data;
1011 	static const uint32_t mult[] = {
1012 		XT_LIMIT_SCALE*24*60*60,	/* day */
1013 		XT_LIMIT_SCALE*60*60,		/* hour */
1014 		XT_LIMIT_SCALE*60,		/* min */
1015 		XT_LIMIT_SCALE,			/* sec */
1016 	};
1017 	struct nftnl_expr *expr;
1018 	int i;
1019 
1020 	expr = nftnl_expr_alloc("limit");
1021 	if (!expr)
1022 		return -ENOMEM;
1023 
1024 	for (i = 1; i < ARRAY_SIZE(mult); i++) {
1025 		if (rinfo->avg > mult[i] ||
1026 		    mult[i] / rinfo->avg < mult[i] % rinfo->avg)
1027 			break;
1028 	}
1029 
1030 	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_TYPE, NFT_LIMIT_PKTS);
1031 	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_FLAGS, 0);
1032 
1033 	nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_RATE,
1034 			   mult[i - 1] / rinfo->avg);
1035         nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_UNIT,
1036 			   mult[i - 1] / XT_LIMIT_SCALE);
1037 
1038 	nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_BURST, rinfo->burst);
1039 
1040 	nftnl_rule_add_expr(r, expr);
1041 	return 0;
1042 }
1043 
add_anon_set(struct nft_handle * h,const char * table,uint32_t flags,uint32_t key_type,uint32_t key_len,uint32_t size)1044 static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
1045 				      uint32_t flags, uint32_t key_type,
1046 				      uint32_t key_len, uint32_t size)
1047 {
1048 	static uint32_t set_id = 0;
1049 	struct nftnl_set *s;
1050 	struct nft_cmd *cmd;
1051 
1052 	s = nftnl_set_alloc();
1053 	if (!s)
1054 		return NULL;
1055 
1056 	nftnl_set_set_u32(s, NFTNL_SET_FAMILY, h->family);
1057 	nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
1058 	nftnl_set_set_str(s, NFTNL_SET_NAME, "__set%d");
1059 	nftnl_set_set_u32(s, NFTNL_SET_ID, ++set_id);
1060 	nftnl_set_set_u32(s, NFTNL_SET_FLAGS,
1061 			  NFT_SET_ANONYMOUS | NFT_SET_CONSTANT | flags);
1062 	nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, key_type);
1063 	nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
1064 	nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
1065 
1066 	cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false);
1067 	if (!cmd) {
1068 		nftnl_set_free(s);
1069 		return NULL;
1070 	}
1071 	cmd->obj.set = s;
1072 
1073 	return s;
1074 }
1075 
1076 static struct nftnl_expr *
gen_payload(uint32_t base,uint32_t offset,uint32_t len,uint32_t dreg)1077 gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg)
1078 {
1079 	struct nftnl_expr *e = nftnl_expr_alloc("payload");
1080 
1081 	if (!e)
1082 		return NULL;
1083 	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
1084 	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
1085 	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
1086 	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
1087 	return e;
1088 }
1089 
1090 static struct nftnl_expr *
gen_lookup(uint32_t sreg,const char * set_name,uint32_t set_id,uint32_t flags)1091 gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
1092 {
1093 	struct nftnl_expr *e = nftnl_expr_alloc("lookup");
1094 
1095 	if (!e)
1096 		return NULL;
1097 	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
1098 	nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
1099 	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SET_ID, set_id);
1100 	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_FLAGS, flags);
1101 	return e;
1102 }
1103 
1104 /* simplified nftables:include/netlink.h, netlink_padded_len() */
1105 #define NETLINK_ALIGN		4
1106 
1107 /* from nftables:include/datatype.h, TYPE_BITS */
1108 #define CONCAT_TYPE_BITS	6
1109 
1110 /* from nftables:include/datatype.h, enum datatypes */
1111 #define NFT_DATATYPE_IPADDR	7
1112 #define NFT_DATATYPE_ETHERADDR	9
1113 
__add_nft_among(struct nft_handle * h,const char * table,struct nftnl_rule * r,struct nft_among_pair * pairs,int cnt,bool dst,bool inv,bool ip)1114 static int __add_nft_among(struct nft_handle *h, const char *table,
1115 			   struct nftnl_rule *r, struct nft_among_pair *pairs,
1116 			   int cnt, bool dst, bool inv, bool ip)
1117 {
1118 	uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN;
1119 	/* { !dst, dst } */
1120 	static const int eth_addr_off[] = {
1121 		offsetof(struct ether_header, ether_shost),
1122 		offsetof(struct ether_header, ether_dhost)
1123 	};
1124 	static const int ip_addr_off[] = {
1125 		offsetof(struct iphdr, saddr),
1126 		offsetof(struct iphdr, daddr)
1127 	};
1128 	struct nftnl_expr *e;
1129 	struct nftnl_set *s;
1130 	uint32_t flags = 0;
1131 	int idx = 0;
1132 
1133 	if (ip) {
1134 		type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
1135 		len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
1136 		len &= ~(NETLINK_ALIGN - 1);
1137 		flags = NFT_SET_INTERVAL;
1138 	}
1139 
1140 	s = add_anon_set(h, table, flags, type, len, cnt);
1141 	if (!s)
1142 		return -ENOMEM;
1143 	set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
1144 
1145 	if (ip) {
1146 		uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) };
1147 
1148 		nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT,
1149 				   field_len, sizeof(field_len));
1150 	}
1151 
1152 	for (idx = 0; idx < cnt; idx++) {
1153 		struct nftnl_set_elem *elem = nftnl_set_elem_alloc();
1154 
1155 		if (!elem)
1156 			return -ENOMEM;
1157 		nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY,
1158 				   &pairs[idx], len);
1159 		if (ip) {
1160 			struct in_addr tmp = pairs[idx].in;
1161 
1162 			if (tmp.s_addr == INADDR_ANY)
1163 				pairs[idx].in.s_addr = INADDR_BROADCAST;
1164 			nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END,
1165 					   &pairs[idx], len);
1166 			pairs[idx].in = tmp;
1167 		}
1168 		nftnl_set_elem_add(s, elem);
1169 	}
1170 
1171 	e = gen_payload(NFT_PAYLOAD_LL_HEADER,
1172 			eth_addr_off[dst], ETH_ALEN, NFT_REG_1);
1173 	if (!e)
1174 		return -ENOMEM;
1175 	nftnl_rule_add_expr(r, e);
1176 
1177 	if (ip) {
1178 		e = gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
1179 				sizeof(struct in_addr), NFT_REG32_02);
1180 		if (!e)
1181 			return -ENOMEM;
1182 		nftnl_rule_add_expr(r, e);
1183 	}
1184 
1185 	e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv);
1186 	if (!e)
1187 		return -ENOMEM;
1188 	nftnl_rule_add_expr(r, e);
1189 
1190 	return 0;
1191 }
1192 
add_nft_among(struct nft_handle * h,struct nftnl_rule * r,struct xt_entry_match * m)1193 static int add_nft_among(struct nft_handle *h,
1194 			 struct nftnl_rule *r, struct xt_entry_match *m)
1195 {
1196 	struct nft_among_data *data = (struct nft_among_data *)m->data;
1197 	const char *table = nftnl_rule_get(r, NFTNL_RULE_TABLE);
1198 
1199 	if ((data->src.cnt && data->src.ip) ||
1200 	    (data->dst.cnt && data->dst.ip)) {
1201 		uint16_t eth_p_ip = htons(ETH_P_IP);
1202 
1203 		add_meta(r, NFT_META_PROTOCOL);
1204 		add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2);
1205 	}
1206 
1207 	if (data->src.cnt)
1208 		__add_nft_among(h, table, r, data->pairs, data->src.cnt,
1209 				false, data->src.inv, data->src.ip);
1210 	if (data->dst.cnt)
1211 		__add_nft_among(h, table, r, data->pairs + data->src.cnt,
1212 				data->dst.cnt, true, data->dst.inv,
1213 				data->dst.ip);
1214 	return 0;
1215 }
1216 
add_match(struct nft_handle * h,struct nftnl_rule * r,struct xt_entry_match * m)1217 int add_match(struct nft_handle *h,
1218 	      struct nftnl_rule *r, struct xt_entry_match *m)
1219 {
1220 	struct nftnl_expr *expr;
1221 	int ret;
1222 
1223 	if (!strcmp(m->u.user.name, "limit"))
1224 		return add_nft_limit(r, m);
1225 	else if (!strcmp(m->u.user.name, "among"))
1226 		return add_nft_among(h, r, m);
1227 
1228 	expr = nftnl_expr_alloc("match");
1229 	if (expr == NULL)
1230 		return -ENOMEM;
1231 
1232 	ret = __add_match(expr, m);
1233 	nftnl_rule_add_expr(r, expr);
1234 
1235 	return ret;
1236 }
1237 
__add_target(struct nftnl_expr * e,struct xt_entry_target * t)1238 static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
1239 {
1240 	void *info;
1241 
1242 	nftnl_expr_set(e, NFTNL_EXPR_TG_NAME, t->u.user.name,
1243 			  strlen(t->u.user.name));
1244 	nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
1245 
1246 	info = calloc(1, t->u.target_size);
1247 	if (info == NULL)
1248 		return -ENOMEM;
1249 
1250 	memcpy(info, t->data, t->u.target_size - sizeof(*t));
1251 	nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
1252 
1253 	return 0;
1254 }
1255 
add_meta_nftrace(struct nftnl_rule * r)1256 static int add_meta_nftrace(struct nftnl_rule *r)
1257 {
1258 	struct nftnl_expr *expr;
1259 
1260 	expr = nftnl_expr_alloc("immediate");
1261 	if (expr == NULL)
1262 		return -ENOMEM;
1263 
1264 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
1265 	nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
1266 	nftnl_rule_add_expr(r, expr);
1267 
1268 	expr = nftnl_expr_alloc("meta");
1269 	if (expr == NULL)
1270 		return -ENOMEM;
1271 	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_NFTRACE);
1272 	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
1273 
1274 	nftnl_rule_add_expr(r, expr);
1275 	return 0;
1276 }
1277 
add_target(struct nftnl_rule * r,struct xt_entry_target * t)1278 int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
1279 {
1280 	struct nftnl_expr *expr;
1281 	int ret;
1282 
1283 	if (strcmp(t->u.user.name, "TRACE") == 0)
1284 		return add_meta_nftrace(r);
1285 
1286 	expr = nftnl_expr_alloc("target");
1287 	if (expr == NULL)
1288 		return -ENOMEM;
1289 
1290 	ret = __add_target(expr, t);
1291 	nftnl_rule_add_expr(r, expr);
1292 
1293 	return ret;
1294 }
1295 
add_jumpto(struct nftnl_rule * r,const char * name,int verdict)1296 int add_jumpto(struct nftnl_rule *r, const char *name, int verdict)
1297 {
1298 	struct nftnl_expr *expr;
1299 
1300 	expr = nftnl_expr_alloc("immediate");
1301 	if (expr == NULL)
1302 		return -ENOMEM;
1303 
1304 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
1305 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
1306 	nftnl_expr_set_str(expr, NFTNL_EXPR_IMM_CHAIN, (char *)name);
1307 	nftnl_rule_add_expr(r, expr);
1308 
1309 	return 0;
1310 }
1311 
add_verdict(struct nftnl_rule * r,int verdict)1312 int add_verdict(struct nftnl_rule *r, int verdict)
1313 {
1314 	struct nftnl_expr *expr;
1315 
1316 	expr = nftnl_expr_alloc("immediate");
1317 	if (expr == NULL)
1318 		return -ENOMEM;
1319 
1320 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
1321 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
1322 	nftnl_rule_add_expr(r, expr);
1323 
1324 	return 0;
1325 }
1326 
add_action(struct nftnl_rule * r,struct iptables_command_state * cs,bool goto_set)1327 int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
1328 	       bool goto_set)
1329 {
1330        int ret = 0;
1331 
1332        /* If no target at all, add nothing (default to continue) */
1333        if (cs->target != NULL) {
1334 	       /* Standard target? */
1335 	       if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
1336 		       ret = add_verdict(r, NF_ACCEPT);
1337 	       else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
1338 		       ret = add_verdict(r, NF_DROP);
1339 	       else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
1340 		       ret = add_verdict(r, NFT_RETURN);
1341 	       else
1342 		       ret = add_target(r, cs->target->t);
1343        } else if (strlen(cs->jumpto) > 0) {
1344 	       /* Not standard, then it's a go / jump to chain */
1345 	       if (goto_set)
1346 		       ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
1347 	       else
1348 		       ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
1349        }
1350        return ret;
1351 }
1352 
nft_rule_print_debug(struct nftnl_rule * r,struct nlmsghdr * nlh)1353 static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
1354 {
1355 #ifdef NLDEBUG
1356 	char tmp[1024];
1357 
1358 	nftnl_rule_snprintf(tmp, sizeof(tmp), r, 0, 0);
1359 	printf("DEBUG: rule: %s\n", tmp);
1360 	mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
1361 #endif
1362 }
1363 
add_counters(struct nftnl_rule * r,uint64_t packets,uint64_t bytes)1364 int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
1365 {
1366 	struct nftnl_expr *expr;
1367 
1368 	expr = nftnl_expr_alloc("counter");
1369 	if (expr == NULL)
1370 		return -ENOMEM;
1371 
1372 	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_PACKETS, packets);
1373 	nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_BYTES, bytes);
1374 
1375 	nftnl_rule_add_expr(r, expr);
1376 
1377 	return 0;
1378 }
1379 
1380 enum udata_type {
1381 	UDATA_TYPE_COMMENT,
1382 	UDATA_TYPE_EBTABLES_POLICY,
1383 	__UDATA_TYPE_MAX,
1384 };
1385 #define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
1386 
parse_udata_cb(const struct nftnl_udata * attr,void * data)1387 static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
1388 {
1389 	unsigned char *value = nftnl_udata_get(attr);
1390 	uint8_t type = nftnl_udata_type(attr);
1391 	uint8_t len = nftnl_udata_len(attr);
1392 	const struct nftnl_udata **tb = data;
1393 
1394 	switch (type) {
1395 	case UDATA_TYPE_COMMENT:
1396 		if (value[len - 1] != '\0')
1397 			return -1;
1398 		break;
1399 	case UDATA_TYPE_EBTABLES_POLICY:
1400 		break;
1401 	default:
1402 		return 0;
1403 	}
1404 	tb[type] = attr;
1405 	return 0;
1406 }
1407 
get_comment(const void * data,uint32_t data_len)1408 char *get_comment(const void *data, uint32_t data_len)
1409 {
1410 	const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
1411 
1412 	if (nftnl_udata_parse(data, data_len, parse_udata_cb, tb) < 0)
1413 		return NULL;
1414 
1415 	if (!tb[UDATA_TYPE_COMMENT])
1416 		return NULL;
1417 
1418 	return nftnl_udata_get(tb[UDATA_TYPE_COMMENT]);
1419 }
1420 
add_compat(struct nftnl_rule * r,uint32_t proto,bool inv)1421 void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
1422 {
1423 	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, proto);
1424 	nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS,
1425 			      inv ? NFT_RULE_COMPAT_F_INV : 0);
1426 }
1427 
1428 struct nftnl_rule *
nft_rule_new(struct nft_handle * h,const char * chain,const char * table,void * data)1429 nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
1430 	     void *data)
1431 {
1432 	struct nftnl_rule *r;
1433 
1434 	r = nftnl_rule_alloc();
1435 	if (r == NULL)
1436 		return NULL;
1437 
1438 	nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
1439 	nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
1440 	nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
1441 
1442 	if (h->ops->add(h, r, data) < 0)
1443 		goto err;
1444 
1445 	return r;
1446 err:
1447 	nftnl_rule_free(r);
1448 	return NULL;
1449 }
1450 
1451 int
nft_rule_append(struct nft_handle * h,const char * chain,const char * table,struct nftnl_rule * r,struct nftnl_rule * ref,bool verbose)1452 nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
1453 		struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
1454 {
1455 	struct nft_chain *c;
1456 	int type;
1457 
1458 	nft_xt_builtin_init(h, table, chain);
1459 
1460 	nft_fn = nft_rule_append;
1461 
1462 	if (ref) {
1463 		nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
1464 				   nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
1465 		type = NFT_COMPAT_RULE_REPLACE;
1466 	} else
1467 		type = NFT_COMPAT_RULE_APPEND;
1468 
1469 	if (batch_rule_add(h, type, r) == NULL)
1470 		return 0;
1471 
1472 	if (verbose)
1473 		h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
1474 
1475 	if (ref) {
1476 		nftnl_chain_rule_insert_at(r, ref);
1477 		nftnl_chain_rule_del(ref);
1478 		nftnl_rule_free(ref);
1479 	} else {
1480 		c = nft_chain_find(h, table, chain);
1481 		if (!c) {
1482 			errno = ENOENT;
1483 			return 0;
1484 		}
1485 		nftnl_chain_rule_add_tail(r, c->nftnl);
1486 	}
1487 
1488 	return 1;
1489 }
1490 
1491 void
nft_rule_print_save(struct nft_handle * h,const struct nftnl_rule * r,enum nft_rule_print type,unsigned int format)1492 nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
1493 		    enum nft_rule_print type, unsigned int format)
1494 {
1495 	const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
1496 	struct iptables_command_state cs = {};
1497 	struct nft_family_ops *ops = h->ops;
1498 
1499 	ops->rule_to_cs(h, r, &cs);
1500 
1501 	if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
1502 		printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
1503 				       (unsigned long long)cs.counters.bcnt);
1504 
1505 	/* print chain name */
1506 	switch(type) {
1507 	case NFT_RULE_APPEND:
1508 		printf("-A %s ", chain);
1509 		break;
1510 	case NFT_RULE_DEL:
1511 		printf("-D %s ", chain);
1512 		break;
1513 	}
1514 
1515 	if (ops->save_rule)
1516 		ops->save_rule(&cs, format);
1517 
1518 	if (ops->clear_cs)
1519 		ops->clear_cs(&cs);
1520 }
1521 
nft_rule_is_policy_rule(struct nftnl_rule * r)1522 static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
1523 {
1524 	const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
1525 	const void *data;
1526 	uint32_t len;
1527 
1528 	if (!nftnl_rule_is_set(r, NFTNL_RULE_USERDATA))
1529 		return false;
1530 
1531 	data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
1532 	if (nftnl_udata_parse(data, len, parse_udata_cb, tb) < 0)
1533 		return NULL;
1534 
1535 	if (!tb[UDATA_TYPE_EBTABLES_POLICY] ||
1536 	    nftnl_udata_get_u32(tb[UDATA_TYPE_EBTABLES_POLICY]) != 1)
1537 		return false;
1538 
1539 	return true;
1540 }
1541 
nft_chain_last_rule(struct nftnl_chain * c)1542 static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
1543 {
1544 	struct nftnl_rule *r = NULL, *last;
1545 	struct nftnl_rule_iter *iter;
1546 
1547 	iter = nftnl_rule_iter_create(c);
1548 	if (!iter)
1549 		return NULL;
1550 
1551 	do {
1552 		last = r;
1553 		r = nftnl_rule_iter_next(iter);
1554 	} while (r);
1555 	nftnl_rule_iter_destroy(iter);
1556 
1557 	return last;
1558 }
1559 
nft_bridge_chain_postprocess(struct nft_handle * h,struct nftnl_chain * c)1560 void nft_bridge_chain_postprocess(struct nft_handle *h,
1561 				  struct nftnl_chain *c)
1562 {
1563 	struct nftnl_rule *last = nft_chain_last_rule(c);
1564 	struct nftnl_expr_iter *iter;
1565 	struct nftnl_expr *expr;
1566 	int verdict;
1567 
1568 	if (!last || !nft_rule_is_policy_rule(last))
1569 		return;
1570 
1571 	iter = nftnl_expr_iter_create(last);
1572 	if (!iter)
1573 		return;
1574 
1575 	expr = nftnl_expr_iter_next(iter);
1576 	if (!expr ||
1577 	    strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)))
1578 		goto out_iter;
1579 
1580 	expr = nftnl_expr_iter_next(iter);
1581 	if (!expr ||
1582 	    strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) ||
1583 	    !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT))
1584 		goto out_iter;
1585 
1586 	verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
1587 	switch (verdict) {
1588 	case NF_ACCEPT:
1589 	case NF_DROP:
1590 		break;
1591 	default:
1592 		goto out_iter;
1593 	}
1594 
1595 	nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
1596 	if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL)
1597 		fprintf(stderr, "Failed to delete old policy rule\n");
1598 	nftnl_chain_rule_del(last);
1599 out_iter:
1600 	nftnl_expr_iter_destroy(iter);
1601 }
1602 static const char *policy_name[NF_ACCEPT+1] = {
1603 	[NF_DROP] = "DROP",
1604 	[NF_ACCEPT] = "ACCEPT",
1605 };
1606 
nft_chain_save(struct nft_chain * nc,void * data)1607 int nft_chain_save(struct nft_chain *nc, void *data)
1608 {
1609 	struct nftnl_chain *c = nc->nftnl;
1610 	struct nft_handle *h = data;
1611 	const char *policy = NULL;
1612 
1613 	if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) {
1614 		policy = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
1615 	} else if (nft_chain_builtin(c)) {
1616 		policy = "ACCEPT";
1617 	} else if (h->family == NFPROTO_BRIDGE) {
1618 		policy = "RETURN";
1619 	}
1620 
1621 	if (h->ops->save_chain)
1622 		h->ops->save_chain(c, policy);
1623 
1624 	return 0;
1625 }
1626 
1627 struct nft_rule_save_data {
1628 	struct nft_handle *h;
1629 	unsigned int format;
1630 };
1631 
nft_rule_save_cb(struct nft_chain * c,void * data)1632 static int nft_rule_save_cb(struct nft_chain *c, void *data)
1633 {
1634 	struct nft_rule_save_data *d = data;
1635 	struct nftnl_rule_iter *iter;
1636 	struct nftnl_rule *r;
1637 
1638 	iter = nftnl_rule_iter_create(c->nftnl);
1639 	if (iter == NULL)
1640 		return 1;
1641 
1642 	r = nftnl_rule_iter_next(iter);
1643 	while (r != NULL) {
1644 		nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format);
1645 		r = nftnl_rule_iter_next(iter);
1646 	}
1647 
1648 	nftnl_rule_iter_destroy(iter);
1649 	return 0;
1650 }
1651 
nft_rule_save(struct nft_handle * h,const char * table,unsigned int format)1652 int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
1653 {
1654 	struct nft_rule_save_data d = {
1655 		.h = h,
1656 		.format = format,
1657 	};
1658 	int ret;
1659 
1660 	ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d);
1661 
1662 	/* the core expects 1 for success and 0 for error */
1663 	return ret == 0 ? 1 : 0;
1664 }
1665 
nft_set_batch_lookup_byid(struct nft_handle * h,uint32_t set_id)1666 struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
1667 					    uint32_t set_id)
1668 {
1669 	struct obj_update *n;
1670 
1671 	list_for_each_entry(n, &h->obj_list, head) {
1672 		if (n->type == NFT_COMPAT_SET_ADD &&
1673 		    nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id)
1674 			return n->set;
1675 	}
1676 
1677 	return NULL;
1678 }
1679 
1680 static void
__nft_rule_flush(struct nft_handle * h,const char * table,const char * chain,bool verbose,bool skip)1681 __nft_rule_flush(struct nft_handle *h, const char *table,
1682 		 const char *chain, bool verbose, bool skip)
1683 {
1684 	struct obj_update *obj;
1685 	struct nftnl_rule *r;
1686 
1687 	if (verbose && chain)
1688 		fprintf(stdout, "Flushing chain `%s'\n", chain);
1689 
1690 	r = nftnl_rule_alloc();
1691 	if (r == NULL)
1692 		return;
1693 
1694 	nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
1695 	if (chain)
1696 		nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
1697 
1698 	obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
1699 	if (!obj) {
1700 		nftnl_rule_free(r);
1701 		return;
1702 	}
1703 
1704 	obj->skip = skip;
1705 }
1706 
1707 struct nft_rule_flush_data {
1708 	struct nft_handle *h;
1709 	const char *table;
1710 	bool verbose;
1711 };
1712 
nft_rule_flush_cb(struct nft_chain * c,void * data)1713 static int nft_rule_flush_cb(struct nft_chain *c, void *data)
1714 {
1715 	const char *chain = nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME);
1716 	struct nft_rule_flush_data *d = data;
1717 
1718 	batch_chain_flush(d->h, d->table, chain);
1719 	__nft_rule_flush(d->h, d->table, chain, d->verbose, false);
1720 	flush_rule_cache(d->h, d->table, c);
1721 	return 0;
1722 }
1723 
nft_rule_flush(struct nft_handle * h,const char * chain,const char * table,bool verbose)1724 int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
1725 		   bool verbose)
1726 {
1727 	struct nft_rule_flush_data d = {
1728 		.h = h,
1729 		.table = table,
1730 		.verbose = verbose,
1731 	};
1732 	struct nft_chain *c = NULL;
1733 	int ret = 0;
1734 
1735 	nft_fn = nft_rule_flush;
1736 
1737 	if (chain || verbose)
1738 		nft_xt_builtin_init(h, table, chain);
1739 	else if (!nft_table_find(h, table))
1740 		return 1;
1741 
1742 	if (chain) {
1743 		c = nft_chain_find(h, table, chain);
1744 		if (!c) {
1745 			errno = ENOENT;
1746 			return 0;
1747 		}
1748 	}
1749 
1750 	if (chain || !verbose) {
1751 		batch_chain_flush(h, table, chain);
1752 		__nft_rule_flush(h, table, chain, verbose, false);
1753 		flush_rule_cache(h, table, c);
1754 		return 1;
1755 	}
1756 
1757 	ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
1758 
1759 	/* the core expects 1 for success and 0 for error */
1760 	return ret == 0 ? 1 : 0;
1761 }
1762 
nft_chain_user_add(struct nft_handle * h,const char * chain,const char * table)1763 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
1764 {
1765 	const struct builtin_table *t;
1766 	struct nftnl_chain *c;
1767 
1768 	nft_fn = nft_chain_user_add;
1769 
1770 	t = nft_xt_builtin_table_init(h, table);
1771 
1772 	if (nft_chain_exists(h, table, chain)) {
1773 		errno = EEXIST;
1774 		return 0;
1775 	}
1776 
1777 	c = nftnl_chain_alloc();
1778 	if (c == NULL)
1779 		return 0;
1780 
1781 	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
1782 	nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
1783 	if (h->family == NFPROTO_BRIDGE)
1784 		nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
1785 
1786 	if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
1787 		return 0;
1788 
1789 	nft_cache_add_chain(h, t, c);
1790 
1791 	/* the core expects 1 for success and 0 for error */
1792 	return 1;
1793 }
1794 
nft_chain_restore(struct nft_handle * h,const char * chain,const char * table)1795 int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
1796 {
1797 	const struct builtin_table *t;
1798 	struct obj_update *obj;
1799 	struct nftnl_chain *c;
1800 	struct nft_chain *nc;
1801 	bool created = false;
1802 
1803 	t = nft_xt_builtin_table_init(h, table);
1804 
1805 	nc = nft_chain_find(h, table, chain);
1806 	if (!nc) {
1807 		c = nftnl_chain_alloc();
1808 		if (!c)
1809 			return 0;
1810 
1811 		nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
1812 		nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
1813 		created = true;
1814 
1815 		nft_cache_add_chain(h, t, c);
1816 	} else {
1817 		c = nc->nftnl;
1818 
1819 		/* If the chain should vanish meanwhile, kernel genid changes
1820 		 * and the transaction is refreshed enabling the chain add
1821 		 * object. With the handle still set, kernel interprets it as a
1822 		 * chain replace job and errors since it is not found anymore.
1823 		 */
1824 		nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
1825 	}
1826 
1827 	__nft_rule_flush(h, table, chain, false, created);
1828 
1829 	obj = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
1830 	if (!obj)
1831 		return 0;
1832 
1833 	obj->skip = !created;
1834 
1835 	/* the core expects 1 for success and 0 for error */
1836 	return 1;
1837 }
1838 
1839 /* From linux/netlink.h */
1840 #ifndef NLM_F_NONREC
1841 #define NLM_F_NONREC	0x100	/* Do not delete recursively    */
1842 #endif
1843 
1844 struct chain_user_del_data {
1845 	struct nft_handle	*handle;
1846 	bool			verbose;
1847 	int			builtin_err;
1848 };
1849 
__nft_chain_user_del(struct nft_chain * nc,void * data)1850 static int __nft_chain_user_del(struct nft_chain *nc, void *data)
1851 {
1852 	struct chain_user_del_data *d = data;
1853 	struct nftnl_chain *c = nc->nftnl;
1854 	struct nft_handle *h = d->handle;
1855 
1856 	/* don't delete built-in chain */
1857 	if (nft_chain_builtin(c))
1858 		return d->builtin_err;
1859 
1860 	if (d->verbose)
1861 		fprintf(stdout, "Deleting chain `%s'\n",
1862 			nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
1863 
1864 
1865 	/* XXX This triggers a fast lookup from the kernel. */
1866 	nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
1867 	if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
1868 		return -1;
1869 
1870 	/* nftnl_chain is freed when deleting the batch object */
1871 	nc->nftnl = NULL;
1872 
1873 	nft_chain_list_del(nc);
1874 	nft_chain_free(nc);
1875 	return 0;
1876 }
1877 
nft_chain_user_del(struct nft_handle * h,const char * chain,const char * table,bool verbose)1878 int nft_chain_user_del(struct nft_handle *h, const char *chain,
1879 		       const char *table, bool verbose)
1880 {
1881 	struct chain_user_del_data d = {
1882 		.handle = h,
1883 		.verbose = verbose,
1884 	};
1885 	struct nft_chain *c;
1886 	int ret = 0;
1887 
1888 	nft_fn = nft_chain_user_del;
1889 
1890 	if (chain) {
1891 		c = nft_chain_find(h, table, chain);
1892 		if (!c) {
1893 			errno = ENOENT;
1894 			return 0;
1895 		}
1896 		d.builtin_err = -2;
1897 		ret = __nft_chain_user_del(c, &d);
1898 		if (ret == -2)
1899 			errno = EINVAL;
1900 		goto out;
1901 	}
1902 
1903 	ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d);
1904 out:
1905 	/* the core expects 1 for success and 0 for error */
1906 	return ret == 0 ? 1 : 0;
1907 }
1908 
nft_chain_exists(struct nft_handle * h,const char * table,const char * chain)1909 bool nft_chain_exists(struct nft_handle *h,
1910 		      const char *table, const char *chain)
1911 {
1912 	const struct builtin_table *t = nft_table_builtin_find(h, table);
1913 
1914 	/* xtables does not support custom tables */
1915 	if (!t)
1916 		return false;
1917 
1918 	if (nft_chain_builtin_find(t, chain))
1919 		return true;
1920 
1921 	return !!nft_chain_find(h, table, chain);
1922 }
1923 
nft_chain_user_rename(struct nft_handle * h,const char * chain,const char * table,const char * newname)1924 int nft_chain_user_rename(struct nft_handle *h,const char *chain,
1925 			  const char *table, const char *newname)
1926 {
1927 	struct nftnl_chain *c;
1928 	struct nft_chain *nc;
1929 	uint64_t handle;
1930 
1931 	nft_fn = nft_chain_user_rename;
1932 
1933 	if (nft_chain_exists(h, table, newname)) {
1934 		errno = EEXIST;
1935 		return 0;
1936 	}
1937 
1938 	/* Find the old chain to be renamed */
1939 	nc = nft_chain_find(h, table, chain);
1940 	if (nc == NULL) {
1941 		errno = ENOENT;
1942 		return 0;
1943 	}
1944 	handle = nftnl_chain_get_u64(nc->nftnl, NFTNL_CHAIN_HANDLE);
1945 
1946 	/* Now prepare the new name for the chain */
1947 	c = nftnl_chain_alloc();
1948 	if (c == NULL)
1949 		return 0;
1950 
1951 	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
1952 	nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
1953 	nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
1954 
1955 	if (!batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c))
1956 		return 0;
1957 
1958 	/* the core expects 1 for success and 0 for error */
1959 	return 1;
1960 }
1961 
nft_table_find(struct nft_handle * h,const char * tablename)1962 bool nft_table_find(struct nft_handle *h, const char *tablename)
1963 {
1964 	const struct builtin_table *t;
1965 
1966 	t = nft_table_builtin_find(h, tablename);
1967 	return t ? h->cache->table[t->type].exists : false;
1968 }
1969 
nft_for_each_table(struct nft_handle * h,int (* func)(struct nft_handle * h,const char * tablename,void * data),void * data)1970 int nft_for_each_table(struct nft_handle *h,
1971 		       int (*func)(struct nft_handle *h, const char *tablename, void *data),
1972 		       void *data)
1973 {
1974 	int i;
1975 
1976 	for (i = 0; i < NFT_TABLE_MAX; i++) {
1977 		if (h->tables[i].name == NULL)
1978 			continue;
1979 
1980 		if (!h->cache->table[h->tables[i].type].exists)
1981 			continue;
1982 
1983 		func(h, h->tables[i].name, data);
1984 	}
1985 
1986 	return 0;
1987 }
1988 
__nft_table_flush(struct nft_handle * h,const char * table,bool exists)1989 static int __nft_table_flush(struct nft_handle *h, const char *table, bool exists)
1990 {
1991 	const struct builtin_table *_t;
1992 	struct obj_update *obj;
1993 	struct nftnl_table *t;
1994 
1995 	t = nftnl_table_alloc();
1996 	if (t == NULL)
1997 		return -1;
1998 
1999 	nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
2000 
2001 	obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
2002 	if (!obj) {
2003 		nftnl_table_free(t);
2004 		return -1;
2005 	}
2006 
2007 	if (!exists)
2008 		obj->skip = 1;
2009 
2010 	_t = nft_table_builtin_find(h, table);
2011 	assert(_t);
2012 	h->cache->table[_t->type].exists = false;
2013 
2014 	flush_chain_cache(h, table);
2015 
2016 	return 0;
2017 }
2018 
nft_table_flush(struct nft_handle * h,const char * table)2019 int nft_table_flush(struct nft_handle *h, const char *table)
2020 {
2021 	const struct builtin_table *t;
2022 	int ret = 0;
2023 
2024 	nft_fn = nft_table_flush;
2025 
2026 	t = nft_table_builtin_find(h, table);
2027 	if (!t)
2028 		return 0;
2029 
2030 	ret = __nft_table_flush(h, table, h->cache->table[t->type].exists);
2031 
2032 	/* the core expects 1 for success and 0 for error */
2033 	return ret == 0 ? 1 : 0;
2034 }
2035 
__nft_rule_del(struct nft_handle * h,struct nftnl_rule * r)2036 static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
2037 {
2038 	struct obj_update *obj;
2039 
2040 	nftnl_rule_list_del(r);
2041 
2042 	if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE))
2043 		nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id);
2044 
2045 	obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
2046 	if (!obj) {
2047 		nftnl_rule_free(r);
2048 		return -1;
2049 	}
2050 	return 1;
2051 }
2052 
nft_rule_cmp(struct nft_handle * h,struct nftnl_rule * r,struct nftnl_rule * rule)2053 static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
2054 			 struct nftnl_rule *rule)
2055 {
2056 	struct iptables_command_state _cs = {}, this = {}, *cs = &_cs;
2057 	bool ret = false;
2058 
2059 	h->ops->rule_to_cs(h, r, &this);
2060 	h->ops->rule_to_cs(h, rule, cs);
2061 
2062 	DEBUGP("comparing with... ");
2063 #ifdef DEBUG_DEL
2064 	nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
2065 #endif
2066 	if (!h->ops->is_same(cs, &this))
2067 		goto out;
2068 
2069 	if (!compare_matches(cs->matches, this.matches)) {
2070 		DEBUGP("Different matches\n");
2071 		goto out;
2072 	}
2073 
2074 	if (!compare_targets(cs->target, this.target)) {
2075 		DEBUGP("Different target\n");
2076 		goto out;
2077 	}
2078 
2079 	if ((!cs->target || !this.target) &&
2080 	    strcmp(cs->jumpto, this.jumpto) != 0) {
2081 		DEBUGP("Different verdict\n");
2082 		goto out;
2083 	}
2084 
2085 	ret = true;
2086 out:
2087 	h->ops->clear_cs(&this);
2088 	h->ops->clear_cs(cs);
2089 	return ret;
2090 }
2091 
2092 static struct nftnl_rule *
nft_rule_find(struct nft_handle * h,struct nft_chain * nc,struct nftnl_rule * rule,int rulenum)2093 nft_rule_find(struct nft_handle *h, struct nft_chain *nc,
2094 	      struct nftnl_rule *rule, int rulenum)
2095 {
2096 	struct nftnl_chain *c = nc->nftnl;
2097 	struct nftnl_rule *r;
2098 	struct nftnl_rule_iter *iter;
2099 	bool found = false;
2100 
2101 	if (rulenum >= 0)
2102 		/* Delete by rule number case */
2103 		return nftnl_rule_lookup_byindex(c, rulenum);
2104 
2105 	iter = nftnl_rule_iter_create(c);
2106 	if (iter == NULL)
2107 		return 0;
2108 
2109 	r = nftnl_rule_iter_next(iter);
2110 	while (r != NULL) {
2111 		found = nft_rule_cmp(h, r, rule);
2112 		if (found)
2113 			break;
2114 		r = nftnl_rule_iter_next(iter);
2115 	}
2116 
2117 	nftnl_rule_iter_destroy(iter);
2118 
2119 	return found ? r : NULL;
2120 }
2121 
nft_rule_check(struct nft_handle * h,const char * chain,const char * table,struct nftnl_rule * rule,bool verbose)2122 int nft_rule_check(struct nft_handle *h, const char *chain,
2123 		   const char *table, struct nftnl_rule *rule, bool verbose)
2124 {
2125 	struct nftnl_rule *r;
2126 	struct nft_chain *c;
2127 
2128 	nft_fn = nft_rule_check;
2129 
2130 	c = nft_chain_find(h, table, chain);
2131 	if (!c)
2132 		goto fail_enoent;
2133 
2134 	r = nft_rule_find(h, c, rule, -1);
2135 	if (r == NULL)
2136 		goto fail_enoent;
2137 
2138 	if (verbose)
2139 		h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
2140 
2141 	return 1;
2142 fail_enoent:
2143 	errno = ENOENT;
2144 	return 0;
2145 }
2146 
nft_rule_delete(struct nft_handle * h,const char * chain,const char * table,struct nftnl_rule * rule,bool verbose)2147 int nft_rule_delete(struct nft_handle *h, const char *chain,
2148 		    const char *table, struct nftnl_rule *rule, bool verbose)
2149 {
2150 	int ret = 0;
2151 	struct nftnl_rule *r;
2152 	struct nft_chain *c;
2153 
2154 	nft_fn = nft_rule_delete;
2155 
2156 	c = nft_chain_find(h, table, chain);
2157 	if (!c) {
2158 		errno = ENOENT;
2159 		return 0;
2160 	}
2161 
2162 	r = nft_rule_find(h, c, rule, -1);
2163 	if (r != NULL) {
2164 		ret =__nft_rule_del(h, r);
2165 		if (ret < 0)
2166 			errno = ENOMEM;
2167 		if (verbose)
2168 			h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
2169 	} else
2170 		errno = ENOENT;
2171 
2172 	return ret;
2173 }
2174 
2175 static struct nftnl_rule *
nft_rule_add(struct nft_handle * h,const char * chain,const char * table,struct nftnl_rule * r,struct nftnl_rule * ref,bool verbose)2176 nft_rule_add(struct nft_handle *h, const char *chain,
2177 	     const char *table, struct nftnl_rule *r,
2178 	     struct nftnl_rule *ref, bool verbose)
2179 {
2180 	uint64_t ref_id;
2181 
2182 	if (ref) {
2183 		ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
2184 		if (ref_id > 0) {
2185 			nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, ref_id);
2186 			DEBUGP("adding after rule handle %"PRIu64"\n", ref_id);
2187 		} else {
2188 			ref_id = nftnl_rule_get_u32(ref, NFTNL_RULE_ID);
2189 			if (!ref_id) {
2190 				ref_id = ++h->rule_id;
2191 				nftnl_rule_set_u32(ref, NFTNL_RULE_ID, ref_id);
2192 			}
2193 			nftnl_rule_set_u32(r, NFTNL_RULE_POSITION_ID, ref_id);
2194 			DEBUGP("adding after rule ID %"PRIu64"\n", ref_id);
2195 		}
2196 	}
2197 
2198 	if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
2199 		return NULL;
2200 
2201 	if (verbose)
2202 		h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
2203 
2204 	return r;
2205 }
2206 
nft_rule_insert(struct nft_handle * h,const char * chain,const char * table,struct nftnl_rule * new_rule,int rulenum,bool verbose)2207 int nft_rule_insert(struct nft_handle *h, const char *chain,
2208 		    const char *table, struct nftnl_rule *new_rule, int rulenum,
2209 		    bool verbose)
2210 {
2211 	struct nftnl_rule *r = NULL;
2212 	struct nft_chain *c;
2213 
2214 	nft_xt_builtin_init(h, table, chain);
2215 
2216 	nft_fn = nft_rule_insert;
2217 
2218 	c = nft_chain_find(h, table, chain);
2219 	if (!c) {
2220 		errno = ENOENT;
2221 		goto err;
2222 	}
2223 
2224 	if (rulenum > 0) {
2225 		r = nft_rule_find(h, c, new_rule, rulenum);
2226 		if (r == NULL) {
2227 			/* special case: iptables allows to insert into
2228 			 * rule_count + 1 position.
2229 			 */
2230 			r = nft_rule_find(h, c, new_rule, rulenum - 1);
2231 			if (r != NULL)
2232 				return nft_rule_append(h, chain, table,
2233 						       new_rule, NULL, verbose);
2234 
2235 			errno = E2BIG;
2236 			goto err;
2237 		}
2238 	}
2239 
2240 	new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose);
2241 	if (!new_rule)
2242 		goto err;
2243 
2244 	if (r)
2245 		nftnl_chain_rule_insert_at(new_rule, r);
2246 	else
2247 		nftnl_chain_rule_add(new_rule, c->nftnl);
2248 
2249 	return 1;
2250 err:
2251 	return 0;
2252 }
2253 
nft_rule_delete_num(struct nft_handle * h,const char * chain,const char * table,int rulenum,bool verbose)2254 int nft_rule_delete_num(struct nft_handle *h, const char *chain,
2255 			const char *table, int rulenum, bool verbose)
2256 {
2257 	int ret = 0;
2258 	struct nftnl_rule *r;
2259 	struct nft_chain *c;
2260 
2261 	nft_fn = nft_rule_delete_num;
2262 
2263 	c = nft_chain_find(h, table, chain);
2264 	if (!c) {
2265 		errno = ENOENT;
2266 		return 0;
2267 	}
2268 
2269 	r = nft_rule_find(h, c, NULL, rulenum);
2270 	if (r != NULL) {
2271 		DEBUGP("deleting rule by number %d\n", rulenum);
2272 		ret = __nft_rule_del(h, r);
2273 		if (ret < 0)
2274 			errno = ENOMEM;
2275 	} else
2276 		errno = E2BIG;
2277 
2278 	return ret;
2279 }
2280 
nft_rule_replace(struct nft_handle * h,const char * chain,const char * table,struct nftnl_rule * rule,int rulenum,bool verbose)2281 int nft_rule_replace(struct nft_handle *h, const char *chain,
2282 		     const char *table, struct nftnl_rule *rule,
2283 		     int rulenum, bool verbose)
2284 {
2285 	int ret = 0;
2286 	struct nftnl_rule *r;
2287 	struct nft_chain *c;
2288 
2289 	nft_fn = nft_rule_replace;
2290 
2291 	c = nft_chain_find(h, table, chain);
2292 	if (!c) {
2293 		errno = ENOENT;
2294 		return 0;
2295 	}
2296 
2297 	r = nft_rule_find(h, c, rule, rulenum);
2298 	if (r != NULL) {
2299 		DEBUGP("replacing rule with handle=%llu\n",
2300 			(unsigned long long)
2301 			nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
2302 
2303 		ret = nft_rule_append(h, chain, table, rule, r, verbose);
2304 	} else
2305 		errno = E2BIG;
2306 
2307 	return ret;
2308 }
2309 
2310 static int
__nft_rule_list(struct nft_handle * h,struct nftnl_chain * c,int rulenum,unsigned int format,void (* cb)(struct nft_handle * h,struct nftnl_rule * r,unsigned int num,unsigned int format))2311 __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
2312 		int rulenum, unsigned int format,
2313 		void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
2314 			   unsigned int num, unsigned int format))
2315 {
2316 	struct nftnl_rule_iter *iter;
2317 	struct nftnl_rule *r;
2318 	int rule_ctr = 0;
2319 
2320 	if (rulenum > 0) {
2321 		r = nftnl_rule_lookup_byindex(c, rulenum - 1);
2322 		if (!r)
2323 			/* iptables-legacy returns 0 when listing for
2324 			 * valid chain but invalid rule number
2325 			 */
2326 			return 1;
2327 		cb(h, r, rulenum, format);
2328 		return 1;
2329 	}
2330 
2331 	iter = nftnl_rule_iter_create(c);
2332 	if (iter == NULL)
2333 		return 0;
2334 
2335 	r = nftnl_rule_iter_next(iter);
2336 	while (r != NULL) {
2337 		cb(h, r, ++rule_ctr, format);
2338 		r = nftnl_rule_iter_next(iter);
2339 	}
2340 
2341 	nftnl_rule_iter_destroy(iter);
2342 	return 1;
2343 }
2344 
nft_rule_count(struct nft_handle * h,struct nftnl_chain * c)2345 static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
2346 {
2347 	struct nftnl_rule_iter *iter;
2348 	struct nftnl_rule *r;
2349 	int rule_ctr = 0;
2350 
2351 	iter = nftnl_rule_iter_create(c);
2352 	if (iter == NULL)
2353 		return 0;
2354 
2355 	r = nftnl_rule_iter_next(iter);
2356 	while (r != NULL) {
2357 		rule_ctr++;
2358 		r = nftnl_rule_iter_next(iter);
2359 	}
2360 
2361 	nftnl_rule_iter_destroy(iter);
2362 	return rule_ctr;
2363 }
2364 
__nft_print_header(struct nft_handle * h,struct nft_chain * nc,unsigned int format)2365 static void __nft_print_header(struct nft_handle *h,
2366 			       struct nft_chain *nc, unsigned int format)
2367 {
2368 	struct nftnl_chain *c = nc->nftnl;
2369 	const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
2370 	bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
2371 	uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
2372 	uint32_t entries = nft_rule_count(h, c);
2373 	struct xt_counters ctrs = {
2374 		.pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
2375 		.bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
2376 	};
2377 	const char *pname = NULL;
2378 
2379 	if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
2380 		pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
2381 
2382 	h->ops->print_header(format, chain_name, pname,
2383 			&ctrs, basechain, refs - entries, entries);
2384 }
2385 
2386 struct nft_rule_list_cb_data {
2387 	struct nft_handle *h;
2388 	unsigned int format;
2389 	int rulenum;
2390 	bool found;
2391 	bool save_fmt;
2392 	void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
2393 		   unsigned int num, unsigned int format);
2394 };
2395 
nft_rule_list_cb(struct nft_chain * c,void * data)2396 static int nft_rule_list_cb(struct nft_chain *c, void *data)
2397 {
2398 	struct nft_rule_list_cb_data *d = data;
2399 
2400 	if (!d->save_fmt) {
2401 		if (d->found)
2402 			printf("\n");
2403 		d->found = true;
2404 
2405 		__nft_print_header(d->h, c, d->format);
2406 	}
2407 
2408 	return __nft_rule_list(d->h, c->nftnl, d->rulenum, d->format, d->cb);
2409 }
2410 
nft_rule_list(struct nft_handle * h,const char * chain,const char * table,int rulenum,unsigned int format)2411 int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
2412 		  int rulenum, unsigned int format)
2413 {
2414 	const struct nft_family_ops *ops = h->ops;
2415 	struct nft_rule_list_cb_data d = {
2416 		.h = h,
2417 		.format = format,
2418 		.rulenum = rulenum,
2419 		.cb = ops->print_rule,
2420 	};
2421 	struct nft_chain *c;
2422 
2423 	nft_xt_fake_builtin_chains(h, table, chain);
2424 	nft_assert_table_compatible(h, table, chain);
2425 
2426 	if (chain) {
2427 		c = nft_chain_find(h, table, chain);
2428 		if (!c)
2429 			return 0;
2430 
2431 		if (rulenum)
2432 			d.save_fmt = true;	/* skip header printing */
2433 		else if (ops->print_table_header)
2434 			ops->print_table_header(table);
2435 
2436 		nft_rule_list_cb(c, &d);
2437 		return 1;
2438 	}
2439 
2440 	if (ops->print_table_header)
2441 		ops->print_table_header(table);
2442 
2443 	nft_chain_foreach(h, table, nft_rule_list_cb, &d);
2444 	return 1;
2445 }
2446 
2447 static void
list_save(struct nft_handle * h,struct nftnl_rule * r,unsigned int num,unsigned int format)2448 list_save(struct nft_handle *h, struct nftnl_rule *r,
2449 	  unsigned int num, unsigned int format)
2450 {
2451 	nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
2452 }
2453 
nft_chain_foreach(struct nft_handle * h,const char * table,int (* cb)(struct nft_chain * c,void * data),void * data)2454 int nft_chain_foreach(struct nft_handle *h, const char *table,
2455 		      int (*cb)(struct nft_chain *c, void *data),
2456 		      void *data)
2457 {
2458 	const struct builtin_table *t;
2459 	struct nft_chain_list *list;
2460 	struct nft_chain *c, *c_bak;
2461 	int i, ret;
2462 
2463 	t = nft_table_builtin_find(h, table);
2464 	if (!t)
2465 		return -1;
2466 
2467 	for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2468 		c = h->cache->table[t->type].base_chains[i];
2469 		if (!c)
2470 			continue;
2471 
2472 		ret = cb(c, data);
2473 		if (ret < 0)
2474 			return ret;
2475 	}
2476 
2477 	list = h->cache->table[t->type].chains;
2478 	if (!list)
2479 		return -1;
2480 
2481 	list_for_each_entry_safe(c, c_bak, &list->list, head) {
2482 		ret = cb(c, data);
2483 		if (ret < 0)
2484 			return ret;
2485 	}
2486 	return 0;
2487 }
2488 
nft_rule_list_chain_save(struct nft_chain * nc,void * data)2489 static int nft_rule_list_chain_save(struct nft_chain *nc, void *data)
2490 {
2491 	struct nftnl_chain *c = nc->nftnl;
2492 	const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
2493 	uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
2494 	int *counters = data;
2495 
2496 	if (!nft_chain_builtin(c)) {
2497 		printf("-N %s\n", chain_name);
2498 		return 0;
2499 	}
2500 
2501 	/* this is a base chain */
2502 
2503 	printf("-P %s %s", chain_name, policy_name[policy]);
2504 	if (*counters)
2505 		printf(" -c %"PRIu64" %"PRIu64,
2506 		       nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
2507 		       nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
2508 	printf("\n");
2509 	return 0;
2510 }
2511 
nft_rule_list_save(struct nft_handle * h,const char * chain,const char * table,int rulenum,int counters)2512 int nft_rule_list_save(struct nft_handle *h, const char *chain,
2513 		       const char *table, int rulenum, int counters)
2514 {
2515 	struct nft_rule_list_cb_data d = {
2516 		.h = h,
2517 		.rulenum = rulenum,
2518 		.save_fmt = true,
2519 		.cb = list_save,
2520 	};
2521 	struct nft_chain *c;
2522 	int ret = 0;
2523 
2524 	nft_xt_fake_builtin_chains(h, table, chain);
2525 	nft_assert_table_compatible(h, table, chain);
2526 
2527 	if (counters < 0)
2528 		d.format = FMT_C_COUNTS;
2529 	else if (counters == 0)
2530 		d.format = FMT_NOCOUNTS;
2531 
2532 	if (chain) {
2533 		c = nft_chain_find(h, table, chain);
2534 		if (!c)
2535 			return 0;
2536 
2537 		if (!rulenum)
2538 			nft_rule_list_chain_save(c, &counters);
2539 
2540 		return nft_rule_list_cb(c, &d);
2541 	}
2542 
2543 	/* Dump policies and custom chains first */
2544 	nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
2545 
2546 	/* Now dump out rules in this table */
2547 	ret = nft_chain_foreach(h, table, nft_rule_list_cb, &d);
2548 	return ret == 0 ? 1 : 0;
2549 }
2550 
nft_rule_zero_counters(struct nft_handle * h,const char * chain,const char * table,int rulenum)2551 int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
2552 			   const char *table, int rulenum)
2553 {
2554 	struct iptables_command_state cs = {};
2555 	struct nftnl_rule *r, *new_rule;
2556 	struct nft_chain *c;
2557 	int ret = 0;
2558 
2559 	nft_fn = nft_rule_delete;
2560 
2561 	c = nft_chain_find(h, table, chain);
2562 	if (!c)
2563 		return 0;
2564 
2565 	r = nft_rule_find(h, c, NULL, rulenum);
2566 	if (r == NULL) {
2567 		errno = ENOENT;
2568 		ret = 1;
2569 		goto error;
2570 	}
2571 
2572 	nft_rule_to_iptables_command_state(h, r, &cs);
2573 
2574 	cs.counters.pcnt = cs.counters.bcnt = 0;
2575 	new_rule = nft_rule_new(h, chain, table, &cs);
2576 	if (!new_rule)
2577 		return 1;
2578 
2579 	ret = nft_rule_append(h, chain, table, new_rule, r, false);
2580 
2581 error:
2582 	return ret;
2583 }
2584 
nft_compat_table_batch_add(struct nft_handle * h,uint16_t type,uint16_t flags,uint32_t seq,struct nftnl_table * table)2585 static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
2586 				       uint16_t flags, uint32_t seq,
2587 				       struct nftnl_table *table)
2588 {
2589 	struct nlmsghdr *nlh;
2590 
2591 	nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
2592 					type, h->family, flags, seq);
2593 	nftnl_table_nlmsg_build_payload(nlh, table);
2594 }
2595 
nft_compat_set_batch_add(struct nft_handle * h,uint16_t type,uint16_t flags,uint32_t seq,struct nftnl_set * set)2596 static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
2597 				     uint16_t flags, uint32_t seq,
2598 				     struct nftnl_set *set)
2599 {
2600 	struct nlmsghdr *nlh;
2601 
2602 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
2603 					type, h->family, flags, seq);
2604 	nftnl_set_nlmsg_build_payload(nlh, set);
2605 }
2606 
nft_compat_setelem_batch_add(struct nft_handle * h,uint16_t type,uint16_t flags,uint32_t * seq,struct nftnl_set * set)2607 static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type,
2608 					 uint16_t flags, uint32_t *seq,
2609 					 struct nftnl_set *set)
2610 {
2611 	struct nftnl_set_elems_iter *iter;
2612 	struct nlmsghdr *nlh;
2613 
2614 	iter = nftnl_set_elems_iter_create(set);
2615 	if (!iter)
2616 		return;
2617 
2618 	while (nftnl_set_elems_iter_cur(iter)) {
2619 		(*seq)++;
2620 		mnl_nft_batch_continue(h->batch);
2621 		nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
2622 					    type, h->family, flags, *seq);
2623 		if (nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter) <= 0)
2624 			break;
2625 	}
2626 	nftnl_set_elems_iter_destroy(iter);
2627 }
2628 
nft_compat_chain_batch_add(struct nft_handle * h,uint16_t type,uint16_t flags,uint32_t seq,struct nftnl_chain * chain)2629 static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
2630 				       uint16_t flags, uint32_t seq,
2631 				       struct nftnl_chain *chain)
2632 {
2633 	struct nlmsghdr *nlh;
2634 
2635 	nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
2636 					type, h->family, flags, seq);
2637 	nftnl_chain_nlmsg_build_payload(nlh, chain);
2638 	nft_chain_print_debug(chain, nlh);
2639 }
2640 
nft_compat_rule_batch_add(struct nft_handle * h,uint16_t type,uint16_t flags,uint32_t seq,struct nftnl_rule * rule)2641 static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
2642 				      uint16_t flags, uint32_t seq,
2643 				      struct nftnl_rule *rule)
2644 {
2645 	struct nlmsghdr *nlh;
2646 
2647 	nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
2648 				       type, h->family, flags, seq);
2649 	nftnl_rule_nlmsg_build_payload(nlh, rule);
2650 	nft_rule_print_debug(rule, nlh);
2651 }
2652 
batch_obj_del(struct nft_handle * h,struct obj_update * o)2653 static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
2654 {
2655 	switch (o->type) {
2656 	case NFT_COMPAT_TABLE_ADD:
2657 	case NFT_COMPAT_TABLE_FLUSH:
2658 		nftnl_table_free(o->table);
2659 		break;
2660 	case NFT_COMPAT_CHAIN_ZERO:
2661 	case NFT_COMPAT_CHAIN_USER_ADD:
2662 	case NFT_COMPAT_CHAIN_ADD:
2663 		break;
2664 	case NFT_COMPAT_CHAIN_USER_DEL:
2665 	case NFT_COMPAT_CHAIN_USER_FLUSH:
2666 	case NFT_COMPAT_CHAIN_UPDATE:
2667 	case NFT_COMPAT_CHAIN_RENAME:
2668 		nftnl_chain_free(o->chain);
2669 		break;
2670 	case NFT_COMPAT_RULE_APPEND:
2671 	case NFT_COMPAT_RULE_INSERT:
2672 	case NFT_COMPAT_RULE_REPLACE:
2673 		break;
2674 	case NFT_COMPAT_RULE_DELETE:
2675 	case NFT_COMPAT_RULE_FLUSH:
2676 		nftnl_rule_free(o->rule);
2677 		break;
2678 	case NFT_COMPAT_SET_ADD:
2679 		nftnl_set_free(o->set);
2680 		break;
2681 	case NFT_COMPAT_RULE_LIST:
2682 	case NFT_COMPAT_RULE_CHECK:
2683 	case NFT_COMPAT_CHAIN_RESTORE:
2684 	case NFT_COMPAT_RULE_SAVE:
2685 	case NFT_COMPAT_RULE_ZERO:
2686 	case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
2687 		assert(0);
2688 		break;
2689 	}
2690 	h->obj_list_num--;
2691 	list_del(&o->head);
2692 	free(o);
2693 }
2694 
nft_refresh_transaction(struct nft_handle * h)2695 static void nft_refresh_transaction(struct nft_handle *h)
2696 {
2697 	const char *tablename, *chainname;
2698 	const struct nft_chain *c;
2699 	struct obj_update *n, *tmp;
2700 	bool exists;
2701 
2702 	h->error.lineno = 0;
2703 
2704 	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
2705 		switch (n->type) {
2706 		case NFT_COMPAT_TABLE_FLUSH:
2707 			tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME);
2708 			if (!tablename)
2709 				continue;
2710 			exists = nft_table_find(h, tablename);
2711 			if (exists)
2712 				n->skip = 0;
2713 			else
2714 				n->skip = 1;
2715 			break;
2716 		case NFT_COMPAT_CHAIN_USER_ADD:
2717 			tablename = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_TABLE);
2718 			if (!tablename)
2719 				continue;
2720 
2721 			chainname = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_NAME);
2722 			if (!chainname)
2723 				continue;
2724 
2725 			if (!h->noflush)
2726 				break;
2727 
2728 			c = nft_chain_find(h, tablename, chainname);
2729 			if (c) {
2730 				n->skip = 1;
2731 			} else if (!c) {
2732 				n->skip = 0;
2733 			}
2734 			break;
2735 		case NFT_COMPAT_RULE_FLUSH:
2736 			tablename = nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE);
2737 			if (!tablename)
2738 				continue;
2739 
2740 			chainname = nftnl_rule_get_str(n->rule, NFTNL_RULE_CHAIN);
2741 			if (!chainname)
2742 				continue;
2743 
2744 			n->skip = !nft_chain_find(h, tablename, chainname);
2745 			break;
2746 		case NFT_COMPAT_TABLE_ADD:
2747 		case NFT_COMPAT_CHAIN_ADD:
2748 		case NFT_COMPAT_CHAIN_ZERO:
2749 		case NFT_COMPAT_CHAIN_USER_DEL:
2750 		case NFT_COMPAT_CHAIN_USER_FLUSH:
2751 		case NFT_COMPAT_CHAIN_UPDATE:
2752 		case NFT_COMPAT_CHAIN_RENAME:
2753 		case NFT_COMPAT_RULE_APPEND:
2754 		case NFT_COMPAT_RULE_INSERT:
2755 		case NFT_COMPAT_RULE_REPLACE:
2756 		case NFT_COMPAT_RULE_DELETE:
2757 		case NFT_COMPAT_SET_ADD:
2758 		case NFT_COMPAT_RULE_LIST:
2759 		case NFT_COMPAT_RULE_CHECK:
2760 		case NFT_COMPAT_CHAIN_RESTORE:
2761 		case NFT_COMPAT_RULE_SAVE:
2762 		case NFT_COMPAT_RULE_ZERO:
2763 		case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
2764 			break;
2765 		}
2766 	}
2767 }
2768 
nft_action(struct nft_handle * h,int action)2769 static int nft_action(struct nft_handle *h, int action)
2770 {
2771 	struct obj_update *n, *tmp;
2772 	struct mnl_err *err, *ne;
2773 	unsigned int buflen, i, len;
2774 	bool show_errors = true;
2775 	char errmsg[1024];
2776 	uint32_t seq;
2777 	int ret = 0;
2778 
2779 retry:
2780 	seq = 1;
2781 	h->batch = mnl_batch_init();
2782 
2783 	mnl_batch_begin(h->batch, h->nft_genid, seq++);
2784 	h->nft_genid++;
2785 
2786 	list_for_each_entry(n, &h->obj_list, head) {
2787 		if (n->skip) {
2788 			n->seq = 0;
2789 			continue;
2790 		}
2791 
2792 		n->seq = seq++;
2793 		switch (n->type) {
2794 		case NFT_COMPAT_TABLE_ADD:
2795 			nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE,
2796 						   NLM_F_CREATE, n->seq,
2797 						   n->table);
2798 			break;
2799 		case NFT_COMPAT_TABLE_FLUSH:
2800 			nft_compat_table_batch_add(h, NFT_MSG_DELTABLE,
2801 						   0,
2802 						   n->seq, n->table);
2803 			break;
2804 		case NFT_COMPAT_CHAIN_ADD:
2805 		case NFT_COMPAT_CHAIN_ZERO:
2806 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
2807 						   NLM_F_CREATE, n->seq,
2808 						   n->chain);
2809 			break;
2810 		case NFT_COMPAT_CHAIN_USER_ADD:
2811 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
2812 						   NLM_F_EXCL, n->seq,
2813 						   n->chain);
2814 			break;
2815 		case NFT_COMPAT_CHAIN_USER_DEL:
2816 			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
2817 						   NLM_F_NONREC, n->seq,
2818 						   n->chain);
2819 			break;
2820 		case NFT_COMPAT_CHAIN_USER_FLUSH:
2821 			nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
2822 						   0, n->seq,
2823 						   n->chain);
2824 			break;
2825 		case NFT_COMPAT_CHAIN_UPDATE:
2826 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
2827 						   h->restore ?
2828 						     NLM_F_CREATE : 0,
2829 						   n->seq, n->chain);
2830 			break;
2831 		case NFT_COMPAT_CHAIN_RENAME:
2832 			nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0,
2833 						   n->seq, n->chain);
2834 			break;
2835 		case NFT_COMPAT_RULE_APPEND:
2836 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
2837 						  NLM_F_CREATE | NLM_F_APPEND,
2838 						  n->seq, n->rule);
2839 			break;
2840 		case NFT_COMPAT_RULE_INSERT:
2841 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
2842 						  NLM_F_CREATE, n->seq,
2843 						  n->rule);
2844 			break;
2845 		case NFT_COMPAT_RULE_REPLACE:
2846 			nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
2847 						  NLM_F_CREATE | NLM_F_REPLACE,
2848 						  n->seq, n->rule);
2849 			break;
2850 		case NFT_COMPAT_RULE_DELETE:
2851 		case NFT_COMPAT_RULE_FLUSH:
2852 			nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
2853 						  n->seq, n->rule);
2854 			break;
2855 		case NFT_COMPAT_SET_ADD:
2856 			nft_compat_set_batch_add(h, NFT_MSG_NEWSET,
2857 						 NLM_F_CREATE, n->seq, n->set);
2858 			nft_compat_setelem_batch_add(h, NFT_MSG_NEWSETELEM,
2859 						     NLM_F_CREATE, &n->seq, n->set);
2860 			seq = n->seq;
2861 			break;
2862 		case NFT_COMPAT_RULE_LIST:
2863 		case NFT_COMPAT_RULE_CHECK:
2864 		case NFT_COMPAT_CHAIN_RESTORE:
2865 		case NFT_COMPAT_RULE_SAVE:
2866 		case NFT_COMPAT_RULE_ZERO:
2867 		case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
2868 			assert(0);
2869 		}
2870 
2871 		mnl_nft_batch_continue(h->batch);
2872 	}
2873 
2874 	switch (action) {
2875 	case NFT_COMPAT_COMMIT:
2876 		mnl_batch_end(h->batch, seq++);
2877 		break;
2878 	case NFT_COMPAT_ABORT:
2879 		break;
2880 	}
2881 
2882 	errno = 0;
2883 	ret = mnl_batch_talk(h, seq);
2884 	if (ret && errno == ERESTART) {
2885 		nft_rebuild_cache(h);
2886 
2887 		nft_refresh_transaction(h);
2888 
2889 		list_for_each_entry_safe(err, ne, &h->err_list, head)
2890 			mnl_err_list_free(err);
2891 
2892 		mnl_batch_reset(h->batch);
2893 		goto retry;
2894 	}
2895 
2896 	i = 0;
2897 	buflen = sizeof(errmsg);
2898 
2899 	list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
2900 		list_for_each_entry_safe(err, ne, &h->err_list, head) {
2901 			if (err->seqnum > n->seq)
2902 				break;
2903 
2904 			if (err->seqnum == n->seq && show_errors) {
2905 				if (n->error.lineno == 0)
2906 					show_errors = false;
2907 				len = mnl_append_error(h, n, err, errmsg + i, buflen);
2908 				if (len > 0 && len <= buflen) {
2909 					buflen -= len;
2910 					i += len;
2911 				}
2912 			}
2913 			mnl_err_list_free(err);
2914 		}
2915 		batch_obj_del(h, n);
2916 	}
2917 
2918 	nft_release_cache(h);
2919 	mnl_batch_reset(h->batch);
2920 
2921 	if (i)
2922 		xtables_error(RESOURCE_PROBLEM, "%s", errmsg);
2923 
2924 	return ret == 0 ? 1 : 0;
2925 }
2926 
ebt_add_policy_rule(struct nftnl_chain * c,void * data)2927 static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
2928 {
2929 	uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
2930 	struct iptables_command_state cs = {
2931 		.eb.bitmask = EBT_NOPROTO,
2932 	};
2933 	struct nftnl_udata_buf *udata;
2934 	struct nft_handle *h = data;
2935 	struct nftnl_rule *r;
2936 	const char *pname;
2937 
2938 	if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
2939 		return 0; /* ignore base chains */
2940 
2941 	if (!nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
2942 		return 0;
2943 
2944 	nftnl_chain_unset(c, NFTNL_CHAIN_POLICY);
2945 
2946 	switch (policy) {
2947 	case NFT_RETURN:
2948 		return 0; /* return policy is default for nft chains */
2949 	case NF_ACCEPT:
2950 		pname = "ACCEPT";
2951 		break;
2952 	case NF_DROP:
2953 		pname = "DROP";
2954 		break;
2955 	default:
2956 		return -1;
2957 	}
2958 
2959 	command_jump(&cs, pname);
2960 
2961 	r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
2962 			 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
2963 	ebt_cs_clean(&cs);
2964 
2965 	if (!r)
2966 		return -1;
2967 
2968 	udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
2969 	if (!udata)
2970 		goto err_free_rule;
2971 
2972 	if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
2973 		goto err_free_rule;
2974 
2975 	nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
2976 			    nftnl_udata_buf_data(udata),
2977 			    nftnl_udata_buf_len(udata));
2978 	nftnl_udata_buf_free(udata);
2979 
2980 	if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
2981 		goto err_free_rule;
2982 
2983 	/* add the rule to chain so it is freed later */
2984 	nftnl_chain_rule_add_tail(r, c);
2985 
2986 	return 0;
2987 err_free_rule:
2988 	nftnl_rule_free(r);
2989 	return -1;
2990 }
2991 
ebt_set_user_chain_policy(struct nft_handle * h,const char * table,const char * chain,const char * policy)2992 int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
2993 			      const char *chain, const char *policy)
2994 {
2995 	struct nft_chain *c = nft_chain_find(h, table, chain);
2996 	int pval;
2997 
2998 	if (!c)
2999 		return 0;
3000 
3001 	if (!strcmp(policy, "DROP"))
3002 		pval = NF_DROP;
3003 	else if (!strcmp(policy, "ACCEPT"))
3004 		pval = NF_ACCEPT;
3005 	else if (!strcmp(policy, "RETURN"))
3006 		pval = NFT_RETURN;
3007 	else
3008 		return 0;
3009 
3010 	nftnl_chain_set_u32(c->nftnl, NFTNL_CHAIN_POLICY, pval);
3011 	return 1;
3012 }
3013 
nft_bridge_commit_prepare(struct nft_handle * h)3014 static void nft_bridge_commit_prepare(struct nft_handle *h)
3015 {
3016 	const struct builtin_table *t;
3017 	struct nft_chain_list *list;
3018 	struct nft_chain *c;
3019 	int i;
3020 
3021 	for (i = 0; i < NFT_TABLE_MAX; i++) {
3022 		t = &h->tables[i];
3023 
3024 		if (!t->name)
3025 			continue;
3026 
3027 		list = h->cache->table[t->type].chains;
3028 		if (!list)
3029 			continue;
3030 
3031 		list_for_each_entry(c, &list->list, head) {
3032 			ebt_add_policy_rule(c->nftnl, h);
3033 		}
3034 	}
3035 }
3036 
assert_chain_exists(struct nft_handle * h,const char * table,const char * chain)3037 static void assert_chain_exists(struct nft_handle *h,
3038 				const char *table, const char *chain)
3039 {
3040 	if (chain && !nft_chain_exists(h, table, chain))
3041 		xtables_error(PARAMETER_PROBLEM,
3042 			      "Chain '%s' does not exist", chain);
3043 }
3044 
nft_prepare(struct nft_handle * h)3045 static int nft_prepare(struct nft_handle *h)
3046 {
3047 	struct nft_cmd *cmd, *next;
3048 	int ret = 1;
3049 
3050 	nft_cache_build(h);
3051 
3052 	list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
3053 		switch (cmd->command) {
3054 		case NFT_COMPAT_TABLE_FLUSH:
3055 			ret = nft_table_flush(h, cmd->table);
3056 			break;
3057 		case NFT_COMPAT_CHAIN_USER_ADD:
3058 			ret = nft_chain_user_add(h, cmd->chain, cmd->table);
3059 			break;
3060 		case NFT_COMPAT_CHAIN_USER_DEL:
3061 			ret = nft_chain_user_del(h, cmd->chain, cmd->table,
3062 						 cmd->verbose);
3063 			break;
3064 		case NFT_COMPAT_CHAIN_RESTORE:
3065 			ret = nft_chain_restore(h, cmd->chain, cmd->table);
3066 			break;
3067 		case NFT_COMPAT_CHAIN_UPDATE:
3068 			ret = nft_chain_set(h, cmd->table, cmd->chain,
3069 					    cmd->policy, &cmd->counters);
3070 			break;
3071 		case NFT_COMPAT_CHAIN_RENAME:
3072 			ret = nft_chain_user_rename(h, cmd->chain, cmd->table,
3073 						    cmd->rename);
3074 			break;
3075 		case NFT_COMPAT_CHAIN_ZERO:
3076 			ret = nft_chain_zero_counters(h, cmd->chain, cmd->table,
3077 						      cmd->verbose);
3078 			break;
3079 		case NFT_COMPAT_RULE_APPEND:
3080 			assert_chain_exists(h, cmd->table, cmd->jumpto);
3081 			ret = nft_rule_append(h, cmd->chain, cmd->table,
3082 					      cmd->obj.rule, NULL, cmd->verbose);
3083 			break;
3084 		case NFT_COMPAT_RULE_INSERT:
3085 			assert_chain_exists(h, cmd->table, cmd->jumpto);
3086 			ret = nft_rule_insert(h, cmd->chain, cmd->table,
3087 					      cmd->obj.rule, cmd->rulenum,
3088 					      cmd->verbose);
3089 			break;
3090 		case NFT_COMPAT_RULE_REPLACE:
3091 			assert_chain_exists(h, cmd->table, cmd->jumpto);
3092 			ret = nft_rule_replace(h, cmd->chain, cmd->table,
3093 					      cmd->obj.rule, cmd->rulenum,
3094 					      cmd->verbose);
3095 			break;
3096 		case NFT_COMPAT_RULE_DELETE:
3097 			assert_chain_exists(h, cmd->table, cmd->jumpto);
3098 			if (cmd->rulenum >= 0)
3099 				ret = nft_rule_delete_num(h, cmd->chain,
3100 							  cmd->table,
3101 							  cmd->rulenum,
3102 							  cmd->verbose);
3103 			else
3104 				ret = nft_rule_delete(h, cmd->chain, cmd->table,
3105 						      cmd->obj.rule, cmd->verbose);
3106 			break;
3107 		case NFT_COMPAT_RULE_FLUSH:
3108 			ret = nft_rule_flush(h, cmd->chain, cmd->table,
3109 					     cmd->verbose);
3110 			break;
3111 		case NFT_COMPAT_RULE_LIST:
3112 			ret = nft_rule_list(h, cmd->chain, cmd->table,
3113 					    cmd->rulenum, cmd->format);
3114 			break;
3115 		case NFT_COMPAT_RULE_CHECK:
3116 			assert_chain_exists(h, cmd->table, cmd->jumpto);
3117 			ret = nft_rule_check(h, cmd->chain, cmd->table,
3118 					     cmd->obj.rule, cmd->rulenum);
3119 			break;
3120 		case NFT_COMPAT_RULE_ZERO:
3121 			ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
3122                                                      cmd->rulenum);
3123 			break;
3124 		case NFT_COMPAT_RULE_SAVE:
3125 			ret = nft_rule_list_save(h, cmd->chain, cmd->table,
3126 						 cmd->rulenum,
3127 						 cmd->counters_save);
3128 			break;
3129 		case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
3130 			ret = ebt_set_user_chain_policy(h, cmd->table,
3131 							cmd->chain, cmd->policy);
3132 			break;
3133 		case NFT_COMPAT_SET_ADD:
3134 			nft_xt_builtin_table_init(h, cmd->table);
3135 			batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
3136 			ret = 1;
3137 			break;
3138 		case NFT_COMPAT_TABLE_ADD:
3139 		case NFT_COMPAT_CHAIN_ADD:
3140 			assert(0);
3141 			break;
3142 		}
3143 
3144 		nft_cmd_free(cmd);
3145 
3146 		if (ret == 0)
3147 			return 0;
3148 	}
3149 
3150 	return 1;
3151 }
3152 
nft_commit(struct nft_handle * h)3153 int nft_commit(struct nft_handle *h)
3154 {
3155 	if (!nft_prepare(h))
3156 		return 0;
3157 
3158 	return nft_action(h, NFT_COMPAT_COMMIT);
3159 }
3160 
nft_bridge_commit(struct nft_handle * h)3161 int nft_bridge_commit(struct nft_handle *h)
3162 {
3163 	if (!nft_prepare(h))
3164 		return 0;
3165 
3166 	nft_bridge_commit_prepare(h);
3167 
3168 	return nft_action(h, NFT_COMPAT_COMMIT);
3169 }
3170 
nft_abort(struct nft_handle * h)3171 int nft_abort(struct nft_handle *h)
3172 {
3173 	struct nft_cmd *cmd, *next;
3174 
3175 	list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
3176 		nft_cmd_free(cmd);
3177 
3178 	return nft_action(h, NFT_COMPAT_ABORT);
3179 }
3180 
nft_compatible_revision(const char * name,uint8_t rev,int opt)3181 int nft_compatible_revision(const char *name, uint8_t rev, int opt)
3182 {
3183 	struct mnl_socket *nl;
3184 	char buf[16536];
3185 	struct nlmsghdr *nlh;
3186 	uint32_t portid, seq, type = 0;
3187 	uint32_t pf = AF_INET;
3188 	int ret = 0;
3189 
3190 	switch (opt) {
3191 	case IPT_SO_GET_REVISION_MATCH:
3192 		break;
3193 	case IP6T_SO_GET_REVISION_MATCH:
3194 		pf = AF_INET6;
3195 		break;
3196 	case IPT_SO_GET_REVISION_TARGET:
3197 		type = 1;
3198 		break;
3199 	case IP6T_SO_GET_REVISION_TARGET:
3200 		type = 1;
3201 		pf = AF_INET6;
3202 		break;
3203 	default:
3204 		/* No revision support (arp, ebtables), assume latest version ok */
3205 		return 1;
3206 	}
3207 
3208 	nlh = mnl_nlmsg_put_header(buf);
3209 	nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
3210 	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
3211 	nlh->nlmsg_seq = seq = time(NULL);
3212 
3213 	struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
3214 	nfg->nfgen_family = pf;
3215 	nfg->version = NFNETLINK_V0;
3216 	nfg->res_id = 0;
3217 
3218 	mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
3219 	mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
3220 	mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
3221 
3222 	DEBUGP("requesting `%s' rev=%d type=%d via nft_compat\n",
3223 		name, rev, type);
3224 
3225 	nl = mnl_socket_open(NETLINK_NETFILTER);
3226 	if (nl == NULL)
3227 		return 0;
3228 
3229 	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
3230 		goto err;
3231 
3232 	portid = mnl_socket_get_portid(nl);
3233 
3234 	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
3235 		goto err;
3236 
3237 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
3238 	if (ret == -1)
3239 		goto err;
3240 
3241 	ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
3242 	if (ret == -1)
3243 		goto err;
3244 
3245 err:
3246 	mnl_socket_close(nl);
3247 
3248 	return ret < 0 ? 0 : 1;
3249 }
3250 
3251 /* Translates errno numbers into more human-readable form than strerror. */
nft_strerror(int err)3252 const char *nft_strerror(int err)
3253 {
3254 	unsigned int i;
3255 	static struct table_struct {
3256 		void *fn;
3257 		int err;
3258 		const char *message;
3259 	} table[] =
3260 	  {
3261 	    { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
3262 	    { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
3263 	    { nft_chain_user_del, EBUSY, "Directory not empty" },
3264 	    { nft_chain_user_del, EMLINK,
3265 	      "Can't delete chain with references left" },
3266 	    { nft_chain_user_add, EEXIST, "Chain already exists" },
3267 	    { nft_chain_user_rename, EEXIST, "File exists" },
3268 	    { nft_rule_insert, E2BIG, "Index of insertion too big" },
3269 	    { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
3270 	    { nft_rule_replace, E2BIG, "Index of replacement too big" },
3271 	    { nft_rule_delete_num, E2BIG, "Index of deletion too big" },
3272 /*	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
3273 	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
3274 	    /* ENOENT for DELETE probably means no matching rule */
3275 	    { nft_rule_delete, ENOENT,
3276 	      "Bad rule (does a matching rule exist in that chain?)" },
3277 	    { nft_chain_set, ENOENT, "Bad built-in chain name" },
3278 	    { nft_chain_set, EINVAL, "Bad policy name" },
3279 	    { nft_chain_set, ENXIO, "Bad table name" },
3280 	    { NULL, ELOOP, "Loop found in table" },
3281 	    { NULL, EPERM, "Permission denied (you must be root)" },
3282 	    { NULL, 0, "Incompatible with this kernel" },
3283 	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
3284 	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
3285 	    { NULL, ENOMEM, "Memory allocation problem" },
3286 	    { NULL, ENOENT, "No chain/target/match by that name" },
3287 	  };
3288 
3289 	for (i = 0; i < ARRAY_SIZE(table); i++) {
3290 		if ((!table[i].fn || table[i].fn == nft_fn)
3291 		    && table[i].err == err)
3292 			return table[i].message;
3293 	}
3294 
3295 	return strerror(err);
3296 }
3297 
recover_rule_compat(struct nftnl_rule * r)3298 static int recover_rule_compat(struct nftnl_rule *r)
3299 {
3300 	struct nftnl_expr_iter *iter;
3301 	struct nftnl_expr *e;
3302 	uint32_t reg;
3303 	int ret = -1;
3304 
3305 	iter = nftnl_expr_iter_create(r);
3306 	if (!iter)
3307 		return -1;
3308 
3309 next_expr:
3310 	e = nftnl_expr_iter_next(iter);
3311 	if (!e)
3312 		goto out;
3313 
3314 	if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
3315 	    nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
3316 		goto next_expr;
3317 
3318 	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
3319 
3320 	e = nftnl_expr_iter_next(iter);
3321 	if (!e)
3322 		goto out;
3323 
3324 	if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
3325 	    reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
3326 		goto next_expr;
3327 
3328 	add_compat(r, nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA),
3329 		   nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ);
3330 	ret = 0;
3331 out:
3332 	nftnl_expr_iter_destroy(iter);
3333 	return ret;
3334 }
3335 
3336 struct chain_zero_data {
3337 	struct nft_handle	*handle;
3338 	bool			verbose;
3339 };
3340 
__nft_chain_zero_counters(struct nft_chain * nc,void * data)3341 static int __nft_chain_zero_counters(struct nft_chain *nc, void *data)
3342 {
3343 	struct nftnl_chain *c = nc->nftnl;
3344 	struct chain_zero_data *d = data;
3345 	struct nft_handle *h = d->handle;
3346 	struct nftnl_rule_iter *iter;
3347 	struct nftnl_rule *r;
3348 
3349 	if (d->verbose)
3350 		fprintf(stdout, "Zeroing chain `%s'\n",
3351 		        nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
3352 
3353 	if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
3354 		/* zero base chain counters. */
3355 		nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
3356 		nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
3357 		nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
3358 		if (!batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
3359 			return -1;
3360 	}
3361 
3362 	iter = nftnl_rule_iter_create(c);
3363 	if (iter == NULL)
3364 		return -1;
3365 
3366 	r = nftnl_rule_iter_next(iter);
3367 	while (r != NULL) {
3368 		struct nftnl_expr_iter *ei;
3369 		struct nftnl_expr *e;
3370 		bool zero_needed;
3371 
3372 		ei = nftnl_expr_iter_create(r);
3373 		if (!ei)
3374 			break;
3375 
3376 		e = nftnl_expr_iter_next(ei);
3377 	        zero_needed = false;
3378 		while (e != NULL) {
3379 			const char *en = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
3380 
3381 			if (strcmp(en, "counter") == 0 && (
3382 			    nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS) ||
3383 			    nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES))) {
3384 				nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_PACKETS, 0);
3385 				nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_BYTES, 0);
3386 				zero_needed = true;
3387 			}
3388 
3389 			e = nftnl_expr_iter_next(ei);
3390 		}
3391 
3392 		nftnl_expr_iter_destroy(ei);
3393 
3394 		if (zero_needed) {
3395 			/*
3396 			 * Unset RULE_POSITION for older kernels, we want to replace
3397 			 * rule based on its handle only.
3398 			 */
3399 			recover_rule_compat(r);
3400 			nftnl_rule_unset(r, NFTNL_RULE_POSITION);
3401 			if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
3402 				nftnl_rule_iter_destroy(iter);
3403 				return -1;
3404 			}
3405 		}
3406 		r = nftnl_rule_iter_next(iter);
3407 	}
3408 
3409 	nftnl_rule_iter_destroy(iter);
3410 	return 0;
3411 }
3412 
nft_chain_zero_counters(struct nft_handle * h,const char * chain,const char * table,bool verbose)3413 int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
3414 			    const char *table, bool verbose)
3415 {
3416 	struct chain_zero_data d = {
3417 		.handle = h,
3418 		.verbose = verbose,
3419 	};
3420 	struct nft_chain *c;
3421 	int ret = 0;
3422 
3423 	if (chain) {
3424 		c = nft_chain_find(h, table, chain);
3425 		if (!c) {
3426 			errno = ENOENT;
3427 			return 0;
3428 		}
3429 
3430 		ret = __nft_chain_zero_counters(c, &d);
3431 		goto err;
3432 	}
3433 
3434 	ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
3435 err:
3436 	/* the core expects 1 for success and 0 for error */
3437 	return ret == 0 ? 1 : 0;
3438 }
3439 
nft_invflags2cmp(uint32_t invflags,uint32_t flag)3440 uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
3441 {
3442 	if (invflags & flag)
3443 		return NFT_CMP_NEQ;
3444 
3445 	return NFT_CMP_EQ;
3446 }
3447 
3448 static const char *supported_exprs[] = {
3449 	"match",
3450 	"target",
3451 	"payload",
3452 	"meta",
3453 	"cmp",
3454 	"bitwise",
3455 	"counter",
3456 	"immediate",
3457 	"lookup",
3458 };
3459 
3460 
nft_is_expr_compatible(struct nftnl_expr * expr,void * data)3461 static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
3462 {
3463 	const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
3464 	int i;
3465 
3466 	for (i = 0; i < ARRAY_SIZE(supported_exprs); i++) {
3467 		if (strcmp(supported_exprs[i], name) == 0)
3468 			return 0;
3469 	}
3470 
3471 	if (!strcmp(name, "limit") &&
3472 	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_TYPE) == NFT_LIMIT_PKTS &&
3473 	    nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
3474 		return 0;
3475 
3476 	return -1;
3477 }
3478 
nft_is_rule_compatible(struct nftnl_rule * rule,void * data)3479 static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
3480 {
3481 	return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
3482 }
3483 
nft_is_chain_compatible(struct nft_chain * nc,void * data)3484 static int nft_is_chain_compatible(struct nft_chain *nc, void *data)
3485 {
3486 	struct nftnl_chain *c = nc->nftnl;
3487 	const struct builtin_table *table;
3488 	const struct builtin_chain *chain;
3489 	const char *tname, *cname, *type;
3490 	struct nft_handle *h = data;
3491 	enum nf_inet_hooks hook;
3492 	int prio;
3493 
3494 	if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
3495 		return -1;
3496 
3497 	if (!nft_chain_builtin(c))
3498 		return 0;
3499 
3500 	tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
3501 	table = nft_table_builtin_find(h, tname);
3502 	if (!table)
3503 		return -1;
3504 
3505 	cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
3506 	chain = nft_chain_builtin_find(table, cname);
3507 	if (!chain)
3508 		return -1;
3509 
3510 	type = nftnl_chain_get_str(c, NFTNL_CHAIN_TYPE);
3511 	prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO);
3512 	hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
3513 	if (strcmp(type, chain->type) ||
3514 	    prio != chain->prio ||
3515 	    hook != chain->hook)
3516 		return -1;
3517 
3518 	return 0;
3519 }
3520 
nft_is_table_compatible(struct nft_handle * h,const char * table,const char * chain)3521 bool nft_is_table_compatible(struct nft_handle *h,
3522 			     const char *table, const char *chain)
3523 {
3524 	if (chain) {
3525 		struct nft_chain *c = nft_chain_find(h, table, chain);
3526 
3527 		return c && !nft_is_chain_compatible(c, h);
3528 	}
3529 
3530 	return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
3531 }
3532 
nft_assert_table_compatible(struct nft_handle * h,const char * table,const char * chain)3533 void nft_assert_table_compatible(struct nft_handle *h,
3534 				 const char *table, const char *chain)
3535 {
3536 	const char *pfx = "", *sfx = "";
3537 
3538 	if (nft_is_table_compatible(h, table, chain))
3539 		return;
3540 
3541 	if (chain) {
3542 		pfx = "chain `";
3543 		sfx = "' in ";
3544 	} else {
3545 		chain = "";
3546 	}
3547 	xtables_error(OTHER_PROBLEM,
3548 		      "%s%s%stable `%s' is incompatible, use 'nft' tool.\n",
3549 		      pfx, chain, sfx, table);
3550 }
3551