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