libiptc.c revision 1336451ead58d608618ff5b0a251d132b73f9866
10f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson/* Library which manipulates firewall rules.  Version $Revision$ */
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Architecture of firewall rules is as follows:
4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *
5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Chains go INPUT, FORWARD, OUTPUT then user chains.
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Each user chain starts with an ERROR node.
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Every chain ends with an unconditional jump: a RETURN for user chains,
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * and a POLICY for built-ins.
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
113ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
123ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte * COPYING for details).
13aae69bed019826ddec93f761514652a93d871e49Harald Welte * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org>
143ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte *
15fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
163ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte *	- Reimplementation of chain cache to use offsets instead of entries
17fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte * 	- performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
19fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 	  don't rebuild the chain cache after every operation, instead fix it
20fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte * 	  up after a ruleset change.
21aae69bed019826ddec93f761514652a93d871e49Harald Welte * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
22aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	- futher performance work: total reimplementation of libiptc.
23aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	- libiptc now has a real internal (linked-list) represntation of the
24aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	  ruleset and a parser/compiler from/to this internal representation
25aae69bed019826ddec93f761514652a93d871e49Harald Welte * 	- again sponsored by Astaro AG (http://www.astaro.com/)
263ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte */
2715920d160760535e51a57b3834eba45257cfa6d8Harald Welte#include <sys/types.h>
2815920d160760535e51a57b3834eba45257cfa6d8Harald Welte#include <sys/socket.h>
297cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette
30aae69bed019826ddec93f761514652a93d871e49Harald Welte#include "linux_list.h"
31aae69bed019826ddec93f761514652a93d871e49Harald Welte
32aae69bed019826ddec93f761514652a93d871e49Harald Welte//#define IPTC_DEBUG2 1
33aae69bed019826ddec93f761514652a93d871e49Harald Welte
34aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
35aae69bed019826ddec93f761514652a93d871e49Harald Welte#include <fcntl.h>
36aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP(x, args...)	fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
37aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP_C(x, args...)	fprintf(stderr, x, ## args)
38aae69bed019826ddec93f761514652a93d871e49Harald Welte#else
39aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP(x, args...)
40aae69bed019826ddec93f761514652a93d871e49Harald Welte#define DEBUGP_C(x, args...)
41aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
42aae69bed019826ddec93f761514652a93d871e49Harald Welte
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
48664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Patesstatic int sockfd_use = 0;
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
510b63936140032deac44072951451bdf47b54296aPatrick McHardystatic const char *hooknames[] = {
520b63936140032deac44072951451bdf47b54296aPatrick McHardy	[HOOK_PRE_ROUTING]	= "PREROUTING",
530b63936140032deac44072951451bdf47b54296aPatrick McHardy	[HOOK_LOCAL_IN]		= "INPUT",
540b63936140032deac44072951451bdf47b54296aPatrick McHardy	[HOOK_FORWARD]		= "FORWARD",
550b63936140032deac44072951451bdf47b54296aPatrick McHardy	[HOOK_LOCAL_OUT]	= "OUTPUT",
560b63936140032deac44072951451bdf47b54296aPatrick McHardy	[HOOK_POST_ROUTING]	= "POSTROUTING",
5710758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#ifdef HOOK_DROPPING
580b63936140032deac44072951451bdf47b54296aPatrick McHardy	[HOOK_DROPPING]		= "DROPPING"
5910758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#endif
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
62aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
63aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct ipt_error_target
64aae69bed019826ddec93f761514652a93d871e49Harald Welte{
65aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY_TARGET t;
66aae69bed019826ddec93f761514652a93d871e49Harald Welte	char error[TABLE_MAXNAMELEN];
67aae69bed019826ddec93f761514652a93d871e49Harald Welte};
68aae69bed019826ddec93f761514652a93d871e49Harald Welte
69aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct chain_head;
70aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct rule_head;
71aae69bed019826ddec93f761514652a93d871e49Harald Welte
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
771cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_ZEROED,
781cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_SET
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
83aae69bed019826ddec93f761514652a93d871e49Harald Welteenum iptcc_rule_type {
84aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_STANDARD,		/* standard target (ACCEPT, ...) */
85aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_MODULE,			/* extension module (SNAT, ...) */
86aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_FALLTHROUGH,		/* fallthrough rule */
87aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_JUMP,			/* jump to other chain */
88aae69bed019826ddec93f761514652a93d871e49Harald Welte};
89aae69bed019826ddec93f761514652a93d871e49Harald Welte
90aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct rule_head
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
92aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head list;
93aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *chain;
94aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map counter_map;
95aae69bed019826ddec93f761514652a93d871e49Harald Welte
96aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;		/* index (needed for counter_map) */
97aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset;		/* offset in rule blob */
98aae69bed019826ddec93f761514652a93d871e49Harald Welte
99aae69bed019826ddec93f761514652a93d871e49Harald Welte	enum iptcc_rule_type type;
100aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *jump;	/* jump target, if IPTCC_R_JUMP */
101aae69bed019826ddec93f761514652a93d871e49Harald Welte
102aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int size;		/* size of entry data */
103aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry[0];
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
106aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct chain_head
10730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
108aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head list;
10979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char name[TABLE_MAXNAMELEN];
110aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int hooknum;		/* hook number+1 if builtin */
111aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int references;	/* how many jumps reference us */
112aae69bed019826ddec93f761514652a93d871e49Harald Welte	int verdict;			/* verdict if builtin */
113aae69bed019826ddec93f761514652a93d871e49Harald Welte
114aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_COUNTERS counters;	/* per-chain counters */
115aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map counter_map;
116aae69bed019826ddec93f761514652a93d871e49Harald Welte
117aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num_rules;		/* number of rules in list */
118aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head rules;		/* list of rules */
119aae69bed019826ddec93f761514652a93d871e49Harald Welte
120aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;		/* index (needed for jump resolval) */
121aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int head_offset;	/* offset in rule blob */
122aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int foot_index;	/* index (needed for counter_map) */
123aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int foot_offset;	/* offset in rule blob */
12430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell};
12530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
12679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellSTRUCT_TC_HANDLE
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
128aae69bed019826ddec93f761514652a93d871e49Harald Welte	int changed;			 /* Have changes been made? */
129aae69bed019826ddec93f761514652a93d871e49Harald Welte
130aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head chains;
131aae69bed019826ddec93f761514652a93d871e49Harald Welte
132aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *chain_iterator_cur;
133aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *rule_iterator_cur;
134aae69bed019826ddec93f761514652a93d871e49Harald Welte
13579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
136aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_GET_ENTRIES *entries;
137aae69bed019826ddec93f761514652a93d871e49Harald Welte};
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139aae69bed019826ddec93f761514652a93d871e49Harald Welte/* allocate a new chain head for the cache */
140aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
141aae69bed019826ddec93f761514652a93d871e49Harald Welte{
142aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = malloc(sizeof(*c));
143aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c)
144aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
145aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(c, 0, sizeof(*c));
146aae69bed019826ddec93f761514652a93d871e49Harald Welte
147aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, name, TABLE_MAXNAMELEN);
148aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->hooknum = hooknum;
149aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&c->rules);
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
151aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c;
152aae69bed019826ddec93f761514652a93d871e49Harald Welte}
15330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
154aae69bed019826ddec93f761514652a93d871e49Harald Welte/* allocate and initialize a new rule for the cache */
155aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
156aae69bed019826ddec93f761514652a93d871e49Harald Welte{
157aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r = malloc(sizeof(*r)+size);
158aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
159aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
160aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(r, 0, sizeof(*r));
16130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
162aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->chain = c;
163aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->size = size;
164175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
165aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r;
166aae69bed019826ddec93f761514652a93d871e49Harald Welte}
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
168aae69bed019826ddec93f761514652a93d871e49Harald Welte/* notify us that the ruleset has been modified by the user */
169175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
17079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_changed(TC_HANDLE_T h)
171175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
172175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
173175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
174175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
175380ba5f3074a16fbaa8869d9594962d58b5f8608Harald Welte#ifdef IPTC_DEBUG
17679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void do_check(TC_HANDLE_T h, unsigned int line);
177849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
17830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else
17930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h)
18030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
182aae69bed019826ddec93f761514652a93d871e49Harald Welte
183aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
184aae69bed019826ddec93f761514652a93d871e49Harald Welte * iptc blob utility functions (iptcb_*)
185aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
186aae69bed019826ddec93f761514652a93d871e49Harald Welte
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
188aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_number(const STRUCT_ENTRY *i,
18979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   const STRUCT_ENTRY *seek,
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
198aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
199aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_entry_n(STRUCT_ENTRY *i,
200aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int number,
201aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int *pos,
202aae69bed019826ddec93f761514652a93d871e49Harald Welte	    STRUCT_ENTRY **pe)
203aae69bed019826ddec93f761514652a93d871e49Harald Welte{
204aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (*pos == number) {
205aae69bed019826ddec93f761514652a93d871e49Harald Welte		*pe = i;
206aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
207aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
208aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*pos)++;
209aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
210aae69bed019826ddec93f761514652a93d871e49Harald Welte}
211aae69bed019826ddec93f761514652a93d871e49Harald Welte
212aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline STRUCT_ENTRY *
213aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_entry(TC_HANDLE_T h, unsigned int offset)
214aae69bed019826ddec93f761514652a93d871e49Harald Welte{
215aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
216aae69bed019826ddec93f761514652a93d871e49Harald Welte}
217aae69bed019826ddec93f761514652a93d871e49Harald Welte
218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
219aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
223aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
224aae69bed019826ddec93f761514652a93d871e49Harald Welte			  iptcb_get_number, seek, &pos) == 0) {
225a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson		fprintf(stderr, "ERROR: offset %u not an entry!\n",
226aae69bed019826ddec93f761514652a93d871e49Harald Welte			(unsigned int)((char *)seek - (char *)h->entries->entrytable));
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
232aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline STRUCT_ENTRY *
233aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_offset2entry(TC_HANDLE_T h, unsigned int offset)
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
235aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
236aae69bed019826ddec93f761514652a93d871e49Harald Welte}
237aae69bed019826ddec93f761514652a93d871e49Harald Welte
238aae69bed019826ddec93f761514652a93d871e49Harald Welte
239aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned long
240aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
241aae69bed019826ddec93f761514652a93d871e49Harald Welte{
242aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (void *)e - (void *)h->entries->entrytable;
243aae69bed019826ddec93f761514652a93d871e49Harald Welte}
244aae69bed019826ddec93f761514652a93d871e49Harald Welte
245aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned int
246aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_offset2index(const TC_HANDLE_T h, unsigned int offset)
247aae69bed019826ddec93f761514652a93d871e49Harald Welte{
248aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
249aae69bed019826ddec93f761514652a93d871e49Harald Welte}
250aae69bed019826ddec93f761514652a93d871e49Harald Welte
251aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns 0 if not hook entry, else hooknumber + 1 */
252aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned int
253aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
254aae69bed019826ddec93f761514652a93d871e49Harald Welte{
255aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i;
256aae69bed019826ddec93f761514652a93d871e49Harald Welte
257aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < NUMHOOKS; i++) {
258aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((h->info.valid_hooks & (1 << i))
259aae69bed019826ddec93f761514652a93d871e49Harald Welte		    && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
260aae69bed019826ddec93f761514652a93d871e49Harald Welte			return i+1;
261aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
262aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
263aae69bed019826ddec93f761514652a93d871e49Harald Welte}
264aae69bed019826ddec93f761514652a93d871e49Harald Welte
265aae69bed019826ddec93f761514652a93d871e49Harald Welte
266aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
267aae69bed019826ddec93f761514652a93d871e49Harald Welte * iptc cache utility functions (iptcc_*)
268aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
269aae69bed019826ddec93f761514652a93d871e49Harald Welte
270aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is the given chain builtin (1) or user-defined (0) */
271aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic unsigned int iptcc_is_builtin(struct chain_head *c)
272aae69bed019826ddec93f761514652a93d871e49Harald Welte{
273aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (c->hooknum ? 1 : 0);
274aae69bed019826ddec93f761514652a93d871e49Harald Welte}
275aae69bed019826ddec93f761514652a93d871e49Harald Welte
276aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get a specific rule within a chain */
277aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct rule_head *iptcc_get_rule_num(struct chain_head *c,
278aae69bed019826ddec93f761514652a93d871e49Harald Welte					    unsigned int rulenum)
279aae69bed019826ddec93f761514652a93d871e49Harald Welte{
280aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
281aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
282aae69bed019826ddec93f761514652a93d871e49Harald Welte
283aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
284aae69bed019826ddec93f761514652a93d871e49Harald Welte		num++;
285aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (num == rulenum)
286aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r;
287aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
288aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
289aae69bed019826ddec93f761514652a93d871e49Harald Welte}
290aae69bed019826ddec93f761514652a93d871e49Harald Welte
291a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson/* Get a specific rule within a chain backwards */
292a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefssonstatic struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c,
293a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson					    unsigned int rulenum)
294a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson{
295a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	struct rule_head *r;
296a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	unsigned int num = 0;
297a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson
298a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	list_for_each_entry_reverse(r, &c->rules, list) {
299a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		num++;
300a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		if (num == rulenum)
301a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson			return r;
302a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	}
303a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	return NULL;
304a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson}
305a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson
306aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns chain head if found, otherwise NULL. */
307aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *
308aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset)
309aae69bed019826ddec93f761514652a93d871e49Harald Welte{
310aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head *pos;
311aae69bed019826ddec93f761514652a93d871e49Harald Welte
312aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&handle->chains))
313aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
314aae69bed019826ddec93f761514652a93d871e49Harald Welte
315aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each(pos, &handle->chains) {
316aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c = list_entry(pos, struct chain_head, list);
317aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (offset >= c->head_offset && offset <= c->foot_offset)
318aae69bed019826ddec93f761514652a93d871e49Harald Welte			return c;
319aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
320aae69bed019826ddec93f761514652a93d871e49Harald Welte
321aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
322aae69bed019826ddec93f761514652a93d871e49Harald Welte}
323aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns chain head if found, otherwise NULL. */
324aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *
325aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_find_label(const char *name, TC_HANDLE_T handle)
326aae69bed019826ddec93f761514652a93d871e49Harald Welte{
327aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head *pos;
328aae69bed019826ddec93f761514652a93d871e49Harald Welte
329aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&handle->chains))
330aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
331aae69bed019826ddec93f761514652a93d871e49Harald Welte
332aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each(pos, &handle->chains) {
333aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c = list_entry(pos, struct chain_head, list);
334aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(c->name, name))
335aae69bed019826ddec93f761514652a93d871e49Harald Welte			return c;
336aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
337aae69bed019826ddec93f761514652a93d871e49Harald Welte
338aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
339aae69bed019826ddec93f761514652a93d871e49Harald Welte}
340aae69bed019826ddec93f761514652a93d871e49Harald Welte
341aae69bed019826ddec93f761514652a93d871e49Harald Welte/* called when rule is to be removed from cache */
342aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_delete_rule(struct rule_head *r)
343aae69bed019826ddec93f761514652a93d871e49Harald Welte{
344aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
345aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* clean up reference count of called chain */
346aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP
347aae69bed019826ddec93f761514652a93d871e49Harald Welte	    && r->jump)
348aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->jump->references--;
349aae69bed019826ddec93f761514652a93d871e49Harald Welte
350aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&r->list);
351aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(r);
352aae69bed019826ddec93f761514652a93d871e49Harald Welte}
353aae69bed019826ddec93f761514652a93d871e49Harald Welte
354aae69bed019826ddec93f761514652a93d871e49Harald Welte
355aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
356aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET PARSER (blob -> cache)
357aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
358aae69bed019826ddec93f761514652a93d871e49Harald Welte
359aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Delete policy rule of previous chain, since cache doesn't contain
360aae69bed019826ddec93f761514652a93d871e49Harald Welte * chain policy rules.
361aae69bed019826ddec93f761514652a93d871e49Harald Welte * WARNING: This function has ugly design and relies on a lot of context, only
362aae69bed019826ddec93f761514652a93d871e49Harald Welte * to be called from specific places within the parser */
363aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num)
364aae69bed019826ddec93f761514652a93d871e49Harald Welte{
365aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (h->chain_iterator_cur) {
366aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* policy rule is last rule */
367aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *pr = (struct rule_head *)
368aae69bed019826ddec93f761514652a93d871e49Harald Welte			h->chain_iterator_cur->rules.prev;
369aae69bed019826ddec93f761514652a93d871e49Harald Welte
370aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* save verdict */
371aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->verdict =
372aae69bed019826ddec93f761514652a93d871e49Harald Welte			*(int *)GET_TARGET(pr->entry)->data;
373aae69bed019826ddec93f761514652a93d871e49Harald Welte
374aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* save counter and counter_map information */
375aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->counter_map.maptype =
376aae69bed019826ddec93f761514652a93d871e49Harald Welte						COUNTER_MAP_NORMAL_MAP;
377aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->counter_map.mappos = num-1;
378aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
379aae69bed019826ddec93f761514652a93d871e49Harald Welte			sizeof(h->chain_iterator_cur->counters));
380aae69bed019826ddec93f761514652a93d871e49Harald Welte
381aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* foot_offset points to verdict rule */
382aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->foot_index = num;
383aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->foot_offset = pr->offset;
384aae69bed019826ddec93f761514652a93d871e49Harald Welte
385aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* delete rule from cache */
386aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(pr);
3878d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefsson		h->chain_iterator_cur->num_rules--;
388aae69bed019826ddec93f761514652a93d871e49Harald Welte
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
394ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte/* alphabetically insert a chain into the list */
395ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Weltestatic inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
396ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte{
397ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	struct chain_head *tmp;
398ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
3999d3ed77341361674994f584ff69a61f31a342739Olaf Rempel	/* sort only user defined chains */
4009d3ed77341361674994f584ff69a61f31a342739Olaf Rempel	if (!c->hooknum) {
4019d3ed77341361674994f584ff69a61f31a342739Olaf Rempel		list_for_each_entry(tmp, &h->chains, list) {
402feca0578a5d035122b4b7cdb8d44d6cca819f35cRobert de Barth			if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
4039d3ed77341361674994f584ff69a61f31a342739Olaf Rempel				list_add(&c->list, tmp->list.prev);
4049d3ed77341361674994f584ff69a61f31a342739Olaf Rempel				return;
4059d3ed77341361674994f584ff69a61f31a342739Olaf Rempel			}
406ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte		}
407ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	}
408ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
409ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	/* survived till end of list: add at tail */
410ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	list_add_tail(&c->list, &h->chains);
411ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte}
412ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
413aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Another ugly helper function split out of cache_add_entry to make it less
414aae69bed019826ddec93f761514652a93d871e49Harald Welte * spaghetti code */
415aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c,
416aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int offset, unsigned int *num)
417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
4181336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	struct list_head  *tail = h->chains.prev;
4191336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	struct chain_head *ctail;
4201336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer
421aae69bed019826ddec93f761514652a93d871e49Harald Welte	__iptcc_p_del_policy(h, *num);
422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
423aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = offset;
424aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->index = *num;
425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
4261336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	/* Chains from kernel are already sorted, as they are inserted
4271336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	 * sorted. But there exists an issue when shifting to 1.4.0
4281336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	 * from an older version, as old versions allow last created
4291336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	 * chain to be unsorted.
4301336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	 */
4311336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	if (iptcc_is_builtin(c)) /* Only user defined chains are sorted*/
4321336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		list_add_tail(&c->list, &h->chains);
4331336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	else {
4341336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		ctail = list_entry(tail, struct chain_head, list);
4351336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		if (strcmp(c->name, ctail->name) > 0)
4361336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer			list_add_tail(&c->list, &h->chains);/* Already sorted*/
4371336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		else
4381336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer			iptc_insert_chain(h, c);/* Was not sorted */
4391336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	}
440d8cb787ab44e9d2de4fd3b04fcaa370c9918fc5dJesper Dangaard Brouer
441aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->chain_iterator_cur = c;
442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
444aae69bed019826ddec93f761514652a93d871e49Harald Welte/* main parser function: add an entry from the blob to the cache */
445aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int cache_add_entry(STRUCT_ENTRY *e,
446aae69bed019826ddec93f761514652a93d871e49Harald Welte			   TC_HANDLE_T h,
447aae69bed019826ddec93f761514652a93d871e49Harald Welte			   STRUCT_ENTRY **prev,
448aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int *num)
449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
450aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int builtin;
451aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = (char *)e - (char *)h->entries->entrytable;
452aae69bed019826ddec93f761514652a93d871e49Harald Welte
453aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("entering...");
454aae69bed019826ddec93f761514652a93d871e49Harald Welte
455aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Last entry ("policy rule"). End it.*/
456aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
457aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* This is the ERROR node at the end of the chain */
458aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u: end of table:\n", *num, offset);
459aae69bed019826ddec93f761514652a93d871e49Harald Welte
460aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_del_policy(h, *num);
461aae69bed019826ddec93f761514652a93d871e49Harald Welte
462aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur = NULL;
463aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_inc;
464aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
465aae69bed019826ddec93f761514652a93d871e49Harald Welte
466aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* We know this is the start of a new chain if it's an ERROR
467aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * target, or a hook entry point */
468aae69bed019826ddec93f761514652a93d871e49Harald Welte
469aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
470aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
471aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
472aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
473aae69bed019826ddec93f761514652a93d871e49Harald Welte			(char *)c->name, c);
474aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
475aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
476aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
477aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
478aae69bed019826ddec93f761514652a93d871e49Harald Welte
479aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
480aae69bed019826ddec93f761514652a93d871e49Harald Welte
481aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
482aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
483aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((char *)hooknames[builtin-1],
484aae69bed019826ddec93f761514652a93d871e49Harald Welte						builtin);
485aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
486aae69bed019826ddec93f761514652a93d871e49Harald Welte			*num, offset, c, &c->rules);
487aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
488aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
489aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
490aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
491aae69bed019826ddec93f761514652a93d871e49Harald Welte
492aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->hooknum = builtin;
493aae69bed019826ddec93f761514652a93d871e49Harald Welte
494aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
495aae69bed019826ddec93f761514652a93d871e49Harald Welte
496aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* FIXME: this is ugly. */
497aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto new_rule;
498aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
499aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* has to be normal rule */
500aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
501aae69bed019826ddec93f761514652a93d871e49Harald Weltenew_rule:
502aae69bed019826ddec93f761514652a93d871e49Harald Welte
503aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
504aae69bed019826ddec93f761514652a93d871e49Harald Welte					   e->next_offset))) {
505aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = ENOMEM;
506aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
507aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
508aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
509aae69bed019826ddec93f761514652a93d871e49Harald Welte
510aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
511aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = offset;
512aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(r->entry, e, e->next_offset);
513aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
514aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.mappos = r->index;
515aae69bed019826ddec93f761514652a93d871e49Harald Welte
516aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* handling of jumps, etc. */
517aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
518aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
519aae69bed019826ddec93f761514652a93d871e49Harald Welte
520aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
521aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->target.u.target_size
522aae69bed019826ddec93f761514652a93d871e49Harald Welte			    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
523aae69bed019826ddec93f761514652a93d871e49Harald Welte				errno = EINVAL;
524aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
525aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
526aae69bed019826ddec93f761514652a93d871e49Harald Welte
527aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->verdict < 0) {
528aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("standard, verdict=%d\n", t->verdict);
529aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_STANDARD;
530aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else if (t->verdict == r->offset+e->next_offset) {
531aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("fallthrough\n");
532aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_FALLTHROUGH;
533aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else {
534aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("jump, target=%u\n", t->verdict);
535aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_JUMP;
536aae69bed019826ddec93f761514652a93d871e49Harald Welte				/* Jump target fixup has to be deferred
537aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * until second pass, since we migh not
538aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * yet have parsed the target */
539aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
54052c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson		} else {
54152c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
54252c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			r->type = IPTCC_R_MODULE;
543aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
544aae69bed019826ddec93f761514652a93d871e49Harald Welte
545aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_add_tail(&r->list, &h->chain_iterator_cur->rules);
5468d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefsson		h->chain_iterator_cur->num_rules++;
547aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
548aae69bed019826ddec93f761514652a93d871e49Harald Welteout_inc:
549aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
550aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
553aae69bed019826ddec93f761514652a93d871e49Harald Welte
554aae69bed019826ddec93f761514652a93d871e49Harald Welte/* parse an iptables blob into it's pieces */
555aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int parse_table(TC_HANDLE_T h)
556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
557aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *prev;
558aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
559aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
560aae69bed019826ddec93f761514652a93d871e49Harald Welte
561aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: over ruleset blob */
562aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
563aae69bed019826ddec93f761514652a93d871e49Harald Welte			cache_add_entry, h, &prev, &num);
564aae69bed019826ddec93f761514652a93d871e49Harald Welte
565aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: fixup parsed data from first pass */
566aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
567aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
568aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
569aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct chain_head *c;
570aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
571aae69bed019826ddec93f761514652a93d871e49Harald Welte
572aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (r->type != IPTCC_R_JUMP)
573aae69bed019826ddec93f761514652a93d871e49Harald Welte				continue;
574aae69bed019826ddec93f761514652a93d871e49Harald Welte
575aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
576aae69bed019826ddec93f761514652a93d871e49Harald Welte			c = iptcc_find_chain_by_offset(h, t->verdict);
577aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (!c)
578aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
579aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
580aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
581aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
582aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
583aae69bed019826ddec93f761514652a93d871e49Harald Welte
584aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* FIXME: sort chains */
585aae69bed019826ddec93f761514652a93d871e49Harald Welte
586aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
5870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
5889e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
589aae69bed019826ddec93f761514652a93d871e49Harald Welte
590aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
591aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET COMPILATION (cache -> blob)
592aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
593aae69bed019826ddec93f761514652a93d871e49Harald Welte
594aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
595aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_start{
596aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
597aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target name;
598aae69bed019826ddec93f761514652a93d871e49Harald Welte};
599aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_START_SIZE	(sizeof(STRUCT_ENTRY) +			\
600aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
601aae69bed019826ddec93f761514652a93d871e49Harald Welte
602aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_foot {
603aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
604aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_STANDARD_TARGET target;
605aae69bed019826ddec93f761514652a93d871e49Harald Welte};
606aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_FOOT_SIZE	(sizeof(STRUCT_ENTRY) +			\
607aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
608aae69bed019826ddec93f761514652a93d871e49Harald Welte
609aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_error {
610aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry;
611aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target target;
612aae69bed019826ddec93f761514652a93d871e49Harald Welte};
613aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_ERROR_SIZE	(sizeof(STRUCT_ENTRY) +			\
614aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
615aae69bed019826ddec93f761514652a93d871e49Harald Welte
616aae69bed019826ddec93f761514652a93d871e49Harald Welte
617aae69bed019826ddec93f761514652a93d871e49Harald Welte
618aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile rule from cache into blob */
619aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
6200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
621aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* handle jumps */
622aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP) {
623aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
624aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
625aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* memset for memcmp convenience on delete/replace */
626aae69bed019826ddec93f761514652a93d871e49Harald Welte		memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
627aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(t->target.u.user.name, STANDARD_TARGET);
628aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Jumps can only happen to builtin chains, so we
629aae69bed019826ddec93f761514652a93d871e49Harald Welte		 * can safely assume that they always have a header */
630aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
631aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if (r->type == IPTCC_R_FALLTHROUGH) {
632aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
633aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
634aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->offset + r->size;
635aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
636aae69bed019826ddec93f761514652a93d871e49Harald Welte
637aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* copy entry from cache to blob */
638aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy((char *)repl->entries+r->offset, r->entry, r->size);
639aae69bed019826ddec93f761514652a93d871e49Harald Welte
640aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
643aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile chain from cache into blob */
644aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
6453ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
646aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
647aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
648aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_start *head;
649aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_foot *foot;
650aae69bed019826ddec93f761514652a93d871e49Harald Welte
651aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* only user-defined chains have heaer */
652aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
653aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* put chain header in place */
654aae69bed019826ddec93f761514652a93d871e49Harald Welte		head = (void *)repl->entries + c->head_offset;
655aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.target_offset = sizeof(STRUCT_ENTRY);
656aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.next_offset = IPTCB_CHAIN_START_SIZE;
657aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.t.u.user.name, ERROR_TARGET);
658aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->name.t.u.target_size =
659aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(struct ipt_error_target));
660aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.error, c->name);
661aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
662aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->hook_entry[c->hooknum-1] = c->head_offset;
663aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->underflow[c->hooknum-1] = c->foot_offset;
664aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
665aae69bed019826ddec93f761514652a93d871e49Harald Welte
666aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* iterate over rules */
667aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
668aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_rule(h, repl, r);
669aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
670aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
671aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
672aae69bed019826ddec93f761514652a93d871e49Harald Welte
673aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* put chain footer in place */
674aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot = (void *)repl->entries + c->foot_offset;
675aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.target_offset = sizeof(STRUCT_ENTRY);
676aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
677aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
678aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->target.target.u.target_size =
679aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(STRUCT_STANDARD_TARGET));
680aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* builtin targets have verdict, others return */
681aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_is_builtin(c))
682aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = c->verdict;
683aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
684aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = RETURN;
685aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* set policy-counters */
686aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
687aae69bed019826ddec93f761514652a93d871e49Harald Welte
688aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
6893ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
6903ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
691aae69bed019826ddec93f761514652a93d871e49Harald Welte/* calculate offset and number for every rule in the cache */
692aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
693efa8fc2123a2a9fc229ab471edd2b2688ce1da3aHarald Welte				       unsigned int *offset, unsigned int *num)
6943ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
695aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
696aae69bed019826ddec93f761514652a93d871e49Harald Welte
697aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = *offset;
698aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
699aae69bed019826ddec93f761514652a93d871e49Harald Welte
700aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))  {
701aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Chain has header */
702aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += sizeof(STRUCT_ENTRY)
703aae69bed019826ddec93f761514652a93d871e49Harald Welte			     + ALIGN(sizeof(struct ipt_error_target));
704aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
705aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
706aae69bed019826ddec93f761514652a93d871e49Harald Welte
707aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
708aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
709aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = *offset;
710aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
711aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += r->size;
712aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
713aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
714aae69bed019826ddec93f761514652a93d871e49Harald Welte
715aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
716aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset, *num);
717aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_offset = *offset;
718aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_index = *num;
719aae69bed019826ddec93f761514652a93d871e49Harald Welte	*offset += sizeof(STRUCT_ENTRY)
720aae69bed019826ddec93f761514652a93d871e49Harald Welte		   + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
721aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
722aae69bed019826ddec93f761514652a93d871e49Harald Welte
723aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
7243ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
7253ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
726aae69bed019826ddec93f761514652a93d871e49Harald Welte/* put the pieces back together again */
727aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
728aae69bed019826ddec93f761514652a93d871e49Harald Welte{
729aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
730aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = 0, num = 0;
731aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret = 0;
7323ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
733aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: calculate offset for every rule */
734aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
735aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
736aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
737aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
738aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
739aae69bed019826ddec93f761514652a93d871e49Harald Welte
740aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append one error rule at end of chain */
741aae69bed019826ddec93f761514652a93d871e49Harald Welte	num++;
742aae69bed019826ddec93f761514652a93d871e49Harald Welte	offset += sizeof(STRUCT_ENTRY)
743aae69bed019826ddec93f761514652a93d871e49Harald Welte		  + ALIGN(sizeof(struct ipt_error_target));
744aae69bed019826ddec93f761514652a93d871e49Harald Welte
745aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* ruleset size is now in offset */
746aae69bed019826ddec93f761514652a93d871e49Harald Welte	*size = offset;
747aae69bed019826ddec93f761514652a93d871e49Harald Welte	return num;
748aae69bed019826ddec93f761514652a93d871e49Harald Welte}
749aae69bed019826ddec93f761514652a93d871e49Harald Welte
750aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
7510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
752aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
753aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_error *error;
7540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
755aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: copy from cache to offsets, fill in jumps */
756aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
757aae69bed019826ddec93f761514652a93d871e49Harald Welte		int ret = iptcc_compile_chain(h, repl, c);
758aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
759aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
7600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
7610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
762aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append error rule at end of chain */
763aae69bed019826ddec93f761514652a93d871e49Harald Welte	error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
764aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.target_offset = sizeof(STRUCT_ENTRY);
765aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
766aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->target.t.u.user.target_size =
767aae69bed019826ddec93f761514652a93d871e49Harald Welte		ALIGN(sizeof(struct ipt_error_target));
768aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
769aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.error, "ERROR");
770aae69bed019826ddec93f761514652a93d871e49Harald Welte
771aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
7720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
774aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
775aae69bed019826ddec93f761514652a93d871e49Harald Welte * EXTERNAL API (operates on cache only)
776aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
777aae69bed019826ddec93f761514652a93d871e49Harald Welte
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
77979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic TC_HANDLE_T
7800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltealloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
78379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
785aae69bed019826ddec93f761514652a93d871e49Harald Welte	len = sizeof(STRUCT_TC_HANDLE) + size;
786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
787aae69bed019826ddec93f761514652a93d871e49Harald Welte	h = malloc(sizeof(STRUCT_TC_HANDLE));
788aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h) {
789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
792aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(h, 0, sizeof(*h));
793aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&h->chains);
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
795aae69bed019826ddec93f761514652a93d871e49Harald Welte
7960371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
797aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h->entries)
798aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_free_handle;
799aae69bed019826ddec93f761514652a93d871e49Harald Welte
800aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(h->entries->name, tablename);
8010371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries->size = size;
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
804aae69bed019826ddec93f761514652a93d871e49Harald Welte
805aae69bed019826ddec93f761514652a93d871e49Harald Welteout_free_handle:
806aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(h);
807aae69bed019826ddec93f761514652a93d871e49Harald Welte
808aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
811aae69bed019826ddec93f761514652a93d871e49Harald Welte
81279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_HANDLE_T
81379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INIT(const char *tablename)
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
81579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
81679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
817efa8fc2123a2a9fc229ab471edd2b2688ce1da3aHarald Welte	unsigned int tmp;
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
82079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INIT;
821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
822841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
823841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		errno = EINVAL;
824841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		return NULL;
825841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
826841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
827664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (sockfd_use == 0) {
828664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
829664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		if (sockfd < 0)
830664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			return NULL;
831664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
832664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	sockfd_use++;
833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
835841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
837664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
838664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		if (--sockfd_use == 0) {
839664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			close(sockfd);
840664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			sockfd = -1;
841664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		}
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
843664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
845aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
846aae69bed019826ddec93f761514652a93d871e49Harald Welte		info.valid_hooks, info.num_entries, info.size);
847aae69bed019826ddec93f761514652a93d871e49Harald Welte
8480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((h = alloc_handle(info.name, info.size, info.num_entries))
849841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == NULL) {
850664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		if (--sockfd_use == 0) {
851664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			close(sockfd);
852664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			sockfd = -1;
853664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		}
854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
855841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
8590113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
860aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->entries->size = h->info.size;
861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
86279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
864aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
865aae69bed019826ddec93f761514652a93d871e49Harald Welte		       &tmp) < 0)
866aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
867aae69bed019826ddec93f761514652a93d871e49Harald Welte
868aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
869aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
870aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_get_entries.blob",
871aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
872aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
873aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, h->entries, tmp);
874aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
875aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
877aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
878aae69bed019826ddec93f761514652a93d871e49Harald Welte
879aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (parse_table(h) < 0)
880aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
8817e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
884aae69bed019826ddec93f761514652a93d871e49Harald Welteerror:
885aae69bed019826ddec93f761514652a93d871e49Harald Welte	TC_FREE(&h);
886aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
889841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssonvoid
890841e4aed2349046eb2c0b1375139c06569a93bd0Martin JosefssonTC_FREE(TC_HANDLE_T *h)
891841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
892aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c, *tmp;
893aae69bed019826ddec93f761514652a93d871e49Harald Welte
894664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_FREE;
895664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (--sockfd_use == 0) {
896664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		close(sockfd);
897664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		sockfd = -1;
898664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
899aae69bed019826ddec93f761514652a93d871e49Harald Welte
900aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
901aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r, *rtmp;
902aae69bed019826ddec93f761514652a93d871e49Harald Welte
903aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry_safe(r, rtmp, &c->rules, list) {
904aae69bed019826ddec93f761514652a93d871e49Harald Welte			free(r);
905aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
906aae69bed019826ddec93f761514652a93d871e49Harald Welte
907aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(c);
908aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
909aae69bed019826ddec93f761514652a93d871e49Harald Welte
910aae69bed019826ddec93f761514652a93d871e49Harald Welte	free((*h)->entries);
911841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	free(*h);
912aae69bed019826ddec93f761514652a93d871e49Harald Welte
913841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	*h = NULL;
914841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson}
915841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
91779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellprint_match(const STRUCT_ENTRY_MATCH *m)
918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
919228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
92379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
92479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
92679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DUMP_ENTRIES(const TC_HANDLE_T handle)
927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
928664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_DUMP_ENTRIES;
929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
93097fb2f1579f0794377db1dca7c5bb07fade1a0dcPatrick McHardy
931e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	printf("libiptc v%s. %u bytes.\n",
932e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	       IPTABLES_VERSION, handle->entries->size);
933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
93567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_PRE_ROUTING],
93667088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_IN],
93767088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_FORWARD],
93867088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_OUT],
93967088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_POST_ROUTING]);
940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
94167088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_PRE_ROUTING],
94267088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_IN],
94367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_FORWARD],
94467088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_OUT],
94567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_POST_ROUTING]);
946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
947aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
94879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      dump_entry, handle);
9490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
95279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
954664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_IS_CHAIN;
955aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_find_label(chain, handle) != NULL;
956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
958aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
959aae69bed019826ddec93f761514652a93d871e49Harald Welte{
960aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = handle->chain_iterator_cur;
961aae69bed019826ddec93f761514652a93d871e49Harald Welte
962aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->list.next == &handle->chains)
963aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur = NULL;
964aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
965aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur =
966aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry(c->list.next, struct chain_head, list);
967aae69bed019826ddec93f761514652a93d871e49Harald Welte}
968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
96930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
9718c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_CHAIN(TC_HANDLE_T *handle)
972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
973aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = list_entry((*handle)->chains.next,
974aae69bed019826ddec93f761514652a93d871e49Harald Welte					  struct chain_head, list);
975aae69bed019826ddec93f761514652a93d871e49Harald Welte
976aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_CHAIN;
977aae69bed019826ddec93f761514652a93d871e49Harald Welte
978aae69bed019826ddec93f761514652a93d871e49Harald Welte
979aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&(*handle)->chains)) {
980aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no chains\n");
9810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
982aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
9830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
984aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->chain_iterator_cur = c;
985aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
98630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
987aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
988aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
98930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
99030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
99130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
99230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
99379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NEXT_CHAIN(TC_HANDLE_T *handle)
99430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
995aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = (*handle)->chain_iterator_cur;
996aae69bed019826ddec93f761514652a93d871e49Harald Welte
997aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_CHAIN;
99830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
999aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1000aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no more chains\n");
100130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1002aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
100330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1004aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
1005aae69bed019826ddec93f761514652a93d871e49Harald Welte
1006aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
1007aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
100830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
100930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
101030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
101179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
10128c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
101330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
1014aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1015aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1016aae69bed019826ddec93f761514652a93d871e49Harald Welte
1017aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_RULE;
101830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1019aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("first rule(%s): ", chain);
1020aae69bed019826ddec93f761514652a93d871e49Harald Welte
1021aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
102230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
102330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
102430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
102730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
1028aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&c->rules)) {
1029aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("no rules, returning NULL\n");
103030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1031aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1032aae69bed019826ddec93f761514652a93d871e49Harald Welte
1033aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry(c->rules.next, struct rule_head, list);
1034aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
1035aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("%p\n", r);
103630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1037aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
104179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
10428c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
104330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
1044aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1045aae69bed019826ddec93f761514652a93d871e49Harald Welte
1046664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_NEXT_RULE;
1047aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
1048aae69bed019826ddec93f761514652a93d871e49Harald Welte
1049aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(*handle)->rule_iterator_cur) {
1050aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("returning NULL\n");
105130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1052aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1053aae69bed019826ddec93f761514652a93d871e49Harald Welte
1054aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry((*handle)->rule_iterator_cur->list.next,
1055aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct rule_head, list);
105630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1057aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_RULE;
1058aae69bed019826ddec93f761514652a93d871e49Harald Welte
1059aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("next=%p, head=%p...", &r->list,
1060aae69bed019826ddec93f761514652a93d871e49Harald Welte		&(*handle)->rule_iterator_cur->chain->rules);
1061aae69bed019826ddec93f761514652a93d871e49Harald Welte
1062aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
1063aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur = NULL;
1064aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("finished, returning NULL\n");
1065aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1066aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1067aae69bed019826ddec93f761514652a93d871e49Harald Welte
1068aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
1069aae69bed019826ddec93f761514652a93d871e49Harald Welte
1070aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* NOTE: prev is without any influence ! */
1071aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("returning rule %p\n", r);
1072aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
107330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
107430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
1076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
107779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
1078e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1079aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1080aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NUM_RULES;
1081e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1082aae69bed019826ddec93f761514652a93d871e49Harald Welte
1083aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1084aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1085e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
1087e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1088aae69bed019826ddec93f761514652a93d871e49Harald Welte
1089aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->num_rules;
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
109279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *TC_GET_RULE(const char *chain,
109379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				unsigned int n,
109479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				TC_HANDLE_T *handle)
1095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1096aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1097aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1098aae69bed019826ddec93f761514652a93d871e49Harald Welte
1099aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_RULE;
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1102aae69bed019826ddec93f761514652a93d871e49Harald Welte
1103aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1104aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1109aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = iptcc_get_rule_num(c, n);
1110aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
1111aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1112aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
1113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1115aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1116aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *standard_target_map(int verdict)
1117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1118aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch (verdict) {
1119aae69bed019826ddec93f761514652a93d871e49Harald Welte		case RETURN:
112079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_RETURN;
1121aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1122aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_ACCEPT-1:
112379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_ACCEPT;
1124aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1125aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_DROP-1:
1126aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_DROP;
1127aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1128aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_QUEUE-1:
1129aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_QUEUE;
1130aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1131aae69bed019826ddec93f761514652a93d871e49Harald Welte		default:
1132aae69bed019826ddec93f761514652a93d871e49Harald Welte			fprintf(stderr, "ERROR: %d not a valid target)\n",
1133aae69bed019826ddec93f761514652a93d871e49Harald Welte				verdict);
1134aae69bed019826ddec93f761514652a93d871e49Harald Welte			abort();
1135aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1137aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* not reached */
1138aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1141aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1142aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
1143aae69bed019826ddec93f761514652a93d871e49Harald Welte			  TC_HANDLE_T *handle)
1144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1145aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
1146e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	struct rule_head *r = container_of(e, struct rule_head, entry[0]);
1147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1148aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_TARGET;
11490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1150aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch(r->type) {
1151aae69bed019826ddec93f761514652a93d871e49Harald Welte		int spos;
1152aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_FALLTHROUGH:
1153aae69bed019826ddec93f761514652a93d871e49Harald Welte			return "";
1154aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1155aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_JUMP:
1156aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1157aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r->jump->name;
1158aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1159aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_STANDARD:
1160aae69bed019826ddec93f761514652a93d871e49Harald Welte			spos = *(int *)GET_TARGET(e)->data;
1161aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, spos=%d'\n", r, spos);
1162aae69bed019826ddec93f761514652a93d871e49Harald Welte			return standard_target_map(spos);
1163aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1164aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_MODULE:
1165aae69bed019826ddec93f761514652a93d871e49Harald Welte			return GET_TARGET(e)->u.user.name;
1166aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
11670113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1168aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1169aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1170aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is this a built-in chain?  Actually returns hook + 1. */
1171aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1172aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
1173aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1174aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1175aae69bed019826ddec93f761514652a93d871e49Harald Welte
1176aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_BUILTIN;
11770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1178aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, handle);
1179aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1180aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1181b0f3d2d7261be3fe256a66abcc237241fea43a02Martin Josefsson		return 0;
11820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1184aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_is_builtin(c);
11850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
11860113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1187aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get the policy of a given built-in chain */
1188aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *
1189aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_GET_POLICY(const char *chain,
1190aae69bed019826ddec93f761514652a93d871e49Harald Welte	      STRUCT_COUNTERS *counters,
1191aae69bed019826ddec93f761514652a93d871e49Harald Welte	      TC_HANDLE_T *handle)
11920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
1193aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
11940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1195aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_POLICY;
1196fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
1197aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("called for chain %s\n", chain);
11980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1199aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1200aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1201aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1202aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
12030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
12040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1205aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))
1206aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
12070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1208aae69bed019826ddec93f761514652a93d871e49Harald Welte	*counters = c->counters;
12090113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1210aae69bed019826ddec93f761514652a93d871e49Harald Welte	return standard_target_map(c->verdict);
12110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
1212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1214aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_standard_map(struct rule_head *r, int verdict)
1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1216aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
121779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
121979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
122167088e73ce7707229c56987868f112051defca5aRusty Russell	if (t->target.u.target_size
12228c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
122779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
122879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(t->target.u.user.name, STANDARD_TARGET);
1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1231aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->type = IPTCC_R_STANDARD;
1232aae69bed019826ddec93f761514652a93d871e49Harald Welte
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
12357e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1237aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_map_target(const TC_HANDLE_T handle,
1238aae69bed019826ddec93f761514652a93d871e49Harald Welte	   struct rule_head *r)
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1240aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
12410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
1244aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(t->u.user.name, "") == 0) {
1245aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->type = IPTCC_R_FALLTHROUGH;
1246aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
1247aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
124979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
1250aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_ACCEPT - 1);
125179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
1252aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_DROP - 1);
125367088e73ce7707229c56987868f112051defca5aRusty Russell	else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1254aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_QUEUE - 1);
125579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
1256aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, RETURN);
125779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (TC_BUILTIN(t->u.user.name, handle)) {
1258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
1259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
1262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
1263aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c;
1264aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("trying to find chain `%s': ", t->u.user.name);
1265aae69bed019826ddec93f761514652a93d871e49Harald Welte
1266aae69bed019826ddec93f761514652a93d871e49Harald Welte		c = iptcc_find_label(t->u.user.name, handle);
1267aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (c) {
1268aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP_C("found!\n");
1269aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->type = IPTCC_R_JUMP;
1270aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
1271aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
1272aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 1;
1273aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1274aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("not found :(\n");
1275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
12783aef54dce4f9bbe0b466478fd33a1d3131efbbb8Rusty Russell	/* memset to all 0 for your memcmp convenience: don't clear version */
1279228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
12813aef54dce4f9bbe0b466478fd33a1d3131efbbb8Rusty Russell	       FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
1282733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	r->type = IPTCC_R_MODULE;
1283aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(handle);
1284aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
128979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
129079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
129179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned int rulenum,
129279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1294aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1295eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	struct rule_head *r;
1296eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	struct list_head *prev;
1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
129879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INSERT_ENTRY;
1299aae69bed019826ddec93f761514652a93d871e49Harald Welte
1300aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1305eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	/* first rulenum index = 0
1306eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	   first c->num_rules index = 1 */
1307eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	if (rulenum > c->num_rules) {
1308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1312631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	/* If we are inserting at the end just take advantage of the
1313631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	   double linked list, insert will happen before the entry
1314631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	   prev points to. */
1315631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	if (rulenum == c->num_rules) {
1316eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		prev = &c->rules;
1317a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else if (rulenum + 1 <= c->num_rules/2) {
1318631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		r = iptcc_get_rule_num(c, rulenum + 1);
1319a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		prev = &r->list;
1320a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else {
1321a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1322631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		prev = &r->list;
1323631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	}
1324eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson
1325aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1326aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1327aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1328aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1329aae69bed019826ddec93f761514652a93d871e49Harald Welte
1330aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1331aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1332aae69bed019826ddec93f761514652a93d871e49Harald Welte
1333aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1334aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1336aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1337aae69bed019826ddec93f761514652a93d871e49Harald Welte
1338eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	list_add_tail(&r->list, prev);
1339aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1340aae69bed019826ddec93f761514652a93d871e49Harald Welte
1341aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1343aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
134879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
134979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 const STRUCT_ENTRY *e,
135079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 unsigned int rulenum,
135179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 TC_HANDLE_T *handle)
1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1353aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1354aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *old;
1355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
135679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_REPLACE_ENTRY;
1357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1358aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13630f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	if (rulenum >= c->num_rules) {
1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13680f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	/* Take advantage of the double linked list if possible. */
13690f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	if (rulenum + 1 <= c->num_rules/2) {
13700f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		old = iptcc_get_rule_num(c, rulenum + 1);
13710f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	} else {
13720f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
13730f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	}
13740f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson
1375aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1376aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1378aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1379aae69bed019826ddec93f761514652a93d871e49Harald Welte
1380aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1381aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1383aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1384aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1386aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1387aae69bed019826ddec93f761514652a93d871e49Harald Welte
1388aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add(&r->list, &old->list);
1389aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(old);
13900113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1391aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1392aae69bed019826ddec93f761514652a93d871e49Harald Welte
1393aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
139979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
140079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
140179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1403aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1404aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
140679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_APPEND_ENTRY;
1407aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1408aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to find chain `%s'\n", chain);
1409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1413aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1414aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1415aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1416aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1417aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1418aae69bed019826ddec93f761514652a93d871e49Harald Welte
1419aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1420aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1421aae69bed019826ddec93f761514652a93d871e49Harald Welte
1422aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
142312009531e6a96a62ee398eb0ab3e9ec0b3b57701Martin Josefsson		DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1424aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
14250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1426aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1427aae69bed019826ddec93f761514652a93d871e49Harald Welte
1428aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&r->list, &c->rules);
1429aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1430aae69bed019826ddec93f761514652a93d871e49Harald Welte
1431aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
14320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1433aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
143779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmatch_different(const STRUCT_ENTRY_MATCH *a,
1438edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1439edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1440edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
144279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY_MATCH *b;
1443edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
144630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1448228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1451228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
145473ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	*maskptr += ALIGN(sizeof(*a));
1455edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
145673ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1457edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1458edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1459edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1460edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1461edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1462edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1463edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1464733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russelltarget_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
1465edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1466edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1467733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	STRUCT_ENTRY_TARGET *ta, *tb;
1468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1469733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	if (a->type != b->type)
1470733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 0;
1471733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1472733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	ta = GET_TARGET(a->entry);
1473733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	tb = GET_TARGET(b->entry);
1474733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1475733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	switch (a->type) {
1476733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_FALLTHROUGH:
1477733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 1;
1478733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_JUMP:
1479733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return a->jump == b->jump;
1480733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_STANDARD:
1481733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return ((STRUCT_STANDARD_TARGET *)ta)->verdict
1482733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			== ((STRUCT_STANDARD_TARGET *)tb)->verdict;
1483733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_MODULE:
1484733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (ta->u.target_size != tb->u.target_size)
1485733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			return 0;
1486733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
1487733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			return 0;
1488733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1489733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
1490daade4452715cbd1feea05d5231c5e38e3b0b98bRusty Russell			if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
1491733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell				return 0;
1492733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 1;
1493733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	default:
1494733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		fprintf(stderr, "ERROR: bad type %i\n", a->type);
1495733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		abort();
1496733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	}
1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1499733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russellstatic unsigned char *
150079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_same(const STRUCT_ENTRY *a,
150179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY *b,
150279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unsigned char *matchmask);
1503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Delete the first rule in `chain' which matches `fw'. */
1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
150679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
150779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *origfw,
150879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned char *matchmask,
150979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1511aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1512e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	struct rule_head *r, *i;
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
151479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_ENTRY;
1515aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1520e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	/* Create a rule_head from origfw. */
1521e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	r = iptcc_alloc_rule(c, origfw->next_offset);
1522e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	if (!r) {
15230113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = ENOMEM;
15240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
15250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
15260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1527e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	memcpy(r->entry, origfw, origfw->next_offset);
1528e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	r->counter_map.maptype = COUNTER_MAP_NOMAP;
1529e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	if (!iptcc_map_target(*handle, r)) {
1530e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell		DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1531e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell		free(r);
1532e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell		return 0;
153304a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer	} else {
153404a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer		/* iptcc_map_target increment target chain references
153504a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer		 * since this is a fake rule only used for matching
153604a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer		 * the chain references count is decremented again.
153704a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer		 */
153804a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer		if (r->type == IPTCC_R_JUMP
153904a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer		    && r->jump)
154004a1e4cabd185d7a93bea1ece276343044d9ecd4Patrick McHardyJesper Brouer			r->jump->references--;
1541e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	}
1542fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1543e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	list_for_each_entry(i, &c->rules, list) {
1544733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		unsigned char *mask;
1545733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1546733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		mask = is_same(r->entry, i->entry, matchmask);
1547733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (!mask)
1548733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			continue;
1549733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1550733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (!target_same(r, i, mask))
1551733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			continue;
1552733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1553733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		/* If we are about to delete the rule that is the
1554733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		 * current iterator, move rule iterator back.  next
1555733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		 * pointer will then point to real next node */
1556733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (i == (*handle)->rule_iterator_cur) {
1557733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			(*handle)->rule_iterator_cur =
1558733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell				list_entry((*handle)->rule_iterator_cur->list.prev,
1559733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell					   struct rule_head, list);
1560733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		}
1561fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1562733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		c->num_rules--;
1563733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		iptcc_delete_rule(i);
15642a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson
1565733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		set_changed(*handle);
1566733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		free(r);
1567733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 1;
1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1570e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	free(r);
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
15737e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1574aae69bed019826ddec93f761514652a93d871e49Harald Welte
1575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
157879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
157979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    unsigned int rulenum,
158079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1582aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1583aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
158579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_NUM_ENTRY;
1586aae69bed019826ddec93f761514652a93d871e49Harald Welte
1587aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1592a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	if (rulenum >= c->num_rules) {
1593631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		errno = E2BIG;
1594631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		return 0;
1595631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	}
1596631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson
1597631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	/* Take advantage of the double linked list if possible. */
1598a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	if (rulenum + 1 <= c->num_rules/2) {
1599a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		r = iptcc_get_rule_num(c, rulenum + 1);
1600a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else {
1601a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1604aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the rule that is the current
1605aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move rule iterator back.  next pointer will then
1606aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * point to real next node */
1607aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r == (*handle)->rule_iterator_cur) {
1608aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur =
1609aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry((*handle)->rule_iterator_cur->list.prev,
1610aae69bed019826ddec93f761514652a93d871e49Harald Welte				   struct rule_head, list);
16110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1613aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules--;
1614aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(r);
1615aae69bed019826ddec93f761514652a93d871e49Harald Welte
16162a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson	set_changed(*handle);
16172a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson
1618aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
162479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CHECK_PACKET(const IPT_CHAINLABEL chain,
162579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY *entry,
162679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1628664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_CHECK_PACKET;
1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
163579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1637aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1638aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *tmp;
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	iptc_fn = TC_FLUSH_ENTRIES;
1641aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1646aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(r, tmp, &c->rules, list) {
1647aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(r);
1648aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1649aae69bed019826ddec93f761514652a93d871e49Harald Welte
1650aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules = 0;
1651aae69bed019826ddec93f761514652a93d871e49Harald Welte
1652aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1653aae69bed019826ddec93f761514652a93d871e49Harald Welte
1654aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
165979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1661aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1662aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16637e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1664664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_ZERO_ENTRIES;
1665aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1670e5bd1d779fab33353c1dc2d2fa49db639dcebd38Andy Gay	if (c->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1671e5bd1d779fab33353c1dc2d2fa49db639dcebd38Andy Gay		c->counter_map.maptype = COUNTER_MAP_ZEROED;
1672e5bd1d779fab33353c1dc2d2fa49db639dcebd38Andy Gay
1673aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
1674aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1675aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->counter_map.maptype = COUNTER_MAP_ZEROED;
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1677aae69bed019826ddec93f761514652a93d871e49Harald Welte
1678175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16831cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteSTRUCT_COUNTERS *
16841cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_READ_COUNTER(const IPT_CHAINLABEL chain,
16851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
16861cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
16871cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1688aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1689aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16901cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16911cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_READ_COUNTER;
16921cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
16931cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1694aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
16951cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16961cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
16971cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
16981cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1699aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
17000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
17010113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
17020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
17030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1704aae69bed019826ddec93f761514652a93d871e49Harald Welte	return &r->entry[0].counters;
17051cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
17061cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17071cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
17081cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
17091cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
17101cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
17111cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1712aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1713aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
17141cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17151cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_ZERO_COUNTER;
17161cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
17171cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1718aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
17191cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
17201cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
17211cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
17221cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1723aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
17240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
17250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
17260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
17270113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1728aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1729aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_ZEROED;
17301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
17321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17331cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
17341cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
17351cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17361cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
17371cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_SET_COUNTER(const IPT_CHAINLABEL chain,
17381cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       unsigned int rulenum,
17391cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       STRUCT_COUNTERS *counters,
17401cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       TC_HANDLE_T *handle)
17411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1742aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1743aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
17441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
17451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_SET_COUNTER;
17471cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
17481cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1749aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
17501cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
17511cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
17521cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
17530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1754aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
17550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
17560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
17570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
17580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1759aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = r->entry;
1760aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
17610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
17620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
17631cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17641cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
17651cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17661cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
17671cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
17681cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
177379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1775aae69bed019826ddec93f761514652a93d871e49Harald Welte	static struct chain_head *c;
1776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
177779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_CREATE_CHAIN;
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
1781aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(chain, *handle)
178279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_DROP) == 0
178379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_ACCEPT) == 0
178467088e73ce7707229c56987868f112051defca5aRusty Russell	    || strcmp(chain, LABEL_QUEUE) == 0
178579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_RETURN) == 0) {
1786aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain `%s' already exists\n", chain);
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
179179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1792aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain name `%s' too long\n", chain);
1793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1797aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_alloc_chain_head(chain, 0);
1798aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1799aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
1800aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1801aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1803aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1805aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("Creating chain `%s'\n", chain);
1806d8cb787ab44e9d2de4fd3b04fcaa370c9918fc5dJesper Dangaard Brouer	iptc_insert_chain(*handle, c); /* Insert sorted */
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1808aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1810aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
181579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
181679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  TC_HANDLE_T *handle)
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1818aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1820664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_GET_REFERENCES;
1821aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1826aae69bed019826ddec93f761514652a93d871e49Harald Welte	*ref = c->references;
1827aae69bed019826ddec93f761514652a93d871e49Harald Welte
1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
183379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
1836aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
18377e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
183879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_CHAIN;
1839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1840aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1841aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1842aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1843aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1844aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1845aae69bed019826ddec93f761514652a93d871e49Harald Welte
184679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (TC_BUILTIN(chain, *handle)) {
1847aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot remove builtin chain `%s'\n", chain);
1848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1852aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!TC_GET_REFERENCES(&references, chain, handle)) {
1853aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot get references on chain `%s'\n", chain);
1854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1857aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (references > 0) {
1858aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' still has references\n", chain);
1859aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EMLINK;
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1863aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->num_rules) {
1864aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' is not empty\n", chain);
1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1869aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the chain that is the current
1870aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move chain iterator firward. */
1871aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c == (*handle)->chain_iterator_cur)
1872aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_chain_iterator_advance(*handle);
1873aae69bed019826ddec93f761514652a93d871e49Harald Welte
1874aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&c->list);
1875aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(c);
18760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1877aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("chain `%s' deleted\n", chain);
18780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1879aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1880aae69bed019826ddec93f761514652a93d871e49Harald Welte
1881aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
188579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
188679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    const IPT_CHAINLABEL newname,
188779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1889aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
189079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_RENAME_CHAIN;
1891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
18921de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
18931de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte           QUEUE, RETURN. */
1894aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(newname, *handle)
189579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_DROP) == 0
189679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_ACCEPT) == 0
18971de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	    || strcmp(newname, LABEL_QUEUE) == 0
189879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_RETURN) == 0) {
1899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1903aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(oldname, *handle))
190479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || TC_BUILTIN(oldname, *handle)) {
1905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
190979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1914aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
1915aae69bed019826ddec93f761514652a93d871e49Harald Welte
19160113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	set_changed(*handle);
19170113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
192379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_SET_POLICY(const IPT_CHAINLABEL chain,
192479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      const IPT_CHAINLABEL policy,
19251cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	      STRUCT_COUNTERS *counters,
192679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1928aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
193079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_SET_POLICY;
1931aae69bed019826ddec93f761514652a93d871e49Harald Welte
1932aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1933aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1934c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1936aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1938aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
1939aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
1940aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
19419e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte		return 0;
19429e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte	}
19439e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
194479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(policy, LABEL_ACCEPT) == 0)
1945aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_ACCEPT - 1;
194679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(policy, LABEL_DROP) == 0)
1947aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_DROP - 1;
1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
19521cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
19531cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (counters) {
19541cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		/* set byte and packet counters */
1955aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
1956aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_SET;
19571cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	} else {
1958aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_NOMAP;
19591cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
19601cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1961175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
196779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell   libiptc.c: In function `TC_COMMIT':
1968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
197379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellsubtract_counters(STRUCT_COUNTERS *answer,
197479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *a,
197579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *b)
1976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1981aae69bed019826ddec93f761514652a93d871e49Harald Welte
1982aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
1983aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int index)
1984aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1985aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
1986aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NOMAP => zero\n");
1987aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1988aae69bed019826ddec93f761514652a93d871e49Harald Welte
1989aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
1990aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1991aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1992aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos)
1993aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1994aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1995aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1996aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1997aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: X + Y + Z.
1998aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in X + Y
1999aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in replacement read.
2000aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
2001aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = repl->counters[mappos];
2002aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
2003aae69bed019826ddec93f761514652a93d871e49Harald Welte}
2004aae69bed019826ddec93f761514652a93d871e49Harald Welte
2005aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
2006aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
2007aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
2008aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos,
2009aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_COUNTERS *counters)
2010aae69bed019826ddec93f761514652a93d871e49Harald Welte{
2011aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
2012aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
2013aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
2014aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: Y + Z.
2015aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in Y.
2016aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in (replacement read - original read).
2017aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
2018aae69bed019826ddec93f761514652a93d871e49Harald Welte	subtract_counters(&newcounters->counters[index],
2019aae69bed019826ddec93f761514652a93d871e49Harald Welte			  &repl->counters[mappos],
2020aae69bed019826ddec93f761514652a93d871e49Harald Welte			  counters);
2021aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("ZEROED => mappos %u\n", mappos);
2022aae69bed019826ddec93f761514652a93d871e49Harald Welte}
2023aae69bed019826ddec93f761514652a93d871e49Harald Welte
2024aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
2025aae69bed019826ddec93f761514652a93d871e49Harald Welte			     unsigned int index,
2026aae69bed019826ddec93f761514652a93d871e49Harald Welte			     STRUCT_COUNTERS *counters)
2027aae69bed019826ddec93f761514652a93d871e49Harald Welte{
2028aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Want to set counter (iptables-restore) */
2029aae69bed019826ddec93f761514652a93d871e49Harald Welte
2030aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&newcounters->counters[index], counters,
2031aae69bed019826ddec93f761514652a93d871e49Harald Welte		sizeof(STRUCT_COUNTERS));
2032aae69bed019826ddec93f761514652a93d871e49Harald Welte
2033aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("SET\n");
2034aae69bed019826ddec93f761514652a93d871e49Harald Welte}
2035aae69bed019826ddec93f761514652a93d871e49Harald Welte
2036aae69bed019826ddec93f761514652a93d871e49Harald Welte
2037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
203879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_COMMIT(TC_HANDLE_T *handle)
2039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2040e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
204179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_REPLACE *repl;
204279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_COUNTERS_INFO *newcounters;
2043aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
2044aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
2045841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	size_t counterlen;
2046aae69bed019826ddec93f761514652a93d871e49Harald Welte	int new_number;
2047aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int new_size;
2048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2049664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_COMMIT;
2050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
2051841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
2052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
2053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
2054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
2055e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2056aae69bed019826ddec93f761514652a93d871e49Harald Welte	new_number = iptcc_compile_table_prep(*handle, &new_size);
2057aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (new_number < 0) {
2058aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
2059d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_zero;
2060aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2061aae69bed019826ddec93f761514652a93d871e49Harald Welte
2062aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl = malloc(sizeof(*repl) + new_size);
2063e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
2064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
2065d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_zero;
2066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2067ad3b4f9973ac15981b98b8fc4d364ef1ce524212Martin Josefsson	memset(repl, 0, sizeof(*repl) + new_size);
2068aae69bed019826ddec93f761514652a93d871e49Harald Welte
2069e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell#if 0
2070e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	TC_DUMP_ENTRIES(*handle);
2071e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell#endif
2072e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell
2073aae69bed019826ddec93f761514652a93d871e49Harald Welte	counterlen = sizeof(STRUCT_COUNTERS_INFO)
2074aae69bed019826ddec93f761514652a93d871e49Harald Welte			+ sizeof(STRUCT_COUNTERS) * new_number;
2075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
207779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	repl->counters = malloc(sizeof(STRUCT_COUNTERS)
2078e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
2079e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
2080e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
2081d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_free_repl;
2082e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2083e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
2084e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
2085e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
2086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
2087d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_free_repl_counters;
2088e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2089aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(newcounters, 0, counterlen);
2090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
2092aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->num_entries = new_number;
2093aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->size = new_size;
2094aae69bed019826ddec93f761514652a93d871e49Harald Welte
2095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
2096e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
2097aae69bed019826ddec93f761514652a93d871e49Harald Welte
2098aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2099aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->num_entries, repl->size, repl->num_counters);
2100aae69bed019826ddec93f761514652a93d871e49Harald Welte
2101aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = iptcc_compile_table(*handle, repl);
2102aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ret < 0) {
2103aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ret;
2104d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_free_newcounters;
2105aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2106aae69bed019826ddec93f761514652a93d871e49Harald Welte
2107aae69bed019826ddec93f761514652a93d871e49Harald Welte
2108aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2109aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2110aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_replace.blob",
2111aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2112aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2113aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, repl, sizeof(*repl) + repl->size);
2114aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2115aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2116aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2117aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2119d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte	ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
2120d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte			 sizeof(*repl) + repl->size);
2121e0865ad29d53b0d3d34b5cc8b5e023eb593172a8Patrick McHardy	if (ret < 0)
2122d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_free_newcounters;
2123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
2125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
2126aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->num_counters = new_number;
2127aae69bed019826ddec93f761514652a93d871e49Harald Welte
2128aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &(*handle)->chains, list) {
2129aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
2130aae69bed019826ddec93f761514652a93d871e49Harald Welte
2131aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Builtin chains have their own counters */
2132aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (iptcc_is_builtin(c)) {
2133aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for chain-index %u: ", c->foot_index);
2134aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch(c->counter_map.maptype) {
2135aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2136aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, c->foot_index);
2137aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2138aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2139aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2140aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2141aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos);
2142aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2143aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2144aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2145aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2146aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos,
2147aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &c->counters);
2148aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2149aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2150aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, c->foot_index,
2151aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &c->counters);
2152aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2153aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2154aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
21551cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
2156aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
2157aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for index %u: ", r->index);
2158aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch (r->counter_map.maptype) {
2159aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2160aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, r->index);
2161aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2162aae69bed019826ddec93f761514652a93d871e49Harald Welte
2163aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2164aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2165aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2166aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos);
2167aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2168aae69bed019826ddec93f761514652a93d871e49Harald Welte
2169aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2170aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2171aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2172aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos,
2173aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &r->entry->counters);
2174aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2175aae69bed019826ddec93f761514652a93d871e49Harald Welte
2176aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2177aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, r->index,
2178aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &r->entry->counters);
2179aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2180aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
2182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
218362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell
2184aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2185aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2186aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_add_counters.blob",
2187aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2188aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2189aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, newcounters, counterlen);
2190aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2191aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2192aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2193aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2194aae69bed019826ddec93f761514652a93d871e49Harald Welte
2195d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte	ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
2196d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte			 newcounters, counterlen);
2197e0865ad29d53b0d3d34b5cc8b5e023eb593172a8Patrick McHardy	if (ret < 0)
2198d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte		goto out_free_newcounters;
2199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
2201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
2202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
2203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2204d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Weltefinished:
2205841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	TC_FREE(handle);
2206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
2207d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte
2208d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welteout_free_newcounters:
2209d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte	free(newcounters);
2210d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welteout_free_repl_counters:
2211d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte	free(repl->counters);
2212d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welteout_free_repl:
2213d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte	free(repl);
2214d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welteout_zero:
2215d6ba6f57658ee2fee7cf763259e8a0c601479989Harald Welte	return 0;
2216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
2219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
22200b63936140032deac44072951451bdf47b54296aPatrick McHardyTC_GET_RAW_SOCKET(void)
2221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
2223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
2226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
222779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_STRERROR(int err)
2228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
2230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
2231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
2232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
2233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
2234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
22354ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	  { { TC_INIT, EPERM, "Permission denied (you must be root)" },
223679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INIT, EINVAL, "Module is wrong version" },
22374ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_INIT, ENOENT,
22384ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte		    "Table does not exist (do you need to insmod?)" },
223979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
224079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
224179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EMLINK,
2242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
224379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
224479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
224579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
224679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
22471cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
22481cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
224979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
225079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, EINVAL, "Target problem" },
2251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
225279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CHECK_PACKET, EINVAL,
2253c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
22544ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_CHECK_PACKET, ENOSYS,
22554ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	      "Checking will most likely never get implemented" },
2256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
225779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_ENTRY, ENOENT,
2258c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
225979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, ENOENT,
2260c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
226179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, EINVAL,
2262c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
22634ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte
22644ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, 0, "Incompatible with this kernel" },
22654ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
22664ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
22674ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
22684ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOENT, "No chain/target/match by that name" },
2269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
2270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
2273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
2274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
2275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
2278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2279