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>
14 #include <sys/types.h>
15 #include <sys/socket.h>
18 #include <netdb.h> /* getprotobynumber */
25 #include <libiptc/libxtc.h>
26 #include <libiptc/xtcshared.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>
59 #include "xshared.h" /* proto_to_name */
60 #include "nft-cache.h"
61 #include "nft-shared.h"
62 #include "nft-bridge.h" /* EBT_NOPROTO */
66 int mnl_talk(struct nft_handle
*h
, struct nlmsghdr
*nlh
,
67 int (*cb
)(const struct nlmsghdr
*nlh
, void *data
),
73 if (mnl_socket_sendto(h
->nl
, nlh
, nlh
->nlmsg_len
) < 0)
76 ret
= mnl_socket_recvfrom(h
->nl
, buf
, sizeof(buf
));
78 ret
= mnl_cb_run(buf
, ret
, h
->seq
, h
->portid
, cb
, data
);
82 ret
= mnl_socket_recvfrom(h
->nl
, buf
, sizeof(buf
));
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
);
110 static void mnl_nft_batch_continue(struct nftnl_batch
*batch
)
112 int ret
= nftnl_batch_update(batch
);
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
);
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
);
142 struct list_head head
;
147 static void mnl_err_list_node_add(struct list_head
*err_list
, int error
,
150 struct mnl_err
*err
= xtables_malloc(sizeof(struct mnl_err
));
152 err
->seqnum
= seqnum
;
154 list_add_tail(&err
->head
, err_list
);
157 static void mnl_err_list_free(struct mnl_err
*err
)
159 list_del(&err
->head
);
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
)
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)
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
)
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)
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
),
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
];
220 struct timeval tv
= {
226 ret
= mnl_nft_socket_sendmsg(h
, numcmds
);
228 fprintf(stderr
, "sendmsg() failed: %s\n", strerror(errno
));
233 FD_SET(fd
, &readfds
);
235 /* receive and digest all the acknowledgments from the kernel. */
236 ret
= select(fd
+1, &readfds
, NULL
, NULL
, &tv
);
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
));
247 ret
= mnl_cb_run(rcv_buf
, ret
, 0, portid
, NULL
, NULL
);
248 /* Continue on error, make sure we get all acknowledgments */
250 mnl_err_list_node_add(&h
->err_list
, errno
,
255 ret
= select(fd
+1, &readfds
, NULL
, NULL
, &tv
);
260 FD_SET(fd
, &readfds
);
271 struct list_head head
;
272 enum obj_update_type type
:8;
276 struct nftnl_table
*table
;
277 struct nftnl_chain
*chain
;
278 struct nftnl_rule
*rule
;
279 struct nftnl_set
*set
;
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",
313 snprintf(errmsg
, sizeof(errmsg
), "\nline %u: %s failed (%s)",
314 o
->error
.lineno
, type_name
[o
->type
], strerror(err
->err
));
316 snprintf(errmsg
, sizeof(errmsg
), " %s failed (%s)",
317 type_name
[o
->type
], strerror(err
->err
));
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
));
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
));
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
));
345 nft_rule_print_save(h
, o
->rule
, NFT_RULE_APPEND
, FMT_NOCOUNTS
);
349 case NFT_COMPAT_SET_ADD
:
350 snprintf(tcr
, sizeof(tcr
), "set %s",
351 nftnl_set_get_str(o
->set
, NFTNL_SET_NAME
));
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
:
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
));
372 obj
->error
.lineno
= h
->error
.lineno
;
374 list_add_tail(&obj
->head
, &h
->obj_list
);
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
,
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
;
419 case NFT_COMPAT_RULE_APPEND
:
420 case NFT_COMPAT_RULE_INSERT
:
421 case NFT_COMPAT_RULE_REPLACE
:
422 case NFT_COMPAT_RULE_DELETE
:
429 strcmp(table
, nftnl_rule_get_str(r
, NFTNL_RULE_TABLE
)))
433 strcmp(chain
, nftnl_rule_get_str(r
, NFTNL_RULE_CHAIN
)))
436 batch_obj_del(h
, obj
);
440 static const struct builtin_table xtables_ipv4
[NFT_TABLE_MAX
] = {
443 .type
= NFT_TABLE_RAW
,
446 .name
= "PREROUTING",
448 .prio
= -300, /* NF_IP_PRI_RAW */
449 .hook
= NF_INET_PRE_ROUTING
,
454 .prio
= -300, /* NF_IP_PRI_RAW */
455 .hook
= NF_INET_LOCAL_OUT
,
459 [NFT_TABLE_MANGLE
] = {
461 .type
= NFT_TABLE_MANGLE
,
464 .name
= "PREROUTING",
466 .prio
= -150, /* NF_IP_PRI_MANGLE */
467 .hook
= NF_INET_PRE_ROUTING
,
472 .prio
= -150, /* NF_IP_PRI_MANGLE */
473 .hook
= NF_INET_LOCAL_IN
,
478 .prio
= -150, /* NF_IP_PRI_MANGLE */
479 .hook
= NF_INET_FORWARD
,
484 .prio
= -150, /* NF_IP_PRI_MANGLE */
485 .hook
= NF_INET_LOCAL_OUT
,
488 .name
= "POSTROUTING",
490 .prio
= -150, /* NF_IP_PRI_MANGLE */
491 .hook
= NF_INET_POST_ROUTING
,
495 [NFT_TABLE_FILTER
] = {
497 .type
= NFT_TABLE_FILTER
,
502 .prio
= 0, /* NF_IP_PRI_FILTER */
503 .hook
= NF_INET_LOCAL_IN
,
508 .prio
= 0, /* NF_IP_PRI_FILTER */
509 .hook
= NF_INET_FORWARD
,
514 .prio
= 0, /* NF_IP_PRI_FILTER */
515 .hook
= NF_INET_LOCAL_OUT
,
519 [NFT_TABLE_SECURITY
] = {
521 .type
= NFT_TABLE_SECURITY
,
526 .prio
= 150, /* NF_IP_PRI_SECURITY */
527 .hook
= NF_INET_LOCAL_IN
,
532 .prio
= 150, /* NF_IP_PRI_SECURITY */
533 .hook
= NF_INET_FORWARD
,
538 .prio
= 150, /* NF_IP_PRI_SECURITY */
539 .hook
= NF_INET_LOCAL_OUT
,
545 .type
= NFT_TABLE_NAT
,
548 .name
= "PREROUTING",
550 .prio
= -100, /* NF_IP_PRI_NAT_DST */
551 .hook
= NF_INET_PRE_ROUTING
,
556 .prio
= 100, /* NF_IP_PRI_NAT_SRC */
557 .hook
= NF_INET_LOCAL_IN
,
560 .name
= "POSTROUTING",
562 .prio
= 100, /* NF_IP_PRI_NAT_SRC */
563 .hook
= NF_INET_POST_ROUTING
,
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
] = {
580 .type
= NFT_TABLE_FILTER
,
585 .prio
= NF_IP_PRI_FILTER
,
591 .prio
= NF_IP_PRI_FILTER
,
598 #include <linux/netfilter_bridge.h>
600 static const struct builtin_table xtables_bridge
[NFT_TABLE_MAX
] = {
601 [NFT_TABLE_FILTER
] = {
603 .type
= NFT_TABLE_FILTER
,
608 .prio
= NF_BR_PRI_FILTER_BRIDGED
,
609 .hook
= NF_BR_LOCAL_IN
,
614 .prio
= NF_BR_PRI_FILTER_BRIDGED
,
615 .hook
= NF_BR_FORWARD
,
620 .prio
= NF_BR_PRI_FILTER_BRIDGED
,
621 .hook
= NF_BR_LOCAL_OUT
,
627 .type
= NFT_TABLE_NAT
,
630 .name
= "PREROUTING",
632 .prio
= NF_BR_PRI_NAT_DST_BRIDGED
,
633 .hook
= NF_BR_PRE_ROUTING
,
638 .prio
= NF_BR_PRI_NAT_DST_OTHER
,
639 .hook
= NF_BR_LOCAL_OUT
,
642 .name
= "POSTROUTING",
644 .prio
= NF_BR_PRI_NAT_SRC
,
645 .hook
= NF_BR_POST_ROUTING
,
649 [NFT_TABLE_BROUTE
] = {
651 .type
= NFT_TABLE_BROUTE
,
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
;
670 if (h
->cache
->table
[_t
->type
].exists
)
673 t
= nftnl_table_alloc();
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;
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();
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
);
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);
711 static void nft_chain_builtin_add(struct nft_handle
*h
,
712 const struct builtin_table
*table
,
713 const struct builtin_chain
*chain
,
716 struct nftnl_chain
*c
;
718 c
= nft_chain_builtin_alloc(h
->family
, table
->name
, chain
, NF_ACCEPT
);
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
)
734 for (i
= 0; i
< NFT_TABLE_MAX
; i
++) {
735 if (h
->tables
[i
].name
== NULL
)
738 if (strcmp(h
->tables
[i
].name
, table
) != 0)
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
)
755 for (i
=0; i
<NF_IP_NUMHOOKS
&& t
->chains
[i
].name
!= NULL
; i
++) {
756 if (strcmp(t
->chains
[i
].name
, chain
) != 0)
762 return found
? &t
->chains
[i
] : NULL
;
765 static void nft_chain_builtin_init(struct nft_handle
*h
,
766 const struct builtin_table
*table
)
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
);
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
);
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
;
792 t
= nft_table_builtin_find(h
, table
);
796 if (nft_table_builtin_add(h
, t
) < 0)
802 static int nft_xt_builtin_init(struct nft_handle
*h
, const char *table
,
805 const struct builtin_table
*t
;
806 const struct builtin_chain
*c
;
807 struct nft_chain
*nc
;
812 t
= nft_xt_builtin_table_init(h
, table
);
816 if (h
->cache_req
.level
< NFT_CL_CHAINS
)
820 nft_chain_builtin_init(h
, t
);
824 c
= nft_chain_builtin_find(t
, chain
);
828 nc
= h
->cache
->table
[t
->type
].base_chains
[c
->hook
];
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
);
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
;
854 t
= nft_table_builtin_find(h
, table
);
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
])
863 if (chain
&& strcmp(chain
, t
->chains
[i
].name
))
866 nft_chain_builtin_add(h
, t
, &t
->chains
[i
], true);
871 int nft_xt_fake_builtin_chains(struct nft_handle
*h
,
872 const char *table
, const char *chain
)
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
);
888 if (mnl_socket_bind(h
->nl
, 0, MNL_SOCKET_AUTOPID
) < 0)
891 h
->portid
= mnl_socket_get_portid(h
->nl
);
898 static const struct builtin_table
*builtin_tables_lookup(int family
)
907 return xtables_bridge
;
913 int nft_init(struct nft_handle
*h
, int family
)
915 memset(h
, 0, sizeof(*h
));
917 h
->nl
= mnl_socket_open(NETLINK_NETFILTER
);
921 if (mnl_socket_bind(h
->nl
, 0, MNL_SOCKET_AUTOPID
) < 0) {
922 mnl_socket_close(h
->nl
);
926 h
->ops
= nft_family_ops_lookup(family
);
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];
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
);
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");
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
,
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
);
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
);
993 /* This is a built-in chain */
994 c
= nft_chain_builtin_alloc(h
->family
, _t
->name
, _c
, policy
);
1004 nftnl_chain_set_u64(c
, NFTNL_CHAIN_BYTES
, counters
->bcnt
);
1005 nftnl_chain_set_u64(c
, NFTNL_CHAIN_PACKETS
, counters
->pcnt
);
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
);
1030 if (!batch_chain_add(h
, NFT_COMPAT_CHAIN_UPDATE
, c
))
1033 /* the core expects 1 for success and 0 for error */
1037 static int __add_match(struct nftnl_expr
*e
, struct xt_entry_match
*m
)
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
));
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
;
1063 expr
= nftnl_expr_alloc("limit");
1067 for (i
= 1; i
< ARRAY_SIZE(mult
); i
++) {
1068 if (rinfo
->avg
> mult
[i
] ||
1069 mult
[i
] / rinfo
->avg
< mult
[i
] % rinfo
->avg
)
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
);
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();
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);
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");
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
);
1135 static struct nftnl_expr
*
1136 gen_payload(struct nft_handle
*h
, uint32_t base
, uint32_t offset
, uint32_t len
,
1139 struct nftnl_expr
*e
;
1143 e
= __gen_payload(base
, offset
, len
, reg
);
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");
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
);
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
;
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
;
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
);
1200 set_id
= nftnl_set_get_u32(s
, NFTNL_SET_ID
);
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();
1214 nftnl_set_elem_set(elem
, NFTNL_SET_ELEM_KEY
,
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
,
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
, ®
);
1232 nftnl_rule_add_expr(r
, e
);
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
);
1240 nftnl_rule_add_expr(r
, e
);
1244 e
= gen_lookup(reg
, "__set%d", set_id
, inv
);
1247 nftnl_rule_add_expr(r
, e
);
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
);
1263 add_meta(h
, r
, NFT_META_PROTOCOL
, ®
);
1264 add_cmp_ptr(r
, NFT_CMP_EQ
, ð_p_ip
, 2, reg
);
1268 __add_nft_among(h
, table
, r
, data
->pairs
, data
->src
.cnt
,
1269 false, data
->src
.inv
, data
->src
.ip
);
1271 __add_nft_among(h
, table
, r
, data
->pairs
+ data
->src
.cnt
,
1272 data
->dst
.cnt
, true, data
->dst
.inv
,
1277 static int expr_gen_range_cmp16(struct nftnl_rule
*r
,
1280 bool invert
, uint8_t reg
)
1282 struct nftnl_expr
*e
;
1285 add_cmp_u16(r
, htons(lo
), invert
? NFT_CMP_NEQ
: NFT_CMP_EQ
, reg
);
1289 if (lo
== 0 && hi
< 0xffff) {
1290 add_cmp_u16(r
, htons(hi
) , invert
? NFT_CMP_GT
: NFT_CMP_LTE
, reg
);
1294 e
= nftnl_expr_alloc("range");
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
);
1302 nftnl_expr_set(e
, NFTNL_EXPR_RANGE_FROM_DATA
, &lo
, sizeof(lo
));
1304 nftnl_expr_set(e
, NFTNL_EXPR_RANGE_TO_DATA
, &hi
, sizeof(hi
));
1306 nftnl_rule_add_expr(r
, e
);
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
;
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, ®
);
1329 nftnl_rule_add_expr(r
, expr
);
1330 add_cmp_u32(r
, htonl(combined
), op
, reg
);
1334 if (src
[0] || src
[1] < UINT16_MAX
|| invert_src
) {
1335 expr
= gen_payload(h
, NFT_PAYLOAD_TRANSPORT_HEADER
, 0, 2, ®
);
1339 nftnl_rule_add_expr(r
, expr
);
1340 ret
= expr_gen_range_cmp16(r
, src
[0], src
[1], invert_src
, reg
);
1345 if (dst
[0] || dst
[1] < UINT16_MAX
|| invert_dst
) {
1346 expr
= gen_payload(h
, NFT_PAYLOAD_TRANSPORT_HEADER
, 2, 2, ®
);
1350 nftnl_rule_add_expr(r
, expr
);
1351 ret
= expr_gen_range_cmp16(r
, dst
[0], dst
[1], invert_dst
, reg
);
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
= {
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");
1383 ret
= __add_match(expr
, m
);
1384 nftnl_rule_add_expr(r
, expr
);
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
,
1399 struct nftnl_expr
*e
;
1402 e
= gen_payload(h
, NFT_PAYLOAD_TRANSPORT_HEADER
, 13, 1, ®
);
1407 nftnl_rule_add_expr(r
, e
);
1409 add_bitwise(h
, r
, &mask
, 1, reg
, ®
);
1410 add_cmp_u8(r
, cmp
, invert
? NFT_CMP_NEQ
: NFT_CMP_EQ
, reg
);
1415 static bool tcp_all_zero(const struct xt_tcp
*t
)
1417 static const struct xt_tcp zero
= {
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");
1436 ret
= __add_match(expr
, m
);
1437 nftnl_rule_add_expr(r
, expr
);
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
);
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
;
1463 add_meta(h
, r
, NFT_META_MARK
, ®
);
1464 if (mark
->mask
!= 0xffffffff)
1465 add_bitwise(h
, r
, (uint8_t *)&mark
->mask
, sizeof(uint32_t), reg
, ®
);
1472 add_cmp_u32(r
, mark
->mark
, op
, reg
);
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
;
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
);
1502 expr
= nftnl_expr_alloc("match");
1506 ret
= __add_match(expr
, m
);
1507 nftnl_rule_add_expr(r
, expr
);
1512 static int __add_target(struct nftnl_expr
*e
, struct xt_entry_target
*t
)
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
));
1527 static int add_meta_nftrace(struct nftnl_rule
*r
)
1529 struct nftnl_expr
*expr
;
1531 expr
= nftnl_expr_alloc("immediate");
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");
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
);
1549 int add_target(struct nftnl_rule
*r
, struct xt_entry_target
*t
)
1551 struct nftnl_expr
*expr
;
1554 if (strcmp(t
->u
.user
.name
, "TRACE") == 0)
1555 return add_meta_nftrace(r
);
1557 expr
= nftnl_expr_alloc("target");
1561 ret
= __add_target(expr
, t
);
1562 nftnl_rule_add_expr(r
, expr
);
1567 int add_jumpto(struct nftnl_rule
*r
, const char *name
, int verdict
)
1569 struct nftnl_expr
*expr
;
1571 expr
= nftnl_expr_alloc("immediate");
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
);
1583 int add_verdict(struct nftnl_rule
*r
, int verdict
)
1585 struct nftnl_expr
*expr
;
1587 expr
= nftnl_expr_alloc("immediate");
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
);
1598 int add_action(struct nftnl_rule
*r
, struct iptables_command_state
*cs
,
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
);
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 */
1619 ret
= add_jumpto(r
, cs
->jumpto
, NFT_GOTO
);
1621 ret
= add_jumpto(r
, cs
->jumpto
, NFT_JUMP
);
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");
1635 if (info
->prefix
[0] != '\0')
1636 nftnl_expr_set_str(expr
, NFTNL_EXPR_LOG_PREFIX
,
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
,
1643 if (info
->threshold
)
1644 nftnl_expr_set_u16(expr
, NFTNL_EXPR_LOG_QTHRESHOLD
,
1647 nftnl_rule_add_expr(r
, expr
);
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");
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");
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
);
1681 UDATA_TYPE_EBTABLES_POLICY
,
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
;
1694 case UDATA_TYPE_COMMENT
:
1695 if (value
[len
- 1] != '\0')
1698 case UDATA_TYPE_EBTABLES_POLICY
:
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)
1714 if (!tb
[UDATA_TYPE_COMMENT
])
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);
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();
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)
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
;
1758 nft_xt_builtin_init(h
, table
, chain
);
1760 nft_fn
= nft_rule_append
;
1763 nftnl_rule_set_u64(r
, NFTNL_RULE_HANDLE
,
1764 nftnl_rule_get_u64(ref
, NFTNL_RULE_HANDLE
));
1765 type
= NFT_COMPAT_RULE_REPLACE
;
1767 type
= NFT_COMPAT_RULE_APPEND
;
1769 if (batch_rule_add(h
, type
, r
) == NULL
)
1773 h
->ops
->print_rule(h
, r
, 0, FMT_PRINT_RULE
);
1776 nftnl_chain_rule_insert_at(r
, ref
);
1777 nftnl_chain_rule_del(ref
);
1778 nftnl_rule_free(ref
);
1780 c
= nft_chain_find(h
, table
, chain
);
1785 nftnl_chain_rule_add_tail(r
, c
->nftnl
);
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
;
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 */
1810 case NFT_RULE_APPEND
:
1811 printf("-A %s", chain
);
1814 printf("-D %s", chain
);
1819 ops
->save_rule(&cs
, format
);
1827 bool nft_rule_is_policy_rule(struct nftnl_rule
*r
)
1829 const struct nftnl_udata
*tb
[UDATA_TYPE_MAX
+ 1] = {};
1833 if (!nftnl_rule_is_set(r
, NFTNL_RULE_USERDATA
))
1836 data
= nftnl_rule_get_data(r
, NFTNL_RULE_USERDATA
, &len
);
1837 if (nftnl_udata_parse(data
, len
, parse_udata_cb
, tb
) < 0)
1840 if (!tb
[UDATA_TYPE_EBTABLES_POLICY
] ||
1841 nftnl_udata_get_u32(tb
[UDATA_TYPE_EBTABLES_POLICY
]) != 1)
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
);
1858 r
= nftnl_rule_iter_next(iter
);
1860 nftnl_rule_iter_destroy(iter
);
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
;
1873 if (!last
|| !nft_rule_is_policy_rule(last
))
1876 iter
= nftnl_expr_iter_create(last
);
1880 expr
= nftnl_expr_iter_next(iter
);
1882 strcmp("counter", nftnl_expr_get_str(expr
, NFTNL_EXPR_NAME
)))
1885 expr
= nftnl_expr_iter_next(iter
);
1887 strcmp("immediate", nftnl_expr_get_str(expr
, NFTNL_EXPR_NAME
)) ||
1888 !nftnl_expr_is_set(expr
, NFTNL_EXPR_IMM_VERDICT
))
1891 verdict
= nftnl_expr_get_u32(expr
, NFTNL_EXPR_IMM_VERDICT
);
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
);
1905 nftnl_expr_iter_destroy(iter
);
1907 static const char *policy_name
[NF_ACCEPT
+1] = {
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
)) {
1922 } else if (h
->family
== NFPROTO_BRIDGE
) {
1926 if (h
->ops
->save_chain
)
1927 h
->ops
->save_chain(c
, policy
);
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
);
1948 r
= nftnl_rule_iter_next(iter
);
1950 bool ret
= nft_rule_print_save(d
->h
, r
, NFT_RULE_APPEND
, d
->format
);
1955 r
= nftnl_rule_iter_next(iter
);
1958 nftnl_rule_iter_destroy(iter
);
1962 int nft_rule_save(struct nft_handle
*h
, const char *table
, unsigned int format
)
1964 struct nft_rule_save_data d
= {
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
,
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
)
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();
2007 nftnl_rule_set_str(r
, NFTNL_RULE_TABLE
, table
);
2009 nftnl_rule_set_str(r
, NFTNL_RULE_CHAIN
, chain
);
2011 obj
= batch_rule_add(h
, NFT_COMPAT_RULE_FLUSH
, r
);
2020 struct nft_rule_flush_data
{
2021 struct nft_handle
*h
;
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
);
2037 int nft_rule_flush(struct nft_handle
*h
, const char *chain
, const char *table
,
2040 struct nft_rule_flush_data d
= {
2045 struct nft_chain
*c
= NULL
;
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
))
2056 c
= nft_chain_find(h
, table
, chain
);
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
);
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
)) {
2092 c
= nftnl_chain_alloc();
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
))
2105 nft_cache_add_chain(h
, t
, c
, false);
2107 /* the core expects 1 for success and 0 for error */
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
);
2123 c
= nftnl_chain_alloc();
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
);
2132 nft_cache_add_chain(h
, t
, c
, false);
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
);
2150 obj
->skip
= !created
;
2152 /* the core expects 1 for success and 0 for error */
2156 /* From linux/netlink.h */
2157 #ifndef NLM_F_NONREC
2158 #define NLM_F_NONREC 0x100 /* Do not delete recursively */
2161 struct chain_del_data
{
2162 struct nft_handle
*handle
;
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
)
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
;
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
);
2197 obj
->skip
= !nft_may_delete_chain(c
);
2198 if (obj
->skip
&& d
->chain
) {
2199 /* complain if explicitly requested */
2203 *nc
->base_slot
= NULL
;
2206 /* nftnl_chain is freed when deleting the batch object */
2209 nft_chain_list_del(nc
);
2214 int nft_chain_del(struct nft_handle
*h
, const char *chain
,
2215 const char *table
, bool verbose
)
2217 struct chain_del_data d
= {
2222 struct nft_chain
*c
;
2225 nft_fn
= nft_chain_del
;
2228 c
= nft_chain_find(h
, table
, chain
);
2234 ret
= __nft_chain_del(c
, &d
);
2239 nft_cache_sort_chains(h
, table
);
2241 ret
= nft_chain_foreach(h
, table
, __nft_chain_del
, &d
);
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 */
2256 if (nft_chain_builtin_find(t
, chain
))
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
;
2269 nft_fn
= nft_chain_user_rename
;
2271 if (nft_chain_exists(h
, table
, newname
)) {
2276 /* Find the old chain to be renamed */
2277 nc
= nft_chain_find(h
, table
, chain
);
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();
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
))
2297 /* the core expects 1 for success and 0 for error */
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
),
2315 for (i
= 0; i
< NFT_TABLE_MAX
; i
++) {
2316 if (h
->tables
[i
].name
== NULL
)
2319 if (!h
->cache
->table
[h
->tables
[i
].type
].exists
)
2322 func(h
, h
->tables
[i
].name
, data
);
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();
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
);
2343 nftnl_table_free(t
);
2350 _t
= nft_table_builtin_find(h
, table
);
2352 h
->cache
->table
[_t
->type
].exists
= false;
2354 flush_chain_cache(h
, table
);
2359 int nft_table_flush(struct nft_handle
*h
, const char *table
)
2361 const struct builtin_table
*t
;
2364 nft_fn
= nft_table_flush
;
2366 t
= nft_table_builtin_find(h
, table
);
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
);
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 ... ");
2407 nft_rule_print_save(h
, r
, NFT_RULE_APPEND
, 0);
2410 DEBUGP("Cannot convert rule: %d\n", ret_this
);
2412 if (!h
->ops
->is_same(cs
, &this))
2415 if (!compare_matches(cs
->matches
, this.matches
)) {
2416 DEBUGP("Different matches\n");
2420 if (!compare_targets(cs
->target
, this.target
)) {
2421 DEBUGP("Different target\n");
2425 if ((!cs
->target
|| !this.target
) &&
2426 strcmp(cs
->jumpto
, this.jumpto
) != 0) {
2427 DEBUGP("Different verdict\n");
2433 h
->ops
->clear_cs(&this);
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
;
2448 /* Delete by rule number case */
2449 return nftnl_rule_lookup_byindex(c
, rulenum
);
2451 iter
= nftnl_rule_iter_create(c
);
2455 if (h
->ops
->init_cs
)
2456 h
->ops
->init_cs(&cs
);
2458 if (!h
->ops
->rule_to_cs(h
, rule
, &cs
))
2461 DEBUGP("comparing ... ");
2463 nft_rule_print_save(h
, rule
, NFT_RULE_APPEND
, 0);
2466 r
= nftnl_rule_iter_next(iter
);
2468 found
= nft_rule_cmp(h
, r
, &cs
);
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
);
2493 r
= nft_rule_find(h
, c
, rule
, -1);
2498 h
->ops
->print_rule(h
, r
, 0, FMT_PRINT_RULE
);
2506 int nft_rule_delete(struct nft_handle
*h
, const char *chain
,
2507 const char *table
, struct nftnl_rule
*rule
, bool verbose
)
2510 struct nftnl_rule
*r
;
2511 struct nft_chain
*c
;
2513 nft_fn
= nft_rule_delete
;
2515 c
= nft_chain_find(h
, table
, chain
);
2521 r
= nft_rule_find(h
, c
, rule
, -1);
2523 ret
=__nft_rule_del(h
, r
);
2527 h
->ops
->print_rule(h
, r
, 0, FMT_PRINT_RULE
);
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
)
2542 ref_id
= nftnl_rule_get_u64(ref
, NFTNL_RULE_HANDLE
);
2544 nftnl_rule_set_u64(r
, NFTNL_RULE_POSITION
, ref_id
);
2545 DEBUGP("adding after rule handle %"PRIu64
"\n", ref_id
);
2547 ref_id
= nftnl_rule_get_u32(ref
, NFTNL_RULE_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
))
2561 h
->ops
->print_rule(h
, r
, 0, FMT_PRINT_RULE
);
2566 int nft_rule_insert(struct nft_handle
*h
, const char *chain
,
2567 const char *table
, struct nftnl_rule
*new_rule
, int rulenum
,
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
);
2584 r
= nft_rule_find(h
, c
, new_rule
, rulenum
);
2586 /* special case: iptables allows to insert into
2587 * rule_count + 1 position.
2589 r
= nft_rule_find(h
, c
, new_rule
, rulenum
- 1);
2591 return nft_rule_append(h
, chain
, table
,
2592 new_rule
, NULL
, verbose
);
2599 new_rule
= nft_rule_add(h
, chain
, table
, new_rule
, r
, verbose
);
2604 nftnl_chain_rule_insert_at(new_rule
, r
);
2606 nftnl_chain_rule_add(new_rule
, c
->nftnl
);
2613 int nft_rule_delete_num(struct nft_handle
*h
, const char *chain
,
2614 const char *table
, int rulenum
, bool verbose
)
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
);
2628 r
= nft_rule_find(h
, c
, NULL
, rulenum
);
2630 DEBUGP("deleting rule by number %d\n", rulenum
);
2631 ret
= __nft_rule_del(h
, r
);
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
)
2645 struct nftnl_rule
*r
;
2646 struct nft_chain
*c
;
2648 nft_fn
= nft_rule_replace
;
2650 c
= nft_chain_find(h
, table
, chain
);
2656 r
= nft_rule_find(h
, c
, rule
, rulenum
);
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
);
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
);
2689 r
= nft_rule_find(h
, c
, rule
, rulenum
);
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
;
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
;
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
);
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
;
2734 r
= nftnl_rule_lookup_byindex(c
, rulenum
- 1);
2736 /* iptables-legacy returns 0 when listing for
2737 * valid chain but invalid rule number
2740 cb(h
, r
, rulenum
, format
);
2744 iter
= nftnl_rule_iter_create(c
);
2748 r
= nftnl_rule_iter_next(iter
);
2750 cb(h
, r
, ++rule_ctr
, format
);
2751 r
= nftnl_rule_iter_next(iter
);
2754 nftnl_rule_iter_destroy(iter
);
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
;
2764 iter
= nftnl_rule_iter_create(c
);
2768 r
= nftnl_rule_iter_next(iter
);
2771 r
= nftnl_rule_iter_next(iter
);
2774 nftnl_rule_iter_destroy(iter
);
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
;
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
;
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
= {
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
);
2840 c
= nft_chain_find(h
, table
, chain
);
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
);
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
);
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
),
2875 const struct builtin_table
*t
;
2876 struct nft_chain_list
*list
;
2877 struct nft_chain
*c
, *c_bak
;
2880 t
= nft_table_builtin_find(h
, table
);
2884 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
2885 c
= h
->cache
->table
[t
->type
].base_chains
[i
];
2894 list
= h
->cache
->table
[t
->type
].chains
;
2898 list_for_each_entry_safe(c
, c_bak
, &list
->list
, head
) {
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
);
2918 /* this is a base chain */
2920 printf("-P %s %s", chain_name
, policy_name
[policy
]);
2922 printf(" -c %"PRIu64
" %"PRIu64
,
2923 nftnl_chain_get_u64(c
, NFTNL_CHAIN_PACKETS
),
2924 nftnl_chain_get_u64(c
, NFTNL_CHAIN_BYTES
));
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
= {
2938 struct nft_chain
*c
;
2941 nft_xt_fake_builtin_chains(h
, table
, chain
);
2942 nft_assert_table_compatible(h
, table
, chain
);
2945 d
.format
= FMT_C_COUNTS
;
2946 else if (counters
== 0)
2947 d
.format
= FMT_NOCOUNTS
;
2950 c
= nft_chain_find(h
, table
, chain
);
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
);
2990 r
= nft_rule_find(h
, c
, NULL
, rulenum
);
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
);
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");
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
);
3055 while (nftnl_set_elems_iter_cur(iter
)) {
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)
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
)
3099 case NFT_COMPAT_TABLE_ADD
:
3100 case NFT_COMPAT_TABLE_FLUSH
:
3101 nftnl_table_free(o
->table
);
3103 case NFT_COMPAT_CHAIN_ZERO
:
3104 case NFT_COMPAT_CHAIN_USER_ADD
:
3105 case NFT_COMPAT_CHAIN_ADD
:
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
);
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
:
3118 case NFT_COMPAT_RULE_DELETE
:
3119 case NFT_COMPAT_RULE_FLUSH
:
3120 nftnl_rule_free(o
->rule
);
3122 case NFT_COMPAT_SET_ADD
:
3123 nftnl_set_free(o
->set
);
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
:
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
;
3146 h
->error
.lineno
= 0;
3148 list_for_each_entry_safe(n
, tmp
, &h
->obj_list
, head
) {
3150 case NFT_COMPAT_TABLE_FLUSH
:
3151 tablename
= nftnl_table_get_str(n
->table
, NFTNL_TABLE_NAME
);
3154 exists
= nft_table_find(h
, tablename
);
3160 case NFT_COMPAT_CHAIN_USER_ADD
:
3161 tablename
= nftnl_chain_get_str(n
->chain
, NFTNL_CHAIN_TABLE
);
3165 chainname
= nftnl_chain_get_str(n
->chain
, NFTNL_CHAIN_NAME
);
3172 c
= nft_chain_find(h
, tablename
, chainname
);
3179 case NFT_COMPAT_RULE_FLUSH
:
3180 tablename
= nftnl_rule_get_str(n
->rule
, NFTNL_RULE_TABLE
);
3184 chainname
= nftnl_rule_get_str(n
->rule
, NFTNL_RULE_CHAIN
);
3188 n
->skip
= !nft_chain_find(h
, tablename
, chainname
);
3190 case NFT_COMPAT_CHAIN_DEL
:
3191 if (!nftnl_chain_get(n
->chain
, NFTNL_CHAIN_HOOKNUM
))
3193 n
->skip
= !nft_may_delete_chain(n
->chain
);
3195 case NFT_COMPAT_CHAIN_ZERO
:
3196 tablename
= nftnl_chain_get_str(n
->chain
, NFTNL_CHAIN_TABLE
);
3200 chainname
= nftnl_chain_get_str(n
->chain
, NFTNL_CHAIN_NAME
);
3204 n
->skip
= nftnl_chain_is_set(n
->chain
,
3205 NFTNL_CHAIN_HOOKNUM
) &&
3206 !nft_chain_find(h
, tablename
, chainname
);
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
:
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;
3242 h
->batch
= mnl_batch_init();
3244 mnl_batch_begin(h
->batch
, h
->nft_genid
, seq
++);
3247 list_for_each_entry(n
, &h
->obj_list
, head
) {
3255 case NFT_COMPAT_TABLE_ADD
:
3256 nft_compat_table_batch_add(h
, NFT_MSG_NEWTABLE
,
3257 NLM_F_CREATE
, n
->seq
,
3260 case NFT_COMPAT_TABLE_FLUSH
:
3261 nft_compat_table_batch_add(h
, NFT_MSG_DELTABLE
,
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
,
3271 case NFT_COMPAT_CHAIN_USER_ADD
:
3272 nft_compat_chain_batch_add(h
, NFT_MSG_NEWCHAIN
,
3276 case NFT_COMPAT_CHAIN_DEL
:
3277 nft_compat_chain_batch_add(h
, NFT_MSG_DELCHAIN
,
3278 NLM_F_NONREC
, n
->seq
,
3281 case NFT_COMPAT_CHAIN_USER_FLUSH
:
3282 nft_compat_chain_batch_add(h
, NFT_MSG_DELCHAIN
,
3286 case NFT_COMPAT_CHAIN_UPDATE
:
3287 nft_compat_chain_batch_add(h
, NFT_MSG_NEWCHAIN
,
3292 case NFT_COMPAT_CHAIN_RENAME
:
3293 nft_compat_chain_batch_add(h
, NFT_MSG_NEWCHAIN
, 0,
3296 case NFT_COMPAT_RULE_APPEND
:
3297 nft_compat_rule_batch_add(h
, NFT_MSG_NEWRULE
,
3298 NLM_F_CREATE
| NLM_F_APPEND
,
3301 case NFT_COMPAT_RULE_INSERT
:
3302 nft_compat_rule_batch_add(h
, NFT_MSG_NEWRULE
,
3303 NLM_F_CREATE
, n
->seq
,
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
,
3312 case NFT_COMPAT_RULE_DELETE
:
3313 case NFT_COMPAT_RULE_FLUSH
:
3314 nft_compat_rule_batch_add(h
, NFT_MSG_DELRULE
, 0,
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
);
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
:
3334 mnl_nft_batch_continue(h
->batch
);
3338 case NFT_COMPAT_COMMIT
:
3339 mnl_batch_end(h
->batch
, seq
++);
3341 case NFT_COMPAT_ABORT
:
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
);
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
)
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
) {
3376 mnl_err_list_free(err
);
3378 batch_obj_del(h
, n
);
3381 nft_release_cache(h
);
3382 mnl_batch_reset(h
->batch
);
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
;
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
))
3410 nftnl_chain_unset(c
, NFTNL_CHAIN_POLICY
);
3414 return 0; /* return policy is default for nft chains */
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
);
3434 udata
= nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN
);
3438 if (!nftnl_udata_put_u32(udata
, UDATA_TYPE_EBTABLES_POLICY
, 1))
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
))
3449 /* add the rule to chain so it is freed later */
3450 nftnl_chain_rule_add_tail(r
, c
);
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
);
3467 if (!strcmp(policy
, "DROP"))
3469 else if (!strcmp(policy
, "ACCEPT"))
3471 else if (!strcmp(policy
, "RETURN"))
3476 nftnl_chain_set_u32(c
->nftnl
, NFTNL_CHAIN_POLICY
, pval
);
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
;
3487 for (i
= 0; i
< NFT_TABLE_MAX
; i
++) {
3493 list
= h
->cache
->table
[t
->type
].chains
;
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
;
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
);
3525 case NFT_COMPAT_CHAIN_USER_ADD
:
3526 ret
= nft_chain_user_add(h
, cmd
->chain
, cmd
->table
);
3528 case NFT_COMPAT_CHAIN_DEL
:
3529 ret
= nft_chain_del(h
, cmd
->chain
, cmd
->table
,
3532 case NFT_COMPAT_CHAIN_RESTORE
:
3533 ret
= nft_chain_restore(h
, cmd
->chain
, cmd
->table
);
3535 case NFT_COMPAT_CHAIN_UPDATE
:
3536 ret
= nft_chain_set(h
, cmd
->table
, cmd
->chain
,
3537 cmd
->policy
, &cmd
->counters
);
3539 case NFT_COMPAT_CHAIN_RENAME
:
3540 ret
= nft_chain_user_rename(h
, cmd
->chain
, cmd
->table
,
3543 case NFT_COMPAT_CHAIN_ZERO
:
3544 ret
= nft_chain_zero_counters(h
, cmd
->chain
, cmd
->table
,
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
);
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
,
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
,
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
,
3572 ret
= nft_rule_delete(h
, cmd
->chain
, cmd
->table
,
3573 cmd
->obj
.rule
, cmd
->verbose
);
3575 case NFT_COMPAT_RULE_FLUSH
:
3576 ret
= nft_rule_flush(h
, cmd
->chain
, cmd
->table
,
3579 case NFT_COMPAT_RULE_LIST
:
3580 ret
= nft_rule_list(h
, cmd
->chain
, cmd
->table
,
3581 cmd
->rulenum
, cmd
->format
);
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
);
3588 case NFT_COMPAT_RULE_ZERO
:
3589 ret
= nft_rule_zero_counters(h
, cmd
->chain
, cmd
->table
,
3592 case NFT_COMPAT_RULE_SAVE
:
3593 ret
= nft_rule_list_save(h
, cmd
->chain
, cmd
->table
,
3595 cmd
->counters_save
);
3597 case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE
:
3598 ret
= ebt_set_user_chain_policy(h
, cmd
->table
,
3599 cmd
->chain
, cmd
->policy
);
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
);
3606 case NFT_COMPAT_TABLE_ADD
:
3607 case NFT_COMPAT_CHAIN_ADD
:
3610 case NFT_COMPAT_RULE_CHANGE_COUNTERS
:
3611 ret
= nft_rule_change_counters(h
, cmd
->table
,
3630 int nft_commit(struct nft_handle
*h
)
3632 if (!nft_prepare(h
))
3635 return nft_action(h
, NFT_COMPAT_COMMIT
);
3638 int nft_bridge_commit(struct nft_handle
*h
)
3640 if (!nft_prepare(h
))
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
)
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
;
3662 struct nlmsghdr
*nlh
;
3663 uint32_t portid
, seq
, type
= 0;
3664 uint32_t pf
= AF_INET
;
3668 case IPT_SO_GET_REVISION_MATCH
:
3670 case IP6T_SO_GET_REVISION_MATCH
:
3673 case IPT_SO_GET_REVISION_TARGET
:
3676 case IP6T_SO_GET_REVISION_TARGET
:
3681 /* No revision support (arp, ebtables), assume latest version ok */
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
;
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",
3702 nl
= mnl_socket_open(NETLINK_NETFILTER
);
3706 if (mnl_socket_bind(nl
, 0, MNL_SOCKET_AUTOPID
) < 0)
3709 portid
= mnl_socket_get_portid(nl
);
3711 if (mnl_socket_sendto(nl
, nlh
, nlh
->nlmsg_len
) < 0)
3714 ret
= mnl_socket_recvfrom(nl
, buf
, sizeof(buf
));
3718 ret
= mnl_cb_run(buf
, ret
, seq
, portid
, NULL
, NULL
);
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 */
3733 "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
3739 return ret
< 0 ? 0 : 1;
3742 /* Translates errno numbers into more human-readable form than strerror. */
3743 const char *nft_strerror(int err
)
3746 static struct table_struct
{
3749 const char *message
;
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
);
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
);
3809 static int recover_rule_compat(struct nftnl_rule
*r
)
3811 struct nftnl_expr_iter
*iter
;
3812 struct nftnl_expr
*e
;
3816 iter
= nftnl_expr_iter_create(r
);
3821 e
= nftnl_expr_iter_next(iter
);
3825 /* may be 'ip protocol' or 'meta l4proto' with identical RHS */
3826 if (l4proto_expr_get_dreg(e
, ®
) < 0)
3829 e
= nftnl_expr_iter_next(iter
);
3833 if (strcmp("cmp", nftnl_expr_get_str(e
, NFTNL_EXPR_NAME
)) ||
3834 reg
!= nftnl_expr_get_u32(e
, NFTNL_EXPR_CMP_SREG
))
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
);
3841 nftnl_expr_iter_destroy(iter
);
3845 struct chain_zero_data
{
3846 struct nft_handle
*handle
;
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
;
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
);
3871 /* may skip if it is a fake entry */
3875 iter
= nftnl_rule_iter_create(c
);
3879 r
= nftnl_rule_iter_next(iter
);
3881 struct nftnl_expr_iter
*ei
;
3882 struct nftnl_expr
*e
;
3885 ei
= nftnl_expr_iter_create(r
);
3889 e
= nftnl_expr_iter_next(ei
);
3890 zero_needed
= false;
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);
3902 e
= nftnl_expr_iter_next(ei
);
3905 nftnl_expr_iter_destroy(ei
);
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
);
3919 r
= nftnl_rule_iter_next(iter
);
3922 nftnl_rule_iter_destroy(iter
);
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
= {
3933 struct nft_chain
*c
;
3936 nft_xt_fake_builtin_chains(h
, table
, chain
);
3939 c
= nft_chain_find(h
, table
, chain
);
3945 ret
= __nft_chain_zero_counters(c
, &d
);
3950 nft_cache_sort_chains(h
, table
);
3952 ret
= nft_chain_foreach(h
, table
, __nft_chain_zero_counters
, &d
);
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
)
3966 static const char *supported_exprs
[] = {
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
);
3985 for (i
= 0; i
< ARRAY_SIZE(supported_exprs
); i
++) {
3986 if (strcmp(supported_exprs
[i
], name
) == 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)
3995 if (!strcmp(name
, "log") &&
3996 nftnl_expr_is_set(expr
, NFTNL_EXPR_LOG_GROUP
))
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
)
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",
4051 xtables_error(OTHER_PROBLEM
,
4052 "%s%s%stable `%s' is incompatible, use 'nft' tool.",
4053 pfx
, chain
, sfx
, table
);