libiptc.c revision 52c380208a87191a8c25608d2c501c0dc32aa9ad
152c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson/* Library which manipulates firewall rules.  Version $Revision: 1.50 $ */
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
470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#ifndef __OPTIMIZE__
480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald WelteSTRUCT_ENTRY_TARGET *
490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald WelteGET_TARGET(STRUCT_ENTRY *e)
500113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
510113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return (void *)e + e->target_offset;
520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#endif
540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
5979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell= { [HOOK_PRE_ROUTING]  "PREROUTING",
6079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_IN]     "INPUT",
6179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_FORWARD]      "FORWARD",
6279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell    [HOOK_LOCAL_OUT]    "OUTPUT",
6310758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_POST_ROUTING] "POSTROUTING",
6410758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#ifdef HOOK_DROPPING
6510758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell    [HOOK_DROPPING]	"DROPPING"
6610758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell#endif
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
69aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
70aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct ipt_error_target
71aae69bed019826ddec93f761514652a93d871e49Harald Welte{
72aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY_TARGET t;
73aae69bed019826ddec93f761514652a93d871e49Harald Welte	char error[TABLE_MAXNAMELEN];
74aae69bed019826ddec93f761514652a93d871e49Harald Welte};
75aae69bed019826ddec93f761514652a93d871e49Harald Welte
76aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct chain_head;
77aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct rule_head;
78aae69bed019826ddec93f761514652a93d871e49Harald Welte
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
841cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_ZEROED,
851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		COUNTER_MAP_SET
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
90aae69bed019826ddec93f761514652a93d871e49Harald Welteenum iptcc_rule_type {
91aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_STANDARD,		/* standard target (ACCEPT, ...) */
92aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_MODULE,			/* extension module (SNAT, ...) */
93aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_FALLTHROUGH,		/* fallthrough rule */
94aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPTCC_R_JUMP,			/* jump to other chain */
95aae69bed019826ddec93f761514652a93d871e49Harald Welte};
96aae69bed019826ddec93f761514652a93d871e49Harald Welte
97aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct rule_head
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
99aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head list;
100aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *chain;
101aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map counter_map;
102aae69bed019826ddec93f761514652a93d871e49Harald Welte
103aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;		/* index (needed for counter_map) */
104aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset;		/* offset in rule blob */
105aae69bed019826ddec93f761514652a93d871e49Harald Welte
106aae69bed019826ddec93f761514652a93d871e49Harald Welte	enum iptcc_rule_type type;
107aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *jump;	/* jump target, if IPTCC_R_JUMP */
108aae69bed019826ddec93f761514652a93d871e49Harald Welte
109aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int size;		/* size of entry data */
110aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry[0];
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
113aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct chain_head
11430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
115aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head list;
11679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	char name[TABLE_MAXNAMELEN];
117aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int hooknum;		/* hook number+1 if builtin */
118aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int references;	/* how many jumps reference us */
119aae69bed019826ddec93f761514652a93d871e49Harald Welte	int verdict;			/* verdict if builtin */
120aae69bed019826ddec93f761514652a93d871e49Harald Welte
121aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_COUNTERS counters;	/* per-chain counters */
122aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map counter_map;
123aae69bed019826ddec93f761514652a93d871e49Harald Welte
124aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num_rules;		/* number of rules in list */
125aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head rules;		/* list of rules */
126aae69bed019826ddec93f761514652a93d871e49Harald Welte
127aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;		/* index (needed for jump resolval) */
128aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int head_offset;	/* offset in rule blob */
129aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int foot_index;	/* index (needed for counter_map) */
130aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int foot_offset;	/* offset in rule blob */
13130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell};
13230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
13379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellSTRUCT_TC_HANDLE
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
135aae69bed019826ddec93f761514652a93d871e49Harald Welte	int changed;			 /* Have changes been made? */
136aae69bed019826ddec93f761514652a93d871e49Harald Welte
137aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head chains;
138aae69bed019826ddec93f761514652a93d871e49Harald Welte
139aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *chain_iterator_cur;
140aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *rule_iterator_cur;
141aae69bed019826ddec93f761514652a93d871e49Harald Welte
14279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
143aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_GET_ENTRIES *entries;
144aae69bed019826ddec93f761514652a93d871e49Harald Welte};
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
146aae69bed019826ddec93f761514652a93d871e49Harald Welte/* allocate a new chain head for the cache */
147aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
148aae69bed019826ddec93f761514652a93d871e49Harald Welte{
149aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = malloc(sizeof(*c));
150aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c)
151aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
152aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(c, 0, sizeof(*c));
153aae69bed019826ddec93f761514652a93d871e49Harald Welte
154aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, name, TABLE_MAXNAMELEN);
155aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->hooknum = hooknum;
156aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&c->rules);
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
158aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c;
159aae69bed019826ddec93f761514652a93d871e49Harald Welte}
16030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
161aae69bed019826ddec93f761514652a93d871e49Harald Welte/* allocate and initialize a new rule for the cache */
162aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
163aae69bed019826ddec93f761514652a93d871e49Harald Welte{
164aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r = malloc(sizeof(*r)+size);
165aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
166aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
167aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(r, 0, sizeof(*r));
16830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
169aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->chain = c;
170aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->size = size;
171175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
172aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r;
173aae69bed019826ddec93f761514652a93d871e49Harald Welte}
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
175aae69bed019826ddec93f761514652a93d871e49Harald Welte/* notify us that the ruleset has been modified by the user */
176175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
17779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellset_changed(TC_HANDLE_T h)
178175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
179175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
180175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
181175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
182380ba5f3074a16fbaa8869d9594962d58b5f8608Harald Welte#ifdef IPTC_DEBUG
18379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void do_check(TC_HANDLE_T h, unsigned int line);
184849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
18530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else
18630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h)
18730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
189aae69bed019826ddec93f761514652a93d871e49Harald Welte
190aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
191aae69bed019826ddec93f761514652a93d871e49Harald Welte * iptc blob utility functions (iptcb_*)
192aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
193aae69bed019826ddec93f761514652a93d871e49Harald Welte
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
195aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_number(const STRUCT_ENTRY *i,
19679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	   const STRUCT_ENTRY *seek,
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
205aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
206aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_entry_n(STRUCT_ENTRY *i,
207aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int number,
208aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int *pos,
209aae69bed019826ddec93f761514652a93d871e49Harald Welte	    STRUCT_ENTRY **pe)
210aae69bed019826ddec93f761514652a93d871e49Harald Welte{
211aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (*pos == number) {
212aae69bed019826ddec93f761514652a93d871e49Harald Welte		*pe = i;
213aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
214aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
215aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*pos)++;
216aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
217aae69bed019826ddec93f761514652a93d871e49Harald Welte}
218aae69bed019826ddec93f761514652a93d871e49Harald Welte
219aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline STRUCT_ENTRY *
220aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_get_entry(TC_HANDLE_T h, unsigned int offset)
221aae69bed019826ddec93f761514652a93d871e49Harald Welte{
222aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
223aae69bed019826ddec93f761514652a93d871e49Harald Welte}
224aae69bed019826ddec93f761514652a93d871e49Harald Welte
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
226aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
230aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
231aae69bed019826ddec93f761514652a93d871e49Harald Welte			  iptcb_get_number, seek, &pos) == 0) {
232a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson		fprintf(stderr, "ERROR: offset %u not an entry!\n",
233aae69bed019826ddec93f761514652a93d871e49Harald Welte			(unsigned int)((char *)seek - (char *)h->entries->entrytable));
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
239aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline STRUCT_ENTRY *
240aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_offset2entry(TC_HANDLE_T h, unsigned int offset)
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
242aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
243aae69bed019826ddec93f761514652a93d871e49Harald Welte}
244aae69bed019826ddec93f761514652a93d871e49Harald Welte
245aae69bed019826ddec93f761514652a93d871e49Harald Welte
246aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned long
247aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
248aae69bed019826ddec93f761514652a93d871e49Harald Welte{
249aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (void *)e - (void *)h->entries->entrytable;
250aae69bed019826ddec93f761514652a93d871e49Harald Welte}
251aae69bed019826ddec93f761514652a93d871e49Harald Welte
252aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned int
253aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_offset2index(const TC_HANDLE_T h, unsigned int offset)
254aae69bed019826ddec93f761514652a93d871e49Harald Welte{
255aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
256aae69bed019826ddec93f761514652a93d871e49Harald Welte}
257aae69bed019826ddec93f761514652a93d871e49Harald Welte
258aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns 0 if not hook entry, else hooknumber + 1 */
259aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline unsigned int
260aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
261aae69bed019826ddec93f761514652a93d871e49Harald Welte{
262aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i;
263aae69bed019826ddec93f761514652a93d871e49Harald Welte
264aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < NUMHOOKS; i++) {
265aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((h->info.valid_hooks & (1 << i))
266aae69bed019826ddec93f761514652a93d871e49Harald Welte		    && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
267aae69bed019826ddec93f761514652a93d871e49Harald Welte			return i+1;
268aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
269aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
270aae69bed019826ddec93f761514652a93d871e49Harald Welte}
271aae69bed019826ddec93f761514652a93d871e49Harald Welte
272aae69bed019826ddec93f761514652a93d871e49Harald Welte
273aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
274aae69bed019826ddec93f761514652a93d871e49Harald Welte * iptc cache utility functions (iptcc_*)
275aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
276aae69bed019826ddec93f761514652a93d871e49Harald Welte
277aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is the given chain builtin (1) or user-defined (0) */
278aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic unsigned int iptcc_is_builtin(struct chain_head *c)
279aae69bed019826ddec93f761514652a93d871e49Harald Welte{
280aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (c->hooknum ? 1 : 0);
281aae69bed019826ddec93f761514652a93d871e49Harald Welte}
282aae69bed019826ddec93f761514652a93d871e49Harald Welte
283aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get a specific rule within a chain */
284aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct rule_head *iptcc_get_rule_num(struct chain_head *c,
285aae69bed019826ddec93f761514652a93d871e49Harald Welte					    unsigned int rulenum)
286aae69bed019826ddec93f761514652a93d871e49Harald Welte{
287aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
288aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
289aae69bed019826ddec93f761514652a93d871e49Harald Welte
290aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
291aae69bed019826ddec93f761514652a93d871e49Harald Welte		num++;
292aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (num == rulenum)
293aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r;
294aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
295aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
296aae69bed019826ddec93f761514652a93d871e49Harald Welte}
297aae69bed019826ddec93f761514652a93d871e49Harald Welte
298aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns chain head if found, otherwise NULL. */
299aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *
300aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset)
301aae69bed019826ddec93f761514652a93d871e49Harald Welte{
302aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head *pos;
303aae69bed019826ddec93f761514652a93d871e49Harald Welte
304aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&handle->chains))
305aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
306aae69bed019826ddec93f761514652a93d871e49Harald Welte
307aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each(pos, &handle->chains) {
308aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c = list_entry(pos, struct chain_head, list);
309aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (offset >= c->head_offset && offset <= c->foot_offset)
310aae69bed019826ddec93f761514652a93d871e49Harald Welte			return c;
311aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
312aae69bed019826ddec93f761514652a93d871e49Harald Welte
313aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
314aae69bed019826ddec93f761514652a93d871e49Harald Welte}
315aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns chain head if found, otherwise NULL. */
316aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct chain_head *
317aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_find_label(const char *name, TC_HANDLE_T handle)
318aae69bed019826ddec93f761514652a93d871e49Harald Welte{
319aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct list_head *pos;
320aae69bed019826ddec93f761514652a93d871e49Harald Welte
321aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&handle->chains))
322aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
323aae69bed019826ddec93f761514652a93d871e49Harald Welte
324aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each(pos, &handle->chains) {
325aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c = list_entry(pos, struct chain_head, list);
326aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(c->name, name))
327aae69bed019826ddec93f761514652a93d871e49Harald Welte			return c;
328aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
329aae69bed019826ddec93f761514652a93d871e49Harald Welte
330aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
331aae69bed019826ddec93f761514652a93d871e49Harald Welte}
332aae69bed019826ddec93f761514652a93d871e49Harald Welte
333aae69bed019826ddec93f761514652a93d871e49Harald Welte/* called when rule is to be removed from cache */
334aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_delete_rule(struct rule_head *r)
335aae69bed019826ddec93f761514652a93d871e49Harald Welte{
336aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
337aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* clean up reference count of called chain */
338aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP
339aae69bed019826ddec93f761514652a93d871e49Harald Welte	    && r->jump)
340aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->jump->references--;
341aae69bed019826ddec93f761514652a93d871e49Harald Welte
342aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&r->list);
343aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(r);
344aae69bed019826ddec93f761514652a93d871e49Harald Welte}
345aae69bed019826ddec93f761514652a93d871e49Harald Welte
346aae69bed019826ddec93f761514652a93d871e49Harald Welte
347aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
348aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET PARSER (blob -> cache)
349aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
350aae69bed019826ddec93f761514652a93d871e49Harald Welte
351aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int alphasort(const void *a, const void *b)
352aae69bed019826ddec93f761514652a93d871e49Harald Welte{
353aae69bed019826ddec93f761514652a93d871e49Harald Welte	return strcmp(((struct chain_head *)a)->name,
354aae69bed019826ddec93f761514652a93d871e49Harald Welte		      ((struct chain_head *)b)->name);
355aae69bed019826ddec93f761514652a93d871e49Harald Welte}
356aae69bed019826ddec93f761514652a93d871e49Harald Welte
357aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Delete policy rule of previous chain, since cache doesn't contain
358aae69bed019826ddec93f761514652a93d871e49Harald Welte * chain policy rules.
359aae69bed019826ddec93f761514652a93d871e49Harald Welte * WARNING: This function has ugly design and relies on a lot of context, only
360aae69bed019826ddec93f761514652a93d871e49Harald Welte * to be called from specific places within the parser */
361aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num)
362aae69bed019826ddec93f761514652a93d871e49Harald Welte{
363aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (h->chain_iterator_cur) {
364aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* policy rule is last rule */
365aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *pr = (struct rule_head *)
366aae69bed019826ddec93f761514652a93d871e49Harald Welte			h->chain_iterator_cur->rules.prev;
367aae69bed019826ddec93f761514652a93d871e49Harald Welte
368aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* save verdict */
369aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->verdict =
370aae69bed019826ddec93f761514652a93d871e49Harald Welte			*(int *)GET_TARGET(pr->entry)->data;
371aae69bed019826ddec93f761514652a93d871e49Harald Welte
372aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* save counter and counter_map information */
373aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->counter_map.maptype =
374aae69bed019826ddec93f761514652a93d871e49Harald Welte						COUNTER_MAP_NORMAL_MAP;
375aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->counter_map.mappos = num-1;
376aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
377aae69bed019826ddec93f761514652a93d871e49Harald Welte			sizeof(h->chain_iterator_cur->counters));
378aae69bed019826ddec93f761514652a93d871e49Harald Welte
379aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* foot_offset points to verdict rule */
380aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->foot_index = num;
381aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur->foot_offset = pr->offset;
382aae69bed019826ddec93f761514652a93d871e49Harald Welte
383aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* delete rule from cache */
384aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(pr);
385aae69bed019826ddec93f761514652a93d871e49Harald Welte
386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
391aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Another ugly helper function split out of cache_add_entry to make it less
392aae69bed019826ddec93f761514652a93d871e49Harald Welte * spaghetti code */
393aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c,
394aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int offset, unsigned int *num)
395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
396aae69bed019826ddec93f761514652a93d871e49Harald Welte	__iptcc_p_del_policy(h, *num);
397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
398aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = offset;
399aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->index = *num;
400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
401aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&c->list, &h->chains);
402aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->chain_iterator_cur = c;
403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
405aae69bed019826ddec93f761514652a93d871e49Harald Welte/* main parser function: add an entry from the blob to the cache */
406aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int cache_add_entry(STRUCT_ENTRY *e,
407aae69bed019826ddec93f761514652a93d871e49Harald Welte			   TC_HANDLE_T h,
408aae69bed019826ddec93f761514652a93d871e49Harald Welte			   STRUCT_ENTRY **prev,
409aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int *num)
410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
411aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int builtin;
412aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = (char *)e - (char *)h->entries->entrytable;
413aae69bed019826ddec93f761514652a93d871e49Harald Welte
414aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("entering...");
415aae69bed019826ddec93f761514652a93d871e49Harald Welte
416aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Last entry ("policy rule"). End it.*/
417aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
418aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* This is the ERROR node at the end of the chain */
419aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u: end of table:\n", *num, offset);
420aae69bed019826ddec93f761514652a93d871e49Harald Welte
421aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_del_policy(h, *num);
422aae69bed019826ddec93f761514652a93d871e49Harald Welte
423aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->chain_iterator_cur = NULL;
424aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_inc;
425aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
426aae69bed019826ddec93f761514652a93d871e49Harald Welte
427aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* We know this is the start of a new chain if it's an ERROR
428aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * target, or a hook entry point */
429aae69bed019826ddec93f761514652a93d871e49Harald Welte
430aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
431aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
432aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
433aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
434aae69bed019826ddec93f761514652a93d871e49Harald Welte			(char *)c->name, c);
435aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
436aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
437aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
438aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
439aae69bed019826ddec93f761514652a93d871e49Harald Welte
440aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
441aae69bed019826ddec93f761514652a93d871e49Harald Welte
442aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
443aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c =
444aae69bed019826ddec93f761514652a93d871e49Harald Welte			iptcc_alloc_chain_head((char *)hooknames[builtin-1],
445aae69bed019826ddec93f761514652a93d871e49Harald Welte						builtin);
446aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
447aae69bed019826ddec93f761514652a93d871e49Harald Welte			*num, offset, c, &c->rules);
448aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!c) {
449aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = -ENOMEM;
450aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
451aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
452aae69bed019826ddec93f761514652a93d871e49Harald Welte
453aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->hooknum = builtin;
454aae69bed019826ddec93f761514652a93d871e49Harald Welte
455aae69bed019826ddec93f761514652a93d871e49Harald Welte		__iptcc_p_add_chain(h, c, offset, num);
456aae69bed019826ddec93f761514652a93d871e49Harald Welte
457aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* FIXME: this is ugly. */
458aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto new_rule;
459aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
460aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* has to be normal rule */
461aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
462aae69bed019826ddec93f761514652a93d871e49Harald Weltenew_rule:
463aae69bed019826ddec93f761514652a93d871e49Harald Welte
464aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
465aae69bed019826ddec93f761514652a93d871e49Harald Welte					   e->next_offset))) {
466aae69bed019826ddec93f761514652a93d871e49Harald Welte			errno = ENOMEM;
467aae69bed019826ddec93f761514652a93d871e49Harald Welte			return -1;
468aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
469aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
470aae69bed019826ddec93f761514652a93d871e49Harald Welte
471aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
472aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = offset;
473aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(r->entry, e, e->next_offset);
474aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
475aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.mappos = r->index;
476aae69bed019826ddec93f761514652a93d871e49Harald Welte
477aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* handling of jumps, etc. */
478aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
479aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
480aae69bed019826ddec93f761514652a93d871e49Harald Welte
481aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
482aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->target.u.target_size
483aae69bed019826ddec93f761514652a93d871e49Harald Welte			    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
484aae69bed019826ddec93f761514652a93d871e49Harald Welte				errno = EINVAL;
485aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
486aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
487aae69bed019826ddec93f761514652a93d871e49Harald Welte
488aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (t->verdict < 0) {
489aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("standard, verdict=%d\n", t->verdict);
490aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_STANDARD;
491aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else if (t->verdict == r->offset+e->next_offset) {
492aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("fallthrough\n");
493aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_FALLTHROUGH;
494aae69bed019826ddec93f761514652a93d871e49Harald Welte			} else {
495aae69bed019826ddec93f761514652a93d871e49Harald Welte				DEBUGP_C("jump, target=%u\n", t->verdict);
496aae69bed019826ddec93f761514652a93d871e49Harald Welte				r->type = IPTCC_R_JUMP;
497aae69bed019826ddec93f761514652a93d871e49Harald Welte				/* Jump target fixup has to be deferred
498aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * until second pass, since we migh not
499aae69bed019826ddec93f761514652a93d871e49Harald Welte				 * yet have parsed the target */
500aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
50152c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson		} else {
50252c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
50352c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson			r->type = IPTCC_R_MODULE;
504aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
505aae69bed019826ddec93f761514652a93d871e49Harald Welte
506aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_add_tail(&r->list, &h->chain_iterator_cur->rules);
507aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
508aae69bed019826ddec93f761514652a93d871e49Harald Welteout_inc:
509aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
510aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
511e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
513aae69bed019826ddec93f761514652a93d871e49Harald Welte
514aae69bed019826ddec93f761514652a93d871e49Harald Welte/* parse an iptables blob into it's pieces */
515aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int parse_table(TC_HANDLE_T h)
516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
517aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *prev;
518aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int num = 0;
519aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
520aae69bed019826ddec93f761514652a93d871e49Harald Welte
521aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: over ruleset blob */
522aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
523aae69bed019826ddec93f761514652a93d871e49Harald Welte			cache_add_entry, h, &prev, &num);
524aae69bed019826ddec93f761514652a93d871e49Harald Welte
525aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: fixup parsed data from first pass */
526aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
527aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
528aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
529aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct chain_head *c;
530aae69bed019826ddec93f761514652a93d871e49Harald Welte			STRUCT_STANDARD_TARGET *t;
531aae69bed019826ddec93f761514652a93d871e49Harald Welte
532aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (r->type != IPTCC_R_JUMP)
533aae69bed019826ddec93f761514652a93d871e49Harald Welte				continue;
534aae69bed019826ddec93f761514652a93d871e49Harald Welte
535aae69bed019826ddec93f761514652a93d871e49Harald Welte			t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
536aae69bed019826ddec93f761514652a93d871e49Harald Welte			c = iptcc_find_chain_by_offset(h, t->verdict);
537aae69bed019826ddec93f761514652a93d871e49Harald Welte			if (!c)
538aae69bed019826ddec93f761514652a93d871e49Harald Welte				return -1;
539aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
540aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
541aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
542aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
543aae69bed019826ddec93f761514652a93d871e49Harald Welte
544aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* FIXME: sort chains */
545aae69bed019826ddec93f761514652a93d871e49Harald Welte
546aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
5470113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
5489e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
549aae69bed019826ddec93f761514652a93d871e49Harald Welte
550aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
551aae69bed019826ddec93f761514652a93d871e49Harald Welte * RULESET COMPILATION (cache -> blob)
552aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
553aae69bed019826ddec93f761514652a93d871e49Harald Welte
554aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Convenience structures */
555aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_start{
556aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
557aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target name;
558aae69bed019826ddec93f761514652a93d871e49Harald Welte};
559aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_START_SIZE	(sizeof(STRUCT_ENTRY) +			\
560aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
561aae69bed019826ddec93f761514652a93d871e49Harald Welte
562aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_foot {
563aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY e;
564aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_STANDARD_TARGET target;
565aae69bed019826ddec93f761514652a93d871e49Harald Welte};
566aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_FOOT_SIZE	(sizeof(STRUCT_ENTRY) +			\
567aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
568aae69bed019826ddec93f761514652a93d871e49Harald Welte
569aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptcb_chain_error {
570aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY entry;
571aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_error_target target;
572aae69bed019826ddec93f761514652a93d871e49Harald Welte};
573aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPTCB_CHAIN_ERROR_SIZE	(sizeof(STRUCT_ENTRY) +			\
574aae69bed019826ddec93f761514652a93d871e49Harald Welte				 ALIGN(sizeof(struct ipt_error_target)))
575aae69bed019826ddec93f761514652a93d871e49Harald Welte
576aae69bed019826ddec93f761514652a93d871e49Harald Welte
577aae69bed019826ddec93f761514652a93d871e49Harald Welte
578aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile rule from cache into blob */
579aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
5800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
581aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* handle jumps */
582aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->type == IPTCC_R_JUMP) {
583aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
584aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
585aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* memset for memcmp convenience on delete/replace */
586aae69bed019826ddec93f761514652a93d871e49Harald Welte		memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
587aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(t->target.u.user.name, STANDARD_TARGET);
588aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Jumps can only happen to builtin chains, so we
589aae69bed019826ddec93f761514652a93d871e49Harald Welte		 * can safely assume that they always have a header */
590aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
591aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if (r->type == IPTCC_R_FALLTHROUGH) {
592aae69bed019826ddec93f761514652a93d871e49Harald Welte		STRUCT_STANDARD_TARGET *t;
593aae69bed019826ddec93f761514652a93d871e49Harald Welte		t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
594aae69bed019826ddec93f761514652a93d871e49Harald Welte		t->verdict = r->offset + r->size;
595aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
596aae69bed019826ddec93f761514652a93d871e49Harald Welte
597aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* copy entry from cache to blob */
598aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy((char *)repl->entries+r->offset, r->entry, r->size);
599aae69bed019826ddec93f761514652a93d871e49Harald Welte
600aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
603aae69bed019826ddec93f761514652a93d871e49Harald Welte/* compile chain from cache into blob */
604aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
6053ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
606aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
607aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
608aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_start *head;
609aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_foot *foot;
610aae69bed019826ddec93f761514652a93d871e49Harald Welte
611aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* only user-defined chains have heaer */
612aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
613aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* put chain header in place */
614aae69bed019826ddec93f761514652a93d871e49Harald Welte		head = (void *)repl->entries + c->head_offset;
615aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.target_offset = sizeof(STRUCT_ENTRY);
616aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->e.next_offset = IPTCB_CHAIN_START_SIZE;
617aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.t.u.user.name, ERROR_TARGET);
618aae69bed019826ddec93f761514652a93d871e49Harald Welte		head->name.t.u.target_size =
619aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(struct ipt_error_target));
620aae69bed019826ddec93f761514652a93d871e49Harald Welte		strcpy(head->name.error, c->name);
621aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else {
622aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->hook_entry[c->hooknum-1] = c->head_offset;
623aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->underflow[c->hooknum-1] = c->foot_offset;
624aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
625aae69bed019826ddec93f761514652a93d871e49Harald Welte
626aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* iterate over rules */
627aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
628aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_rule(h, repl, r);
629aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
630aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
631aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
632aae69bed019826ddec93f761514652a93d871e49Harald Welte
633aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* put chain footer in place */
634aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot = (void *)repl->entries + c->foot_offset;
635aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.target_offset = sizeof(STRUCT_ENTRY);
636aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
637aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
638aae69bed019826ddec93f761514652a93d871e49Harald Welte	foot->target.target.u.target_size =
639aae69bed019826ddec93f761514652a93d871e49Harald Welte				ALIGN(sizeof(STRUCT_STANDARD_TARGET));
640aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* builtin targets have verdict, others return */
641aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_is_builtin(c))
642aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = c->verdict;
643aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
644aae69bed019826ddec93f761514652a93d871e49Harald Welte		foot->target.verdict = RETURN;
645aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* set policy-counters */
646aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
647aae69bed019826ddec93f761514652a93d871e49Harald Welte
648aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
6493ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
6503ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
651aae69bed019826ddec93f761514652a93d871e49Harald Welte/* calculate offset and number for every rule in the cache */
652aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
653aae69bed019826ddec93f761514652a93d871e49Harald Welte				       int *offset, int *num)
6543ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte{
655aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
656aae69bed019826ddec93f761514652a93d871e49Harald Welte
657aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->head_offset = *offset;
658aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
659aae69bed019826ddec93f761514652a93d871e49Harald Welte
660aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))  {
661aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Chain has header */
662aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += sizeof(STRUCT_ENTRY)
663aae69bed019826ddec93f761514652a93d871e49Harald Welte			     + ALIGN(sizeof(struct ipt_error_target));
664aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
665aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
666aae69bed019826ddec93f761514652a93d871e49Harald Welte
667aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
668aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
669aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->offset = *offset;
670aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->index = *num;
671aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset += r->size;
672aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*num)++;
673aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
674aae69bed019826ddec93f761514652a93d871e49Harald Welte
675aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
676aae69bed019826ddec93f761514652a93d871e49Harald Welte		*offset, *num);
677aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_offset = *offset;
678aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->foot_index = *num;
679aae69bed019826ddec93f761514652a93d871e49Harald Welte	*offset += sizeof(STRUCT_ENTRY)
680aae69bed019826ddec93f761514652a93d871e49Harald Welte		   + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
681aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*num)++;
682aae69bed019826ddec93f761514652a93d871e49Harald Welte
683aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
6843ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte}
6853ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
686aae69bed019826ddec93f761514652a93d871e49Harald Welte/* put the pieces back together again */
687aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
688aae69bed019826ddec93f761514652a93d871e49Harald Welte{
689aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
690aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset = 0, num = 0;
691aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret = 0;
6923ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
693aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* First pass: calculate offset for every rule */
694aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
695aae69bed019826ddec93f761514652a93d871e49Harald Welte		ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
696aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
697aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
698aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
699aae69bed019826ddec93f761514652a93d871e49Harald Welte
700aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append one error rule at end of chain */
701aae69bed019826ddec93f761514652a93d871e49Harald Welte	num++;
702aae69bed019826ddec93f761514652a93d871e49Harald Welte	offset += sizeof(STRUCT_ENTRY)
703aae69bed019826ddec93f761514652a93d871e49Harald Welte		  + ALIGN(sizeof(struct ipt_error_target));
704aae69bed019826ddec93f761514652a93d871e49Harald Welte
705aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* ruleset size is now in offset */
706aae69bed019826ddec93f761514652a93d871e49Harald Welte	*size = offset;
707aae69bed019826ddec93f761514652a93d871e49Harald Welte	return num;
708aae69bed019826ddec93f761514652a93d871e49Harald Welte}
709aae69bed019826ddec93f761514652a93d871e49Harald Welte
710aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
7110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
712aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
713aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct iptcb_chain_error *error;
7140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
715aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Second pass: copy from cache to offsets, fill in jumps */
716aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &h->chains, list) {
717aae69bed019826ddec93f761514652a93d871e49Harald Welte		int ret = iptcc_compile_chain(h, repl, c);
718aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (ret < 0)
719aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
7200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
7210113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
722aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Append error rule at end of chain */
723aae69bed019826ddec93f761514652a93d871e49Harald Welte	error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
724aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.target_offset = sizeof(STRUCT_ENTRY);
725aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
726aae69bed019826ddec93f761514652a93d871e49Harald Welte	error->target.t.u.user.target_size =
727aae69bed019826ddec93f761514652a93d871e49Harald Welte		ALIGN(sizeof(struct ipt_error_target));
728aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
729aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy((char *)&error->target.error, "ERROR");
730aae69bed019826ddec93f761514652a93d871e49Harald Welte
731aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
7320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
734aae69bed019826ddec93f761514652a93d871e49Harald Welte/**********************************************************************
735aae69bed019826ddec93f761514652a93d871e49Harald Welte * EXTERNAL API (operates on cache only)
736aae69bed019826ddec93f761514652a93d871e49Harald Welte **********************************************************************/
737aae69bed019826ddec93f761514652a93d871e49Harald Welte
738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
73979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic TC_HANDLE_T
7400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltealloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
74379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
745aae69bed019826ddec93f761514652a93d871e49Harald Welte	len = sizeof(STRUCT_TC_HANDLE) + size;
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
747aae69bed019826ddec93f761514652a93d871e49Harald Welte	h = malloc(sizeof(STRUCT_TC_HANDLE));
748aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h) {
749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
752aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(h, 0, sizeof(*h));
753aae69bed019826ddec93f761514652a93d871e49Harald Welte	INIT_LIST_HEAD(&h->chains);
754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
755aae69bed019826ddec93f761514652a93d871e49Harald Welte
7560371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
757aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h->entries)
758aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto out_free_handle;
759aae69bed019826ddec93f761514652a93d871e49Harald Welte
760aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(h->entries->name, tablename);
7610371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	h->entries->size = size;
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
764aae69bed019826ddec93f761514652a93d871e49Harald Welte
765aae69bed019826ddec93f761514652a93d871e49Harald Welteout_free_handle:
766aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(h);
767aae69bed019826ddec93f761514652a93d871e49Harald Welte
768aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
771aae69bed019826ddec93f761514652a93d871e49Harald Welte
77279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_HANDLE_T
77379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INIT(const char *tablename)
774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
77579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	TC_HANDLE_T h;
77679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_GETINFO info;
777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
78079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INIT;
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
782e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	if (sockfd != -1) {
783366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte		close(sockfd);
784e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
785e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	}
786366454bc69f781fdafc3a30eb6dd77155ee4efb6Harald Welte
787841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
788841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		errno = EINVAL;
789841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		return NULL;
790841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
791841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
79279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (sockfd < 0)
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
797841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
79979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
802aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
803aae69bed019826ddec93f761514652a93d871e49Harald Welte		info.valid_hooks, info.num_entries, info.size);
804aae69bed019826ddec93f761514652a93d871e49Harald Welte
8050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if ((h = alloc_handle(info.name, info.size, info.num_entries))
806841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	    == NULL) {
807841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		close(sockfd);
808e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson		sockfd = -1;
809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
810841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
8140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
815aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->entries->size = h->info.size;
816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
81779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
819aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
820aae69bed019826ddec93f761514652a93d871e49Harald Welte		       &tmp) < 0)
821aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
822aae69bed019826ddec93f761514652a93d871e49Harald Welte
823aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
824aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
825aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_get_entries.blob",
826aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
827aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
828aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, h->entries, tmp);
829aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
830aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
832aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
833aae69bed019826ddec93f761514652a93d871e49Harald Welte
834aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (parse_table(h) < 0)
835aae69bed019826ddec93f761514652a93d871e49Harald Welte		goto error;
8367e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
839aae69bed019826ddec93f761514652a93d871e49Harald Welteerror:
840aae69bed019826ddec93f761514652a93d871e49Harald Welte	TC_FREE(&h);
841aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
844841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssonvoid
845841e4aed2349046eb2c0b1375139c06569a93bd0Martin JosefssonTC_FREE(TC_HANDLE_T *h)
846841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
847aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c, *tmp;
848aae69bed019826ddec93f761514652a93d871e49Harald Welte
849841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	close(sockfd);
850e560fd604284180f3ab522993c5b8e6f424ef1d9Martin Josefsson	sockfd = -1;
851aae69bed019826ddec93f761514652a93d871e49Harald Welte
852aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
853aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r, *rtmp;
854aae69bed019826ddec93f761514652a93d871e49Harald Welte
855aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry_safe(r, rtmp, &c->rules, list) {
856aae69bed019826ddec93f761514652a93d871e49Harald Welte			free(r);
857aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
858aae69bed019826ddec93f761514652a93d871e49Harald Welte
859aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(c);
860aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
861aae69bed019826ddec93f761514652a93d871e49Harald Welte
862aae69bed019826ddec93f761514652a93d871e49Harald Welte	free((*h)->entries);
863841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	free(*h);
864aae69bed019826ddec93f761514652a93d871e49Harald Welte
865841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	*h = NULL;
866841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson}
867841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
86979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellprint_match(const STRUCT_ENTRY_MATCH *m)
870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
871228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
87579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
87679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
87879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DUMP_ENTRIES(const TC_HANDLE_T handle)
879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
881aae69bed019826ddec93f761514652a93d871e49Harald Welte#if 0
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("libiptc v%s.  %u entries, %u bytes.\n",
88380fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte	       IPTABLES_VERSION,
884aae69bed019826ddec93f761514652a93d871e49Harald Welte	       handle->new_number, handle->entries->size);
885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
88767088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_PRE_ROUTING],
88867088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_IN],
88967088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_FORWARD],
89067088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_LOCAL_OUT],
89167088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.hook_entry[HOOK_POST_ROUTING]);
892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
89367088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_PRE_ROUTING],
89467088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_IN],
89567088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_FORWARD],
89667088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_LOCAL_OUT],
89767088e73ce7707229c56987868f112051defca5aRusty Russell	       handle->info.underflow[HOOK_POST_ROUTING]);
898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
899aae69bed019826ddec93f761514652a93d871e49Harald Welte	ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
90079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      dump_entry, handle);
901aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
9020113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
90579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
907aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_find_label(chain, handle) != NULL;
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
910aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
911aae69bed019826ddec93f761514652a93d871e49Harald Welte{
912aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = handle->chain_iterator_cur;
913aae69bed019826ddec93f761514652a93d871e49Harald Welte
914aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->list.next == &handle->chains)
915aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur = NULL;
916aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
917aae69bed019826ddec93f761514652a93d871e49Harald Welte		handle->chain_iterator_cur =
918aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry(c->list.next, struct chain_head, list);
919aae69bed019826ddec93f761514652a93d871e49Harald Welte}
920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
92130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
9238c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_CHAIN(TC_HANDLE_T *handle)
924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
925aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = list_entry((*handle)->chains.next,
926aae69bed019826ddec93f761514652a93d871e49Harald Welte					  struct chain_head, list);
927aae69bed019826ddec93f761514652a93d871e49Harald Welte
928aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_CHAIN;
929aae69bed019826ddec93f761514652a93d871e49Harald Welte
930aae69bed019826ddec93f761514652a93d871e49Harald Welte
931aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&(*handle)->chains)) {
932aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no chains\n");
9330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
934aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
9350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
936aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->chain_iterator_cur = c;
937aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
93830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
939aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
940aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
94130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
94230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
94330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
94430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
94579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NEXT_CHAIN(TC_HANDLE_T *handle)
94630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
947aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c = (*handle)->chain_iterator_cur;
948aae69bed019826ddec93f761514652a93d871e49Harald Welte
949aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_CHAIN;
95030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
951aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
952aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP(": no more chains\n");
95330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
954aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
95530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
956aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_chain_iterator_advance(*handle);
957aae69bed019826ddec93f761514652a93d871e49Harald Welte
958aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP(": returning `%s'\n", c->name);
959aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->name;
96030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
96130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
96230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
96379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
9648c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
96530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
966aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
967aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
968aae69bed019826ddec93f761514652a93d871e49Harald Welte
969aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_FIRST_RULE;
97030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
971aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("first rule(%s): ", chain);
972aae69bed019826ddec93f761514652a93d871e49Harald Welte
973aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
97430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
97530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
97630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
97930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
980aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (list_empty(&c->rules)) {
981aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("no rules, returning NULL\n");
98230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
983aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
984aae69bed019826ddec93f761514652a93d871e49Harald Welte
985aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry(c->rules.next, struct rule_head, list);
986aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
987aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("%p\n", r);
98830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
989aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
991e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
99230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
99379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *
9948c700900e2a0cf87d7917cb62578583a60ad1210Philip BlundellTC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
99530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
996aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
997aae69bed019826ddec93f761514652a93d871e49Harald Welte
998aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
999aae69bed019826ddec93f761514652a93d871e49Harald Welte
1000aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(*handle)->rule_iterator_cur) {
1001aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("returning NULL\n");
100230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
1003aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1004aae69bed019826ddec93f761514652a93d871e49Harald Welte
1005aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = list_entry((*handle)->rule_iterator_cur->list.next,
1006aae69bed019826ddec93f761514652a93d871e49Harald Welte			struct rule_head, list);
100730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1008aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NEXT_RULE;
1009aae69bed019826ddec93f761514652a93d871e49Harald Welte
1010aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("next=%p, head=%p...", &r->list,
1011aae69bed019826ddec93f761514652a93d871e49Harald Welte		&(*handle)->rule_iterator_cur->chain->rules);
1012aae69bed019826ddec93f761514652a93d871e49Harald Welte
1013aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
1014aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur = NULL;
1015aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("finished, returning NULL\n");
1016aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1017aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1018aae69bed019826ddec93f761514652a93d871e49Harald Welte
1019aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->rule_iterator_cur = r;
1020aae69bed019826ddec93f761514652a93d871e49Harald Welte
1021aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* NOTE: prev is without any influence ! */
1022aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("returning rule %p\n", r);
1023aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
102430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
102530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
1027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
102879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1030aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1031aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_NUM_RULES;
1032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1033aae69bed019826ddec93f761514652a93d871e49Harald Welte
1034aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1035aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1039aae69bed019826ddec93f761514652a93d871e49Harald Welte
1040aae69bed019826ddec93f761514652a93d871e49Harald Welte	return c->num_rules;
1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1042e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellconst STRUCT_ENTRY *TC_GET_RULE(const char *chain,
104479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				unsigned int n,
104579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell				TC_HANDLE_T *handle)
1046e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1047aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1048aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1049aae69bed019826ddec93f761514652a93d871e49Harald Welte
1050aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_RULE;
1051e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1053aae69bed019826ddec93f761514652a93d871e49Harald Welte
1054aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1055aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1057e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1060aae69bed019826ddec93f761514652a93d871e49Harald Welte	r = iptcc_get_rule_num(c, n);
1061aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!r)
1062aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
1063aae69bed019826ddec93f761514652a93d871e49Harald Welte	return r->entry;
1064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1066aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1067aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *standard_target_map(int verdict)
1068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1069aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch (verdict) {
1070aae69bed019826ddec93f761514652a93d871e49Harald Welte		case RETURN:
107179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_RETURN;
1072aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1073aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_ACCEPT-1:
107479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			return LABEL_ACCEPT;
1075aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1076aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_DROP-1:
1077aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_DROP;
1078aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1079aae69bed019826ddec93f761514652a93d871e49Harald Welte		case -NF_QUEUE-1:
1080aae69bed019826ddec93f761514652a93d871e49Harald Welte			return LABEL_QUEUE;
1081aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1082aae69bed019826ddec93f761514652a93d871e49Harald Welte		default:
1083aae69bed019826ddec93f761514652a93d871e49Harald Welte			fprintf(stderr, "ERROR: %d not a valid target)\n",
1084aae69bed019826ddec93f761514652a93d871e49Harald Welte				verdict);
1085aae69bed019826ddec93f761514652a93d871e49Harald Welte			abort();
1086aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1087e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1088aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* not reached */
1089aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1092aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Returns a pointer to the target name of this position. */
1093aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
1094aae69bed019826ddec93f761514652a93d871e49Harald Welte			  TC_HANDLE_T *handle)
1095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1096aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
1097aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r = container_of(e, struct rule_head, entry);
1098e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1099aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_TARGET;
11000113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1101aae69bed019826ddec93f761514652a93d871e49Harald Welte	switch(r->type) {
1102aae69bed019826ddec93f761514652a93d871e49Harald Welte		int spos;
1103aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_FALLTHROUGH:
1104aae69bed019826ddec93f761514652a93d871e49Harald Welte			return "";
1105aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1106aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_JUMP:
1107aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1108aae69bed019826ddec93f761514652a93d871e49Harald Welte			return r->jump->name;
1109aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1110aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_STANDARD:
1111aae69bed019826ddec93f761514652a93d871e49Harald Welte			spos = *(int *)GET_TARGET(e)->data;
1112aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("r=%p, spos=%d'\n", r, spos);
1113aae69bed019826ddec93f761514652a93d871e49Harald Welte			return standard_target_map(spos);
1114aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1115aae69bed019826ddec93f761514652a93d871e49Harald Welte		case IPTCC_R_MODULE:
1116aae69bed019826ddec93f761514652a93d871e49Harald Welte			return GET_TARGET(e)->u.user.name;
1117aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
11180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1119aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1120aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1121aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Is this a built-in chain?  Actually returns hook + 1. */
1122aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1123aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
1124aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1125aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1126aae69bed019826ddec93f761514652a93d871e49Harald Welte
1127aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_BUILTIN;
11280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1129aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, handle);
1130aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1131aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1132aae69bed019826ddec93f761514652a93d871e49Harald Welte		return -1;
11330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1135aae69bed019826ddec93f761514652a93d871e49Harald Welte	return iptcc_is_builtin(c);
11360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
11370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1138aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Get the policy of a given built-in chain */
1139aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *
1140aae69bed019826ddec93f761514652a93d871e49Harald WelteTC_GET_POLICY(const char *chain,
1141aae69bed019826ddec93f761514652a93d871e49Harald Welte	      STRUCT_COUNTERS *counters,
1142aae69bed019826ddec93f761514652a93d871e49Harald Welte	      TC_HANDLE_T *handle)
11430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
1144aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
11450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1146aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = TC_GET_POLICY;
1147fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
1148aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("called for chain %s\n", chain);
11490113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1150aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_find_label(chain, *handle);
1151aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1152aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1153aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
11540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
11550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1156aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c))
1157aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
11580113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1159aae69bed019826ddec93f761514652a93d871e49Harald Welte	*counters = c->counters;
11600113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1161aae69bed019826ddec93f761514652a93d871e49Harald Welte	return standard_target_map(c->verdict);
11620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte}
1163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1165aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_standard_map(struct rule_head *r, int verdict)
1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1167aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
116879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_STANDARD_TARGET *t;
1169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
117079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
117267088e73ce7707229c56987868f112051defca5aRusty Russell	if (t->target.u.target_size
11738c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	    != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
117879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
117979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	strcpy(t->target.u.user.name, STANDARD_TARGET);
1180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
1181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1182aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->type = IPTCC_R_STANDARD;
1183aae69bed019826ddec93f761514652a93d871e49Harald Welte
1184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
11867e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1188aae69bed019826ddec93f761514652a93d871e49Harald Welteiptcc_map_target(const TC_HANDLE_T handle,
1189aae69bed019826ddec93f761514652a93d871e49Harald Welte	   struct rule_head *r)
1190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1191aae69bed019826ddec93f761514652a93d871e49Harald Welte	STRUCT_ENTRY *e = r->entry;
11920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
1195aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(t->u.user.name, "") == 0) {
1196aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->type = IPTCC_R_FALLTHROUGH;
1197aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
1198aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
120079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
1201aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_ACCEPT - 1);
120279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
1203aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_DROP - 1);
120467088e73ce7707229c56987868f112051defca5aRusty Russell	else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1205aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, -NF_QUEUE - 1);
120679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
1207aae69bed019826ddec93f761514652a93d871e49Harald Welte		return iptcc_standard_map(r, RETURN);
120879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (TC_BUILTIN(t->u.user.name, handle)) {
1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
1210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
1214aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct chain_head *c;
1215aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("trying to find chain `%s': ", t->u.user.name);
1216aae69bed019826ddec93f761514652a93d871e49Harald Welte
1217aae69bed019826ddec93f761514652a93d871e49Harald Welte		c = iptcc_find_label(t->u.user.name, handle);
1218aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (c) {
1219aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP_C("found!\n");
1220aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->type = IPTCC_R_JUMP;
1221aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->jump = c;
1222aae69bed019826ddec93f761514652a93d871e49Harald Welte			c->references++;
1223aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 1;
1224aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1225aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP_C("not found :(\n");
1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset to all 0 for your memcmp convenience. */
1230228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
123279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	       FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1234aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(handle);
1235aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
124079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
124179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
124279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned int rulenum,
124379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1245aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1246aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *prev;
1247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
124879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_INSERT_ENTRY;
1249aae69bed019826ddec93f761514652a93d871e49Harald Welte
1250aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1255aae69bed019826ddec93f761514652a93d871e49Harald Welte	prev = iptcc_get_rule_num(c, rulenum);
1256aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!prev) {
1257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1261aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1262aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1263aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1264aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1265aae69bed019826ddec93f761514652a93d871e49Harald Welte
1266aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1267aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1268aae69bed019826ddec93f761514652a93d871e49Harald Welte
1269aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1270aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
12710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1272aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1273aae69bed019826ddec93f761514652a93d871e49Harald Welte
1274aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&r->list, &prev->list);
1275aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1276aae69bed019826ddec93f761514652a93d871e49Harald Welte
1277aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1279aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
128479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
128579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 const STRUCT_ENTRY *e,
128679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 unsigned int rulenum,
128779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		 TC_HANDLE_T *handle)
1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1289aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1290aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *old;
1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
129279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_REPLACE_ENTRY;
1293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1294aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1299aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(old = iptcc_get_rule_num(c, rulenum))) {
1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1304aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1305aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1307aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1308aae69bed019826ddec93f761514652a93d871e49Harald Welte
1309aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1310aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1312aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1313aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13140113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1315aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1316aae69bed019826ddec93f761514652a93d871e49Harald Welte
1317aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add(&r->list, &old->list);
1318aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(old);
13190113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1320aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1321aae69bed019826ddec93f761514652a93d871e49Harald Welte
1322aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13250113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
132879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
132979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *e,
133079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1332aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1333aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
133579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_APPEND_ENTRY;
1336aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1337aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to find chain `%s'\n", chain);
1338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1342aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1343aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1344aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1345aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1346aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1347aae69bed019826ddec93f761514652a93d871e49Harald Welte
1348aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(r->entry, e, e->next_offset);
1349aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
1350aae69bed019826ddec93f761514652a93d871e49Harald Welte
1351aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_map_target(*handle, r)) {
1352aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("unable to ma target of rule for chain `%s'\n", chain);
1353aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(r);
13540113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1355aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1356aae69bed019826ddec93f761514652a93d871e49Harald Welte
1357aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&r->list, &c->rules);
1358aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules++;
1359aae69bed019826ddec93f761514652a93d871e49Harald Welte
1360aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
13610113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1362aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
136679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellmatch_different(const STRUCT_ENTRY_MATCH *a,
1367edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1368edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1369edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
137179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY_MATCH *b;
1372edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1373e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
137530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1377228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1380228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
138373ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	*maskptr += ALIGN(sizeof(*a));
1384edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
138573ef09b21573ddb17ff75e5fd06fd4b52ec8ea40Rusty Russell	for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1386edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1387edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1388edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1389edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1390edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1391edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1392edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1393edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russelltarget_different(const unsigned char *a_targdata,
1394edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *b_targdata,
1395edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 unsigned int tdatasize,
1396edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *mask)
1397edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1398edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1399edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	for (i = 0; i < tdatasize; i++)
1400edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
140190e712a00913fe2a2f885142439c392392dc08a8Rusty Russell			return 1;
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
140679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic int
140779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellis_same(const STRUCT_ENTRY *a,
140879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	const STRUCT_ENTRY *b,
140979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	unsigned char *matchmask);
1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14110113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte/* Delete the first rule in `chain' which matches `fw'. */
1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
141379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
141479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		const STRUCT_ENTRY *origfw,
141579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		unsigned char *matchmask,
141679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1418aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1419fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte	struct rule_head *r;
14200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	STRUCT_ENTRY *e, *fw;
1421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
142279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_ENTRY;
1423aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14280113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	fw = malloc(origfw->next_offset);
14290113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	if (fw == NULL) {
14300113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = ENOMEM;
14310113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
14320113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
14330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1434fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte	list_for_each_entry(r, &c->rules, list) {
14350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
14360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		memcpy(fw, origfw, origfw->next_offset);
14370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1438fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte#if 0
14390113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		/* FIXME: handle this in is_same --RR */
14400113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (!map_target(*handle, fw, offset, &discard)) {
14410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			free(fw);
14420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			return 0;
14430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		}
14440113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#endif
1445fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1446fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte		e = r->entry;
1447fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
14480113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		if (is_same(e, fw, matchmask)) {
1449fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			/* If we are about to delete the rule that is the
1450fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			 * current iterator, move rule iterator back.  next
1451fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			 * pointer will then point to real next node */
1452fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			if (r == (*handle)->rule_iterator_cur) {
1453fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte				(*handle)->rule_iterator_cur =
1454fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte					list_entry((*handle)->rule_iterator_cur->list.prev,
1455fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte						   struct rule_head, list);
1456fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			}
1457fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte
1458fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			c->num_rules--;
1459fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			iptcc_delete_rule(r);
1460fe53707285c250c6bb1e434ea6f8271cf061c67bHarald Welte			return 1;
1461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	free(fw);
1465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
14677e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1468aae69bed019826ddec93f761514652a93d871e49Harald Welte
1469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
147279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
147379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    unsigned int rulenum,
147479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1476aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1477aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
1478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
147979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_NUM_ENTRY;
1480aae69bed019826ddec93f761514652a93d871e49Harald Welte
1481aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1483e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1486aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1491aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the rule that is the current
1492aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move rule iterator back.  next pointer will then
1493aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * point to real next node */
1494aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r == (*handle)->rule_iterator_cur) {
1495aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->rule_iterator_cur =
1496aae69bed019826ddec93f761514652a93d871e49Harald Welte			list_entry((*handle)->rule_iterator_cur->list.prev,
1497aae69bed019826ddec93f761514652a93d871e49Harald Welte				   struct rule_head, list);
14980113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1500aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules--;
1501aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptcc_delete_rule(r);
1502aae69bed019826ddec93f761514652a93d871e49Harald Welte
1503aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
150979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CHECK_PACKET(const IPT_CHAINLABEL chain,
151079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		STRUCT_ENTRY *entry,
151179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		TC_HANDLE_T *handle)
1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
151979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1521aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1522aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r, *tmp;
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15240113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	iptc_fn = TC_FLUSH_ENTRIES;
1525aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1530aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry_safe(r, tmp, &c->rules, list) {
1531aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_delete_rule(r);
1532aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1533aae69bed019826ddec93f761514652a93d871e49Harald Welte
1534aae69bed019826ddec93f761514652a93d871e49Harald Welte	c->num_rules = 0;
1535aae69bed019826ddec93f761514652a93d871e49Harald Welte
1536aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1537aae69bed019826ddec93f761514652a93d871e49Harald Welte
1538aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
154379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1545aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1546aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
15477e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1548aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1553aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(r, &c->rules, list) {
1554aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1555aae69bed019826ddec93f761514652a93d871e49Harald Welte			r->counter_map.maptype = COUNTER_MAP_ZEROED;
1556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1557aae69bed019826ddec93f761514652a93d871e49Harald Welte
1558175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15631cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteSTRUCT_COUNTERS *
15641cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_READ_COUNTER(const IPT_CHAINLABEL chain,
15651cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
15661cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
15671cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1568aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1569aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
15701cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15711cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_READ_COUNTER;
15721cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
15731cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1574aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
15751cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
15761cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return NULL;
15771cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
15781cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1579aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
15800113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
15810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return NULL;
15820113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
15830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1584aae69bed019826ddec93f761514652a93d871e49Harald Welte	return &r->entry[0].counters;
15851cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
15861cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15871cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
15881cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
15891cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		unsigned int rulenum,
15901cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		TC_HANDLE_T *handle)
15911cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1592aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1593aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
15941cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
15951cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_ZERO_COUNTER;
15961cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
15971cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1598aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
15991cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16001cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
16011cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
16021cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1603aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
16040113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
16050113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
16060113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
16070113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1608aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1609aae69bed019826ddec93f761514652a93d871e49Harald Welte		r->counter_map.maptype = COUNTER_MAP_ZEROED;
16101cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16111cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
16121cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16131cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
16141cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
16151cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16161cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welteint
16171cef74d943055668b5e356eebea877fdaa1ce3e0Harald WelteTC_SET_COUNTER(const IPT_CHAINLABEL chain,
16181cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       unsigned int rulenum,
16191cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       STRUCT_COUNTERS *counters,
16201cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	       TC_HANDLE_T *handle)
16211cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte{
1622aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1623aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct rule_head *r;
16241cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	STRUCT_ENTRY *e;
16251cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16261cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	iptc_fn = TC_SET_COUNTER;
16271cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	CHECK(*handle);
16281cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1629aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
16301cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		errno = ENOENT;
16311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		return 0;
16321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
16330113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1634aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(r = iptcc_get_rule_num(c, rulenum))) {
16350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		errno = E2BIG;
16360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
16370113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	}
16380113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1639aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = r->entry;
1640aae69bed019826ddec93f761514652a93d871e49Harald Welte	r->counter_map.maptype = COUNTER_MAP_SET;
16410113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
16420113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
16431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	set_changed(*handle);
16451cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
16461cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	return 1;
16471cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte}
16481cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
165379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1655aae69bed019826ddec93f761514652a93d871e49Harald Welte	static struct chain_head *c;
1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
165779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_CREATE_CHAIN;
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
1661aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(chain, *handle)
166279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_DROP) == 0
166379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_ACCEPT) == 0
166467088e73ce7707229c56987868f112051defca5aRusty Russell	    || strcmp(chain, LABEL_QUEUE) == 0
166579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(chain, LABEL_RETURN) == 0) {
1666aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain `%s' already exists\n", chain);
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
167179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1672aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Chain name `%s' too long\n", chain);
1673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1677aae69bed019826ddec93f761514652a93d871e49Harald Welte	c = iptcc_alloc_chain_head(chain, 0);
1678aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!c) {
1679aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
1680aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1681aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1683aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1685aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("Creating chain `%s'\n", chain);
1686aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_add_tail(&c->list, &(*handle)->chains);
1687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1688aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1690aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
169579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
169679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  TC_HANDLE_T *handle)
1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1698aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1700aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1705aae69bed019826ddec93f761514652a93d871e49Harald Welte	*ref = c->references;
1706aae69bed019826ddec93f761514652a93d871e49Harald Welte
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
171279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
1715aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
17167e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
171779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_DELETE_CHAIN;
1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1719aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1720aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1721aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1722aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1723aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1724aae69bed019826ddec93f761514652a93d871e49Harald Welte
172579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (TC_BUILTIN(chain, *handle)) {
1726aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot remove builtin chain `%s'\n", chain);
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1731aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!TC_GET_REFERENCES(&references, chain, handle)) {
1732aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot get references on chain `%s'\n", chain);
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1736aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (references > 0) {
1737aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' still has references\n", chain);
1738aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EMLINK;
1739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1742aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c->num_rules) {
1743aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("chain `%s' is not empty\n", chain);
1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1748aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* If we are about to delete the chain that is the current
1749aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * iterator, move chain iterator firward. */
1750aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (c == (*handle)->chain_iterator_cur)
1751aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptcc_chain_iterator_advance(*handle);
1752aae69bed019826ddec93f761514652a93d871e49Harald Welte
1753aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_del(&c->list);
1754aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(c);
17550113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1756aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("chain `%s' deleted\n", chain);
17570113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1758aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1759aae69bed019826ddec93f761514652a93d871e49Harald Welte
1760aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
176479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellint TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
176579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    const IPT_CHAINLABEL newname,
176679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		    TC_HANDLE_T *handle)
1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1768aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
176979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_RENAME_CHAIN;
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
17711de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
17721de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte           QUEUE, RETURN. */
1773aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptcc_find_label(newname, *handle)
177479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_DROP) == 0
177579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_ACCEPT) == 0
17761de804642d4c8e9c71b7e225a1528fff15fa7faaHarald Welte	    || strcmp(newname, LABEL_QUEUE) == 0
177779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || strcmp(newname, LABEL_RETURN) == 0) {
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1782aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(oldname, *handle))
178379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    || TC_BUILTIN(oldname, *handle)) {
1784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
178879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1793aae69bed019826ddec93f761514652a93d871e49Harald Welte	strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
1794aae69bed019826ddec93f761514652a93d871e49Harald Welte
17950113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	set_changed(*handle);
17960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
180279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_SET_POLICY(const IPT_CHAINLABEL chain,
180379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      const IPT_CHAINLABEL policy,
18041cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	      STRUCT_COUNTERS *counters,
180579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	      TC_HANDLE_T *handle)
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1807aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
180979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	iptc_fn = TC_SET_POLICY;
1810aae69bed019826ddec93f761514652a93d871e49Harald Welte
1811aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(c = iptcc_find_label(chain, *handle))) {
1812aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot find chain `%s'\n", chain);
1813c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1815aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1817aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptcc_is_builtin(c)) {
1818aae69bed019826ddec93f761514652a93d871e49Harald Welte		DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
1819aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
18209e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte		return 0;
18219e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte	}
18229e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte
182379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (strcmp(policy, LABEL_ACCEPT) == 0)
1824aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_ACCEPT - 1;
182579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	else if (strcmp(policy, LABEL_DROP) == 0)
1826aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->verdict = -NF_DROP - 1;
1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
18311cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
18321cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	if (counters) {
18331cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte		/* set byte and packet counters */
1834aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
1835aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_SET;
18361cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	} else {
1837aae69bed019826ddec93f761514652a93d871e49Harald Welte		c->counter_map.maptype = COUNTER_MAP_NOMAP;
18381cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	}
18391cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
1840175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
184679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell   libiptc.c: In function `TC_COMMIT':
1847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
185279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellsubtract_counters(STRUCT_COUNTERS *answer,
185379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *a,
185479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		  const STRUCT_COUNTERS *b)
1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1860aae69bed019826ddec93f761514652a93d871e49Harald Welte
1861aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
1862aae69bed019826ddec93f761514652a93d871e49Harald Welte			   unsigned int index)
1863aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1864aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
1865aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NOMAP => zero\n");
1866aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1867aae69bed019826ddec93f761514652a93d871e49Harald Welte
1868aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
1869aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1870aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1871aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos)
1872aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1873aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1874aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1875aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1876aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: X + Y + Z.
1877aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in X + Y
1878aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in replacement read.
1879aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
1880aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->counters[index] = repl->counters[mappos];
1881aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
1882aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1883aae69bed019826ddec93f761514652a93d871e49Harald Welte
1884aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
1885aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_REPLACE *repl,
1886aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int index,
1887aae69bed019826ddec93f761514652a93d871e49Harald Welte				unsigned int mappos,
1888aae69bed019826ddec93f761514652a93d871e49Harald Welte				STRUCT_COUNTERS *counters)
1889aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1890aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Original read: X.
1891aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Atomic read on replacement: X + Y.
1892aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Currently in kernel: Z.
1893aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * Want in kernel: Y + Z.
1894aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in Y.
1895aae69bed019826ddec93f761514652a93d871e49Harald Welte	 * => Add in (replacement read - original read).
1896aae69bed019826ddec93f761514652a93d871e49Harald Welte	 */
1897aae69bed019826ddec93f761514652a93d871e49Harald Welte	subtract_counters(&newcounters->counters[index],
1898aae69bed019826ddec93f761514652a93d871e49Harald Welte			  &repl->counters[mappos],
1899aae69bed019826ddec93f761514652a93d871e49Harald Welte			  counters);
1900aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("ZEROED => mappos %u\n", mappos);
1901aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1902aae69bed019826ddec93f761514652a93d871e49Harald Welte
1903aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
1904aae69bed019826ddec93f761514652a93d871e49Harald Welte			     unsigned int index,
1905aae69bed019826ddec93f761514652a93d871e49Harald Welte			     STRUCT_COUNTERS *counters)
1906aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1907aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Want to set counter (iptables-restore) */
1908aae69bed019826ddec93f761514652a93d871e49Harald Welte
1909aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(&newcounters->counters[index], counters,
1910aae69bed019826ddec93f761514652a93d871e49Harald Welte		sizeof(STRUCT_COUNTERS));
1911aae69bed019826ddec93f761514652a93d871e49Harald Welte
1912aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP_C("SET\n");
1913aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1914aae69bed019826ddec93f761514652a93d871e49Harald Welte
1915aae69bed019826ddec93f761514652a93d871e49Harald Welte
1916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
191779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_COMMIT(TC_HANDLE_T *handle)
1918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
192079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_REPLACE *repl;
192179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	STRUCT_COUNTERS_INFO *newcounters;
1922aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct chain_head *c;
1923aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
1924841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	size_t counterlen;
1925aae69bed019826ddec93f761514652a93d871e49Harald Welte	int new_number;
1926aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int new_size;
1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1929841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
193154c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	TC_DUMP_ENTRIES(*handle);
1932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
1935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
1936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1938aae69bed019826ddec93f761514652a93d871e49Harald Welte	new_number = iptcc_compile_table_prep(*handle, &new_size);
1939aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (new_number < 0) {
1940aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1941aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1942aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1943aae69bed019826ddec93f761514652a93d871e49Harald Welte
1944aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl = malloc(sizeof(*repl) + new_size);
1945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
1946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1947e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1949aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(repl, 0, sizeof(*repl));
1950aae69bed019826ddec93f761514652a93d871e49Harald Welte
1951aae69bed019826ddec93f761514652a93d871e49Harald Welte	counterlen = sizeof(STRUCT_COUNTERS_INFO)
1952aae69bed019826ddec93f761514652a93d871e49Harald Welte			+ sizeof(STRUCT_COUNTERS) * new_number;
1953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
195579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
1957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
1958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1961e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
1963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
1964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
1965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1970aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(newcounters, 0, counterlen);
1971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
1973aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->num_entries = new_number;
1974aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->size = new_size;
1975aae69bed019826ddec93f761514652a93d871e49Harald Welte
1976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
1977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
1978aae69bed019826ddec93f761514652a93d871e49Harald Welte
1979aae69bed019826ddec93f761514652a93d871e49Harald Welte	DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
1980aae69bed019826ddec93f761514652a93d871e49Harald Welte		repl->num_entries, repl->size, repl->num_counters);
1981aae69bed019826ddec93f761514652a93d871e49Harald Welte
1982aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = iptcc_compile_table(*handle, repl);
1983aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ret < 0) {
1984aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ret;
1985aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl->counters);
1986aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
1987aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1988aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1989aae69bed019826ddec93f761514652a93d871e49Harald Welte
1990aae69bed019826ddec93f761514652a93d871e49Harald Welte
1991aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
1992aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
1993aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_replace.blob",
1994aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
1995aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
1996aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, repl, sizeof(*repl) + repl->size);
1997aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
1998aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1999aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2000aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
200279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
2003aae69bed019826ddec93f761514652a93d871e49Harald Welte		       sizeof(*repl) + repl->size) < 0) {
2004e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
2007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
2011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
2012aae69bed019826ddec93f761514652a93d871e49Harald Welte	newcounters->num_counters = new_number;
2013aae69bed019826ddec93f761514652a93d871e49Harald Welte
2014aae69bed019826ddec93f761514652a93d871e49Harald Welte	list_for_each_entry(c, &(*handle)->chains, list) {
2015aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct rule_head *r;
2016aae69bed019826ddec93f761514652a93d871e49Harald Welte
2017aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Builtin chains have their own counters */
2018aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (iptcc_is_builtin(c)) {
2019aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for chain-index %u: ", c->foot_index);
2020aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch(c->counter_map.maptype) {
2021aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2022aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, c->foot_index);
2023aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2024aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2025aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2026aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2027aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos);
2028aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2029aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2030aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2031aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->foot_index,
2032aae69bed019826ddec93f761514652a93d871e49Harald Welte						    c->counter_map.mappos,
2033aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &c->counters);
2034aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2035aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2036aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, c->foot_index,
2037aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &c->counters);
2038aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2039aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2040aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
20411cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
2042aae69bed019826ddec93f761514652a93d871e49Harald Welte		list_for_each_entry(r, &c->rules, list) {
2043aae69bed019826ddec93f761514652a93d871e49Harald Welte			DEBUGP("counter for index %u: ", r->index);
2044aae69bed019826ddec93f761514652a93d871e49Harald Welte			switch (r->counter_map.maptype) {
2045aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NOMAP:
2046aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_nomap(newcounters, r->index);
2047aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2048aae69bed019826ddec93f761514652a93d871e49Harald Welte
2049aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_NORMAL_MAP:
2050aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_normal_map(newcounters, repl,
2051aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2052aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos);
2053aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2054aae69bed019826ddec93f761514652a93d871e49Harald Welte
2055aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_ZEROED:
2056aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_zeroed(newcounters, repl,
2057aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->index,
2058aae69bed019826ddec93f761514652a93d871e49Harald Welte						    r->counter_map.mappos,
2059aae69bed019826ddec93f761514652a93d871e49Harald Welte						    &r->entry->counters);
2060aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2061aae69bed019826ddec93f761514652a93d871e49Harald Welte
2062aae69bed019826ddec93f761514652a93d871e49Harald Welte			case COUNTER_MAP_SET:
2063aae69bed019826ddec93f761514652a93d871e49Harald Welte				counters_map_set(newcounters, r->index,
2064aae69bed019826ddec93f761514652a93d871e49Harald Welte						 &r->entry->counters);
2065aae69bed019826ddec93f761514652a93d871e49Harald Welte				break;
2066aae69bed019826ddec93f761514652a93d871e49Harald Welte			}
2067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
2068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
206962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell
2070aae69bed019826ddec93f761514652a93d871e49Harald Welte
207162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#ifdef KERNEL_64_USERSPACE_32
207262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell	{
207362527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		/* Kernel will think that pointer should be 64-bits, and get
207462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   padding.  So we accomodate here (assumption: alignment of
207562527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		   `counters' is on 64-bit boundary). */
207662527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
207762527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		if ((unsigned long)&newcounters->counters % 8 != 0) {
207862527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			fprintf(stderr,
207962527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell				"counters alignment incorrect! Mail rusty!\n");
208062527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell			abort();
208162527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		}
208262527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell		*kernptr = newcounters->counters;
208354c307e0ff401f40a6fe382af4ae5bff0f5b40baRusty Russell	}
208462527ce5f0ffaa5b18aa118f64c21af238ddc156Rusty Russell#endif /* KERNEL_64_USERSPACE_32 */
2085e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2086aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifdef IPTC_DEBUG2
2087aae69bed019826ddec93f761514652a93d871e49Harald Welte	{
2088aae69bed019826ddec93f761514652a93d871e49Harald Welte		int fd = open("/tmp/libiptc-so_set_add_counters.blob",
2089aae69bed019826ddec93f761514652a93d871e49Harald Welte				O_CREAT|O_WRONLY);
2090aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (fd >= 0) {
2091aae69bed019826ddec93f761514652a93d871e49Harald Welte			write(fd, newcounters, counterlen);
2092aae69bed019826ddec93f761514652a93d871e49Harald Welte			close(fd);
2093aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
2094aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
2095aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
2096aae69bed019826ddec93f761514652a93d871e49Harald Welte
209779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
209879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		       newcounters, counterlen) < 0) {
2099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
2100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
2101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
2102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
2103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
2106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
2107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
2108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
2110841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	TC_FREE(handle);
2111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
2112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
2115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
211679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_GET_RAW_SOCKET()
2117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
2119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
2122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
212379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty RussellTC_STRERROR(int err)
2124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
2125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
2126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
2127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
2128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
2129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
2130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
21314ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	  { { TC_INIT, EPERM, "Permission denied (you must be root)" },
213279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INIT, EINVAL, "Module is wrong version" },
21334ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_INIT, ENOENT,
21344ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte		    "Table does not exist (do you need to insmod?)" },
213579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
213679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
213779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_CHAIN, EMLINK,
2138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
213979dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
214079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
214179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
214279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
21431cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
21441cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	    { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
214579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
214679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_INSERT_ENTRY, EINVAL, "Target problem" },
2147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
214879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_CHECK_PACKET, EINVAL,
2149c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
21504ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { TC_CHECK_PACKET, ENOSYS,
21514ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	      "Checking will most likely never get implemented" },
2152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
215379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_DELETE_ENTRY, ENOENT,
2154c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
215579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, ENOENT,
2156c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
215779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    { TC_SET_POLICY, EINVAL,
2158c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
21594ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte
21604ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, 0, "Incompatible with this kernel" },
21614ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
21624ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
21634ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
21644ccfa630d9a588d4b852abef8bc467642427c8cfHarald Welte	    { NULL, ENOENT, "No chain/target/match by that name" },
2165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
2166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
2169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
2170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
2171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
2174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2175