libiptc.c revision efa8fc2123a2a9fc229ab471edd2b2688ce1da3a
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
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
5279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell= { [HOOK_PRE_ROUTING]  "PREROUTING",
5379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_IN]     "INPUT",
5479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_FORWARD]      "FORWARD",
5579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_OUT]    "OUTPUT",
5610758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_POST_ROUTING] "POSTROUTING",
5710758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#ifdef HOOK_DROPPING
5810758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [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) {
4029d3ed77341361674994f584ff69a61f31a342739Olaf Rempel			if (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{
418aae69bed019826ddec93f761514652a93d871e49Harald Welte	__iptcc_p_del_policy(h, *num);
419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
420aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = offset;
421aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->index = *num;
422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
423ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	iptc_insert_chain(h, c);
424ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
425aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->chain_iterator_cur = c;
426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
428aae69bed019826ddec93f761514652a93d871e49Harald Welte/* main parser function: add an entry from the blob to the cache */
429aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int cache_add_entry(STRUCT_ENTRY *e,
430aae69bed019826ddec93f761514652a93d871e49Harald Welte			   TC_HANDLE_T h,
431aae69bed019826ddec93f761514652a93d871e49Harald Welte			   STRUCT_ENTRY **prev,
432aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int *num)
433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
434aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int builtin;
435aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = (char *)e - (char *)h->entries->entrytable;
436aae69bed019826ddec93f761514652a93d871e49Harald Welte
437aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("entering...");
438aae69bed019826ddec93f761514652a93d871e49Harald Welte
439aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Last entry ("policy rule"). End it.*/
440aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
441aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* This is the ERROR node at the end of the chain */
442aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u: end of table:\n", *num, offset);
443aae69bed019826ddec93f761514652a93d871e49Harald Welte
444aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_del_policy(h, *num);
445aae69bed019826ddec93f761514652a93d871e49Harald Welte
446aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur = NULL;
447aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_inc;
448aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
449aae69bed019826ddec93f761514652a93d871e49Harald Welte
450aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* We know this is the start of a new chain if it's an ERROR
451aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * target, or a hook entry point */
452aae69bed019826ddec93f761514652a93d871e49Harald Welte
453aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
454aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
455aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
456aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
457aae69bed019826ddec93f761514652a93d871e49Harald Welte			(char *)c->name, c);
458aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
459aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
460aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
461aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
462aae69bed019826ddec93f761514652a93d871e49Harald Welte
463aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
464aae69bed019826ddec93f761514652a93d871e49Harald Welte
465aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
466aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
467aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((char *)hooknames[builtin-1],
468aae69bed019826ddec93f761514652a93d871e49Harald Welte						builtin);
469aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
470aae69bed019826ddec93f761514652a93d871e49Harald Welte			*num, offset, c, &c->rules);
471aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
472aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
473aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
474aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
475aae69bed019826ddec93f761514652a93d871e49Harald Welte
476aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->hooknum = builtin;
477aae69bed019826ddec93f761514652a93d871e49Harald Welte
478aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
479aae69bed019826ddec93f761514652a93d871e49Harald Welte
480aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* FIXME: this is ugly. */
481aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto new_rule;
482aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
483aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* has to be normal rule */
484aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
485aae69bed019826ddec93f761514652a93d871e49Harald Weltenew_rule:
486aae69bed019826ddec93f761514652a93d871e49Harald Welte
487aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
488aae69bed019826ddec93f761514652a93d871e49Harald Welte					   e->next_offset))) {
489aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = ENOMEM;
490aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
491aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
492aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
493aae69bed019826ddec93f761514652a93d871e49Harald Welte
494aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
495aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = offset;
496aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(r->entry, e, e->next_offset);
497aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
498aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.mappos = r->index;
499aae69bed019826ddec93f761514652a93d871e49Harald Welte
500aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* handling of jumps, etc. */
501aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
502aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
503aae69bed019826ddec93f761514652a93d871e49Harald Welte
504aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
505aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->target.u.target_size
506aae69bed019826ddec93f761514652a93d871e49Harald Welte			    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
507aae69bed019826ddec93f761514652a93d871e49Harald Welte				errno = EINVAL;
508aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
509aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
510aae69bed019826ddec93f761514652a93d871e49Harald Welte
511aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->verdict < 0) {
512aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("standard, verdict=%d\n", t->verdict);
513aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_STANDARD;
514aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else if (t->verdict == r->offset+e->next_offset) {
515aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("fallthrough\n");
516aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_FALLTHROUGH;
517aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else {
518aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("jump, target=%u\n", t->verdict);
519aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_JUMP;
520aae69bed019826ddec93f761514652a93d871e49Harald Welte				/* Jump target fixup has to be deferred
521aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * until second pass, since we migh not
522aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * yet have parsed the target */
523aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
52452c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson		} else {
52552c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
52652c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			r->type = IPTCC_R_MODULE;
527aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
528aae69bed019826ddec93f761514652a93d871e49Harald Welte
529aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_add_tail(&r->list, &h->chain_iterator_cur->rules);
5308d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefsson		h->chain_iterator_cur->num_rules++;
531aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
532aae69bed019826ddec93f761514652a93d871e49Harald Welteout_inc:
533aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
534aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
537aae69bed019826ddec93f761514652a93d871e49Harald Welte
538aae69bed019826ddec93f761514652a93d871e49Harald Welte/* parse an iptables blob into it's pieces */
539aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int parse_table(TC_HANDLE_T h)
540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
541aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *prev;
542aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
543aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
544aae69bed019826ddec93f761514652a93d871e49Harald Welte
545aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: over ruleset blob */
546aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
547aae69bed019826ddec93f761514652a93d871e49Harald Welte			cache_add_entry, h, &prev, &num);
548aae69bed019826ddec93f761514652a93d871e49Harald Welte
549aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: fixup parsed data from first pass */
550aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
551aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
552aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
553aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct chain_head *c;
554aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
555aae69bed019826ddec93f761514652a93d871e49Harald Welte
556aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (r->type != IPTCC_R_JUMP)
557aae69bed019826ddec93f761514652a93d871e49Harald Welte				continue;
558aae69bed019826ddec93f761514652a93d871e49Harald Welte
559aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
560aae69bed019826ddec93f761514652a93d871e49Harald Welte			c = iptcc_find_chain_by_offset(h, t->verdict);
561aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (!c)
562aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
563aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
564aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
565aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
566aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
567aae69bed019826ddec93f761514652a93d871e49Harald Welte
568aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* FIXME: sort chains */
569aae69bed019826ddec93f761514652a93d871e49Harald Welte
570aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
5710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
5729e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
573aae69bed019826ddec93f761514652a93d871e49Harald Welte
574aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
575aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET COMPILATION (cache -> blob)
576aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
577aae69bed019826ddec93f761514652a93d871e49Harald Welte
578aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
579aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_start{
580aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
581aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target name;
582aae69bed019826ddec93f761514652a93d871e49Harald Welte};
583aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_START_SIZE	(sizeof(STRUCT_ENTRY) +			\
584aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
585aae69bed019826ddec93f761514652a93d871e49Harald Welte
586aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_foot {
587aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
588aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_STANDARD_TARGET target;
589aae69bed019826ddec93f761514652a93d871e49Harald Welte};
590aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_FOOT_SIZE	(sizeof(STRUCT_ENTRY) +			\
591aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
592aae69bed019826ddec93f761514652a93d871e49Harald Welte
593aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_error {
594aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry;
595aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target target;
596aae69bed019826ddec93f761514652a93d871e49Harald Welte};
597aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_ERROR_SIZE	(sizeof(STRUCT_ENTRY) +			\
598aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
599aae69bed019826ddec93f761514652a93d871e49Harald Welte
600aae69bed019826ddec93f761514652a93d871e49Harald Welte
601aae69bed019826ddec93f761514652a93d871e49Harald Welte
602aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile rule from cache into blob */
603aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
6040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
605aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* handle jumps */
606aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP) {
607aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
608aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
609aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* memset for memcmp convenience on delete/replace */
610aae69bed019826ddec93f761514652a93d871e49Harald Welte		memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
611aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(t->target.u.user.name, STANDARD_TARGET);
612aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Jumps can only happen to builtin chains, so we
613aae69bed019826ddec93f761514652a93d871e49Harald Welte		 * can safely assume that they always have a header */
614aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
615aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if (r->type == IPTCC_R_FALLTHROUGH) {
616aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
617aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
618aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->offset + r->size;
619aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
620aae69bed019826ddec93f761514652a93d871e49Harald Welte
621aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* copy entry from cache to blob */
622aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy((char *)repl->entries+r->offset, r->entry, r->size);
623aae69bed019826ddec93f761514652a93d871e49Harald Welte
624aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
627aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile chain from cache into blob */
628aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
6293ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
630aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
631aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
632aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_start *head;
633aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_foot *foot;
634aae69bed019826ddec93f761514652a93d871e49Harald Welte
635aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* only user-defined chains have heaer */
636aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
637aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* put chain header in place */
638aae69bed019826ddec93f761514652a93d871e49Harald Welte		head = (void *)repl->entries + c->head_offset;
639aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.target_offset = sizeof(STRUCT_ENTRY);
640aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.next_offset = IPTCB_CHAIN_START_SIZE;
641aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.t.u.user.name, ERROR_TARGET);
642aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->name.t.u.target_size =
643aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(struct ipt_error_target));
644aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.error, c->name);
645aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
646aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->hook_entry[c->hooknum-1] = c->head_offset;
647aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->underflow[c->hooknum-1] = c->foot_offset;
648aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
649aae69bed019826ddec93f761514652a93d871e49Harald Welte
650aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* iterate over rules */
651aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
652aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_rule(h, repl, r);
653aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
654aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
655aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
656aae69bed019826ddec93f761514652a93d871e49Harald Welte
657aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* put chain footer in place */
658aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot = (void *)repl->entries + c->foot_offset;
659aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.target_offset = sizeof(STRUCT_ENTRY);
660aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
661aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
662aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->target.target.u.target_size =
663aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(STRUCT_STANDARD_TARGET));
664aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* builtin targets have verdict, others return */
665aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_is_builtin(c))
666aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = c->verdict;
667aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
668aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = RETURN;
669aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* set policy-counters */
670aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
671aae69bed019826ddec93f761514652a93d871e49Harald Welte
672aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
6733ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
6743ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
675aae69bed019826ddec93f761514652a93d871e49Harald Welte/* calculate offset and number for every rule in the cache */
676aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
677efa8fc2123a2a9fc229ab471edd2b2688ce1da3aHarald Welte				       unsigned int *offset, unsigned int *num)
6783ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
679aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
680aae69bed019826ddec93f761514652a93d871e49Harald Welte
681aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = *offset;
682aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
683aae69bed019826ddec93f761514652a93d871e49Harald Welte
684aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))  {
685aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Chain has header */
686aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += sizeof(STRUCT_ENTRY)
687aae69bed019826ddec93f761514652a93d871e49Harald Welte			     + ALIGN(sizeof(struct ipt_error_target));
688aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
689aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
690aae69bed019826ddec93f761514652a93d871e49Harald Welte
691aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
692aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
693aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = *offset;
694aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
695aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += r->size;
696aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
697aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
698aae69bed019826ddec93f761514652a93d871e49Harald Welte
699aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
700aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset, *num);
701aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_offset = *offset;
702aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_index = *num;
703aae69bed019826ddec93f761514652a93d871e49Harald Welte	*offset += sizeof(STRUCT_ENTRY)
704aae69bed019826ddec93f761514652a93d871e49Harald Welte		   + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
705aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
706aae69bed019826ddec93f761514652a93d871e49Harald Welte
707aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
7083ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
7093ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
710aae69bed019826ddec93f761514652a93d871e49Harald Welte/* put the pieces back together again */
711aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
712aae69bed019826ddec93f761514652a93d871e49Harald Welte{
713aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
714aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = 0, num = 0;
715aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret = 0;
7163ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
717aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: calculate offset for every rule */
718aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
719aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
720aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
721aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
722aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
723aae69bed019826ddec93f761514652a93d871e49Harald Welte
724aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append one error rule at end of chain */
725aae69bed019826ddec93f761514652a93d871e49Harald Welte	num++;
726aae69bed019826ddec93f761514652a93d871e49Harald Welte	offset += sizeof(STRUCT_ENTRY)
727aae69bed019826ddec93f761514652a93d871e49Harald Welte		  + ALIGN(sizeof(struct ipt_error_target));
728aae69bed019826ddec93f761514652a93d871e49Harald Welte
729aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* ruleset size is now in offset */
730aae69bed019826ddec93f761514652a93d871e49Harald Welte	*size = offset;
731aae69bed019826ddec93f761514652a93d871e49Harald Welte	return num;
732aae69bed019826ddec93f761514652a93d871e49Harald Welte}
733aae69bed019826ddec93f761514652a93d871e49Harald Welte
734aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
7350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
736aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
737aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_error *error;
7380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
739aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: copy from cache to offsets, fill in jumps */
740aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
741aae69bed019826ddec93f761514652a93d871e49Harald Welte		int ret = iptcc_compile_chain(h, repl, c);
742aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
743aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
7440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
7450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
746aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append error rule at end of chain */
747aae69bed019826ddec93f761514652a93d871e49Harald Welte	error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
748aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.target_offset = sizeof(STRUCT_ENTRY);
749aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
750aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->target.t.u.user.target_size =
751aae69bed019826ddec93f761514652a93d871e49Harald Welte		ALIGN(sizeof(struct ipt_error_target));
752aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
753aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.error, "ERROR");
754aae69bed019826ddec93f761514652a93d871e49Harald Welte
755aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
7560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
758aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
759aae69bed019826ddec93f761514652a93d871e49Harald Welte * EXTERNAL API (operates on cache only)
760aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
761aae69bed019826ddec93f761514652a93d871e49Harald Welte
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
76379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic TC_HANDLE_T
7640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltealloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
76779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
769aae69bed019826ddec93f761514652a93d871e49Harald Welte	len = sizeof(STRUCT_TC_HANDLE) + size;
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
771aae69bed019826ddec93f761514652a93d871e49Harald Welte	h = malloc(sizeof(STRUCT_TC_HANDLE));
772aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h) {
773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
776aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(h, 0, sizeof(*h));
777aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&h->chains);
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
779aae69bed019826ddec93f761514652a93d871e49Harald Welte
7800371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
781aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h->entries)
782aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_free_handle;
783aae69bed019826ddec93f761514652a93d871e49Harald Welte
784aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(h->entries->name, tablename);
7850371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries->size = size;
786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
788aae69bed019826ddec93f761514652a93d871e49Harald Welte
789aae69bed019826ddec93f761514652a93d871e49Harald Welteout_free_handle:
790aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(h);
791aae69bed019826ddec93f761514652a93d871e49Harald Welte
792aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
795aae69bed019826ddec93f761514652a93d871e49Harald Welte
79679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_HANDLE_T
79779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INIT(const char *tablename)
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
79979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
80079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
801efa8fc2123a2a9fc229ab471edd2b2688ce1da3aHarald Welte	unsigned int tmp;
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
80479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INIT;
805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
806841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
807841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		errno = EINVAL;
808841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		return NULL;
809841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
810841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
811664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (sockfd_use == 0) {
812664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
813664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		if (sockfd < 0)
814664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			return NULL;
815664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
816664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	sockfd_use++;
817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
819841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
821664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
822664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		if (--sockfd_use == 0) {
823664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			close(sockfd);
824664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			sockfd = -1;
825664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		}
826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
827664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
829aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
830aae69bed019826ddec93f761514652a93d871e49Harald Welte		info.valid_hooks, info.num_entries, info.size);
831aae69bed019826ddec93f761514652a93d871e49Harald Welte
8320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((h = alloc_handle(info.name, info.size, info.num_entries))
833841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == NULL) {
834664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		if (--sockfd_use == 0) {
835664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			close(sockfd);
836664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates			sockfd = -1;
837664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		}
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
839841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
8430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
844aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->entries->size = h->info.size;
845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
84679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
848aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
849aae69bed019826ddec93f761514652a93d871e49Harald Welte		       &tmp) < 0)
850aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
851aae69bed019826ddec93f761514652a93d871e49Harald Welte
852aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
853aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
854aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_get_entries.blob",
855aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
856aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
857aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, h->entries, tmp);
858aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
859aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
861aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
862aae69bed019826ddec93f761514652a93d871e49Harald Welte
863aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (parse_table(h) < 0)
864aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
8657e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
868aae69bed019826ddec93f761514652a93d871e49Harald Welteerror:
869664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (--sockfd_use == 0) {
870664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		close(sockfd);
871664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		sockfd = -1;
872664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
873aae69bed019826ddec93f761514652a93d871e49Harald Welte	TC_FREE(&h);
874aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
877841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssonvoid
878841e4aed2349046eb2c0b1375139c06569a93bd0Martin JosefssonTC_FREE(TC_HANDLE_T *h)
879841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
880aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c, *tmp;
881aae69bed019826ddec93f761514652a93d871e49Harald Welte
882664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_FREE;
883664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	if (--sockfd_use == 0) {
884664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		close(sockfd);
885664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		sockfd = -1;
886664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
887aae69bed019826ddec93f761514652a93d871e49Harald Welte
888aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
889aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r, *rtmp;
890aae69bed019826ddec93f761514652a93d871e49Harald Welte
891aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry_safe(r, rtmp, &c->rules, list) {
892aae69bed019826ddec93f761514652a93d871e49Harald Welte			free(r);
893aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
894aae69bed019826ddec93f761514652a93d871e49Harald Welte
895aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(c);
896aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
897aae69bed019826ddec93f761514652a93d871e49Harald Welte
898aae69bed019826ddec93f761514652a93d871e49Harald Welte	free((*h)->entries);
899841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	free(*h);
900aae69bed019826ddec93f761514652a93d871e49Harald Welte
901841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	*h = NULL;
902841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson}
903841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
90579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellprint_match(const STRUCT_ENTRY_MATCH *m)
906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
907228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
91179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
91279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
91479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DUMP_ENTRIES(const TC_HANDLE_T handle)
915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
916664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_DUMP_ENTRIES;
917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
918aae69bed019826ddec93f761514652a93d871e49Harald Welte#if 0
919e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	printf("libiptc v%s. %u bytes.\n",
920e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	       IPTABLES_VERSION, handle->entries->size);
921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
92367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_PRE_ROUTING],
92467088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_IN],
92567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_FORWARD],
92667088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_OUT],
92767088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_POST_ROUTING]);
928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
92967088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_PRE_ROUTING],
93067088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_IN],
93167088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_FORWARD],
93267088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_OUT],
93367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_POST_ROUTING]);
934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
935aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
93679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      dump_entry, handle);
937aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
9380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
94179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
943664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_IS_CHAIN;
944aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_find_label(chain, handle) != NULL;
945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
947aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
948aae69bed019826ddec93f761514652a93d871e49Harald Welte{
949aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = handle->chain_iterator_cur;
950aae69bed019826ddec93f761514652a93d871e49Harald Welte
951aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->list.next == &handle->chains)
952aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur = NULL;
953aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
954aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur =
955aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry(c->list.next, struct chain_head, list);
956aae69bed019826ddec93f761514652a93d871e49Harald Welte}
957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
95830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
9608c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_CHAIN(TC_HANDLE_T *handle)
961e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
962aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = list_entry((*handle)->chains.next,
963aae69bed019826ddec93f761514652a93d871e49Harald Welte					  struct chain_head, list);
964aae69bed019826ddec93f761514652a93d871e49Harald Welte
965aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_CHAIN;
966aae69bed019826ddec93f761514652a93d871e49Harald Welte
967aae69bed019826ddec93f761514652a93d871e49Harald Welte
968aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&(*handle)->chains)) {
969aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no chains\n");
9700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
971aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
9720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
973aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->chain_iterator_cur = c;
974aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
97530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
976aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
977aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
97830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
97930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
98030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
98130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
98279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NEXT_CHAIN(TC_HANDLE_T *handle)
98330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
984aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = (*handle)->chain_iterator_cur;
985aae69bed019826ddec93f761514652a93d871e49Harald Welte
986aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_CHAIN;
98730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
988aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
989aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no more chains\n");
99030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
991aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
99230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
993aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
994aae69bed019826ddec93f761514652a93d871e49Harald Welte
995aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
996aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
99730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
99830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
99930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
100079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
10018c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
100230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
1003aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1004aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1005aae69bed019826ddec93f761514652a93d871e49Harald Welte
1006aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_RULE;
100730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1008aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("first rule(%s): ", chain);
1009aae69bed019826ddec93f761514652a93d871e49Harald Welte
1010aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
101130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
101230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
101330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1014e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
101630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
1017aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&c->rules)) {
1018aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("no rules, returning NULL\n");
101930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1020aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1021aae69bed019826ddec93f761514652a93d871e49Harald Welte
1022aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry(c->rules.next, struct rule_head, list);
1023aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
1024aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("%p\n", r);
102530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1026aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
1027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1028e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
102930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
103079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
10318c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
103230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
1033aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1034aae69bed019826ddec93f761514652a93d871e49Harald Welte
1035664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_NEXT_RULE;
1036aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
1037aae69bed019826ddec93f761514652a93d871e49Harald Welte
1038aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(*handle)->rule_iterator_cur) {
1039aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("returning NULL\n");
104030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1041aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1042aae69bed019826ddec93f761514652a93d871e49Harald Welte
1043aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry((*handle)->rule_iterator_cur->list.next,
1044aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct rule_head, list);
104530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1046aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_RULE;
1047aae69bed019826ddec93f761514652a93d871e49Harald Welte
1048aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("next=%p, head=%p...", &r->list,
1049aae69bed019826ddec93f761514652a93d871e49Harald Welte		&(*handle)->rule_iterator_cur->chain->rules);
1050aae69bed019826ddec93f761514652a93d871e49Harald Welte
1051aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
1052aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur = NULL;
1053aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("finished, returning NULL\n");
1054aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1055aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1056aae69bed019826ddec93f761514652a93d871e49Harald Welte
1057aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
1058aae69bed019826ddec93f761514652a93d871e49Harald Welte
1059aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* NOTE: prev is without any influence ! */
1060aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("returning rule %p\n", r);
1061aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
106230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
106330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
1065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
106679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1068aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1069aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NUM_RULES;
1070e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1071aae69bed019826ddec93f761514652a93d871e49Harald Welte
1072aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1073aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1074e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
1076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1077aae69bed019826ddec93f761514652a93d871e49Harald Welte
1078aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->num_rules;
1079e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1080e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
108179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *TC_GET_RULE(const char *chain,
108279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				unsigned int n,
108379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				TC_HANDLE_T *handle)
1084e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1085aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1086aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1087aae69bed019826ddec93f761514652a93d871e49Harald Welte
1088aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_RULE;
1089e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1091aae69bed019826ddec93f761514652a93d871e49Harald Welte
1092aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1093aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1094e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
1096e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1097e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1098aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = iptcc_get_rule_num(c, n);
1099aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
1100aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1101aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
1102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1104aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1105aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *standard_target_map(int verdict)
1106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1107aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch (verdict) {
1108aae69bed019826ddec93f761514652a93d871e49Harald Welte		case RETURN:
110979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_RETURN;
1110aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1111aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_ACCEPT-1:
111279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_ACCEPT;
1113aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1114aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_DROP-1:
1115aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_DROP;
1116aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1117aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_QUEUE-1:
1118aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_QUEUE;
1119aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1120aae69bed019826ddec93f761514652a93d871e49Harald Welte		default:
1121aae69bed019826ddec93f761514652a93d871e49Harald Welte			fprintf(stderr, "ERROR: %d not a valid target)\n",
1122aae69bed019826ddec93f761514652a93d871e49Harald Welte				verdict);
1123aae69bed019826ddec93f761514652a93d871e49Harald Welte			abort();
1124aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1126aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* not reached */
1127aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1130aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1131aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
1132aae69bed019826ddec93f761514652a93d871e49Harald Welte			  TC_HANDLE_T *handle)
1133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1134aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
1135e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	struct rule_head *r = container_of(e, struct rule_head, entry[0]);
1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1137aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_TARGET;
11380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1139aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch(r->type) {
1140aae69bed019826ddec93f761514652a93d871e49Harald Welte		int spos;
1141aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_FALLTHROUGH:
1142aae69bed019826ddec93f761514652a93d871e49Harald Welte			return "";
1143aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1144aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_JUMP:
1145aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1146aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r->jump->name;
1147aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1148aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_STANDARD:
1149aae69bed019826ddec93f761514652a93d871e49Harald Welte			spos = *(int *)GET_TARGET(e)->data;
1150aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, spos=%d'\n", r, spos);
1151aae69bed019826ddec93f761514652a93d871e49Harald Welte			return standard_target_map(spos);
1152aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1153aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_MODULE:
1154aae69bed019826ddec93f761514652a93d871e49Harald Welte			return GET_TARGET(e)->u.user.name;
1155aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
11560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1157aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1158aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1159aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is this a built-in chain?  Actually returns hook + 1. */
1160aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1161aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
1162aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1163aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1164aae69bed019826ddec93f761514652a93d871e49Harald Welte
1165aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_BUILTIN;
11660113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1167aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, handle);
1168aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1169aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1170b0f3d2d7261be3fe256a66abcc237241fea43a02Martin Josefsson		return 0;
11710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1173aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_is_builtin(c);
11740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
11750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1176aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get the policy of a given built-in chain */
1177aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *
1178aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_GET_POLICY(const char *chain,
1179aae69bed019826ddec93f761514652a93d871e49Harald Welte	      STRUCT_COUNTERS *counters,
1180aae69bed019826ddec93f761514652a93d871e49Harald Welte	      TC_HANDLE_T *handle)
11810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
1182aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
11830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1184aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_POLICY;
1185fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
1186aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("called for chain %s\n", chain);
11870113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1188aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1189aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1190aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1191aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
11920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1194aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))
1195aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
11960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1197aae69bed019826ddec93f761514652a93d871e49Harald Welte	*counters = c->counters;
11980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1199aae69bed019826ddec93f761514652a93d871e49Harald Welte	return standard_target_map(c->verdict);
12000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
1201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1203aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_standard_map(struct rule_head *r, int verdict)
1204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1205aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
120679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
120879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
121067088e73ce7707229c56987868f112051defca5aRusty Russell	if (t->target.u.target_size
12118c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
121679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
121779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(t->target.u.user.name, STANDARD_TARGET);
1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
1219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1220aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->type = IPTCC_R_STANDARD;
1221aae69bed019826ddec93f761514652a93d871e49Harald Welte
1222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
12247e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1226aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_map_target(const TC_HANDLE_T handle,
1227aae69bed019826ddec93f761514652a93d871e49Harald Welte	   struct rule_head *r)
1228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1229aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
12300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
1233aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(t->u.user.name, "") == 0) {
1234aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->type = IPTCC_R_FALLTHROUGH;
1235aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
1236aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
123879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
1239aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_ACCEPT - 1);
124079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
1241aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_DROP - 1);
124267088e73ce7707229c56987868f112051defca5aRusty Russell	else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1243aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_QUEUE - 1);
124479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
1245aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, RETURN);
124679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (TC_BUILTIN(t->u.user.name, handle)) {
1247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
1248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
1251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
1252aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c;
1253aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("trying to find chain `%s': ", t->u.user.name);
1254aae69bed019826ddec93f761514652a93d871e49Harald Welte
1255aae69bed019826ddec93f761514652a93d871e49Harald Welte		c = iptcc_find_label(t->u.user.name, handle);
1256aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (c) {
1257aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP_C("found!\n");
1258aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->type = IPTCC_R_JUMP;
1259aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
1260aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
1261aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 1;
1262aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1263aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("not found :(\n");
1264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
12673aef54dce4f9bbe0b466478fd33a1d3131efbbb8Rusty Russell	/* memset to all 0 for your memcmp convenience: don't clear version */
1268228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
1269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
12703aef54dce4f9bbe0b466478fd33a1d3131efbbb8Rusty Russell	       FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
1271733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	r->type = IPTCC_R_MODULE;
1272aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(handle);
1273aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12760113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
127879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
127979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
128079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned int rulenum,
128179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1283aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1284eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	struct rule_head *r;
1285eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	struct list_head *prev;
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
128779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INSERT_ENTRY;
1288aae69bed019826ddec93f761514652a93d871e49Harald Welte
1289aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1294eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	/* first rulenum index = 0
1295eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	   first c->num_rules index = 1 */
1296eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	if (rulenum > c->num_rules) {
1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1301631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	/* If we are inserting at the end just take advantage of the
1302631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	   double linked list, insert will happen before the entry
1303631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	   prev points to. */
1304631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	if (rulenum == c->num_rules) {
1305eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		prev = &c->rules;
1306a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else if (rulenum + 1 <= c->num_rules/2) {
1307631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		r = iptcc_get_rule_num(c, rulenum + 1);
1308a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		prev = &r->list;
1309a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else {
1310a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1311631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		prev = &r->list;
1312631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	}
1313eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson
1314aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1315aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1316aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1317aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1318aae69bed019826ddec93f761514652a93d871e49Harald Welte
1319aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1320aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1321aae69bed019826ddec93f761514652a93d871e49Harald Welte
1322aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1323aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1325aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1326aae69bed019826ddec93f761514652a93d871e49Harald Welte
1327eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	list_add_tail(&r->list, prev);
1328aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1329aae69bed019826ddec93f761514652a93d871e49Harald Welte
1330aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1332aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
133779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
133879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 const STRUCT_ENTRY *e,
133979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 unsigned int rulenum,
134079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 TC_HANDLE_T *handle)
1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1342aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1343aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *old;
1344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
134579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_REPLACE_ENTRY;
1346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1347aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13520f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	if (rulenum >= c->num_rules) {
1353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1354e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13570f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	/* Take advantage of the double linked list if possible. */
13580f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	if (rulenum + 1 <= c->num_rules/2) {
13590f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		old = iptcc_get_rule_num(c, rulenum + 1);
13600f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	} else {
13610f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
13620f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson	}
13630f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson
1364aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1365aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1367aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1368aae69bed019826ddec93f761514652a93d871e49Harald Welte
1369aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1370aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1372aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1373aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13740113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1375aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1376aae69bed019826ddec93f761514652a93d871e49Harald Welte
1377aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add(&r->list, &old->list);
1378aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(old);
13790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1380aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1381aae69bed019826ddec93f761514652a93d871e49Harald Welte
1382aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13850113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
138879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
138979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
139079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1392aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1393aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_APPEND_ENTRY;
1396aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1397aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to find chain `%s'\n", chain);
1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1402aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1403aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1404aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1405aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1406aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1407aae69bed019826ddec93f761514652a93d871e49Harald Welte
1408aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1409aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1410aae69bed019826ddec93f761514652a93d871e49Harald Welte
1411aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
141212009531e6a96a62ee398eb0ab3e9ec0b3b57701Martin Josefsson		DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1413aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
14140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1415aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1416aae69bed019826ddec93f761514652a93d871e49Harald Welte
1417aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&r->list, &c->rules);
1418aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1419aae69bed019826ddec93f761514652a93d871e49Harald Welte
1420aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
14210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1422aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
142679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmatch_different(const STRUCT_ENTRY_MATCH *a,
1427edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1428edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1429edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
143179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY_MATCH *b;
1432edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
143530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1437228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1440228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
144373ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	*maskptr += ALIGN(sizeof(*a));
1444edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
144573ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1446edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1447edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1448edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1449edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1450edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1451edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1452edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1453733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russelltarget_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
1454edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1455edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1456733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	STRUCT_ENTRY_TARGET *ta, *tb;
1457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1458733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	if (a->type != b->type)
1459733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 0;
1460733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1461733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	ta = GET_TARGET(a->entry);
1462733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	tb = GET_TARGET(b->entry);
1463733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1464733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	switch (a->type) {
1465733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_FALLTHROUGH:
1466733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 1;
1467733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_JUMP:
1468733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return a->jump == b->jump;
1469733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_STANDARD:
1470733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return ((STRUCT_STANDARD_TARGET *)ta)->verdict
1471733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			== ((STRUCT_STANDARD_TARGET *)tb)->verdict;
1472733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	case IPTCC_R_MODULE:
1473733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (ta->u.target_size != tb->u.target_size)
1474733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			return 0;
1475733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
1476733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			return 0;
1477733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1478733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
1479daade4452715cbd1feea05d5231c5e38e3b0b98bRusty Russell			if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
1480733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell				return 0;
1481733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 1;
1482733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	default:
1483733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		fprintf(stderr, "ERROR: bad type %i\n", a->type);
1484733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		abort();
1485733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	}
1486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1488733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russellstatic unsigned char *
148979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_same(const STRUCT_ENTRY *a,
149079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY *b,
149179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unsigned char *matchmask);
1492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14930113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Delete the first rule in `chain' which matches `fw'. */
1494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
149579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
149679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *origfw,
149779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned char *matchmask,
149879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1500aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1501e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	struct rule_head *r, *i;
1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
150379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_ENTRY;
1504aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1509e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	/* Create a rule_head from origfw. */
1510e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	r = iptcc_alloc_rule(c, origfw->next_offset);
1511e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	if (!r) {
15120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = ENOMEM;
15130113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
15140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
15150113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1516e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	memcpy(r->entry, origfw, origfw->next_offset);
1517e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	r->counter_map.maptype = COUNTER_MAP_NOMAP;
1518e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	if (!iptcc_map_target(*handle, r)) {
1519e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell		DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1520e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell		free(r);
1521e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell		return 0;
1522e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	}
1523fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1524e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	list_for_each_entry(i, &c->rules, list) {
1525733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		unsigned char *mask;
1526733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1527733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		mask = is_same(r->entry, i->entry, matchmask);
1528733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (!mask)
1529733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			continue;
1530733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1531733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (!target_same(r, i, mask))
1532733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			continue;
1533733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell
1534733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		/* If we are about to delete the rule that is the
1535733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		 * current iterator, move rule iterator back.  next
1536733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		 * pointer will then point to real next node */
1537733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		if (i == (*handle)->rule_iterator_cur) {
1538733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell			(*handle)->rule_iterator_cur =
1539733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell				list_entry((*handle)->rule_iterator_cur->list.prev,
1540733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell					   struct rule_head, list);
1541733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		}
1542fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1543733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		c->num_rules--;
1544733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		iptcc_delete_rule(i);
15452a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson
1546733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		set_changed(*handle);
1547733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		free(r);
1548733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell		return 1;
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1551e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	free(r);
1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
15547e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1555aae69bed019826ddec93f761514652a93d871e49Harald Welte
1556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
155979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
156079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    unsigned int rulenum,
156179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1563aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1564aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
156679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_NUM_ENTRY;
1567aae69bed019826ddec93f761514652a93d871e49Harald Welte
1568aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1573a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	if (rulenum >= c->num_rules) {
1574631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		errno = E2BIG;
1575631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		return 0;
1576631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	}
1577631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson
1578631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson	/* Take advantage of the double linked list if possible. */
1579a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	if (rulenum + 1 <= c->num_rules/2) {
1580a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		r = iptcc_get_rule_num(c, rulenum + 1);
1581a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else {
1582a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1585aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the rule that is the current
1586aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move rule iterator back.  next pointer will then
1587aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * point to real next node */
1588aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r == (*handle)->rule_iterator_cur) {
1589aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur =
1590aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry((*handle)->rule_iterator_cur->list.prev,
1591aae69bed019826ddec93f761514652a93d871e49Harald Welte				   struct rule_head, list);
15920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1594aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules--;
1595aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(r);
1596aae69bed019826ddec93f761514652a93d871e49Harald Welte
15972a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson	set_changed(*handle);
15982a5dbbb883fb0cc8a122b47a5d8e08ef3e6ff5bcMartin Josefsson
1599aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
160579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CHECK_PACKET(const IPT_CHAINLABEL chain,
160679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY *entry,
160779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1609664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_CHECK_PACKET;
1610e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
161679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1618aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1619aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *tmp;
1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	iptc_fn = TC_FLUSH_ENTRIES;
1622aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1627aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(r, tmp, &c->rules, list) {
1628aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(r);
1629aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1630aae69bed019826ddec93f761514652a93d871e49Harald Welte
1631aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules = 0;
1632aae69bed019826ddec93f761514652a93d871e49Harald Welte
1633aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1634aae69bed019826ddec93f761514652a93d871e49Harald Welte
1635aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
164079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1642aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1643aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16447e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1645664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_ZERO_ENTRIES;
1646aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1651aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
1652aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1653aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->counter_map.maptype = COUNTER_MAP_ZEROED;
1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1655aae69bed019826ddec93f761514652a93d871e49Harald Welte
1656175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16611cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteSTRUCT_COUNTERS *
16621cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_READ_COUNTER(const IPT_CHAINLABEL chain,
16631cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
16641cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
16651cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1666aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1667aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16681cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16691cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_READ_COUNTER;
16701cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
16711cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1672aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
16731cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16741cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
16751cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
16761cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1677aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
16780113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
16790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
16800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
16810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1682aae69bed019826ddec93f761514652a93d871e49Harald Welte	return &r->entry[0].counters;
16831cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
16841cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
16861cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
16871cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
16881cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
16891cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1690aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1691aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16921cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16931cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_ZERO_COUNTER;
16941cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
16951cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1696aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
16971cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16981cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
16991cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
17001cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1701aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
17020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
17030113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
17040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
17050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1706aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1707aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_ZEROED;
17081cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17091cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
17101cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17111cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
17121cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
17131cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17141cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
17151cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_SET_COUNTER(const IPT_CHAINLABEL chain,
17161cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       unsigned int rulenum,
17171cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       STRUCT_COUNTERS *counters,
17181cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       TC_HANDLE_T *handle)
17191cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1720aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1721aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
17221cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
17231cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17241cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_SET_COUNTER;
17251cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
17261cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1727aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
17281cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
17291cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
17301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
17310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1732aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
17330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
17340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
17350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
17360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1737aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = r->entry;
1738aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
17390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
17400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
17411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17421cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
17431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
17441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
17451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
17461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
175179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1753aae69bed019826ddec93f761514652a93d871e49Harald Welte	static struct chain_head *c;
1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
175579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_CREATE_CHAIN;
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
1759aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(chain, *handle)
176079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_DROP) == 0
176179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_ACCEPT) == 0
176267088e73ce7707229c56987868f112051defca5aRusty Russell	    || strcmp(chain, LABEL_QUEUE) == 0
176379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_RETURN) == 0) {
1764aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain `%s' already exists\n", chain);
1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
176979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1770aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain name `%s' too long\n", chain);
1771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1775aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_alloc_chain_head(chain, 0);
1776aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1777aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
1778aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1779aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1781aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1783aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("Creating chain `%s'\n", chain);
1784aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&c->list, &(*handle)->chains);
1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1786aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1788aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
179379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
179479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  TC_HANDLE_T *handle)
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1796aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1798664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_GET_REFERENCES;
1799aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1804aae69bed019826ddec93f761514652a93d871e49Harald Welte	*ref = c->references;
1805aae69bed019826ddec93f761514652a93d871e49Harald Welte
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
181179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
1814aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
18157e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
181679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_CHAIN;
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1818aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1819aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1820aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1821aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1822aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1823aae69bed019826ddec93f761514652a93d871e49Harald Welte
182479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (TC_BUILTIN(chain, *handle)) {
1825aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot remove builtin chain `%s'\n", chain);
1826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1830aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!TC_GET_REFERENCES(&references, chain, handle)) {
1831aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot get references on chain `%s'\n", chain);
1832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1835aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (references > 0) {
1836aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' still has references\n", chain);
1837aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EMLINK;
1838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1841aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->num_rules) {
1842aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' is not empty\n", chain);
1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1847aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the chain that is the current
1848aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move chain iterator firward. */
1849aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c == (*handle)->chain_iterator_cur)
1850aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_chain_iterator_advance(*handle);
1851aae69bed019826ddec93f761514652a93d871e49Harald Welte
1852aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&c->list);
1853aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(c);
18540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1855aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("chain `%s' deleted\n", chain);
18560113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1857aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1858aae69bed019826ddec93f761514652a93d871e49Harald Welte
1859aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
186379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
186479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    const IPT_CHAINLABEL newname,
186579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1867aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
186879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_RENAME_CHAIN;
1869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
18701de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
18711de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte           QUEUE, RETURN. */
1872aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(newname, *handle)
187379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_DROP) == 0
187479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_ACCEPT) == 0
18751de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	    || strcmp(newname, LABEL_QUEUE) == 0
187679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_RETURN) == 0) {
1877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1881aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(oldname, *handle))
188279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || TC_BUILTIN(oldname, *handle)) {
1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
188779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1892aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
1893aae69bed019826ddec93f761514652a93d871e49Harald Welte
18940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	set_changed(*handle);
18950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
190179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_SET_POLICY(const IPT_CHAINLABEL chain,
190279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      const IPT_CHAINLABEL policy,
19031cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	      STRUCT_COUNTERS *counters,
190479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
1905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1906aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
190879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_SET_POLICY;
1909aae69bed019826ddec93f761514652a93d871e49Harald Welte
1910aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1911aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1912c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1914aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1916aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
1917aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
1918aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
19199e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte		return 0;
19209e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte	}
19219e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
192279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(policy, LABEL_ACCEPT) == 0)
1923aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_ACCEPT - 1;
192479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(policy, LABEL_DROP) == 0)
1925aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_DROP - 1;
1926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
19301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
19311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (counters) {
19321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		/* set byte and packet counters */
1933aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
1934aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_SET;
19351cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	} else {
1936aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_NOMAP;
19371cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
19381cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1939175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
194579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell   libiptc.c: In function `TC_COMMIT':
1946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1947e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
195179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellsubtract_counters(STRUCT_COUNTERS *answer,
195279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *a,
195379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *b)
1954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1959aae69bed019826ddec93f761514652a93d871e49Harald Welte
1960aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
1961aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int index)
1962aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1963aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
1964aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NOMAP => zero\n");
1965aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1966aae69bed019826ddec93f761514652a93d871e49Harald Welte
1967aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
1968aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1969aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1970aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos)
1971aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1972aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1973aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1974aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1975aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: X + Y + Z.
1976aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in X + Y
1977aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in replacement read.
1978aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
1979aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = repl->counters[mappos];
1980aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
1981aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1982aae69bed019826ddec93f761514652a93d871e49Harald Welte
1983aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
1984aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1985aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1986aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos,
1987aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_COUNTERS *counters)
1988aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1989aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1990aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1991aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1992aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: Y + Z.
1993aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in Y.
1994aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in (replacement read - original read).
1995aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
1996aae69bed019826ddec93f761514652a93d871e49Harald Welte	subtract_counters(&newcounters->counters[index],
1997aae69bed019826ddec93f761514652a93d871e49Harald Welte			  &repl->counters[mappos],
1998aae69bed019826ddec93f761514652a93d871e49Harald Welte			  counters);
1999aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("ZEROED => mappos %u\n", mappos);
2000aae69bed019826ddec93f761514652a93d871e49Harald Welte}
2001aae69bed019826ddec93f761514652a93d871e49Harald Welte
2002aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
2003aae69bed019826ddec93f761514652a93d871e49Harald Welte			     unsigned int index,
2004aae69bed019826ddec93f761514652a93d871e49Harald Welte			     STRUCT_COUNTERS *counters)
2005aae69bed019826ddec93f761514652a93d871e49Harald Welte{
2006aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Want to set counter (iptables-restore) */
2007aae69bed019826ddec93f761514652a93d871e49Harald Welte
2008aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&newcounters->counters[index], counters,
2009aae69bed019826ddec93f761514652a93d871e49Harald Welte		sizeof(STRUCT_COUNTERS));
2010aae69bed019826ddec93f761514652a93d871e49Harald Welte
2011aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("SET\n");
2012aae69bed019826ddec93f761514652a93d871e49Harald Welte}
2013aae69bed019826ddec93f761514652a93d871e49Harald Welte
2014aae69bed019826ddec93f761514652a93d871e49Harald Welte
2015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
201679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_COMMIT(TC_HANDLE_T *handle)
2017e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2018e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
201979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_REPLACE *repl;
202079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_COUNTERS_INFO *newcounters;
2021aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
2022aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
2023841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	size_t counterlen;
2024aae69bed019826ddec93f761514652a93d871e49Harald Welte	int new_number;
2025aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int new_size;
2026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2027664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	iptc_fn = TC_COMMIT;
2028e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
2029841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
2030e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
2031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
2032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
2033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2034aae69bed019826ddec93f761514652a93d871e49Harald Welte	new_number = iptcc_compile_table_prep(*handle, &new_size);
2035aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (new_number < 0) {
2036aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
2037aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
2038aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2039aae69bed019826ddec93f761514652a93d871e49Harald Welte
2040aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl = malloc(sizeof(*repl) + new_size);
2041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
2042e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
2043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2045ad3b4f9973ac15981b98b8fc4d364ef1ce524212Martin Josefsson	memset(repl, 0, sizeof(*repl) + new_size);
2046aae69bed019826ddec93f761514652a93d871e49Harald Welte
2047e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell#if 0
2048e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell	TC_DUMP_ENTRIES(*handle);
2049e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell#endif
2050e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell
2051aae69bed019826ddec93f761514652a93d871e49Harald Welte	counterlen = sizeof(STRUCT_COUNTERS_INFO)
2052aae69bed019826ddec93f761514652a93d871e49Harald Welte			+ sizeof(STRUCT_COUNTERS) * new_number;
2053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
205579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	repl->counters = malloc(sizeof(STRUCT_COUNTERS)
2056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
2057e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
2058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
2060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2061e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2062e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
2063e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
2064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
2065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
2068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2069e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2070aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(newcounters, 0, counterlen);
2071e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2072e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
2073aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->num_entries = new_number;
2074aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->size = new_size;
2075aae69bed019826ddec93f761514652a93d871e49Harald Welte
2076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
2077e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
2078aae69bed019826ddec93f761514652a93d871e49Harald Welte
2079aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2080aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->num_entries, repl->size, repl->num_counters);
2081aae69bed019826ddec93f761514652a93d871e49Harald Welte
2082aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = iptcc_compile_table(*handle, repl);
2083aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ret < 0) {
2084aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ret;
2085aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl->counters);
2086aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
2087aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
2088aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2089aae69bed019826ddec93f761514652a93d871e49Harald Welte
2090aae69bed019826ddec93f761514652a93d871e49Harald Welte
2091aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2092aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2093aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_replace.blob",
2094aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2095aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2096aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, repl, sizeof(*repl) + repl->size);
2097aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2098aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2099aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2100aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
210279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
2103aae69bed019826ddec93f761514652a93d871e49Harald Welte		       sizeof(*repl) + repl->size) < 0) {
2104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
2107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
2111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
2112aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->num_counters = new_number;
2113aae69bed019826ddec93f761514652a93d871e49Harald Welte
2114aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &(*handle)->chains, list) {
2115aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
2116aae69bed019826ddec93f761514652a93d871e49Harald Welte
2117aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Builtin chains have their own counters */
2118aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (iptcc_is_builtin(c)) {
2119aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for chain-index %u: ", c->foot_index);
2120aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch(c->counter_map.maptype) {
2121aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2122aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, c->foot_index);
2123aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2124aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2125aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2126aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2127aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos);
2128aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2129aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2130aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2131aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2132aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos,
2133aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &c->counters);
2134aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2135aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2136aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, c->foot_index,
2137aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &c->counters);
2138aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2139aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2140aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
21411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
2142aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
2143aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for index %u: ", r->index);
2144aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch (r->counter_map.maptype) {
2145aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2146aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, r->index);
2147aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2148aae69bed019826ddec93f761514652a93d871e49Harald Welte
2149aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2150aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2151aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2152aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos);
2153aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2154aae69bed019826ddec93f761514652a93d871e49Harald Welte
2155aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2156aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2157aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2158aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos,
2159aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &r->entry->counters);
2160aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2161aae69bed019826ddec93f761514652a93d871e49Harald Welte
2162aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2163aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, r->index,
2164aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &r->entry->counters);
2165aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2166aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
2168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
216962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell
2170aae69bed019826ddec93f761514652a93d871e49Harald Welte
217162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#ifdef KERNEL_64_USERSPACE_32
217262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell	{
217362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		/* Kernel will think that pointer should be 64-bits, and get
217462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   padding.  So we accomodate here (assumption: alignment of
217562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   `counters' is on 64-bit boundary). */
217662527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
217762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		if ((unsigned long)&newcounters->counters % 8 != 0) {
217862527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			fprintf(stderr,
217962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell				"counters alignment incorrect! Mail rusty!\n");
218062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			abort();
218162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		}
218262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		*kernptr = newcounters->counters;
218354c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	}
218462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#endif /* KERNEL_64_USERSPACE_32 */
2185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2186aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2187aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2188aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_add_counters.blob",
2189aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2190aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2191aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, newcounters, counterlen);
2192aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2193aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2194aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2195aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2196aae69bed019826ddec93f761514652a93d871e49Harald Welte
219779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
219879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		       newcounters, counterlen) < 0) {
2199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
2202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
2206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
2207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
2208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
2210841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	TC_FREE(handle);
2211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
2212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
2215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
221679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_RAW_SOCKET()
2217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
2219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
2222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
222379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_STRERROR(int err)
2224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
2226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
2227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
2228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
2229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
2230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
22314ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	  { { TC_INIT, EPERM, "Permission denied (you must be root)" },
223279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INIT, EINVAL, "Module is wrong version" },
22334ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_INIT, ENOENT,
22344ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte		    "Table does not exist (do you need to insmod?)" },
223579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
223679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
223779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EMLINK,
2238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
223979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
224079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
224179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
224279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
22431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
22441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
224579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
224679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, EINVAL, "Target problem" },
2247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
224879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CHECK_PACKET, EINVAL,
2249c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
22504ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_CHECK_PACKET, ENOSYS,
22514ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	      "Checking will most likely never get implemented" },
2252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
225379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_ENTRY, ENOENT,
2254c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
225579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, ENOENT,
2256c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
225779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, EINVAL,
2258c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
22594ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte
22604ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, 0, "Incompatible with this kernel" },
22614ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
22624ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
22634ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
22644ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOENT, "No chain/target/match by that name" },
2265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
2266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
2269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
2270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
2271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
2274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2275