• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #include <assert.h>
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <xtables.h>
17 
18 #include <linux/netfilter/nf_tables.h>
19 
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/gen.h>
22 #include <libnftnl/set.h>
23 #include <libnftnl/table.h>
24 
25 #include "nft.h"
26 #include "nft-cache.h"
27 #include "nft-chain.h"
28 
cache_chain_list_insert(struct list_head * list,const char * name)29 static void cache_chain_list_insert(struct list_head *list, const char *name)
30 {
31 	struct cache_chain *pos = NULL, *new;
32 
33 	list_for_each_entry(pos, list, head) {
34 		int cmp = strcmp(pos->name, name);
35 
36 		if (!cmp)
37 			return;
38 		if (cmp > 0)
39 			break;
40 	}
41 
42 	new = xtables_malloc(sizeof(*new));
43 	new->name = strdup(name);
44 	list_add_tail(&new->head, pos ? &pos->head : list);
45 }
46 
nft_cache_level_set(struct nft_handle * h,int level,const struct nft_cmd * cmd)47 void nft_cache_level_set(struct nft_handle *h, int level,
48 			 const struct nft_cmd *cmd)
49 {
50 	struct nft_cache_req *req = &h->cache_req;
51 
52 	if (level > req->level)
53 		req->level = level;
54 
55 	if (!cmd || !cmd->table || req->all_chains)
56 		return;
57 
58 	if (!req->table)
59 		req->table = strdup(cmd->table);
60 	else
61 		assert(!strcmp(req->table, cmd->table));
62 
63 	if (!cmd->chain) {
64 		req->all_chains = true;
65 		return;
66 	}
67 
68 	cache_chain_list_insert(&req->chain_list, cmd->chain);
69 	if (cmd->rename)
70 		cache_chain_list_insert(&req->chain_list, cmd->rename);
71 	if (cmd->jumpto)
72 		cache_chain_list_insert(&req->chain_list, cmd->jumpto);
73 }
74 
genid_cb(const struct nlmsghdr * nlh,void * data)75 static int genid_cb(const struct nlmsghdr *nlh, void *data)
76 {
77 	uint32_t *genid = data;
78 	struct nftnl_gen *gen;
79 
80 	gen = nftnl_gen_alloc();
81 	if (!gen)
82 		return MNL_CB_ERROR;
83 
84 	if (nftnl_gen_nlmsg_parse(nlh, gen) < 0)
85 		goto out;
86 
87 	*genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID);
88 
89 	nftnl_gen_free(gen);
90 	return MNL_CB_STOP;
91 out:
92 	nftnl_gen_free(gen);
93 	return MNL_CB_ERROR;
94 }
95 
mnl_genid_get(struct nft_handle * h,uint32_t * genid)96 static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
97 {
98 	char buf[MNL_SOCKET_BUFFER_SIZE];
99 	struct nlmsghdr *nlh;
100 	int ret;
101 
102 	nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq);
103 	ret = mnl_talk(h, nlh, genid_cb, genid);
104 	if (ret == 0)
105 		return;
106 
107 	xtables_error(RESOURCE_PROBLEM,
108 		      "Could not fetch rule set generation id: %s\n", nft_strerror(errno));
109 }
110 
nftnl_table_list_cb(const struct nlmsghdr * nlh,void * data)111 static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
112 {
113 	struct nftnl_table *nftnl = nftnl_table_alloc();
114 	const struct builtin_table *t;
115 	struct nft_handle *h = data;
116 	const char *name;
117 
118 	if (!nftnl)
119 		return MNL_CB_OK;
120 
121 	if (nftnl_table_nlmsg_parse(nlh, nftnl) < 0)
122 		goto out;
123 
124 	name = nftnl_table_get_str(nftnl, NFTNL_TABLE_NAME);
125 	if (!name)
126 		goto out;
127 
128 	t = nft_table_builtin_find(h, name);
129 	if (!t)
130 		goto out;
131 
132 	h->cache->table[t->type].exists = true;
133 out:
134 	nftnl_table_free(nftnl);
135 	return MNL_CB_OK;
136 }
137 
fetch_table_cache(struct nft_handle * h)138 static int fetch_table_cache(struct nft_handle *h)
139 {
140 	struct nlmsghdr *nlh;
141 	char buf[16536];
142 	int i, ret;
143 
144 	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
145 					NLM_F_DUMP, h->seq);
146 
147 	ret = mnl_talk(h, nlh, nftnl_table_list_cb, h);
148 	if (ret < 0 && errno == EINTR)
149 		assert(nft_restart(h) >= 0);
150 
151 	for (i = 0; i < NFT_TABLE_MAX; i++) {
152 		enum nft_table_type type = h->tables[i].type;
153 
154 		if (!h->tables[i].name)
155 			continue;
156 
157 		h->cache->table[type].chains = nft_chain_list_alloc();
158 
159 		h->cache->table[type].sets = nftnl_set_list_alloc();
160 		if (!h->cache->table[type].sets)
161 			return 0;
162 	}
163 
164 	return 1;
165 }
166 
djb_hash(const char * key)167 static uint32_t djb_hash(const char *key)
168 {
169 	uint32_t i, hash = 5381;
170 
171 	for (i = 0; i < strlen(key); i++)
172 		hash = ((hash << 5) + hash) + key[i];
173 
174 	return hash;
175 }
176 
chain_name_hlist(struct nft_handle * h,const struct builtin_table * t,const char * chain)177 static struct hlist_head *chain_name_hlist(struct nft_handle *h,
178 					   const struct builtin_table *t,
179 					   const char *chain)
180 {
181 	int key = djb_hash(chain) % CHAIN_NAME_HSIZE;
182 
183 	return &h->cache->table[t->type].chains->names[key];
184 }
185 
186 struct nft_chain *
nft_chain_find(struct nft_handle * h,const char * table,const char * chain)187 nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
188 {
189 	const struct builtin_table *t;
190 	struct hlist_node *node;
191 	struct nft_chain *c;
192 
193 	t = nft_table_builtin_find(h, table);
194 	if (!t)
195 		return NULL;
196 
197 	hlist_for_each_entry(c, node, chain_name_hlist(h, t, chain), hnode) {
198 		if (!strcmp(nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME),
199 			    chain))
200 			return c;
201 	}
202 	return NULL;
203 }
204 
nft_cache_add_chain(struct nft_handle * h,const struct builtin_table * t,struct nftnl_chain * c)205 int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
206 			struct nftnl_chain *c)
207 {
208 	const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
209 	struct nft_chain *nc = nft_chain_alloc(c);
210 
211 	if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
212 		uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
213 
214 		if (hooknum >= NF_INET_NUMHOOKS) {
215 			nft_chain_free(nc);
216 			return -EINVAL;
217 		}
218 
219 		if (h->cache->table[t->type].base_chains[hooknum]) {
220 			nft_chain_free(nc);
221 			return -EEXIST;
222 		}
223 
224 		h->cache->table[t->type].base_chains[hooknum] = nc;
225 	} else {
226 		struct nft_chain_list *clist = h->cache->table[t->type].chains;
227 		struct list_head *pos = &clist->list;
228 		struct nft_chain *cur;
229 		const char *n;
230 
231 		list_for_each_entry(cur, &clist->list, head) {
232 			n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME);
233 			if (strcmp(cname, n) <= 0) {
234 				pos = &cur->head;
235 				break;
236 			}
237 		}
238 		list_add_tail(&nc->head, pos);
239 	}
240 	hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
241 	return 0;
242 }
243 
244 struct nftnl_chain_list_cb_data {
245 	struct nft_handle *h;
246 	const struct builtin_table *t;
247 };
248 
nftnl_chain_list_cb(const struct nlmsghdr * nlh,void * data)249 static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
250 {
251 	struct nftnl_chain_list_cb_data *d = data;
252 	const struct builtin_table *t = d->t;
253 	struct nft_handle *h = d->h;
254 	struct nftnl_chain *c;
255 	const char *tname;
256 
257 	c = nftnl_chain_alloc();
258 	if (c == NULL)
259 		goto err;
260 
261 	if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
262 		goto out;
263 
264 	tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
265 
266 	if (!t) {
267 		t = nft_table_builtin_find(h, tname);
268 		if (!t)
269 			goto out;
270 	} else if (strcmp(t->name, tname)) {
271 		goto out;
272 	}
273 
274 	if (nft_cache_add_chain(h, t, c))
275 		goto out;
276 
277 	return MNL_CB_OK;
278 out:
279 	nftnl_chain_free(c);
280 err:
281 	return MNL_CB_OK;
282 }
283 
284 struct nftnl_set_list_cb_data {
285 	struct nft_handle *h;
286 	const struct builtin_table *t;
287 };
288 
nftnl_set_list_cb(const struct nlmsghdr * nlh,void * data)289 static int nftnl_set_list_cb(const struct nlmsghdr *nlh, void *data)
290 {
291 	struct nftnl_set_list_cb_data *d = data;
292 	const struct builtin_table *t = d->t;
293 	struct nftnl_set_list *list;
294 	struct nft_handle *h = d->h;
295 	const char *tname, *sname;
296 	struct nftnl_set *s;
297 
298 	s = nftnl_set_alloc();
299 	if (s == NULL)
300 		return MNL_CB_OK;
301 
302 	if (nftnl_set_nlmsg_parse(nlh, s) < 0)
303 		goto out_free;
304 
305 	tname = nftnl_set_get_str(s, NFTNL_SET_TABLE);
306 
307 	if (!t)
308 		t = nft_table_builtin_find(h, tname);
309 	else if (strcmp(t->name, tname))
310 		goto out_free;
311 
312 	if (!t)
313 		goto out_free;
314 
315 	list = h->cache->table[t->type].sets;
316 	sname = nftnl_set_get_str(s, NFTNL_SET_NAME);
317 
318 	if (nftnl_set_list_lookup_byname(list, sname))
319 		goto out_free;
320 
321 	nftnl_set_list_add_tail(s, list);
322 
323 	return MNL_CB_OK;
324 out_free:
325 	nftnl_set_free(s);
326 	return MNL_CB_OK;
327 }
328 
set_elem_cb(const struct nlmsghdr * nlh,void * data)329 static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
330 {
331 	return nftnl_set_elems_nlmsg_parse(nlh, data) ? -1 : MNL_CB_OK;
332 }
333 
set_has_elements(struct nftnl_set * s)334 static bool set_has_elements(struct nftnl_set *s)
335 {
336 	struct nftnl_set_elems_iter *iter;
337 	bool ret = false;
338 
339 	iter = nftnl_set_elems_iter_create(s);
340 	if (iter) {
341 		ret = !!nftnl_set_elems_iter_cur(iter);
342 		nftnl_set_elems_iter_destroy(iter);
343 	}
344 	return ret;
345 }
346 
set_fetch_elem_cb(struct nftnl_set * s,void * data)347 static int set_fetch_elem_cb(struct nftnl_set *s, void *data)
348 {
349 	char buf[MNL_SOCKET_BUFFER_SIZE];
350 	struct nft_handle *h = data;
351 	struct nlmsghdr *nlh;
352 
353 	if (set_has_elements(s))
354 		return 0;
355 
356 	nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, h->family,
357 				    NLM_F_DUMP, h->seq);
358 	nftnl_set_elems_nlmsg_build_payload(nlh, s);
359 
360 	return mnl_talk(h, nlh, set_elem_cb, s);
361 }
362 
fetch_set_cache(struct nft_handle * h,const struct builtin_table * t,const char * set)363 static int fetch_set_cache(struct nft_handle *h,
364 			   const struct builtin_table *t, const char *set)
365 {
366 	struct nftnl_set_list_cb_data d = {
367 		.h = h,
368 		.t = t,
369 	};
370 	uint16_t flags = NLM_F_DUMP;
371 	struct nftnl_set *s = NULL;
372 	struct nlmsghdr *nlh;
373 	char buf[16536];
374 	int i, ret;
375 
376 	if (t) {
377 		s = nftnl_set_alloc();
378 		if (!s)
379 			return -1;
380 
381 		nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
382 
383 		if (set) {
384 			nftnl_set_set_str(s, NFTNL_SET_NAME, set);
385 			flags = NLM_F_ACK;
386 		}
387 	}
388 
389 	nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
390 					h->family, flags, h->seq);
391 
392 	if (s) {
393 		nftnl_set_nlmsg_build_payload(nlh, s);
394 		nftnl_set_free(s);
395 	}
396 
397 	ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
398 	if (ret < 0 && errno == EINTR) {
399 		assert(nft_restart(h) >= 0);
400 		return ret;
401 	}
402 
403 	if (t) {
404 		nftnl_set_list_foreach(h->cache->table[t->type].sets,
405 				       set_fetch_elem_cb, h);
406 	} else {
407 		for (i = 0; i < NFT_TABLE_MAX; i++) {
408 			enum nft_table_type type = h->tables[i].type;
409 
410 			if (!h->tables[i].name)
411 				continue;
412 
413 			nftnl_set_list_foreach(h->cache->table[type].sets,
414 					       set_fetch_elem_cb, h);
415 		}
416 	}
417 	return ret;
418 }
419 
__fetch_chain_cache(struct nft_handle * h,const struct builtin_table * t,const struct nftnl_chain * c)420 static int __fetch_chain_cache(struct nft_handle *h,
421 			       const struct builtin_table *t,
422 			       const struct nftnl_chain *c)
423 {
424 	struct nftnl_chain_list_cb_data d = {
425 		.h = h,
426 		.t = t,
427 	};
428 	char buf[16536];
429 	struct nlmsghdr *nlh;
430 	int ret;
431 
432 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
433 					  c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
434 	if (c)
435 		nftnl_chain_nlmsg_build_payload(nlh, c);
436 
437 	ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
438 	if (ret < 0 && errno == EINTR)
439 		assert(nft_restart(h) >= 0);
440 
441 	return ret;
442 }
443 
fetch_chain_cache(struct nft_handle * h,const struct builtin_table * t,struct list_head * chains)444 static int fetch_chain_cache(struct nft_handle *h,
445 			     const struct builtin_table *t,
446 			     struct list_head *chains)
447 {
448 	struct cache_chain *cc;
449 	struct nftnl_chain *c;
450 	int rc, ret = 0;
451 
452 	if (!chains)
453 		return __fetch_chain_cache(h, t, NULL);
454 
455 	assert(t);
456 
457 	c = nftnl_chain_alloc();
458 	if (!c)
459 		return -1;
460 
461 	nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
462 
463 	list_for_each_entry(cc, chains, head) {
464 		nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, cc->name);
465 		rc = __fetch_chain_cache(h, t, c);
466 		if (rc)
467 			ret = rc;
468 	}
469 
470 	nftnl_chain_free(c);
471 	return ret;
472 }
473 
nftnl_rule_list_cb(const struct nlmsghdr * nlh,void * data)474 static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
475 {
476 	struct nftnl_chain *c = data;
477 	struct nftnl_rule *r;
478 
479 	r = nftnl_rule_alloc();
480 	if (r == NULL)
481 		return MNL_CB_OK;
482 
483 	if (nftnl_rule_nlmsg_parse(nlh, r) < 0) {
484 		nftnl_rule_free(r);
485 		return MNL_CB_OK;
486 	}
487 
488 	nftnl_chain_rule_add_tail(r, c);
489 	return MNL_CB_OK;
490 }
491 
nft_rule_list_update(struct nft_chain * nc,void * data)492 static int nft_rule_list_update(struct nft_chain *nc, void *data)
493 {
494 	struct nftnl_chain *c = nc->nftnl;
495 	struct nft_handle *h = data;
496 	char buf[16536];
497 	struct nlmsghdr *nlh;
498 	struct nftnl_rule *rule;
499 	int ret;
500 
501 	if (nftnl_rule_lookup_byindex(c, 0))
502 		return 0;
503 
504 	rule = nftnl_rule_alloc();
505 	if (!rule)
506 		return -1;
507 
508 	nftnl_rule_set_str(rule, NFTNL_RULE_TABLE,
509 			   nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE));
510 	nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
511 			   nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
512 
513 	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
514 					NLM_F_DUMP, h->seq);
515 	nftnl_rule_nlmsg_build_payload(nlh, rule);
516 
517 	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
518 	if (ret < 0 && errno == EINTR)
519 		assert(nft_restart(h) >= 0);
520 
521 	nftnl_rule_free(rule);
522 
523 	if (h->family == NFPROTO_BRIDGE)
524 		nft_bridge_chain_postprocess(h, c);
525 
526 	return 0;
527 }
528 
fetch_rule_cache(struct nft_handle * h,const struct builtin_table * t)529 static int fetch_rule_cache(struct nft_handle *h,
530 			    const struct builtin_table *t)
531 {
532 	int i;
533 
534 	if (t)
535 		return nft_chain_foreach(h, t->name, nft_rule_list_update, h);
536 
537 	for (i = 0; i < NFT_TABLE_MAX; i++) {
538 
539 		if (!h->tables[i].name)
540 			continue;
541 
542 		if (nft_chain_foreach(h, h->tables[i].name,
543 				      nft_rule_list_update, h))
544 			return -1;
545 	}
546 	return 0;
547 }
548 
549 static int flush_cache(struct nft_handle *h, struct nft_cache *c,
550 		       const char *tablename);
551 
552 static void
__nft_build_cache(struct nft_handle * h)553 __nft_build_cache(struct nft_handle *h)
554 {
555 	struct nft_cache_req *req = &h->cache_req;
556 	const struct builtin_table *t = NULL;
557 	struct list_head *chains = NULL;
558 	uint32_t genid_check;
559 
560 	if (h->cache_init)
561 		return;
562 
563 	if (req->table) {
564 		t = nft_table_builtin_find(h, req->table);
565 		if (!req->all_chains)
566 			chains = &req->chain_list;
567 	}
568 
569 	h->cache_init = true;
570 retry:
571 	mnl_genid_get(h, &h->nft_genid);
572 
573 	if (req->level >= NFT_CL_TABLES)
574 		fetch_table_cache(h);
575 	if (req->level == NFT_CL_FAKE)
576 		goto genid_check;
577 	if (req->level >= NFT_CL_CHAINS)
578 		fetch_chain_cache(h, t, chains);
579 	if (req->level >= NFT_CL_SETS)
580 		fetch_set_cache(h, t, NULL);
581 	if (req->level >= NFT_CL_RULES)
582 		fetch_rule_cache(h, t);
583 genid_check:
584 	mnl_genid_get(h, &genid_check);
585 	if (h->nft_genid != genid_check) {
586 		flush_cache(h, h->cache, NULL);
587 		goto retry;
588 	}
589 }
590 
__nft_flush_cache(struct nft_handle * h)591 static void __nft_flush_cache(struct nft_handle *h)
592 {
593 	if (!h->cache_index) {
594 		h->cache_index++;
595 		h->cache = &h->__cache[h->cache_index];
596 	} else {
597 		flush_chain_cache(h, NULL);
598 	}
599 }
600 
____flush_rule_cache(struct nftnl_rule * r,void * data)601 static int ____flush_rule_cache(struct nftnl_rule *r, void *data)
602 {
603 	nftnl_rule_list_del(r);
604 	nftnl_rule_free(r);
605 
606 	return 0;
607 }
608 
__flush_rule_cache(struct nft_chain * c,void * data)609 static int __flush_rule_cache(struct nft_chain *c, void *data)
610 {
611 	return nftnl_rule_foreach(c->nftnl, ____flush_rule_cache, NULL);
612 }
613 
flush_rule_cache(struct nft_handle * h,const char * table,struct nft_chain * c)614 int flush_rule_cache(struct nft_handle *h, const char *table,
615 		     struct nft_chain *c)
616 {
617 	if (c)
618 		return __flush_rule_cache(c, NULL);
619 
620 	nft_chain_foreach(h, table, __flush_rule_cache, NULL);
621 	return 0;
622 }
623 
__flush_chain_cache(struct nft_chain * c,void * data)624 static int __flush_chain_cache(struct nft_chain *c, void *data)
625 {
626 	nft_chain_list_del(c);
627 	nft_chain_free(c);
628 
629 	return 0;
630 }
631 
__flush_set_cache(struct nftnl_set * s,void * data)632 static int __flush_set_cache(struct nftnl_set *s, void *data)
633 {
634 	nftnl_set_list_del(s);
635 	nftnl_set_free(s);
636 
637 	return 0;
638 }
639 
flush_base_chain_cache(struct nft_chain ** base_chains)640 static void flush_base_chain_cache(struct nft_chain **base_chains)
641 {
642 	int i;
643 
644 	for (i = 0; i < NF_INET_NUMHOOKS; i++) {
645 		if (!base_chains[i])
646 			continue;
647 		hlist_del(&base_chains[i]->hnode);
648 		nft_chain_free(base_chains[i]);
649 		base_chains[i] = NULL;
650 	}
651 }
652 
flush_cache(struct nft_handle * h,struct nft_cache * c,const char * tablename)653 static int flush_cache(struct nft_handle *h, struct nft_cache *c,
654 		       const char *tablename)
655 {
656 	const struct builtin_table *table;
657 	int i;
658 
659 	if (tablename) {
660 		table = nft_table_builtin_find(h, tablename);
661 		if (!table)
662 			return 0;
663 
664 		flush_base_chain_cache(c->table[table->type].base_chains);
665 		nft_chain_foreach(h, tablename, __flush_chain_cache, NULL);
666 
667 		if (c->table[table->type].sets)
668 			nftnl_set_list_foreach(c->table[table->type].sets,
669 					       __flush_set_cache, NULL);
670 		return 0;
671 	}
672 
673 	for (i = 0; i < NFT_TABLE_MAX; i++) {
674 		if (h->tables[i].name == NULL)
675 			continue;
676 
677 		flush_base_chain_cache(c->table[i].base_chains);
678 		if (c->table[i].chains) {
679 			nft_chain_list_free(c->table[i].chains);
680 			c->table[i].chains = NULL;
681 		}
682 
683 		if (c->table[i].sets) {
684 			nftnl_set_list_free(c->table[i].sets);
685 			c->table[i].sets = NULL;
686 		}
687 
688 		c->table[i].exists = false;
689 	}
690 
691 	return 1;
692 }
693 
flush_chain_cache(struct nft_handle * h,const char * tablename)694 void flush_chain_cache(struct nft_handle *h, const char *tablename)
695 {
696 	if (!h->cache_init)
697 		return;
698 
699 	if (flush_cache(h, h->cache, tablename))
700 		h->cache_init = false;
701 }
702 
nft_rebuild_cache(struct nft_handle * h)703 void nft_rebuild_cache(struct nft_handle *h)
704 {
705 	if (h->cache_init) {
706 		__nft_flush_cache(h);
707 		h->cache_init = false;
708 	}
709 
710 	__nft_build_cache(h);
711 }
712 
nft_cache_build(struct nft_handle * h)713 void nft_cache_build(struct nft_handle *h)
714 {
715 	struct nft_cache_req *req = &h->cache_req;
716 	const struct builtin_table *t = NULL;
717 	int i;
718 
719 	if (req->table)
720 		t = nft_table_builtin_find(h, req->table);
721 
722 	/* fetch builtin chains as well (if existing) so nft_xt_builtin_init()
723 	 * doesn't override policies by accident */
724 	if (t && !req->all_chains) {
725 		for (i = 0; i < NF_INET_NUMHOOKS; i++) {
726 			const char *cname = t->chains[i].name;
727 
728 			if (!cname)
729 				break;
730 			cache_chain_list_insert(&req->chain_list, cname);
731 		}
732 	}
733 
734 	__nft_build_cache(h);
735 }
736 
nft_release_cache(struct nft_handle * h)737 void nft_release_cache(struct nft_handle *h)
738 {
739 	struct nft_cache_req *req = &h->cache_req;
740 	struct cache_chain *cc, *cc_tmp;
741 
742 	while (h->cache_index)
743 		flush_cache(h, &h->__cache[h->cache_index--], NULL);
744 	flush_cache(h, &h->__cache[0], NULL);
745 	h->cache = &h->__cache[0];
746 	h->cache_init = false;
747 
748 	if (req->level != NFT_CL_FAKE)
749 		req->level = NFT_CL_TABLES;
750 	if (req->table) {
751 		free(req->table);
752 		req->table = NULL;
753 	}
754 	req->all_chains = false;
755 	list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) {
756 		list_del(&cc->head);
757 		free(cc->name);
758 		free(cc);
759 	}
760 }
761 
762 struct nftnl_set_list *
nft_set_list_get(struct nft_handle * h,const char * table,const char * set)763 nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
764 {
765 	const struct builtin_table *t;
766 
767 	t = nft_table_builtin_find(h, table);
768 	if (!t)
769 		return NULL;
770 
771 	return h->cache->table[t->type].sets;
772 }
773