nft: Drop interface mask leftovers from post_parse callbacks
[iptables-mirror.git] / iptables / nft.c
blob21a7e211d7d780de5485d43e3bfe5b3a79f39771
1 /*
2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
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.
9 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
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>
24 #include <xtables.h>
25 #include <libiptc/libxtc.h>
26 #include <libiptc/xtcshared.h>
28 #include <stdlib.h>
29 #include <string.h>
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>
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>
41 #include <linux/netfilter/xt_limit.h>
42 #include <linux/netfilter/xt_NFLOG.h>
43 #include <linux/netfilter/xt_mark.h>
45 #include <libmnl/libmnl.h>
46 #include <libnftnl/gen.h>
47 #include <libnftnl/table.h>
48 #include <libnftnl/chain.h>
49 #include <libnftnl/rule.h>
50 #include <libnftnl/expr.h>
51 #include <libnftnl/set.h>
52 #include <libnftnl/udata.h>
53 #include <libnftnl/batch.h>
55 #include <netinet/in.h> /* inet_ntoa */
56 #include <arpa/inet.h>
58 #include "nft.h"
59 #include "xshared.h" /* proto_to_name */
60 #include "nft-cache.h"
61 #include "nft-shared.h"
62 #include "nft-bridge.h" /* EBT_NOPROTO */
64 static void *nft_fn;
66 int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
67 int (*cb)(const struct nlmsghdr *nlh, void *data),
68 void *data)
70 int ret;
71 char buf[32768];
73 if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
74 return -1;
76 ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
77 while (ret > 0) {
78 ret = mnl_cb_run(buf, ret, h->seq, h->portid, cb, data);
79 if (ret <= 0)
80 break;
82 ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
84 if (ret == -1) {
85 return -1;
88 return 0;
91 #define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
93 /* Selected batch page is 2 Mbytes long to support loading a ruleset of 3.5M
94 * rules matching on source and destination address as well as input and output
95 * interfaces. This is what legacy iptables supports.
97 #define BATCH_PAGE_SIZE 2 * 1024 * 1024
99 static struct nftnl_batch *mnl_batch_init(void)
101 struct nftnl_batch *batch;
103 batch = nftnl_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE);
104 if (batch == NULL)
105 return NULL;
107 return batch;
110 static void mnl_nft_batch_continue(struct nftnl_batch *batch)
112 int ret = nftnl_batch_update(batch);
114 assert(ret >= 0);
117 static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum)
119 struct nlmsghdr *nlh;
121 nlh = nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
123 mnl_attr_put_u32(nlh, NFTA_GEN_ID, htonl(genid));
125 mnl_nft_batch_continue(batch);
127 return seqnum;
130 static void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum)
132 nftnl_batch_end(nftnl_batch_buffer(batch), seqnum);
133 mnl_nft_batch_continue(batch);
136 static void mnl_batch_reset(struct nftnl_batch *batch)
138 nftnl_batch_free(batch);
141 struct mnl_err {
142 struct list_head head;
143 int err;
144 uint32_t seqnum;
147 static void mnl_err_list_node_add(struct list_head *err_list, int error,
148 int seqnum)
150 struct mnl_err *err = xtables_malloc(sizeof(struct mnl_err));
152 err->seqnum = seqnum;
153 err->err = error;
154 list_add_tail(&err->head, err_list);
157 static void mnl_err_list_free(struct mnl_err *err)
159 list_del(&err->head);
160 free(err);
163 static void mnl_set_sndbuffer(struct nft_handle *h)
165 int newbuffsiz = nftnl_batch_iovec_len(h->batch) * BATCH_PAGE_SIZE;
167 if (newbuffsiz <= h->nlsndbuffsiz)
168 return;
170 /* Rise sender buffer length to avoid hitting -EMSGSIZE */
171 if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_SNDBUFFORCE,
172 &newbuffsiz, sizeof(socklen_t)) < 0)
173 return;
175 h->nlsndbuffsiz = newbuffsiz;
178 static void mnl_set_rcvbuffer(struct nft_handle *h, int numcmds)
180 int newbuffsiz = getpagesize() * numcmds;
182 if (newbuffsiz <= h->nlrcvbuffsiz)
183 return;
185 /* Rise receiver buffer length to avoid hitting -ENOBUFS */
186 if (setsockopt(mnl_socket_get_fd(h->nl), SOL_SOCKET, SO_RCVBUFFORCE,
187 &newbuffsiz, sizeof(socklen_t)) < 0)
188 return;
190 h->nlrcvbuffsiz = newbuffsiz;
193 static ssize_t mnl_nft_socket_sendmsg(struct nft_handle *h, int numcmds)
195 static const struct sockaddr_nl snl = {
196 .nl_family = AF_NETLINK
198 uint32_t iov_len = nftnl_batch_iovec_len(h->batch);
199 struct iovec iov[iov_len];
200 struct msghdr msg = {
201 .msg_name = (struct sockaddr *) &snl,
202 .msg_namelen = sizeof(snl),
203 .msg_iov = iov,
204 .msg_iovlen = iov_len,
207 mnl_set_sndbuffer(h);
208 mnl_set_rcvbuffer(h, numcmds);
209 nftnl_batch_iovec(h->batch, iov, iov_len);
211 return sendmsg(mnl_socket_get_fd(h->nl), &msg, 0);
214 static int mnl_batch_talk(struct nft_handle *h, int numcmds)
216 const struct mnl_socket *nl = h->nl;
217 int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
218 char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
219 fd_set readfds;
220 struct timeval tv = {
221 .tv_sec = 0,
222 .tv_usec = 0
224 int err = 0;
226 ret = mnl_nft_socket_sendmsg(h, numcmds);
227 if (ret == -1) {
228 fprintf(stderr, "sendmsg() failed: %s\n", strerror(errno));
229 return -1;
232 FD_ZERO(&readfds);
233 FD_SET(fd, &readfds);
235 /* receive and digest all the acknowledgments from the kernel. */
236 ret = select(fd+1, &readfds, NULL, NULL, &tv);
237 if (ret == -1)
238 return -1;
240 while (ret > 0 && FD_ISSET(fd, &readfds)) {
241 struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
243 ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
244 if (ret == -1)
245 return -1;
247 ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL);
248 /* Continue on error, make sure we get all acknowledgments */
249 if (ret == -1) {
250 mnl_err_list_node_add(&h->err_list, errno,
251 nlh->nlmsg_seq);
252 err = -1;
255 ret = select(fd+1, &readfds, NULL, NULL, &tv);
256 if (ret == -1)
257 return -1;
259 FD_ZERO(&readfds);
260 FD_SET(fd, &readfds);
262 return err;
265 enum obj_action {
266 NFT_COMPAT_COMMIT,
267 NFT_COMPAT_ABORT,
270 struct obj_update {
271 struct list_head head;
272 enum obj_update_type type:8;
273 uint8_t skip:1;
274 unsigned int seq;
275 union {
276 struct nftnl_table *table;
277 struct nftnl_chain *chain;
278 struct nftnl_rule *rule;
279 struct nftnl_set *set;
280 void *ptr;
282 struct {
283 unsigned int lineno;
284 } error;
287 static int mnl_append_error(const struct nft_handle *h,
288 const struct obj_update *o,
289 const struct mnl_err *err,
290 char *buf, unsigned int len)
292 static const char *type_name[] = {
293 [NFT_COMPAT_TABLE_ADD] = "TABLE_ADD",
294 [NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
295 [NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
296 [NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
297 [NFT_COMPAT_CHAIN_DEL] = "CHAIN_DEL",
298 [NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
299 [NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
300 [NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
301 [NFT_COMPAT_CHAIN_ZERO] = "CHAIN_ZERO",
302 [NFT_COMPAT_RULE_APPEND] = "RULE_APPEND",
303 [NFT_COMPAT_RULE_INSERT] = "RULE_INSERT",
304 [NFT_COMPAT_RULE_REPLACE] = "RULE_REPLACE",
305 [NFT_COMPAT_RULE_DELETE] = "RULE_DELETE",
306 [NFT_COMPAT_RULE_FLUSH] = "RULE_FLUSH",
307 [NFT_COMPAT_SET_ADD] = "SET_ADD",
309 char errmsg[256];
310 char tcr[128];
312 if (o->error.lineno)
313 snprintf(errmsg, sizeof(errmsg), "\nline %u: %s failed (%s)",
314 o->error.lineno, type_name[o->type], strerror(err->err));
315 else
316 snprintf(errmsg, sizeof(errmsg), " %s failed (%s)",
317 type_name[o->type], strerror(err->err));
319 switch (o->type) {
320 case NFT_COMPAT_TABLE_ADD:
321 case NFT_COMPAT_TABLE_FLUSH:
322 snprintf(tcr, sizeof(tcr), "table %s",
323 nftnl_table_get_str(o->table, NFTNL_TABLE_NAME));
324 break;
325 case NFT_COMPAT_CHAIN_ADD:
326 case NFT_COMPAT_CHAIN_ZERO:
327 case NFT_COMPAT_CHAIN_USER_ADD:
328 case NFT_COMPAT_CHAIN_DEL:
329 case NFT_COMPAT_CHAIN_USER_FLUSH:
330 case NFT_COMPAT_CHAIN_UPDATE:
331 case NFT_COMPAT_CHAIN_RENAME:
332 snprintf(tcr, sizeof(tcr), "chain %s",
333 nftnl_chain_get_str(o->chain, NFTNL_CHAIN_NAME));
334 break;
335 case NFT_COMPAT_RULE_APPEND:
336 case NFT_COMPAT_RULE_INSERT:
337 case NFT_COMPAT_RULE_REPLACE:
338 case NFT_COMPAT_RULE_DELETE:
339 case NFT_COMPAT_RULE_FLUSH:
340 case NFT_COMPAT_RULE_CHANGE_COUNTERS:
341 snprintf(tcr, sizeof(tcr), "rule in chain %s",
342 nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
343 #if 0
345 nft_rule_print_save(h, o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
347 #endif
348 break;
349 case NFT_COMPAT_SET_ADD:
350 snprintf(tcr, sizeof(tcr), "set %s",
351 nftnl_set_get_str(o->set, NFTNL_SET_NAME));
352 break;
353 case NFT_COMPAT_RULE_LIST:
354 case NFT_COMPAT_RULE_CHECK:
355 case NFT_COMPAT_CHAIN_RESTORE:
356 case NFT_COMPAT_RULE_SAVE:
357 case NFT_COMPAT_RULE_ZERO:
358 case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
359 assert(0);
360 break;
363 return snprintf(buf, len, "%s: %s", errmsg, tcr);
366 static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
368 struct obj_update *obj;
370 obj = xtables_calloc(1, sizeof(struct obj_update));
371 obj->ptr = ptr;
372 obj->error.lineno = h->error.lineno;
373 obj->type = type;
374 list_add_tail(&obj->head, &h->obj_list);
375 h->obj_list_num++;
377 return obj;
380 static struct obj_update *
381 batch_table_add(struct nft_handle *h, enum obj_update_type type,
382 struct nftnl_table *t)
384 return batch_add(h, type, t);
387 static struct obj_update *
388 batch_set_add(struct nft_handle *h, enum obj_update_type type,
389 struct nftnl_set *s)
391 return batch_add(h, type, s);
394 static struct obj_update *
395 batch_chain_add(struct nft_handle *h, enum obj_update_type type,
396 struct nftnl_chain *c)
398 return batch_add(h, type, c);
401 static struct obj_update *
402 batch_rule_add(struct nft_handle *h, enum obj_update_type type,
403 struct nftnl_rule *r)
405 return batch_add(h, type, r);
408 static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
410 static void batch_chain_flush(struct nft_handle *h,
411 const char *table, const char *chain)
413 struct obj_update *obj, *tmp;
415 list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
416 struct nftnl_rule *r = obj->ptr;
418 switch (obj->type) {
419 case NFT_COMPAT_RULE_APPEND:
420 case NFT_COMPAT_RULE_INSERT:
421 case NFT_COMPAT_RULE_REPLACE:
422 case NFT_COMPAT_RULE_DELETE:
423 break;
424 default:
425 continue;
428 if (table &&
429 strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
430 continue;
432 if (chain &&
433 strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
434 continue;
436 batch_obj_del(h, obj);
440 static const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
441 [NFT_TABLE_RAW] = {
442 .name = "raw",
443 .type = NFT_TABLE_RAW,
444 .chains = {
446 .name = "PREROUTING",
447 .type = "filter",
448 .prio = -300, /* NF_IP_PRI_RAW */
449 .hook = NF_INET_PRE_ROUTING,
452 .name = "OUTPUT",
453 .type = "filter",
454 .prio = -300, /* NF_IP_PRI_RAW */
455 .hook = NF_INET_LOCAL_OUT,
459 [NFT_TABLE_MANGLE] = {
460 .name = "mangle",
461 .type = NFT_TABLE_MANGLE,
462 .chains = {
464 .name = "PREROUTING",
465 .type = "filter",
466 .prio = -150, /* NF_IP_PRI_MANGLE */
467 .hook = NF_INET_PRE_ROUTING,
470 .name = "INPUT",
471 .type = "filter",
472 .prio = -150, /* NF_IP_PRI_MANGLE */
473 .hook = NF_INET_LOCAL_IN,
476 .name = "FORWARD",
477 .type = "filter",
478 .prio = -150, /* NF_IP_PRI_MANGLE */
479 .hook = NF_INET_FORWARD,
482 .name = "OUTPUT",
483 .type = "route",
484 .prio = -150, /* NF_IP_PRI_MANGLE */
485 .hook = NF_INET_LOCAL_OUT,
488 .name = "POSTROUTING",
489 .type = "filter",
490 .prio = -150, /* NF_IP_PRI_MANGLE */
491 .hook = NF_INET_POST_ROUTING,
495 [NFT_TABLE_FILTER] = {
496 .name = "filter",
497 .type = NFT_TABLE_FILTER,
498 .chains = {
500 .name = "INPUT",
501 .type = "filter",
502 .prio = 0, /* NF_IP_PRI_FILTER */
503 .hook = NF_INET_LOCAL_IN,
506 .name = "FORWARD",
507 .type = "filter",
508 .prio = 0, /* NF_IP_PRI_FILTER */
509 .hook = NF_INET_FORWARD,
512 .name = "OUTPUT",
513 .type = "filter",
514 .prio = 0, /* NF_IP_PRI_FILTER */
515 .hook = NF_INET_LOCAL_OUT,
519 [NFT_TABLE_SECURITY] = {
520 .name = "security",
521 .type = NFT_TABLE_SECURITY,
522 .chains = {
524 .name = "INPUT",
525 .type = "filter",
526 .prio = 150, /* NF_IP_PRI_SECURITY */
527 .hook = NF_INET_LOCAL_IN,
530 .name = "FORWARD",
531 .type = "filter",
532 .prio = 150, /* NF_IP_PRI_SECURITY */
533 .hook = NF_INET_FORWARD,
536 .name = "OUTPUT",
537 .type = "filter",
538 .prio = 150, /* NF_IP_PRI_SECURITY */
539 .hook = NF_INET_LOCAL_OUT,
543 [NFT_TABLE_NAT] = {
544 .name = "nat",
545 .type = NFT_TABLE_NAT,
546 .chains = {
548 .name = "PREROUTING",
549 .type = "nat",
550 .prio = -100, /* NF_IP_PRI_NAT_DST */
551 .hook = NF_INET_PRE_ROUTING,
554 .name = "INPUT",
555 .type = "nat",
556 .prio = 100, /* NF_IP_PRI_NAT_SRC */
557 .hook = NF_INET_LOCAL_IN,
560 .name = "POSTROUTING",
561 .type = "nat",
562 .prio = 100, /* NF_IP_PRI_NAT_SRC */
563 .hook = NF_INET_POST_ROUTING,
566 .name = "OUTPUT",
567 .type = "nat",
568 .prio = -100, /* NF_IP_PRI_NAT_DST */
569 .hook = NF_INET_LOCAL_OUT,
575 #include <linux/netfilter_arp.h>
577 static const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
578 [NFT_TABLE_FILTER] = {
579 .name = "filter",
580 .type = NFT_TABLE_FILTER,
581 .chains = {
583 .name = "INPUT",
584 .type = "filter",
585 .prio = NF_IP_PRI_FILTER,
586 .hook = NF_ARP_IN,
589 .name = "OUTPUT",
590 .type = "filter",
591 .prio = NF_IP_PRI_FILTER,
592 .hook = NF_ARP_OUT,
598 #include <linux/netfilter_bridge.h>
600 static const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
601 [NFT_TABLE_FILTER] = {
602 .name = "filter",
603 .type = NFT_TABLE_FILTER,
604 .chains = {
606 .name = "INPUT",
607 .type = "filter",
608 .prio = NF_BR_PRI_FILTER_BRIDGED,
609 .hook = NF_BR_LOCAL_IN,
612 .name = "FORWARD",
613 .type = "filter",
614 .prio = NF_BR_PRI_FILTER_BRIDGED,
615 .hook = NF_BR_FORWARD,
618 .name = "OUTPUT",
619 .type = "filter",
620 .prio = NF_BR_PRI_FILTER_BRIDGED,
621 .hook = NF_BR_LOCAL_OUT,
625 [NFT_TABLE_NAT] = {
626 .name = "nat",
627 .type = NFT_TABLE_NAT,
628 .chains = {
630 .name = "PREROUTING",
631 .type = "filter",
632 .prio = NF_BR_PRI_NAT_DST_BRIDGED,
633 .hook = NF_BR_PRE_ROUTING,
636 .name = "OUTPUT",
637 .type = "filter",
638 .prio = NF_BR_PRI_NAT_DST_OTHER,
639 .hook = NF_BR_LOCAL_OUT,
642 .name = "POSTROUTING",
643 .type = "filter",
644 .prio = NF_BR_PRI_NAT_SRC,
645 .hook = NF_BR_POST_ROUTING,
649 [NFT_TABLE_BROUTE] = {
650 .name = "broute",
651 .type = NFT_TABLE_BROUTE,
652 .chains = {
654 .name = "BROUTING",
655 .type = "filter",
656 .prio = NF_BR_PRI_FIRST,
657 .hook = NF_BR_PRE_ROUTING,
664 static int nft_table_builtin_add(struct nft_handle *h,
665 const struct builtin_table *_t)
667 struct nftnl_table *t;
668 int ret;
670 if (h->cache->table[_t->type].exists)
671 return 0;
673 t = nftnl_table_alloc();
674 if (t == NULL)
675 return -1;
677 nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family);
678 nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
680 ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
682 return ret;
685 static struct nftnl_chain *
686 nft_chain_builtin_alloc(int family, const char *tname,
687 const struct builtin_chain *chain, int policy)
689 struct nftnl_chain *c;
691 c = nftnl_chain_alloc();
692 if (c == NULL)
693 return NULL;
695 nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, family);
696 nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, tname);
697 nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
698 nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
699 nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
700 if (policy >= 0)
701 nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
703 nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
705 nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
706 nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
708 return c;
711 static void nft_chain_builtin_add(struct nft_handle *h,
712 const struct builtin_table *table,
713 const struct builtin_chain *chain,
714 bool fake)
716 struct nftnl_chain *c;
718 c = nft_chain_builtin_alloc(h->family, table->name, chain, NF_ACCEPT);
719 if (c == NULL)
720 return;
722 if (!fake)
723 batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
724 nft_cache_add_chain(h, table, c, fake);
727 /* find if built-in table already exists */
728 const struct builtin_table *
729 nft_table_builtin_find(struct nft_handle *h, const char *table)
731 int i;
732 bool found = false;
734 for (i = 0; i < NFT_TABLE_MAX; i++) {
735 if (h->tables[i].name == NULL)
736 continue;
738 if (strcmp(h->tables[i].name, table) != 0)
739 continue;
741 found = true;
742 break;
745 return found ? &h->tables[i] : NULL;
748 /* find if built-in chain already exists */
749 const struct builtin_chain *
750 nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
752 int i;
753 bool found = false;
755 for (i=0; i<NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
756 if (strcmp(t->chains[i].name, chain) != 0)
757 continue;
759 found = true;
760 break;
762 return found ? &t->chains[i] : NULL;
765 static void nft_chain_builtin_init(struct nft_handle *h,
766 const struct builtin_table *table)
768 struct nft_chain *c;
769 int i;
771 /* Initialize built-in chains if they don't exist yet */
772 for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
773 c = nft_chain_find(h, table->name, table->chains[i].name);
774 if (!c) {
775 nft_chain_builtin_add(h, table,
776 &table->chains[i], false);
777 } else if (c->fake) {
778 batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c->nftnl);
779 c->fake = false;
784 static const struct builtin_table *
785 nft_xt_builtin_table_init(struct nft_handle *h, const char *table)
787 const struct builtin_table *t;
789 if (!h->cache_init)
790 return NULL;
792 t = nft_table_builtin_find(h, table);
793 if (t == NULL)
794 return NULL;
796 if (nft_table_builtin_add(h, t) < 0)
797 return NULL;
799 return t;
802 static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
803 const char *chain)
805 const struct builtin_table *t;
806 const struct builtin_chain *c;
807 struct nft_chain *nc;
809 if (!h->cache_init)
810 return 0;
812 t = nft_xt_builtin_table_init(h, table);
813 if (!t)
814 return -1;
816 if (h->cache_req.level < NFT_CL_CHAINS)
817 return 0;
819 if (!chain) {
820 nft_chain_builtin_init(h, t);
821 return 0;
824 c = nft_chain_builtin_find(t, chain);
825 if (!c)
826 return -1;
828 nc = h->cache->table[t->type].base_chains[c->hook];
829 if (!nc) {
830 nft_chain_builtin_add(h, t, c, false);
831 } else if (nc->fake) {
832 batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, nc->nftnl);
833 nc->fake = false;
835 return 0;
838 static bool nft_chain_builtin(struct nftnl_chain *c)
840 /* Check if this chain has hook number, in that case is built-in.
841 * Should we better export the flags to user-space via nf_tables?
843 return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
846 static int __nft_xt_fake_builtin_chains(struct nft_handle *h,
847 const char *table, void *data)
849 const char *chain = data ? *(const char **)data : NULL;
850 const struct builtin_table *t;
851 struct nft_chain **bcp;
852 int i;
854 t = nft_table_builtin_find(h, table);
855 if (!t)
856 return -1;
858 bcp = h->cache->table[t->type].base_chains;
859 for (i = 0; i < NF_INET_NUMHOOKS && t->chains[i].name; i++) {
860 if (bcp[t->chains[i].hook])
861 continue;
863 if (chain && strcmp(chain, t->chains[i].name))
864 continue;
866 nft_chain_builtin_add(h, t, &t->chains[i], true);
868 return 0;
871 int nft_xt_fake_builtin_chains(struct nft_handle *h,
872 const char *table, const char *chain)
874 if (table)
875 return __nft_xt_fake_builtin_chains(h, table, &chain);
877 return nft_for_each_table(h, __nft_xt_fake_builtin_chains, &chain);
880 int nft_restart(struct nft_handle *h)
882 mnl_socket_close(h->nl);
884 h->nl = mnl_socket_open(NETLINK_NETFILTER);
885 if (h->nl == NULL)
886 return -1;
888 if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
889 return -1;
891 h->portid = mnl_socket_get_portid(h->nl);
892 h->nlsndbuffsiz = 0;
893 h->nlrcvbuffsiz = 0;
895 return 0;
898 static const struct builtin_table *builtin_tables_lookup(int family)
900 switch (family) {
901 case AF_INET:
902 case AF_INET6:
903 return xtables_ipv4;
904 case NFPROTO_ARP:
905 return xtables_arp;
906 case NFPROTO_BRIDGE:
907 return xtables_bridge;
908 default:
909 return NULL;
913 int nft_init(struct nft_handle *h, int family)
915 memset(h, 0, sizeof(*h));
917 h->nl = mnl_socket_open(NETLINK_NETFILTER);
918 if (h->nl == NULL)
919 return -1;
921 if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
922 mnl_socket_close(h->nl);
923 return -1;
926 h->ops = nft_family_ops_lookup(family);
927 if (!h->ops)
928 xtables_error(PARAMETER_PROBLEM, "Unknown family");
930 h->portid = mnl_socket_get_portid(h->nl);
931 h->tables = builtin_tables_lookup(family);
932 h->cache = &h->__cache[0];
933 h->family = family;
935 INIT_LIST_HEAD(&h->obj_list);
936 INIT_LIST_HEAD(&h->err_list);
937 INIT_LIST_HEAD(&h->cmd_list);
938 INIT_LIST_HEAD(&h->cache_req.chain_list);
940 return 0;
943 void nft_fini(struct nft_handle *h)
945 struct list_head *pos, *n;
947 list_for_each_safe(pos, n, &h->cmd_list)
948 nft_cmd_free(list_entry(pos, struct nft_cmd, head));
950 list_for_each_safe(pos, n, &h->obj_list)
951 batch_obj_del(h, list_entry(pos, struct obj_update, head));
953 list_for_each_safe(pos, n, &h->err_list)
954 mnl_err_list_free(list_entry(pos, struct mnl_err, head));
956 nft_release_cache(h);
957 mnl_socket_close(h->nl);
960 static void nft_chain_print_debug(struct nft_handle *h,
961 struct nftnl_chain *c, struct nlmsghdr *nlh)
963 if (h->verbose > 1) {
964 nftnl_chain_fprintf(stdout, c, 0, 0);
965 fprintf(stdout, "\n");
967 if (h->verbose > 2)
968 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
969 sizeof(struct nfgenmsg));
972 static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
973 const char *table, const char *chain,
974 int policy,
975 const struct xt_counters *counters)
977 static const struct xt_counters zero = {};
978 struct nftnl_chain *c;
979 const struct builtin_table *_t;
980 const struct builtin_chain *_c;
982 _t = nft_table_builtin_find(h, table);
983 if (!_t) {
984 errno = ENXIO;
985 return NULL;
988 /* if this built-in table does not exists, create it */
989 nft_xt_builtin_init(h, table, chain);
991 _c = nft_chain_builtin_find(_t, chain);
992 if (_c != NULL) {
993 /* This is a built-in chain */
994 c = nft_chain_builtin_alloc(h->family, _t->name, _c, policy);
995 if (c == NULL)
996 return NULL;
997 } else {
998 errno = ENOENT;
999 return NULL;
1002 if (!counters)
1003 counters = &zero;
1004 nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, counters->bcnt);
1005 nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, counters->pcnt);
1007 return c;
1010 int nft_chain_set(struct nft_handle *h, const char *table,
1011 const char *chain, const char *policy,
1012 const struct xt_counters *counters)
1014 struct nftnl_chain *c = NULL;
1016 nft_fn = nft_chain_set;
1018 if (strcmp(policy, "DROP") == 0)
1019 c = nft_chain_new(h, table, chain, NF_DROP, counters);
1020 else if (strcmp(policy, "ACCEPT") == 0)
1021 c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
1022 else if (strcmp(policy, "-") == 0)
1023 c = nft_chain_new(h, table, chain, -1, counters);
1024 else
1025 errno = EINVAL;
1027 if (c == NULL)
1028 return 0;
1030 if (!batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c))
1031 return 0;
1033 /* the core expects 1 for success and 0 for error */
1034 return 1;
1037 static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
1039 void *info;
1041 nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
1042 nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
1044 info = xtables_calloc(1, m->u.match_size);
1045 memcpy(info, m->data, m->u.match_size - sizeof(*m));
1046 nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
1048 return 0;
1051 static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
1053 struct xt_rateinfo *rinfo = (void *)m->data;
1054 static const uint32_t mult[] = {
1055 XT_LIMIT_SCALE*24*60*60, /* day */
1056 XT_LIMIT_SCALE*60*60, /* hour */
1057 XT_LIMIT_SCALE*60, /* min */
1058 XT_LIMIT_SCALE, /* sec */
1060 struct nftnl_expr *expr;
1061 int i;
1063 expr = nftnl_expr_alloc("limit");
1064 if (!expr)
1065 return -ENOMEM;
1067 for (i = 1; i < ARRAY_SIZE(mult); i++) {
1068 if (rinfo->avg > mult[i] ||
1069 mult[i] / rinfo->avg < mult[i] % rinfo->avg)
1070 break;
1073 nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_TYPE, NFT_LIMIT_PKTS);
1074 nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_FLAGS, 0);
1076 nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_RATE,
1077 mult[i - 1] / rinfo->avg);
1078 nftnl_expr_set_u64(expr, NFTNL_EXPR_LIMIT_UNIT,
1079 mult[i - 1] / XT_LIMIT_SCALE);
1081 nftnl_expr_set_u32(expr, NFTNL_EXPR_LIMIT_BURST, rinfo->burst);
1083 nftnl_rule_add_expr(r, expr);
1084 return 0;
1087 static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
1088 uint32_t flags, uint32_t key_type,
1089 uint32_t key_len, uint32_t size)
1091 static uint32_t set_id = 0;
1092 struct nftnl_set *s;
1093 struct nft_cmd *cmd;
1095 s = nftnl_set_alloc();
1096 if (!s)
1097 return NULL;
1099 nftnl_set_set_u32(s, NFTNL_SET_FAMILY, h->family);
1100 nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
1101 nftnl_set_set_str(s, NFTNL_SET_NAME, "__set%d");
1102 nftnl_set_set_u32(s, NFTNL_SET_ID, ++set_id);
1103 nftnl_set_set_u32(s, NFTNL_SET_FLAGS,
1104 NFT_SET_ANONYMOUS | NFT_SET_CONSTANT | flags);
1105 nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, key_type);
1106 nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
1107 nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
1109 cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false);
1110 if (!cmd) {
1111 nftnl_set_free(s);
1112 return NULL;
1114 cmd->obj.set = s;
1116 return s;
1119 static struct nftnl_expr *
1120 __gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint8_t reg)
1122 struct nftnl_expr *e = nftnl_expr_alloc("payload");
1124 if (!e)
1125 return NULL;
1127 nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
1128 nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
1129 nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
1130 nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, reg);
1132 return e;
1135 static struct nftnl_expr *
1136 gen_payload(struct nft_handle *h, uint32_t base, uint32_t offset, uint32_t len,
1137 uint8_t *dreg)
1139 struct nftnl_expr *e;
1140 uint8_t reg;
1142 reg = NFT_REG_1;
1143 e = __gen_payload(base, offset, len, reg);
1144 *dreg = reg;
1146 return e;
1149 static struct nftnl_expr *
1150 gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
1152 struct nftnl_expr *e = nftnl_expr_alloc("lookup");
1154 if (!e)
1155 return NULL;
1156 nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
1157 nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
1158 nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SET_ID, set_id);
1159 nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_FLAGS, flags);
1160 return e;
1163 /* from nftables:include/datatype.h, TYPE_BITS */
1164 #define CONCAT_TYPE_BITS 6
1166 /* from nftables:include/datatype.h, enum datatypes */
1167 #define NFT_DATATYPE_IPADDR 7
1168 #define NFT_DATATYPE_ETHERADDR 9
1170 static int __add_nft_among(struct nft_handle *h, const char *table,
1171 struct nftnl_rule *r, struct nft_among_pair *pairs,
1172 int cnt, bool dst, bool inv, bool ip)
1174 uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN;
1175 /* { !dst, dst } */
1176 static const int eth_addr_off[] = {
1177 offsetof(struct ether_header, ether_shost),
1178 offsetof(struct ether_header, ether_dhost)
1180 static const int ip_addr_off[] = {
1181 offsetof(struct iphdr, saddr),
1182 offsetof(struct iphdr, daddr)
1184 struct nftnl_expr *e;
1185 struct nftnl_set *s;
1186 uint32_t flags = 0;
1187 uint8_t reg;
1188 int idx = 0;
1190 if (ip) {
1191 type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
1192 len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
1193 len &= ~(NETLINK_ALIGN - 1);
1194 flags = NFT_SET_INTERVAL | NFT_SET_CONCAT;
1197 s = add_anon_set(h, table, flags, type, len, cnt);
1198 if (!s)
1199 return -ENOMEM;
1200 set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
1202 if (ip) {
1203 uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) };
1205 nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT,
1206 field_len, sizeof(field_len));
1209 for (idx = 0; idx < cnt; idx++) {
1210 struct nftnl_set_elem *elem = nftnl_set_elem_alloc();
1212 if (!elem)
1213 return -ENOMEM;
1214 nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY,
1215 &pairs[idx], len);
1216 if (ip) {
1217 struct in_addr tmp = pairs[idx].in;
1219 if (tmp.s_addr == INADDR_ANY)
1220 pairs[idx].in.s_addr = INADDR_BROADCAST;
1221 nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END,
1222 &pairs[idx], len);
1223 pairs[idx].in = tmp;
1225 nftnl_set_elem_add(s, elem);
1228 e = gen_payload(h, NFT_PAYLOAD_LL_HEADER,
1229 eth_addr_off[dst], ETH_ALEN, &reg);
1230 if (!e)
1231 return -ENOMEM;
1232 nftnl_rule_add_expr(r, e);
1234 if (ip) {
1235 reg = nft_get_next_reg(reg, ETH_ALEN);
1236 e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
1237 sizeof(struct in_addr), reg);
1238 if (!e)
1239 return -ENOMEM;
1240 nftnl_rule_add_expr(r, e);
1243 reg = NFT_REG_1;
1244 e = gen_lookup(reg, "__set%d", set_id, inv);
1245 if (!e)
1246 return -ENOMEM;
1247 nftnl_rule_add_expr(r, e);
1249 return 0;
1252 static int add_nft_among(struct nft_handle *h,
1253 struct nftnl_rule *r, struct xt_entry_match *m)
1255 struct nft_among_data *data = (struct nft_among_data *)m->data;
1256 const char *table = nftnl_rule_get(r, NFTNL_RULE_TABLE);
1258 if ((data->src.cnt && data->src.ip) ||
1259 (data->dst.cnt && data->dst.ip)) {
1260 uint16_t eth_p_ip = htons(ETH_P_IP);
1261 uint8_t reg;
1263 add_meta(h, r, NFT_META_PROTOCOL, &reg);
1264 add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2, reg);
1267 if (data->src.cnt)
1268 __add_nft_among(h, table, r, data->pairs, data->src.cnt,
1269 false, data->src.inv, data->src.ip);
1270 if (data->dst.cnt)
1271 __add_nft_among(h, table, r, data->pairs + data->src.cnt,
1272 data->dst.cnt, true, data->dst.inv,
1273 data->dst.ip);
1274 return 0;
1277 static int expr_gen_range_cmp16(struct nftnl_rule *r,
1278 uint16_t lo,
1279 uint16_t hi,
1280 bool invert, uint8_t reg)
1282 struct nftnl_expr *e;
1284 if (lo == hi) {
1285 add_cmp_u16(r, htons(lo), invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg);
1286 return 0;
1289 if (lo == 0 && hi < 0xffff) {
1290 add_cmp_u16(r, htons(hi) , invert ? NFT_CMP_GT : NFT_CMP_LTE, reg);
1291 return 0;
1294 e = nftnl_expr_alloc("range");
1295 if (!e)
1296 return -ENOMEM;
1298 nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_SREG, reg);
1299 nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_OP, invert ? NFT_RANGE_NEQ : NFT_RANGE_EQ);
1301 lo = htons(lo);
1302 nftnl_expr_set(e, NFTNL_EXPR_RANGE_FROM_DATA, &lo, sizeof(lo));
1303 hi = htons(hi);
1304 nftnl_expr_set(e, NFTNL_EXPR_RANGE_TO_DATA, &hi, sizeof(hi));
1306 nftnl_rule_add_expr(r, e);
1307 return 0;
1310 static int add_nft_tcpudp(struct nft_handle *h,struct nftnl_rule *r,
1311 uint16_t src[2], bool invert_src,
1312 uint16_t dst[2], bool invert_dst)
1314 struct nftnl_expr *expr;
1315 uint8_t op = NFT_CMP_EQ;
1316 uint8_t reg;
1317 int ret;
1319 if (!invert_src &&
1320 src[0] && src[0] == src[1] &&
1321 dst[0] && dst[0] == dst[1] &&
1322 invert_src == invert_dst) {
1323 uint32_t combined = dst[0] | (src[0] << 16);
1325 expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 4, &reg);
1326 if (!expr)
1327 return -ENOMEM;
1329 nftnl_rule_add_expr(r, expr);
1330 add_cmp_u32(r, htonl(combined), op, reg);
1331 return 0;
1334 if (src[0] || src[1] < UINT16_MAX || invert_src) {
1335 expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 2, &reg);
1336 if (!expr)
1337 return -ENOMEM;
1339 nftnl_rule_add_expr(r, expr);
1340 ret = expr_gen_range_cmp16(r, src[0], src[1], invert_src, reg);
1341 if (ret)
1342 return ret;
1345 if (dst[0] || dst[1] < UINT16_MAX || invert_dst) {
1346 expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 2, 2, &reg);
1347 if (!expr)
1348 return -ENOMEM;
1350 nftnl_rule_add_expr(r, expr);
1351 ret = expr_gen_range_cmp16(r, dst[0], dst[1], invert_dst, reg);
1352 if (ret)
1353 return ret;
1356 return 0;
1359 /* without this, "iptables -A INPUT -m udp" is
1360 * turned into "iptables -A INPUT", which isn't
1361 * compatible with iptables-legacy behaviour.
1363 static bool udp_all_zero(const struct xt_udp *u)
1365 static const struct xt_udp zero = {
1366 .spts[1] = 0xffff,
1367 .dpts[1] = 0xffff,
1370 return memcmp(u, &zero, sizeof(*u)) == 0;
1373 static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r,
1374 struct xt_entry_match *m)
1376 struct xt_udp *udp = (void *)m->data;
1378 if (udp->invflags > XT_UDP_INV_MASK ||
1379 udp_all_zero(udp)) {
1380 struct nftnl_expr *expr = nftnl_expr_alloc("match");
1381 int ret;
1383 ret = __add_match(expr, m);
1384 nftnl_rule_add_expr(r, expr);
1385 return ret;
1388 if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_UDP)
1389 xtables_error(PARAMETER_PROBLEM, "UDP match requires '-p udp'");
1391 return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT,
1392 udp->dpts, udp->invflags & XT_UDP_INV_DSTPT);
1395 static int add_nft_tcpflags(struct nft_handle *h, struct nftnl_rule *r,
1396 uint8_t cmp, uint8_t mask,
1397 bool invert)
1399 struct nftnl_expr *e;
1400 uint8_t reg;
1402 e = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 13, 1, &reg);
1404 if (!e)
1405 return -ENOMEM;
1407 nftnl_rule_add_expr(r, e);
1409 add_bitwise(h, r, &mask, 1, reg, &reg);
1410 add_cmp_u8(r, cmp, invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg);
1412 return 0;
1415 static bool tcp_all_zero(const struct xt_tcp *t)
1417 static const struct xt_tcp zero = {
1418 .spts[1] = 0xffff,
1419 .dpts[1] = 0xffff,
1422 return memcmp(t, &zero, sizeof(*t)) == 0;
1425 static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r,
1426 struct xt_entry_match *m)
1428 static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT | XT_TCP_INV_FLAGS;
1429 struct xt_tcp *tcp = (void *)m->data;
1431 if (tcp->invflags & ~supported || tcp->option ||
1432 tcp_all_zero(tcp)) {
1433 struct nftnl_expr *expr = nftnl_expr_alloc("match");
1434 int ret;
1436 ret = __add_match(expr, m);
1437 nftnl_rule_add_expr(r, expr);
1438 return ret;
1441 if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_TCP)
1442 xtables_error(PARAMETER_PROBLEM, "TCP match requires '-p tcp'");
1444 if (tcp->flg_mask) {
1445 int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask,
1446 tcp->invflags & XT_TCP_INV_FLAGS);
1448 if (ret < 0)
1449 return ret;
1452 return add_nft_tcpudp(h, r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT,
1453 tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT);
1456 static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r,
1457 struct xt_entry_match *m)
1459 struct xt_mark_mtinfo1 *mark = (void *)m->data;
1460 uint8_t reg;
1461 int op;
1463 add_meta(h, r, NFT_META_MARK, &reg);
1464 if (mark->mask != 0xffffffff)
1465 add_bitwise(h, r, (uint8_t *)&mark->mask, sizeof(uint32_t), reg, &reg);
1467 if (mark->invert)
1468 op = NFT_CMP_NEQ;
1469 else
1470 op = NFT_CMP_EQ;
1472 add_cmp_u32(r, mark->mark, op, reg);
1474 return 0;
1477 int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
1478 struct nftnl_rule *r, struct xt_entry_match *m)
1480 struct nftnl_expr *expr;
1481 int ret;
1483 switch (ctx->command) {
1484 case NFT_COMPAT_RULE_APPEND:
1485 case NFT_COMPAT_RULE_INSERT:
1486 case NFT_COMPAT_RULE_REPLACE:
1487 if (!strcmp(m->u.user.name, "limit"))
1488 return add_nft_limit(r, m);
1489 else if (!strcmp(m->u.user.name, "among"))
1490 return add_nft_among(h, r, m);
1491 else if (!strcmp(m->u.user.name, "udp"))
1492 return add_nft_udp(h, r, m);
1493 else if (!strcmp(m->u.user.name, "tcp"))
1494 return add_nft_tcp(h, r, m);
1495 else if (!strcmp(m->u.user.name, "mark"))
1496 return add_nft_mark(h, r, m);
1497 break;
1498 default:
1499 break;
1502 expr = nftnl_expr_alloc("match");
1503 if (expr == NULL)
1504 return -ENOMEM;
1506 ret = __add_match(expr, m);
1507 nftnl_rule_add_expr(r, expr);
1509 return ret;
1512 static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
1514 void *info;
1516 nftnl_expr_set(e, NFTNL_EXPR_TG_NAME, t->u.user.name,
1517 strlen(t->u.user.name));
1518 nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
1520 info = xtables_calloc(1, t->u.target_size);
1521 memcpy(info, t->data, t->u.target_size - sizeof(*t));
1522 nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
1524 return 0;
1527 static int add_meta_nftrace(struct nftnl_rule *r)
1529 struct nftnl_expr *expr;
1531 expr = nftnl_expr_alloc("immediate");
1532 if (expr == NULL)
1533 return -ENOMEM;
1535 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
1536 nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
1537 nftnl_rule_add_expr(r, expr);
1539 expr = nftnl_expr_alloc("meta");
1540 if (expr == NULL)
1541 return -ENOMEM;
1542 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_NFTRACE);
1543 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
1545 nftnl_rule_add_expr(r, expr);
1546 return 0;
1549 int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
1551 struct nftnl_expr *expr;
1552 int ret;
1554 if (strcmp(t->u.user.name, "TRACE") == 0)
1555 return add_meta_nftrace(r);
1557 expr = nftnl_expr_alloc("target");
1558 if (expr == NULL)
1559 return -ENOMEM;
1561 ret = __add_target(expr, t);
1562 nftnl_rule_add_expr(r, expr);
1564 return ret;
1567 int add_jumpto(struct nftnl_rule *r, const char *name, int verdict)
1569 struct nftnl_expr *expr;
1571 expr = nftnl_expr_alloc("immediate");
1572 if (expr == NULL)
1573 return -ENOMEM;
1575 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
1576 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
1577 nftnl_expr_set_str(expr, NFTNL_EXPR_IMM_CHAIN, (char *)name);
1578 nftnl_rule_add_expr(r, expr);
1580 return 0;
1583 int add_verdict(struct nftnl_rule *r, int verdict)
1585 struct nftnl_expr *expr;
1587 expr = nftnl_expr_alloc("immediate");
1588 if (expr == NULL)
1589 return -ENOMEM;
1591 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
1592 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict);
1593 nftnl_rule_add_expr(r, expr);
1595 return 0;
1598 int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
1599 bool goto_set)
1601 int ret = 0;
1603 /* If no target at all, add nothing (default to continue) */
1604 if (cs->target != NULL) {
1605 /* Standard target? */
1606 if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
1607 ret = add_verdict(r, NF_ACCEPT);
1608 else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
1609 ret = add_verdict(r, NF_DROP);
1610 else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
1611 ret = add_verdict(r, NFT_RETURN);
1612 else if (strcmp(cs->jumpto, "NFLOG") == 0)
1613 ret = add_log(r, cs);
1614 else
1615 ret = add_target(r, cs->target->t);
1616 } else if (strlen(cs->jumpto) > 0) {
1617 /* Not standard, then it's a go / jump to chain */
1618 if (goto_set)
1619 ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
1620 else
1621 ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
1623 return ret;
1626 int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
1628 struct nftnl_expr *expr;
1629 struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
1631 expr = nftnl_expr_alloc("log");
1632 if (!expr)
1633 return -ENOMEM;
1635 if (info->prefix[0] != '\0')
1636 nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX,
1637 cs->target->udata);
1639 nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_GROUP, info->group);
1640 if (info->flags & XT_NFLOG_F_COPY_LEN)
1641 nftnl_expr_set_u32(expr, NFTNL_EXPR_LOG_SNAPLEN,
1642 info->len);
1643 if (info->threshold)
1644 nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_QTHRESHOLD,
1645 info->threshold);
1647 nftnl_rule_add_expr(r, expr);
1648 return 0;
1651 static void nft_rule_print_debug(struct nft_handle *h,
1652 struct nftnl_rule *r, struct nlmsghdr *nlh)
1654 if (h->verbose > 1) {
1655 nftnl_rule_fprintf(stdout, r, 0, 0);
1656 fprintf(stdout, "\n");
1658 if (h->verbose > 2)
1659 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
1660 sizeof(struct nfgenmsg));
1663 int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
1665 struct nftnl_expr *expr;
1667 expr = nftnl_expr_alloc("counter");
1668 if (expr == NULL)
1669 return -ENOMEM;
1671 nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_PACKETS, packets);
1672 nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_BYTES, bytes);
1674 nftnl_rule_add_expr(r, expr);
1676 return 0;
1679 enum udata_type {
1680 UDATA_TYPE_COMMENT,
1681 UDATA_TYPE_EBTABLES_POLICY,
1682 __UDATA_TYPE_MAX,
1684 #define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
1686 static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
1688 unsigned char *value = nftnl_udata_get(attr);
1689 uint8_t type = nftnl_udata_type(attr);
1690 uint8_t len = nftnl_udata_len(attr);
1691 const struct nftnl_udata **tb = data;
1693 switch (type) {
1694 case UDATA_TYPE_COMMENT:
1695 if (value[len - 1] != '\0')
1696 return -1;
1697 break;
1698 case UDATA_TYPE_EBTABLES_POLICY:
1699 break;
1700 default:
1701 return 0;
1703 tb[type] = attr;
1704 return 0;
1707 char *get_comment(const void *data, uint32_t data_len)
1709 const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
1711 if (nftnl_udata_parse(data, data_len, parse_udata_cb, tb) < 0)
1712 return NULL;
1714 if (!tb[UDATA_TYPE_COMMENT])
1715 return NULL;
1717 return nftnl_udata_get(tb[UDATA_TYPE_COMMENT]);
1720 void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
1722 nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, proto);
1723 nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS,
1724 inv ? NFT_RULE_COMPAT_F_INV : 0);
1727 struct nftnl_rule *
1728 nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *ctx,
1729 const char *chain, const char *table,
1730 struct iptables_command_state *cs)
1732 struct nftnl_rule *r;
1734 r = nftnl_rule_alloc();
1735 if (r == NULL)
1736 return NULL;
1738 nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family);
1739 nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
1740 nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
1742 if (h->ops->add(h, ctx, r, cs) < 0)
1743 goto err;
1745 return r;
1746 err:
1747 nftnl_rule_free(r);
1748 return NULL;
1752 nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
1753 struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
1755 struct nft_chain *c;
1756 int type;
1758 nft_xt_builtin_init(h, table, chain);
1760 nft_fn = nft_rule_append;
1762 if (ref) {
1763 nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
1764 nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
1765 type = NFT_COMPAT_RULE_REPLACE;
1766 } else
1767 type = NFT_COMPAT_RULE_APPEND;
1769 if (batch_rule_add(h, type, r) == NULL)
1770 return 0;
1772 if (verbose)
1773 h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
1775 if (ref) {
1776 nftnl_chain_rule_insert_at(r, ref);
1777 nftnl_chain_rule_del(ref);
1778 nftnl_rule_free(ref);
1779 } else {
1780 c = nft_chain_find(h, table, chain);
1781 if (!c) {
1782 errno = ENOENT;
1783 return 0;
1785 nftnl_chain_rule_add_tail(r, c->nftnl);
1788 return 1;
1791 bool
1792 nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
1793 enum nft_rule_print type, unsigned int format)
1795 const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
1796 struct iptables_command_state cs = {};
1797 struct nft_family_ops *ops = h->ops;
1798 bool ret;
1800 if (ops->init_cs)
1801 ops->init_cs(&cs);
1802 ret = ops->rule_to_cs(h, r, &cs);
1804 if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
1805 printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
1806 (unsigned long long)cs.counters.bcnt);
1808 /* print chain name */
1809 switch(type) {
1810 case NFT_RULE_APPEND:
1811 printf("-A %s", chain);
1812 break;
1813 case NFT_RULE_DEL:
1814 printf("-D %s", chain);
1815 break;
1818 if (ops->save_rule)
1819 ops->save_rule(&cs, format);
1821 if (ops->clear_cs)
1822 ops->clear_cs(&cs);
1824 return ret;
1827 bool nft_rule_is_policy_rule(struct nftnl_rule *r)
1829 const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
1830 const void *data;
1831 uint32_t len;
1833 if (!nftnl_rule_is_set(r, NFTNL_RULE_USERDATA))
1834 return false;
1836 data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
1837 if (nftnl_udata_parse(data, len, parse_udata_cb, tb) < 0)
1838 return NULL;
1840 if (!tb[UDATA_TYPE_EBTABLES_POLICY] ||
1841 nftnl_udata_get_u32(tb[UDATA_TYPE_EBTABLES_POLICY]) != 1)
1842 return false;
1844 return true;
1847 static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
1849 struct nftnl_rule *r = NULL, *last;
1850 struct nftnl_rule_iter *iter;
1852 iter = nftnl_rule_iter_create(c);
1853 if (!iter)
1854 return NULL;
1856 do {
1857 last = r;
1858 r = nftnl_rule_iter_next(iter);
1859 } while (r);
1860 nftnl_rule_iter_destroy(iter);
1862 return last;
1865 void nft_bridge_chain_postprocess(struct nft_handle *h,
1866 struct nftnl_chain *c)
1868 struct nftnl_rule *last = nft_chain_last_rule(c);
1869 struct nftnl_expr_iter *iter;
1870 struct nftnl_expr *expr;
1871 int verdict;
1873 if (!last || !nft_rule_is_policy_rule(last))
1874 return;
1876 iter = nftnl_expr_iter_create(last);
1877 if (!iter)
1878 return;
1880 expr = nftnl_expr_iter_next(iter);
1881 if (!expr ||
1882 strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)))
1883 goto out_iter;
1885 expr = nftnl_expr_iter_next(iter);
1886 if (!expr ||
1887 strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) ||
1888 !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT))
1889 goto out_iter;
1891 verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
1892 switch (verdict) {
1893 case NF_ACCEPT:
1894 case NF_DROP:
1895 break;
1896 default:
1897 goto out_iter;
1900 nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
1901 if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL)
1902 fprintf(stderr, "Failed to delete old policy rule\n");
1903 nftnl_chain_rule_del(last);
1904 out_iter:
1905 nftnl_expr_iter_destroy(iter);
1907 static const char *policy_name[NF_ACCEPT+1] = {
1908 [NF_DROP] = "DROP",
1909 [NF_ACCEPT] = "ACCEPT",
1912 int nft_chain_save(struct nft_chain *nc, void *data)
1914 struct nftnl_chain *c = nc->nftnl;
1915 struct nft_handle *h = data;
1916 const char *policy = NULL;
1918 if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) {
1919 policy = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
1920 } else if (nft_chain_builtin(c)) {
1921 policy = "ACCEPT";
1922 } else if (h->family == NFPROTO_BRIDGE) {
1923 policy = "RETURN";
1926 if (h->ops->save_chain)
1927 h->ops->save_chain(c, policy);
1929 return 0;
1932 struct nft_rule_save_data {
1933 struct nft_handle *h;
1934 unsigned int format;
1935 unsigned int errors;
1938 static int nft_rule_save_cb(struct nft_chain *c, void *data)
1940 struct nft_rule_save_data *d = data;
1941 struct nftnl_rule_iter *iter;
1942 struct nftnl_rule *r;
1944 iter = nftnl_rule_iter_create(c->nftnl);
1945 if (iter == NULL)
1946 return 1;
1948 r = nftnl_rule_iter_next(iter);
1949 while (r != NULL) {
1950 bool ret = nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format);
1952 if (!ret)
1953 d->errors++;
1955 r = nftnl_rule_iter_next(iter);
1958 nftnl_rule_iter_destroy(iter);
1959 return 0;
1962 int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
1964 struct nft_rule_save_data d = {
1965 .h = h,
1966 .format = format,
1968 int ret;
1970 ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d);
1972 if (ret == 0 && d.errors)
1973 xtables_error(VERSION_PROBLEM, "Cannot decode all rules provided by kernel");
1975 /* the core expects 1 for success and 0 for error */
1976 return ret == 0 ? 1 : 0;
1979 struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
1980 uint32_t set_id)
1982 struct obj_update *n;
1984 list_for_each_entry(n, &h->obj_list, head) {
1985 if (n->type == NFT_COMPAT_SET_ADD &&
1986 nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id)
1987 return n->set;
1990 return NULL;
1993 static void
1994 __nft_rule_flush(struct nft_handle *h, const char *table,
1995 const char *chain, bool verbose, bool skip)
1997 struct obj_update *obj;
1998 struct nftnl_rule *r;
2000 if (verbose && chain)
2001 fprintf(stdout, "Flushing chain `%s'\n", chain);
2003 r = nftnl_rule_alloc();
2004 if (r == NULL)
2005 return;
2007 nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
2008 if (chain)
2009 nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
2011 obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r);
2012 if (!obj) {
2013 nftnl_rule_free(r);
2014 return;
2017 obj->skip = skip;
2020 struct nft_rule_flush_data {
2021 struct nft_handle *h;
2022 const char *table;
2023 bool verbose;
2026 static int nft_rule_flush_cb(struct nft_chain *c, void *data)
2028 const char *chain = nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME);
2029 struct nft_rule_flush_data *d = data;
2031 batch_chain_flush(d->h, d->table, chain);
2032 __nft_rule_flush(d->h, d->table, chain, d->verbose, false);
2033 flush_rule_cache(d->h, d->table, c);
2034 return 0;
2037 int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
2038 bool verbose)
2040 struct nft_rule_flush_data d = {
2041 .h = h,
2042 .table = table,
2043 .verbose = verbose,
2045 struct nft_chain *c = NULL;
2046 int ret = 0;
2048 nft_fn = nft_rule_flush;
2050 if (chain || verbose)
2051 nft_xt_builtin_init(h, table, chain);
2052 else if (!nft_table_find(h, table))
2053 return 1;
2055 if (chain) {
2056 c = nft_chain_find(h, table, chain);
2057 if (!c) {
2058 errno = ENOENT;
2059 return 0;
2063 if (chain || !verbose) {
2064 batch_chain_flush(h, table, chain);
2065 __nft_rule_flush(h, table, chain, verbose, false);
2066 flush_rule_cache(h, table, c);
2067 return 1;
2070 nft_cache_sort_chains(h, table);
2072 ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
2074 /* the core expects 1 for success and 0 for error */
2075 return ret == 0 ? 1 : 0;
2078 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
2080 const struct builtin_table *t;
2081 struct nftnl_chain *c;
2083 nft_fn = nft_chain_user_add;
2085 t = nft_xt_builtin_table_init(h, table);
2087 if (nft_chain_exists(h, table, chain)) {
2088 errno = EEXIST;
2089 return 0;
2092 c = nftnl_chain_alloc();
2093 if (c == NULL)
2094 return 0;
2096 nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
2097 nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
2098 nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
2099 if (h->family == NFPROTO_BRIDGE)
2100 nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
2102 if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
2103 return 0;
2105 nft_cache_add_chain(h, t, c, false);
2107 /* the core expects 1 for success and 0 for error */
2108 return 1;
2111 int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
2113 const struct builtin_table *t;
2114 struct obj_update *obj;
2115 struct nftnl_chain *c;
2116 struct nft_chain *nc;
2117 bool created = false;
2119 t = nft_xt_builtin_table_init(h, table);
2121 nc = nft_chain_find(h, table, chain);
2122 if (!nc) {
2123 c = nftnl_chain_alloc();
2124 if (!c)
2125 return 0;
2127 nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
2128 nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
2129 nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
2130 created = true;
2132 nft_cache_add_chain(h, t, c, false);
2133 } else {
2134 c = nc->nftnl;
2136 /* If the chain should vanish meanwhile, kernel genid changes
2137 * and the transaction is refreshed enabling the chain add
2138 * object. With the handle still set, kernel interprets it as a
2139 * chain replace job and errors since it is not found anymore.
2141 nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
2144 __nft_rule_flush(h, table, chain, false, created);
2146 obj = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
2147 if (!obj)
2148 return 0;
2150 obj->skip = !created;
2152 /* the core expects 1 for success and 0 for error */
2153 return 1;
2156 /* From linux/netlink.h */
2157 #ifndef NLM_F_NONREC
2158 #define NLM_F_NONREC 0x100 /* Do not delete recursively */
2159 #endif
2161 struct chain_del_data {
2162 struct nft_handle *handle;
2163 const char *chain;
2164 bool verbose;
2167 static bool nft_may_delete_chain(struct nftnl_chain *c)
2169 if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY) &&
2170 nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY) != NF_ACCEPT)
2171 return false;
2173 return nftnl_rule_lookup_byindex(c, 0) == NULL;
2176 static int __nft_chain_del(struct nft_chain *nc, void *data)
2178 struct chain_del_data *d = data;
2179 struct nftnl_chain *c = nc->nftnl;
2180 struct nft_handle *h = d->handle;
2181 bool builtin = nft_chain_builtin(c);
2182 struct obj_update *obj;
2183 int ret = 0;
2185 if (d->verbose && !builtin)
2186 fprintf(stdout, "Deleting chain `%s'\n",
2187 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
2190 /* XXX This triggers a fast lookup from the kernel. */
2191 nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
2192 obj = batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c);
2193 if (!obj)
2194 return -1;
2196 if (builtin) {
2197 obj->skip = !nft_may_delete_chain(c);
2198 if (obj->skip && d->chain) {
2199 /* complain if explicitly requested */
2200 errno = EBUSY;
2201 ret = -1;
2203 *nc->base_slot = NULL;
2206 /* nftnl_chain is freed when deleting the batch object */
2207 nc->nftnl = NULL;
2209 nft_chain_list_del(nc);
2210 nft_chain_free(nc);
2211 return ret;
2214 int nft_chain_del(struct nft_handle *h, const char *chain,
2215 const char *table, bool verbose)
2217 struct chain_del_data d = {
2218 .handle = h,
2219 .chain = chain,
2220 .verbose = verbose,
2222 struct nft_chain *c;
2223 int ret = 0;
2225 nft_fn = nft_chain_del;
2227 if (chain) {
2228 c = nft_chain_find(h, table, chain);
2229 if (!c) {
2230 errno = ENOENT;
2231 return 0;
2234 ret = __nft_chain_del(c, &d);
2235 goto out;
2238 if (verbose)
2239 nft_cache_sort_chains(h, table);
2241 ret = nft_chain_foreach(h, table, __nft_chain_del, &d);
2242 out:
2243 /* the core expects 1 for success and 0 for error */
2244 return ret == 0 ? 1 : 0;
2247 bool nft_chain_exists(struct nft_handle *h,
2248 const char *table, const char *chain)
2250 const struct builtin_table *t = nft_table_builtin_find(h, table);
2252 /* xtables does not support custom tables */
2253 if (!t)
2254 return false;
2256 if (nft_chain_builtin_find(t, chain))
2257 return true;
2259 return !!nft_chain_find(h, table, chain);
2262 int nft_chain_user_rename(struct nft_handle *h,const char *chain,
2263 const char *table, const char *newname)
2265 struct nftnl_chain *c;
2266 struct nft_chain *nc;
2267 uint64_t handle;
2269 nft_fn = nft_chain_user_rename;
2271 if (nft_chain_exists(h, table, newname)) {
2272 errno = EEXIST;
2273 return 0;
2276 /* Find the old chain to be renamed */
2277 nc = nft_chain_find(h, table, chain);
2278 if (nc == NULL) {
2279 errno = ENOENT;
2280 return 0;
2282 handle = nftnl_chain_get_u64(nc->nftnl, NFTNL_CHAIN_HANDLE);
2284 /* Now prepare the new name for the chain */
2285 c = nftnl_chain_alloc();
2286 if (c == NULL)
2287 return 0;
2289 nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
2290 nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
2291 nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
2292 nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
2294 if (!batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c))
2295 return 0;
2297 /* the core expects 1 for success and 0 for error */
2298 return 1;
2301 bool nft_table_find(struct nft_handle *h, const char *tablename)
2303 const struct builtin_table *t;
2305 t = nft_table_builtin_find(h, tablename);
2306 return t ? h->cache->table[t->type].exists : false;
2309 int nft_for_each_table(struct nft_handle *h,
2310 int (*func)(struct nft_handle *h, const char *tablename, void *data),
2311 void *data)
2313 int i;
2315 for (i = 0; i < NFT_TABLE_MAX; i++) {
2316 if (h->tables[i].name == NULL)
2317 continue;
2319 if (!h->cache->table[h->tables[i].type].exists)
2320 continue;
2322 func(h, h->tables[i].name, data);
2325 return 0;
2328 static int __nft_table_flush(struct nft_handle *h, const char *table, bool exists)
2330 const struct builtin_table *_t;
2331 struct obj_update *obj;
2332 struct nftnl_table *t;
2334 t = nftnl_table_alloc();
2335 if (t == NULL)
2336 return -1;
2338 nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family);
2339 nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
2341 obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
2342 if (!obj) {
2343 nftnl_table_free(t);
2344 return -1;
2347 if (!exists)
2348 obj->skip = 1;
2350 _t = nft_table_builtin_find(h, table);
2351 assert(_t);
2352 h->cache->table[_t->type].exists = false;
2354 flush_chain_cache(h, table);
2356 return 0;
2359 int nft_table_flush(struct nft_handle *h, const char *table)
2361 const struct builtin_table *t;
2362 int ret = 0;
2364 nft_fn = nft_table_flush;
2366 t = nft_table_builtin_find(h, table);
2367 if (!t)
2368 return 0;
2370 ret = __nft_table_flush(h, table, h->cache->table[t->type].exists);
2372 /* the core expects 1 for success and 0 for error */
2373 return ret == 0 ? 1 : 0;
2376 static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
2378 struct obj_update *obj;
2380 nftnl_rule_list_del(r);
2382 if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE) &&
2383 !nftnl_rule_get_u32(r, NFTNL_RULE_ID))
2384 nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id);
2386 obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
2387 if (!obj) {
2388 nftnl_rule_free(r);
2389 return -1;
2391 return 1;
2394 static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
2395 struct iptables_command_state *cs)
2397 struct iptables_command_state this = {};
2398 bool ret = false, ret_this;
2400 if (h->ops->init_cs)
2401 h->ops->init_cs(&this);
2403 ret_this = h->ops->rule_to_cs(h, r, &this);
2405 DEBUGP("with ... ");
2406 #ifdef DEBUG_DEL
2407 nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
2408 #endif
2409 if (!ret_this)
2410 DEBUGP("Cannot convert rule: %d\n", ret_this);
2412 if (!h->ops->is_same(cs, &this))
2413 goto out;
2415 if (!compare_matches(cs->matches, this.matches)) {
2416 DEBUGP("Different matches\n");
2417 goto out;
2420 if (!compare_targets(cs->target, this.target)) {
2421 DEBUGP("Different target\n");
2422 goto out;
2425 if ((!cs->target || !this.target) &&
2426 strcmp(cs->jumpto, this.jumpto) != 0) {
2427 DEBUGP("Different verdict\n");
2428 goto out;
2431 ret = true;
2432 out:
2433 h->ops->clear_cs(&this);
2434 return ret;
2437 static struct nftnl_rule *
2438 nft_rule_find(struct nft_handle *h, struct nft_chain *nc,
2439 struct nftnl_rule *rule, int rulenum)
2441 struct iptables_command_state cs = {};
2442 struct nftnl_chain *c = nc->nftnl;
2443 struct nftnl_rule *r;
2444 struct nftnl_rule_iter *iter;
2445 bool found = false;
2447 if (rulenum >= 0)
2448 /* Delete by rule number case */
2449 return nftnl_rule_lookup_byindex(c, rulenum);
2451 iter = nftnl_rule_iter_create(c);
2452 if (iter == NULL)
2453 return 0;
2455 if (h->ops->init_cs)
2456 h->ops->init_cs(&cs);
2458 if (!h->ops->rule_to_cs(h, rule, &cs))
2459 return NULL;
2461 DEBUGP("comparing ... ");
2462 #ifdef DEBUG_DEL
2463 nft_rule_print_save(h, rule, NFT_RULE_APPEND, 0);
2464 #endif
2466 r = nftnl_rule_iter_next(iter);
2467 while (r != NULL) {
2468 found = nft_rule_cmp(h, r, &cs);
2469 if (found)
2470 break;
2471 r = nftnl_rule_iter_next(iter);
2474 nftnl_rule_iter_destroy(iter);
2476 h->ops->clear_cs(&cs);
2478 return found ? r : NULL;
2481 int nft_rule_check(struct nft_handle *h, const char *chain,
2482 const char *table, struct nftnl_rule *rule, bool verbose)
2484 struct nftnl_rule *r;
2485 struct nft_chain *c;
2487 nft_fn = nft_rule_check;
2489 c = nft_chain_find(h, table, chain);
2490 if (!c)
2491 goto fail_enoent;
2493 r = nft_rule_find(h, c, rule, -1);
2494 if (r == NULL)
2495 goto fail_enoent;
2497 if (verbose)
2498 h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
2500 return 1;
2501 fail_enoent:
2502 errno = ENOENT;
2503 return 0;
2506 int nft_rule_delete(struct nft_handle *h, const char *chain,
2507 const char *table, struct nftnl_rule *rule, bool verbose)
2509 int ret = 0;
2510 struct nftnl_rule *r;
2511 struct nft_chain *c;
2513 nft_fn = nft_rule_delete;
2515 c = nft_chain_find(h, table, chain);
2516 if (!c) {
2517 errno = ENOENT;
2518 return 0;
2521 r = nft_rule_find(h, c, rule, -1);
2522 if (r != NULL) {
2523 ret =__nft_rule_del(h, r);
2524 if (ret < 0)
2525 errno = ENOMEM;
2526 if (verbose)
2527 h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
2528 } else
2529 errno = ENOENT;
2531 return ret;
2534 static struct nftnl_rule *
2535 nft_rule_add(struct nft_handle *h, const char *chain,
2536 const char *table, struct nftnl_rule *r,
2537 struct nftnl_rule *ref, bool verbose)
2539 uint64_t ref_id;
2541 if (ref) {
2542 ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
2543 if (ref_id > 0) {
2544 nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, ref_id);
2545 DEBUGP("adding after rule handle %"PRIu64"\n", ref_id);
2546 } else {
2547 ref_id = nftnl_rule_get_u32(ref, NFTNL_RULE_ID);
2548 if (!ref_id) {
2549 ref_id = ++h->rule_id;
2550 nftnl_rule_set_u32(ref, NFTNL_RULE_ID, ref_id);
2552 nftnl_rule_set_u32(r, NFTNL_RULE_POSITION_ID, ref_id);
2553 DEBUGP("adding after rule ID %"PRIu64"\n", ref_id);
2557 if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
2558 return NULL;
2560 if (verbose)
2561 h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
2563 return r;
2566 int nft_rule_insert(struct nft_handle *h, const char *chain,
2567 const char *table, struct nftnl_rule *new_rule, int rulenum,
2568 bool verbose)
2570 struct nftnl_rule *r = NULL;
2571 struct nft_chain *c;
2573 nft_xt_builtin_init(h, table, chain);
2575 nft_fn = nft_rule_insert;
2577 c = nft_chain_find(h, table, chain);
2578 if (!c) {
2579 errno = ENOENT;
2580 goto err;
2583 if (rulenum > 0) {
2584 r = nft_rule_find(h, c, new_rule, rulenum);
2585 if (r == NULL) {
2586 /* special case: iptables allows to insert into
2587 * rule_count + 1 position.
2589 r = nft_rule_find(h, c, new_rule, rulenum - 1);
2590 if (r != NULL)
2591 return nft_rule_append(h, chain, table,
2592 new_rule, NULL, verbose);
2594 errno = E2BIG;
2595 goto err;
2599 new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose);
2600 if (!new_rule)
2601 goto err;
2603 if (r)
2604 nftnl_chain_rule_insert_at(new_rule, r);
2605 else
2606 nftnl_chain_rule_add(new_rule, c->nftnl);
2608 return 1;
2609 err:
2610 return 0;
2613 int nft_rule_delete_num(struct nft_handle *h, const char *chain,
2614 const char *table, int rulenum, bool verbose)
2616 int ret = 0;
2617 struct nftnl_rule *r;
2618 struct nft_chain *c;
2620 nft_fn = nft_rule_delete_num;
2622 c = nft_chain_find(h, table, chain);
2623 if (!c) {
2624 errno = ENOENT;
2625 return 0;
2628 r = nft_rule_find(h, c, NULL, rulenum);
2629 if (r != NULL) {
2630 DEBUGP("deleting rule by number %d\n", rulenum);
2631 ret = __nft_rule_del(h, r);
2632 if (ret < 0)
2633 errno = ENOMEM;
2634 } else
2635 errno = E2BIG;
2637 return ret;
2640 int nft_rule_replace(struct nft_handle *h, const char *chain,
2641 const char *table, struct nftnl_rule *rule,
2642 int rulenum, bool verbose)
2644 int ret = 0;
2645 struct nftnl_rule *r;
2646 struct nft_chain *c;
2648 nft_fn = nft_rule_replace;
2650 c = nft_chain_find(h, table, chain);
2651 if (!c) {
2652 errno = ENOENT;
2653 return 0;
2656 r = nft_rule_find(h, c, rule, rulenum);
2657 if (r != NULL) {
2658 DEBUGP("replacing rule with handle=%llu\n",
2659 (unsigned long long)
2660 nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
2662 ret = nft_rule_append(h, chain, table, rule, r, verbose);
2663 } else
2664 errno = E2BIG;
2666 return ret;
2669 static int nft_rule_change_counters(struct nft_handle *h, const char *table,
2670 const char *chain, struct nftnl_rule *rule,
2671 int rulenum, struct xt_counters *counters,
2672 uint8_t counter_op, bool verbose)
2674 struct iptables_command_state cs = {};
2675 struct nftnl_rule *r, *new_rule;
2676 struct nft_rule_ctx ctx = {
2677 .command = NFT_COMPAT_RULE_APPEND,
2679 struct nft_chain *c;
2681 nft_fn = nft_rule_change_counters;
2683 c = nft_chain_find(h, table, chain);
2684 if (!c) {
2685 errno = ENOENT;
2686 return 0;
2689 r = nft_rule_find(h, c, rule, rulenum);
2690 if (!r) {
2691 errno = E2BIG;
2692 return 0;
2695 DEBUGP("changing counters of rule with handle=%llu\n",
2696 (unsigned long long)
2697 nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
2699 if (h->ops->init_cs)
2700 h->ops->init_cs(&cs);
2701 h->ops->rule_to_cs(h, r, &cs);
2703 if (counter_op & CTR_OP_INC_PKTS)
2704 cs.counters.pcnt += counters->pcnt;
2705 else if (counter_op & CTR_OP_DEC_PKTS)
2706 cs.counters.pcnt -= counters->pcnt;
2707 else
2708 cs.counters.pcnt = counters->pcnt;
2710 if (counter_op & CTR_OP_INC_BYTES)
2711 cs.counters.bcnt += counters->bcnt;
2712 else if (counter_op & CTR_OP_DEC_BYTES)
2713 cs.counters.bcnt -= counters->bcnt;
2714 else
2715 cs.counters.bcnt = counters->bcnt;
2717 new_rule = nft_rule_new(h, &ctx, chain, table, &cs);
2718 h->ops->clear_cs(&cs);
2720 return nft_rule_append(h, chain, table, new_rule, r, verbose);
2723 static int
2724 __nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
2725 int rulenum, unsigned int format,
2726 void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
2727 unsigned int num, unsigned int format))
2729 struct nftnl_rule_iter *iter;
2730 struct nftnl_rule *r;
2731 int rule_ctr = 0;
2733 if (rulenum > 0) {
2734 r = nftnl_rule_lookup_byindex(c, rulenum - 1);
2735 if (!r)
2736 /* iptables-legacy returns 0 when listing for
2737 * valid chain but invalid rule number
2739 return 1;
2740 cb(h, r, rulenum, format);
2741 return 1;
2744 iter = nftnl_rule_iter_create(c);
2745 if (iter == NULL)
2746 return 0;
2748 r = nftnl_rule_iter_next(iter);
2749 while (r != NULL) {
2750 cb(h, r, ++rule_ctr, format);
2751 r = nftnl_rule_iter_next(iter);
2754 nftnl_rule_iter_destroy(iter);
2755 return 1;
2758 static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
2760 struct nftnl_rule_iter *iter;
2761 struct nftnl_rule *r;
2762 int rule_ctr = 0;
2764 iter = nftnl_rule_iter_create(c);
2765 if (iter == NULL)
2766 return 0;
2768 r = nftnl_rule_iter_next(iter);
2769 while (r != NULL) {
2770 rule_ctr++;
2771 r = nftnl_rule_iter_next(iter);
2774 nftnl_rule_iter_destroy(iter);
2775 return rule_ctr;
2778 static void __nft_print_header(struct nft_handle *h,
2779 struct nft_chain *nc, unsigned int format)
2781 struct nftnl_chain *c = nc->nftnl;
2782 const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
2783 uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
2784 uint32_t entries = nft_rule_count(h, c);
2785 struct xt_counters ctrs = {
2786 .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
2787 .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
2789 const char *pname = NULL;
2791 if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) &&
2792 nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
2793 pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
2795 h->ops->print_header(format, chain_name, pname,
2796 &ctrs, refs - entries, entries);
2799 struct nft_rule_list_cb_data {
2800 struct nft_handle *h;
2801 unsigned int format;
2802 int rulenum;
2803 bool found;
2804 bool save_fmt;
2805 void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
2806 unsigned int num, unsigned int format);
2809 static int nft_rule_list_cb(struct nft_chain *c, void *data)
2811 struct nft_rule_list_cb_data *d = data;
2813 if (!d->save_fmt) {
2814 if (d->found)
2815 printf("\n");
2816 d->found = true;
2818 __nft_print_header(d->h, c, d->format);
2821 return __nft_rule_list(d->h, c->nftnl, d->rulenum, d->format, d->cb);
2824 int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
2825 int rulenum, unsigned int format)
2827 const struct nft_family_ops *ops = h->ops;
2828 struct nft_rule_list_cb_data d = {
2829 .h = h,
2830 .format = format,
2831 .rulenum = rulenum,
2832 .cb = ops->print_rule,
2834 struct nft_chain *c;
2836 nft_xt_fake_builtin_chains(h, table, chain);
2837 nft_assert_table_compatible(h, table, chain);
2839 if (chain) {
2840 c = nft_chain_find(h, table, chain);
2841 if (!c) {
2842 errno = ENOENT;
2843 return 0;
2846 if (rulenum)
2847 d.save_fmt = true; /* skip header printing */
2848 else if (ops->print_table_header)
2849 ops->print_table_header(table);
2851 nft_rule_list_cb(c, &d);
2852 return 1;
2855 nft_cache_sort_chains(h, table);
2857 if (ops->print_table_header)
2858 ops->print_table_header(table);
2860 nft_chain_foreach(h, table, nft_rule_list_cb, &d);
2861 return 1;
2864 static void
2865 list_save(struct nft_handle *h, struct nftnl_rule *r,
2866 unsigned int num, unsigned int format)
2868 nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
2871 int nft_chain_foreach(struct nft_handle *h, const char *table,
2872 int (*cb)(struct nft_chain *c, void *data),
2873 void *data)
2875 const struct builtin_table *t;
2876 struct nft_chain_list *list;
2877 struct nft_chain *c, *c_bak;
2878 int i, ret;
2880 t = nft_table_builtin_find(h, table);
2881 if (!t)
2882 return -1;
2884 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
2885 c = h->cache->table[t->type].base_chains[i];
2886 if (!c)
2887 continue;
2889 ret = cb(c, data);
2890 if (ret < 0)
2891 return ret;
2894 list = h->cache->table[t->type].chains;
2895 if (!list)
2896 return -1;
2898 list_for_each_entry_safe(c, c_bak, &list->list, head) {
2899 ret = cb(c, data);
2900 if (ret < 0)
2901 return ret;
2903 return 0;
2906 static int nft_rule_list_chain_save(struct nft_chain *nc, void *data)
2908 struct nftnl_chain *c = nc->nftnl;
2909 const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
2910 uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
2911 int *counters = data;
2913 if (!nft_chain_builtin(c)) {
2914 printf("-N %s\n", chain_name);
2915 return 0;
2918 /* this is a base chain */
2920 printf("-P %s %s", chain_name, policy_name[policy]);
2921 if (*counters)
2922 printf(" -c %"PRIu64" %"PRIu64,
2923 nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
2924 nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES));
2925 printf("\n");
2926 return 0;
2929 int nft_rule_list_save(struct nft_handle *h, const char *chain,
2930 const char *table, int rulenum, int counters)
2932 struct nft_rule_list_cb_data d = {
2933 .h = h,
2934 .rulenum = rulenum,
2935 .save_fmt = true,
2936 .cb = list_save,
2938 struct nft_chain *c;
2939 int ret = 0;
2941 nft_xt_fake_builtin_chains(h, table, chain);
2942 nft_assert_table_compatible(h, table, chain);
2944 if (counters < 0)
2945 d.format = FMT_C_COUNTS;
2946 else if (counters == 0)
2947 d.format = FMT_NOCOUNTS;
2949 if (chain) {
2950 c = nft_chain_find(h, table, chain);
2951 if (!c) {
2952 errno = ENOENT;
2953 return 0;
2956 if (!rulenum)
2957 nft_rule_list_chain_save(c, &counters);
2959 return nft_rule_list_cb(c, &d);
2962 nft_cache_sort_chains(h, table);
2964 /* Dump policies and custom chains first */
2965 nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
2967 /* Now dump out rules in this table */
2968 ret = nft_chain_foreach(h, table, nft_rule_list_cb, &d);
2969 return ret == 0 ? 1 : 0;
2972 int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
2973 const char *table, int rulenum)
2975 struct iptables_command_state cs = {};
2976 struct nftnl_rule *r, *new_rule;
2977 struct nft_rule_ctx ctx = {
2978 .command = NFT_COMPAT_RULE_APPEND,
2980 struct nft_chain *c;
2982 nft_fn = nft_rule_delete;
2984 c = nft_chain_find(h, table, chain);
2985 if (!c) {
2986 errno = ENOENT;
2987 return 0;
2990 r = nft_rule_find(h, c, NULL, rulenum);
2991 if (r == NULL) {
2992 errno = ENOENT;
2993 return 0;
2996 if (h->ops->init_cs)
2997 h->ops->init_cs(&cs);
2998 h->ops->rule_to_cs(h, r, &cs);
2999 cs.counters.pcnt = cs.counters.bcnt = 0;
3000 new_rule = nft_rule_new(h, &ctx, chain, table, &cs);
3001 h->ops->clear_cs(&cs);
3003 if (!new_rule)
3004 return 1;
3006 return nft_rule_append(h, chain, table, new_rule, r, false);
3009 static void nft_table_print_debug(struct nft_handle *h,
3010 struct nftnl_table *t, struct nlmsghdr *nlh)
3012 if (h->verbose > 1) {
3013 nftnl_table_fprintf(stdout, t, 0, 0);
3014 fprintf(stdout, "\n");
3016 if (h->verbose > 2)
3017 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
3018 sizeof(struct nfgenmsg));
3021 static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
3022 uint16_t flags, uint32_t seq,
3023 struct nftnl_table *table)
3025 struct nlmsghdr *nlh;
3027 nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
3028 type, h->family, flags, seq);
3029 nftnl_table_nlmsg_build_payload(nlh, table);
3030 nft_table_print_debug(h, table, nlh);
3033 static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
3034 uint16_t flags, uint32_t seq,
3035 struct nftnl_set *set)
3037 struct nlmsghdr *nlh;
3039 nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
3040 type, h->family, flags, seq);
3041 nftnl_set_nlmsg_build_payload(nlh, set);
3044 static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type,
3045 uint16_t flags, uint32_t *seq,
3046 struct nftnl_set *set)
3048 struct nftnl_set_elems_iter *iter;
3049 struct nlmsghdr *nlh;
3051 iter = nftnl_set_elems_iter_create(set);
3052 if (!iter)
3053 return;
3055 while (nftnl_set_elems_iter_cur(iter)) {
3056 (*seq)++;
3057 mnl_nft_batch_continue(h->batch);
3058 nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
3059 type, h->family, flags, *seq);
3060 if (nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter) <= 0)
3061 break;
3063 nftnl_set_elems_iter_destroy(iter);
3065 if (h->verbose > 1) {
3066 fprintf(stdout, "set ");
3067 nftnl_set_fprintf(stdout, set, 0, 0);
3068 fprintf(stdout, "\n");
3072 static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
3073 uint16_t flags, uint32_t seq,
3074 struct nftnl_chain *chain)
3076 struct nlmsghdr *nlh;
3078 nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
3079 type, h->family, flags, seq);
3080 nftnl_chain_nlmsg_build_payload(nlh, chain);
3081 nft_chain_print_debug(h, chain, nlh);
3084 static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
3085 uint16_t flags, uint32_t seq,
3086 struct nftnl_rule *rule)
3088 struct nlmsghdr *nlh;
3090 nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
3091 type, h->family, flags, seq);
3092 nftnl_rule_nlmsg_build_payload(nlh, rule);
3093 nft_rule_print_debug(h, rule, nlh);
3096 static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
3098 switch (o->type) {
3099 case NFT_COMPAT_TABLE_ADD:
3100 case NFT_COMPAT_TABLE_FLUSH:
3101 nftnl_table_free(o->table);
3102 break;
3103 case NFT_COMPAT_CHAIN_ZERO:
3104 case NFT_COMPAT_CHAIN_USER_ADD:
3105 case NFT_COMPAT_CHAIN_ADD:
3106 break;
3107 case NFT_COMPAT_CHAIN_DEL:
3108 case NFT_COMPAT_CHAIN_USER_FLUSH:
3109 case NFT_COMPAT_CHAIN_UPDATE:
3110 case NFT_COMPAT_CHAIN_RENAME:
3111 nftnl_chain_free(o->chain);
3112 break;
3113 case NFT_COMPAT_RULE_APPEND:
3114 case NFT_COMPAT_RULE_INSERT:
3115 case NFT_COMPAT_RULE_REPLACE:
3116 case NFT_COMPAT_RULE_CHANGE_COUNTERS:
3117 break;
3118 case NFT_COMPAT_RULE_DELETE:
3119 case NFT_COMPAT_RULE_FLUSH:
3120 nftnl_rule_free(o->rule);
3121 break;
3122 case NFT_COMPAT_SET_ADD:
3123 nftnl_set_free(o->set);
3124 break;
3125 case NFT_COMPAT_RULE_LIST:
3126 case NFT_COMPAT_RULE_CHECK:
3127 case NFT_COMPAT_CHAIN_RESTORE:
3128 case NFT_COMPAT_RULE_SAVE:
3129 case NFT_COMPAT_RULE_ZERO:
3130 case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
3131 assert(0);
3132 break;
3134 h->obj_list_num--;
3135 list_del(&o->head);
3136 free(o);
3139 static void nft_refresh_transaction(struct nft_handle *h)
3141 const char *tablename, *chainname;
3142 const struct nft_chain *c;
3143 struct obj_update *n, *tmp;
3144 bool exists;
3146 h->error.lineno = 0;
3148 list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
3149 switch (n->type) {
3150 case NFT_COMPAT_TABLE_FLUSH:
3151 tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME);
3152 if (!tablename)
3153 continue;
3154 exists = nft_table_find(h, tablename);
3155 if (exists)
3156 n->skip = 0;
3157 else
3158 n->skip = 1;
3159 break;
3160 case NFT_COMPAT_CHAIN_USER_ADD:
3161 tablename = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_TABLE);
3162 if (!tablename)
3163 continue;
3165 chainname = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_NAME);
3166 if (!chainname)
3167 continue;
3169 if (!h->noflush)
3170 break;
3172 c = nft_chain_find(h, tablename, chainname);
3173 if (c) {
3174 n->skip = 1;
3175 } else if (!c) {
3176 n->skip = 0;
3178 break;
3179 case NFT_COMPAT_RULE_FLUSH:
3180 tablename = nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE);
3181 if (!tablename)
3182 continue;
3184 chainname = nftnl_rule_get_str(n->rule, NFTNL_RULE_CHAIN);
3185 if (!chainname)
3186 continue;
3188 n->skip = !nft_chain_find(h, tablename, chainname);
3189 break;
3190 case NFT_COMPAT_CHAIN_DEL:
3191 if (!nftnl_chain_get(n->chain, NFTNL_CHAIN_HOOKNUM))
3192 break;
3193 n->skip = !nft_may_delete_chain(n->chain);
3194 break;
3195 case NFT_COMPAT_CHAIN_ZERO:
3196 tablename = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_TABLE);
3197 if (!tablename)
3198 continue;
3200 chainname = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_NAME);
3201 if (!chainname)
3202 continue;
3204 n->skip = nftnl_chain_is_set(n->chain,
3205 NFTNL_CHAIN_HOOKNUM) &&
3206 !nft_chain_find(h, tablename, chainname);
3207 break;
3208 case NFT_COMPAT_TABLE_ADD:
3209 case NFT_COMPAT_CHAIN_ADD:
3210 case NFT_COMPAT_CHAIN_USER_FLUSH:
3211 case NFT_COMPAT_CHAIN_UPDATE:
3212 case NFT_COMPAT_CHAIN_RENAME:
3213 case NFT_COMPAT_RULE_APPEND:
3214 case NFT_COMPAT_RULE_INSERT:
3215 case NFT_COMPAT_RULE_REPLACE:
3216 case NFT_COMPAT_RULE_CHANGE_COUNTERS:
3217 case NFT_COMPAT_RULE_DELETE:
3218 case NFT_COMPAT_SET_ADD:
3219 case NFT_COMPAT_RULE_LIST:
3220 case NFT_COMPAT_RULE_CHECK:
3221 case NFT_COMPAT_CHAIN_RESTORE:
3222 case NFT_COMPAT_RULE_SAVE:
3223 case NFT_COMPAT_RULE_ZERO:
3224 case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
3225 break;
3230 static int nft_action(struct nft_handle *h, int action)
3232 struct obj_update *n, *tmp;
3233 struct mnl_err *err, *ne;
3234 unsigned int buflen, i, len;
3235 bool show_errors = true;
3236 char errmsg[1024];
3237 uint32_t seq;
3238 int ret = 0;
3240 retry:
3241 seq = 1;
3242 h->batch = mnl_batch_init();
3244 mnl_batch_begin(h->batch, h->nft_genid, seq++);
3245 h->nft_genid++;
3247 list_for_each_entry(n, &h->obj_list, head) {
3248 if (n->skip) {
3249 n->seq = 0;
3250 continue;
3253 n->seq = seq++;
3254 switch (n->type) {
3255 case NFT_COMPAT_TABLE_ADD:
3256 nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE,
3257 NLM_F_CREATE, n->seq,
3258 n->table);
3259 break;
3260 case NFT_COMPAT_TABLE_FLUSH:
3261 nft_compat_table_batch_add(h, NFT_MSG_DELTABLE,
3263 n->seq, n->table);
3264 break;
3265 case NFT_COMPAT_CHAIN_ADD:
3266 case NFT_COMPAT_CHAIN_ZERO:
3267 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
3268 NLM_F_CREATE, n->seq,
3269 n->chain);
3270 break;
3271 case NFT_COMPAT_CHAIN_USER_ADD:
3272 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
3273 NLM_F_EXCL, n->seq,
3274 n->chain);
3275 break;
3276 case NFT_COMPAT_CHAIN_DEL:
3277 nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
3278 NLM_F_NONREC, n->seq,
3279 n->chain);
3280 break;
3281 case NFT_COMPAT_CHAIN_USER_FLUSH:
3282 nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
3283 0, n->seq,
3284 n->chain);
3285 break;
3286 case NFT_COMPAT_CHAIN_UPDATE:
3287 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN,
3288 h->restore ?
3289 NLM_F_CREATE : 0,
3290 n->seq, n->chain);
3291 break;
3292 case NFT_COMPAT_CHAIN_RENAME:
3293 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0,
3294 n->seq, n->chain);
3295 break;
3296 case NFT_COMPAT_RULE_APPEND:
3297 nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
3298 NLM_F_CREATE | NLM_F_APPEND,
3299 n->seq, n->rule);
3300 break;
3301 case NFT_COMPAT_RULE_INSERT:
3302 nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
3303 NLM_F_CREATE, n->seq,
3304 n->rule);
3305 break;
3306 case NFT_COMPAT_RULE_REPLACE:
3307 case NFT_COMPAT_RULE_CHANGE_COUNTERS:
3308 nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
3309 NLM_F_CREATE | NLM_F_REPLACE,
3310 n->seq, n->rule);
3311 break;
3312 case NFT_COMPAT_RULE_DELETE:
3313 case NFT_COMPAT_RULE_FLUSH:
3314 nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
3315 n->seq, n->rule);
3316 break;
3317 case NFT_COMPAT_SET_ADD:
3318 nft_compat_set_batch_add(h, NFT_MSG_NEWSET,
3319 NLM_F_CREATE, n->seq, n->set);
3320 nft_compat_setelem_batch_add(h, NFT_MSG_NEWSETELEM,
3321 NLM_F_CREATE, &n->seq, n->set);
3322 seq = n->seq;
3323 break;
3324 case NFT_COMPAT_RULE_LIST:
3325 case NFT_COMPAT_RULE_CHECK:
3326 case NFT_COMPAT_CHAIN_RESTORE:
3327 case NFT_COMPAT_RULE_SAVE:
3328 case NFT_COMPAT_RULE_ZERO:
3329 case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
3330 assert(0);
3331 return 0;
3334 mnl_nft_batch_continue(h->batch);
3337 switch (action) {
3338 case NFT_COMPAT_COMMIT:
3339 mnl_batch_end(h->batch, seq++);
3340 break;
3341 case NFT_COMPAT_ABORT:
3342 break;
3345 errno = 0;
3346 ret = mnl_batch_talk(h, seq);
3347 if (ret && errno == ERESTART) {
3348 nft_rebuild_cache(h);
3350 nft_refresh_transaction(h);
3352 list_for_each_entry_safe(err, ne, &h->err_list, head)
3353 mnl_err_list_free(err);
3355 mnl_batch_reset(h->batch);
3356 goto retry;
3359 i = 0;
3360 buflen = sizeof(errmsg);
3362 list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
3363 list_for_each_entry_safe(err, ne, &h->err_list, head) {
3364 if (err->seqnum > n->seq)
3365 break;
3367 if (err->seqnum == n->seq && show_errors) {
3368 if (n->error.lineno == 0)
3369 show_errors = false;
3370 len = mnl_append_error(h, n, err, errmsg + i, buflen);
3371 if (len > 0 && len <= buflen) {
3372 buflen -= len;
3373 i += len;
3376 mnl_err_list_free(err);
3378 batch_obj_del(h, n);
3381 nft_release_cache(h);
3382 mnl_batch_reset(h->batch);
3384 if (i)
3385 xtables_error(RESOURCE_PROBLEM, "%s", errmsg);
3387 return ret == 0 ? 1 : 0;
3390 static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
3392 uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
3393 struct iptables_command_state cs = {
3394 .eb.bitmask = EBT_NOPROTO,
3396 struct nftnl_udata_buf *udata;
3397 struct nft_rule_ctx ctx = {
3398 .command = NFT_COMPAT_RULE_APPEND,
3400 struct nft_handle *h = data;
3401 struct nftnl_rule *r;
3402 const char *pname;
3404 if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
3405 return 0; /* ignore base chains */
3407 if (!nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
3408 return 0;
3410 nftnl_chain_unset(c, NFTNL_CHAIN_POLICY);
3412 switch (policy) {
3413 case NFT_RETURN:
3414 return 0; /* return policy is default for nft chains */
3415 case NF_ACCEPT:
3416 pname = "ACCEPT";
3417 break;
3418 case NF_DROP:
3419 pname = "DROP";
3420 break;
3421 default:
3422 return -1;
3425 command_jump(&cs, pname);
3427 r = nft_rule_new(h, &ctx, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
3428 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
3429 ebt_cs_clean(&cs);
3431 if (!r)
3432 return -1;
3434 udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
3435 if (!udata)
3436 goto err_free_rule;
3438 if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
3439 goto err_free_rule;
3441 nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
3442 nftnl_udata_buf_data(udata),
3443 nftnl_udata_buf_len(udata));
3444 nftnl_udata_buf_free(udata);
3446 if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
3447 goto err_free_rule;
3449 /* add the rule to chain so it is freed later */
3450 nftnl_chain_rule_add_tail(r, c);
3452 return 0;
3453 err_free_rule:
3454 nftnl_rule_free(r);
3455 return -1;
3458 int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
3459 const char *chain, const char *policy)
3461 struct nft_chain *c = nft_chain_find(h, table, chain);
3462 int pval;
3464 if (!c)
3465 return 0;
3467 if (!strcmp(policy, "DROP"))
3468 pval = NF_DROP;
3469 else if (!strcmp(policy, "ACCEPT"))
3470 pval = NF_ACCEPT;
3471 else if (!strcmp(policy, "RETURN"))
3472 pval = NFT_RETURN;
3473 else
3474 return 0;
3476 nftnl_chain_set_u32(c->nftnl, NFTNL_CHAIN_POLICY, pval);
3477 return 1;
3480 static void nft_bridge_commit_prepare(struct nft_handle *h)
3482 const struct builtin_table *t;
3483 struct nft_chain_list *list;
3484 struct nft_chain *c;
3485 int i;
3487 for (i = 0; i < NFT_TABLE_MAX; i++) {
3488 t = &h->tables[i];
3490 if (!t->name)
3491 continue;
3493 list = h->cache->table[t->type].chains;
3494 if (!list)
3495 continue;
3497 list_for_each_entry(c, &list->list, head) {
3498 ebt_add_policy_rule(c->nftnl, h);
3503 static void assert_chain_exists(struct nft_handle *h,
3504 const char *table, const char *chain)
3506 if (chain && !nft_chain_exists(h, table, chain))
3507 xtables_error(PARAMETER_PROBLEM,
3508 "Chain '%s' does not exist", chain);
3511 static int nft_prepare(struct nft_handle *h)
3513 struct nft_cmd *cmd, *next;
3514 int ret = 1;
3516 nft_cache_build(h);
3518 list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
3519 h->error.lineno = cmd->error.lineno;
3521 switch (cmd->command) {
3522 case NFT_COMPAT_TABLE_FLUSH:
3523 ret = nft_table_flush(h, cmd->table);
3524 break;
3525 case NFT_COMPAT_CHAIN_USER_ADD:
3526 ret = nft_chain_user_add(h, cmd->chain, cmd->table);
3527 break;
3528 case NFT_COMPAT_CHAIN_DEL:
3529 ret = nft_chain_del(h, cmd->chain, cmd->table,
3530 cmd->verbose);
3531 break;
3532 case NFT_COMPAT_CHAIN_RESTORE:
3533 ret = nft_chain_restore(h, cmd->chain, cmd->table);
3534 break;
3535 case NFT_COMPAT_CHAIN_UPDATE:
3536 ret = nft_chain_set(h, cmd->table, cmd->chain,
3537 cmd->policy, &cmd->counters);
3538 break;
3539 case NFT_COMPAT_CHAIN_RENAME:
3540 ret = nft_chain_user_rename(h, cmd->chain, cmd->table,
3541 cmd->rename);
3542 break;
3543 case NFT_COMPAT_CHAIN_ZERO:
3544 ret = nft_chain_zero_counters(h, cmd->chain, cmd->table,
3545 cmd->verbose);
3546 break;
3547 case NFT_COMPAT_RULE_APPEND:
3548 assert_chain_exists(h, cmd->table, cmd->jumpto);
3549 ret = nft_rule_append(h, cmd->chain, cmd->table,
3550 cmd->obj.rule, NULL, cmd->verbose);
3551 break;
3552 case NFT_COMPAT_RULE_INSERT:
3553 assert_chain_exists(h, cmd->table, cmd->jumpto);
3554 ret = nft_rule_insert(h, cmd->chain, cmd->table,
3555 cmd->obj.rule, cmd->rulenum,
3556 cmd->verbose);
3557 break;
3558 case NFT_COMPAT_RULE_REPLACE:
3559 assert_chain_exists(h, cmd->table, cmd->jumpto);
3560 ret = nft_rule_replace(h, cmd->chain, cmd->table,
3561 cmd->obj.rule, cmd->rulenum,
3562 cmd->verbose);
3563 break;
3564 case NFT_COMPAT_RULE_DELETE:
3565 assert_chain_exists(h, cmd->table, cmd->jumpto);
3566 if (cmd->rulenum >= 0)
3567 ret = nft_rule_delete_num(h, cmd->chain,
3568 cmd->table,
3569 cmd->rulenum,
3570 cmd->verbose);
3571 else
3572 ret = nft_rule_delete(h, cmd->chain, cmd->table,
3573 cmd->obj.rule, cmd->verbose);
3574 break;
3575 case NFT_COMPAT_RULE_FLUSH:
3576 ret = nft_rule_flush(h, cmd->chain, cmd->table,
3577 cmd->verbose);
3578 break;
3579 case NFT_COMPAT_RULE_LIST:
3580 ret = nft_rule_list(h, cmd->chain, cmd->table,
3581 cmd->rulenum, cmd->format);
3582 break;
3583 case NFT_COMPAT_RULE_CHECK:
3584 assert_chain_exists(h, cmd->table, cmd->jumpto);
3585 ret = nft_rule_check(h, cmd->chain, cmd->table,
3586 cmd->obj.rule, cmd->verbose);
3587 break;
3588 case NFT_COMPAT_RULE_ZERO:
3589 ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
3590 cmd->rulenum);
3591 break;
3592 case NFT_COMPAT_RULE_SAVE:
3593 ret = nft_rule_list_save(h, cmd->chain, cmd->table,
3594 cmd->rulenum,
3595 cmd->counters_save);
3596 break;
3597 case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
3598 ret = ebt_set_user_chain_policy(h, cmd->table,
3599 cmd->chain, cmd->policy);
3600 break;
3601 case NFT_COMPAT_SET_ADD:
3602 nft_xt_builtin_table_init(h, cmd->table);
3603 batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
3604 ret = 1;
3605 break;
3606 case NFT_COMPAT_TABLE_ADD:
3607 case NFT_COMPAT_CHAIN_ADD:
3608 assert(0);
3609 return 0;
3610 case NFT_COMPAT_RULE_CHANGE_COUNTERS:
3611 ret = nft_rule_change_counters(h, cmd->table,
3612 cmd->chain,
3613 cmd->obj.rule,
3614 cmd->rulenum,
3615 &cmd->counters,
3616 cmd->counter_op,
3617 cmd->verbose);
3618 break;
3621 nft_cmd_free(cmd);
3623 if (ret == 0)
3624 return 0;
3627 return 1;
3630 int nft_commit(struct nft_handle *h)
3632 if (!nft_prepare(h))
3633 return 0;
3635 return nft_action(h, NFT_COMPAT_COMMIT);
3638 int nft_bridge_commit(struct nft_handle *h)
3640 if (!nft_prepare(h))
3641 return 0;
3643 nft_bridge_commit_prepare(h);
3645 return nft_action(h, NFT_COMPAT_COMMIT);
3648 int nft_abort(struct nft_handle *h)
3650 struct nft_cmd *cmd, *next;
3652 list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
3653 nft_cmd_free(cmd);
3655 return nft_action(h, NFT_COMPAT_ABORT);
3658 int nft_compatible_revision(const char *name, uint8_t rev, int opt)
3660 struct mnl_socket *nl;
3661 char buf[16536];
3662 struct nlmsghdr *nlh;
3663 uint32_t portid, seq, type = 0;
3664 uint32_t pf = AF_INET;
3665 int ret = 0;
3667 switch (opt) {
3668 case IPT_SO_GET_REVISION_MATCH:
3669 break;
3670 case IP6T_SO_GET_REVISION_MATCH:
3671 pf = AF_INET6;
3672 break;
3673 case IPT_SO_GET_REVISION_TARGET:
3674 type = 1;
3675 break;
3676 case IP6T_SO_GET_REVISION_TARGET:
3677 type = 1;
3678 pf = AF_INET6;
3679 break;
3680 default:
3681 /* No revision support (arp, ebtables), assume latest version ok */
3682 return 1;
3685 nlh = mnl_nlmsg_put_header(buf);
3686 nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
3687 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
3688 nlh->nlmsg_seq = seq = time(NULL);
3690 struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
3691 nfg->nfgen_family = pf;
3692 nfg->version = NFNETLINK_V0;
3693 nfg->res_id = 0;
3695 mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
3696 mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
3697 mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
3699 DEBUGP("requesting `%s' rev=%d type=%d via nft_compat\n",
3700 name, rev, type);
3702 nl = mnl_socket_open(NETLINK_NETFILTER);
3703 if (nl == NULL)
3704 return 0;
3706 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
3707 goto err;
3709 portid = mnl_socket_get_portid(nl);
3711 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
3712 goto err;
3714 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
3715 if (ret == -1)
3716 goto err;
3718 ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
3719 if (ret == -1)
3720 goto err;
3722 err:
3723 mnl_socket_close(nl);
3725 /* ignore EPERM and errors for revision 0 -
3726 * this is required for printing extension help texts as user, also
3727 * helps error messaging on unavailable kernel extension */
3728 if (ret < 0) {
3729 if (errno == EPERM)
3730 return 1;
3731 if (rev == 0) {
3732 fprintf(stderr,
3733 "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
3734 name);
3735 return 1;
3739 return ret < 0 ? 0 : 1;
3742 /* Translates errno numbers into more human-readable form than strerror. */
3743 const char *nft_strerror(int err)
3745 unsigned int i;
3746 static struct table_struct {
3747 void *fn;
3748 int err;
3749 const char *message;
3750 } table[] =
3752 { nft_chain_del, ENOTEMPTY, "Chain is not empty" },
3753 { nft_chain_del, EBUSY, "Directory not empty" },
3754 { nft_chain_del, EMLINK,
3755 "Can't delete chain with references left" },
3756 { nft_chain_user_add, EEXIST, "Chain already exists" },
3757 { nft_chain_user_rename, EEXIST, "File exists" },
3758 { nft_rule_insert, E2BIG, "Index of insertion too big" },
3759 { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" },
3760 { nft_rule_replace, E2BIG, "Index of replacement too big" },
3761 { nft_rule_delete_num, E2BIG, "Index of deletion too big" },
3762 /* { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
3763 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
3764 /* ENOENT for DELETE probably means no matching rule */
3765 { nft_rule_delete, ENOENT,
3766 "Bad rule (does a matching rule exist in that chain?)" },
3767 { nft_chain_set, ENOENT, "Bad built-in chain name" },
3768 { nft_chain_set, EINVAL, "Bad policy name" },
3769 { nft_chain_set, ENXIO, "Bad table name" },
3770 { NULL, ELOOP, "Loop found in table" },
3771 { NULL, EPERM, "Permission denied (you must be root)" },
3772 { NULL, 0, "Incompatible with this kernel" },
3773 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
3774 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
3775 { NULL, ENOMEM, "Memory allocation problem" },
3776 { NULL, ENOENT, "No chain/target/match by that name" },
3779 for (i = 0; i < ARRAY_SIZE(table); i++) {
3780 if ((!table[i].fn || table[i].fn == nft_fn)
3781 && table[i].err == err)
3782 return table[i].message;
3785 return strerror(err);
3788 static int l4proto_expr_get_dreg(struct nftnl_expr *e, uint32_t *dregp)
3790 const char *name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
3791 uint32_t poff = offsetof(struct iphdr, protocol);
3792 uint32_t pbase = NFT_PAYLOAD_NETWORK_HEADER;
3794 if (!strcmp(name, "payload") &&
3795 nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE) == pbase &&
3796 nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET) == poff &&
3797 nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN) == sizeof(uint8_t)) {
3798 *dregp = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
3799 return 0;
3801 if (!strcmp(name, "meta") &&
3802 nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) == NFT_META_L4PROTO) {
3803 *dregp = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
3804 return 0;
3806 return -1;
3809 static int recover_rule_compat(struct nftnl_rule *r)
3811 struct nftnl_expr_iter *iter;
3812 struct nftnl_expr *e;
3813 uint32_t reg;
3814 int ret = -1;
3816 iter = nftnl_expr_iter_create(r);
3817 if (!iter)
3818 return -1;
3820 next_expr:
3821 e = nftnl_expr_iter_next(iter);
3822 if (!e)
3823 goto out;
3825 /* may be 'ip protocol' or 'meta l4proto' with identical RHS */
3826 if (l4proto_expr_get_dreg(e, &reg) < 0)
3827 goto next_expr;
3829 e = nftnl_expr_iter_next(iter);
3830 if (!e)
3831 goto out;
3833 if (strcmp("cmp", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
3834 reg != nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG))
3835 goto next_expr;
3837 add_compat(r, nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA),
3838 nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ);
3839 ret = 0;
3840 out:
3841 nftnl_expr_iter_destroy(iter);
3842 return ret;
3845 struct chain_zero_data {
3846 struct nft_handle *handle;
3847 bool verbose;
3850 static int __nft_chain_zero_counters(struct nft_chain *nc, void *data)
3852 struct nftnl_chain *c = nc->nftnl;
3853 struct chain_zero_data *d = data;
3854 struct nft_handle *h = d->handle;
3855 struct nftnl_rule_iter *iter;
3856 struct nftnl_rule *r;
3857 struct obj_update *o;
3859 if (d->verbose)
3860 fprintf(stdout, "Zeroing chain `%s'\n",
3861 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
3863 if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
3864 /* zero base chain counters. */
3865 nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
3866 nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
3867 nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
3868 o = batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c);
3869 if (!o)
3870 return -1;
3871 /* may skip if it is a fake entry */
3872 o->skip = nc->fake;
3875 iter = nftnl_rule_iter_create(c);
3876 if (iter == NULL)
3877 return -1;
3879 r = nftnl_rule_iter_next(iter);
3880 while (r != NULL) {
3881 struct nftnl_expr_iter *ei;
3882 struct nftnl_expr *e;
3883 bool zero_needed;
3885 ei = nftnl_expr_iter_create(r);
3886 if (!ei)
3887 break;
3889 e = nftnl_expr_iter_next(ei);
3890 zero_needed = false;
3891 while (e != NULL) {
3892 const char *en = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
3894 if (strcmp(en, "counter") == 0 && (
3895 nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS) ||
3896 nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES))) {
3897 nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_PACKETS, 0);
3898 nftnl_expr_set_u64(e, NFTNL_EXPR_CTR_BYTES, 0);
3899 zero_needed = true;
3902 e = nftnl_expr_iter_next(ei);
3905 nftnl_expr_iter_destroy(ei);
3907 if (zero_needed) {
3909 * Unset RULE_POSITION for older kernels, we want to replace
3910 * rule based on its handle only.
3912 recover_rule_compat(r);
3913 nftnl_rule_unset(r, NFTNL_RULE_POSITION);
3914 if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) {
3915 nftnl_rule_iter_destroy(iter);
3916 return -1;
3919 r = nftnl_rule_iter_next(iter);
3922 nftnl_rule_iter_destroy(iter);
3923 return 0;
3926 int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
3927 const char *table, bool verbose)
3929 struct chain_zero_data d = {
3930 .handle = h,
3931 .verbose = verbose,
3933 struct nft_chain *c;
3934 int ret = 0;
3936 nft_xt_fake_builtin_chains(h, table, chain);
3938 if (chain) {
3939 c = nft_chain_find(h, table, chain);
3940 if (!c) {
3941 errno = ENOENT;
3942 return 0;
3945 ret = __nft_chain_zero_counters(c, &d);
3946 goto err;
3949 if (verbose)
3950 nft_cache_sort_chains(h, table);
3952 ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
3953 err:
3954 /* the core expects 1 for success and 0 for error */
3955 return ret == 0 ? 1 : 0;
3958 uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
3960 if (invflags & flag)
3961 return NFT_CMP_NEQ;
3963 return NFT_CMP_EQ;
3966 static const char *supported_exprs[] = {
3967 "match",
3968 "target",
3969 "payload",
3970 "meta",
3971 "cmp",
3972 "bitwise",
3973 "counter",
3974 "immediate",
3975 "lookup",
3976 "range",
3980 static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
3982 const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
3983 int i;
3985 for (i = 0; i < ARRAY_SIZE(supported_exprs); i++) {
3986 if (strcmp(supported_exprs[i], name) == 0)
3987 return 0;
3990 if (!strcmp(name, "limit") &&
3991 nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_TYPE) == NFT_LIMIT_PKTS &&
3992 nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
3993 return 0;
3995 if (!strcmp(name, "log") &&
3996 nftnl_expr_is_set(expr, NFTNL_EXPR_LOG_GROUP))
3997 return 0;
3999 return -1;
4002 static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
4004 return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
4007 static int nft_is_chain_compatible(struct nft_chain *nc, void *data)
4009 struct nftnl_chain *c = nc->nftnl;
4011 return nftnl_rule_foreach(c, nft_is_rule_compatible, NULL);
4014 bool nft_is_table_compatible(struct nft_handle *h,
4015 const char *table, const char *chain)
4017 if (chain) {
4018 struct nft_chain *c = nft_chain_find(h, table, chain);
4020 return !c || !nft_is_chain_compatible(c, h);
4023 return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
4026 bool nft_is_table_tainted(struct nft_handle *h, const char *table)
4028 const struct builtin_table *t = nft_table_builtin_find(h, table);
4030 return t ? h->cache->table[t->type].tainted : false;
4033 void nft_assert_table_compatible(struct nft_handle *h,
4034 const char *table, const char *chain)
4036 const char *pfx = "", *sfx = "";
4038 if (nft_is_table_compatible(h, table, chain)) {
4039 if (nft_is_table_tainted(h, table))
4040 printf("# Table `%s' contains incompatible base-chains, use 'nft' tool to list them.\n",
4041 table);
4042 return;
4045 if (chain) {
4046 pfx = "chain `";
4047 sfx = "' in ";
4048 } else {
4049 chain = "";
4051 xtables_error(OTHER_PROBLEM,
4052 "%s%s%stable `%s' is incompatible, use 'nft' tool.",
4053 pfx, chain, sfx, table);