libiptc.c revision 228e98dd6303af11925235af4cf3c3ec450f3f41
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Library which manipulates firewall rules.  Version 0.1. */
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
11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
12e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   COPYING for details). */
13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <assert.h>
15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h>
16e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <errno.h>
17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h>
18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
19edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell#include <limits.h>
20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if !defined(__GLIBC__) || (__GLIBC__ < 2)
22e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchertypedef unsigned int socklen_t;
23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <libiptc/libiptc.h>
26edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell#include <linux/netfilter_ipv4/ipt_limit.h>
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_VERSION	4
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_OFFSET	0x1FFF
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
3530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#if 0
3630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic struct ipt_entry_target *
3730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellipt_get_target(struct ipt_entry *e)
3830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
3930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (void *)e + e->target_offset;
4030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
4130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
4230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher= { [NF_IP_PRE_ROUTING]  "PREROUTING",
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_LOCAL_IN]     "INPUT",
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_FORWARD]      "FORWARD",
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_LOCAL_OUT]    "OUTPUT",
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_POST_ROUTING] "POSTROUTING"
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_ZEROED
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Convenience structures */
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct ipt_error_target
66e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target t;
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char error[IPT_TABLE_MAXNAMELEN];
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
7130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstruct chain_cache
7230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
7330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	char name[IPT_TABLE_MAXNAMELEN];
7430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* This is the first rule in chain. */
7530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct ipt_entry *start;
7630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Last rule in chain */
7730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct ipt_entry *end;
7830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell};
7930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptc_handle
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Have changes been made? */
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int changed;
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Size in here reflects original state. */
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo info;
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct counter_map *counter_map;
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Array of hook names */
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char **hooknames;
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
9130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Cached position of chain heads (NULL = no cache). */
9230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int cache_num_chains;
9330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int cache_num_builtins;
9430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *cache_chain_heads;
9530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
9630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Chain iterator: current chain cache entry. */
9730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *cache_chain_iteration;
9830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
9930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Rule iterator: terminal rule */
10030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct ipt_entry *cache_rule_end;
101175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Number in here reflects current state. */
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int new_number;
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_get_entries entries;
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
107175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
108175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellset_changed(iptc_handle_t h)
109175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
11030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (h->cache_chain_heads) {
11130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		free(h->cache_chain_heads);
11230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads = NULL;
11330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_num_chains = 0;
11430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_iteration = NULL;
11530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_rule_end = NULL;
11630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
117175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
118175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
119175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
12030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#ifndef NDEBUG
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void do_check(iptc_handle_t h, unsigned int line);
122849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
12330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else
12430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h)
12530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_number(const struct ipt_entry *i,
129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   const struct ipt_entry *seek,
130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherentry2index(const iptc_handle_t h, const struct ipt_entry *seek)
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      get_number, seek, &pos) == 0) {
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %i not an entry!\n",
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(unsigned char *)seek - h->entries.entries);
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_entry_n(struct ipt_entry *i,
154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int number,
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int *pos,
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    struct ipt_entry **pe)
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*pos == number) {
159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*pe = i;
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct ipt_entry *
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherindex2entry(iptc_handle_t h, unsigned int index)
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *ret = NULL;
171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  get_entry_n, index, &pos, &ret);
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline struct ipt_entry *
179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_entry(iptc_handle_t h, unsigned int offset)
180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (struct ipt_entry *)(h->entries.entries + offset);
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline unsigned long
185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherentry2offset(const iptc_handle_t h, const struct ipt_entry *e)
186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (unsigned char *)e - h->entries.entries;
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned long
191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherindex2offset(iptc_handle_t h, unsigned int index)
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2offset(h, index2entry(h, index));
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_errorlabel(iptc_handle_t h, unsigned int offset)
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(h, offset);
202228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) != 0) {
203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %u not an error node!\n",
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			offset);
205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (const char *)ipt_get_target(e)->data;
209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic iptc_handle_t
213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheralloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t h;
217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	len = sizeof(struct iptc_handle)
219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size
220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ num_rules * sizeof(struct counter_map);
221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = malloc(len)) == NULL) {
223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->changed = 0;
22830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_num_chains = 0;
22930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_chain_heads = NULL;
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->counter_map = (void *)h
231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ sizeof(struct iptc_handle)
232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size;
233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->entries.name, tablename);
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_handle_t
240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_init(const char *tablename)
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t h;
243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo info;
244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_init;
249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (sockfd < 0)
252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(tablename) >= IPT_TABLE_MAXNAMELEN) {
256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_INFO, &info, &s) < 0)
261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = alloc_handle(info.name, info.size, info.num_entries))
264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    == NULL)
265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Too hard --RR */
268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dynlib = dlopen(pathname, RTLD_NOW);
271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!dynlib) {
272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = dlsym(dynlib, "hooknames");
276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!h->hooknames) {
277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#else
281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = hooknames;
282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->new_number = h->info.num_entries;
287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < h->info.num_entries; i++)
288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		h->counter_map[i]
289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			= ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->entries.size = h->info.size;
292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	tmp = sizeof(struct ipt_get_entries) + h->info.size;
294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_ENTRIES, &h->entries,
296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       &tmp) < 0) {
297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(h);
298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
3007e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS_NATIVE(n)			\
306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>24)&0xFF,			\
307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>16)&0xFF,			\
308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>8)&0xFF,			\
309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)&0xFF)
310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_match(const struct ipt_entry_match *m)
315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
316228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Match name: `%s'\n", m->u.user.name);
317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdump_entry(struct ipt_entry *e, const iptc_handle_t handle)
322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t i;
324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t;
325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Entry %u (%lu):\n", entry2index(handle, e),
327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       entry2offset(handle, e));
328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr));
330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr));
332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Interface: `%s'/", e->ip.iniface);
333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++)
334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%c", e->ip.iniface_mask[i] ? 'X' : '.');
335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("to `%s'/", e->ip.outiface);
336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++)
337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%c", e->ip.outiface_mask[i] ? 'X' : '.');
338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\nProtocol: %u\n", e->ip.proto);
339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Flags: %02X\n", e->ip.flags);
340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Invflags: %02X\n", e->ip.invflags);
341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Counters: %llu packets, %llu bytes\n",
342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       e->counters.pcnt, e->counters.bcnt);
343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Cache: %08X ", e->nfcache);
344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_ALTERED) printf("ALTERED ");
345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN ");
346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_SRC) printf("IP_SRC ");
347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_DST) printf("IP_DST ");
348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN ");
349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT ");
350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_TOS) printf("IP_TOS ");
351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO ");
352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS ");
353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS ");
354e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT ");
355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT ");
356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN ");
357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_MATCH_ITERATE(e, print_match);
360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = ipt_get_target(e);
362228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size);
363228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(t->u.user.name, IPT_STANDARD_TARGET) == 0) {
364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int pos = *(int *)t->data;
365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (pos < 0)
366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("verdict=%s\n",
367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       pos == -NF_ACCEPT-1 ? "NF_ACCEPT"
368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : pos == -NF_DROP-1 ? "NF_DROP"
369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : pos == -NF_QUEUE-1 ? "NF_QUEUE"
370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : pos == IPT_RETURN ? "RETURN"
371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : "UNKNOWN");
372e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
373e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("verdict=%u\n", pos);
374228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	} else if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0)
375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("error=`%s'\n", t->data);
376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdump_entries(const iptc_handle_t handle)
383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("libiptc v%s.  %u entries, %u bytes.\n",
387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       NETFILTER_VERSION,
388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->new_number, handle->entries.size);
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_PRE_ROUTING],
392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_LOCAL_IN],
393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_FORWARD],
394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_LOCAL_OUT],
395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_POST_ROUTING]);
396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_PRE_ROUTING],
398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_LOCAL_IN],
399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_FORWARD],
400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_LOCAL_OUT],
401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_POST_ROUTING]);
402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size,
404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  dump_entry, handle);
405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
40730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns 0 if not hook entry, else hooknumber + 1 */
40830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic inline unsigned int
40930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellis_hook_entry(struct ipt_entry *e, iptc_handle_t h)
41030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
41130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int i;
41230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
41330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
41430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if ((h->info.valid_hooks & (1 << i))
41530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		    && get_entry(h, h->info.hook_entry[i]) == e)
41630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			return i+1;
41730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
41830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return 0;
41930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
42030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
42230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelladd_chain(struct ipt_entry *e, iptc_handle_t h, struct ipt_entry **prev)
423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
42430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int builtin;
425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
42630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Last entry.  End it. */
42730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (entry2offset(h, e) + e->next_offset == h->entries.size) {
42830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		/* This is the ERROR node at end of the table */
42930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains-1].end = *prev;
43030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return 0;
43130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
43330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* We know this is the start of a new chain if it's an ERROR
43430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	   target, or a hook entry point */
435228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) == 0) {
43630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		/* prev was last entry in previous chain */
43730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains-1].end
43830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			= *prev;
43930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
44030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		strcpy(h->cache_chain_heads[h->cache_num_chains].name,
44130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		       (const char *)ipt_get_target(e)->data);
44230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains].start
44330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			= (void *)e + e->next_offset;
44430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_num_chains++;
44530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	} else if ((builtin = is_hook_entry(e, h)) != 0) {
44630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (h->cache_num_chains > 0)
44730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			/* prev was last entry in previous chain */
44830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			h->cache_chain_heads[h->cache_num_chains-1].end
44930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell				= *prev;
45030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
45130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		strcpy(h->cache_chain_heads[h->cache_num_chains].name,
45230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		       h->hooknames[builtin-1]);
45330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_chain_heads[h->cache_num_chains].start
45430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			= (void *)e;
45530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		h->cache_num_chains++;
45630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	}
45730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
45830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	*prev = e;
459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
46230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic int alphasort(const void *a, const void *b)
46330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
46430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return strcmp(((struct chain_cache *)a)->name,
46530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		      ((struct chain_cache *)b)->name);
46630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
46730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
46830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic int populate_cache(iptc_handle_t h)
469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
47130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct ipt_entry *prev;
472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
47330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* # chains < # rules / 2 + num builtins - 1 */
47430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_chain_heads = malloc((h->new_number / 2 + 4)
47530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell				      * sizeof(struct chain_cache));
47630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!h->cache_chain_heads) {
47730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOMEM;
47830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return 0;
479175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	}
480175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
48130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_num_chains = 0;
48230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_num_builtins = 0;
48330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
48430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Count builtins */
48530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
48630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (h->info.valid_hooks & (1 << i))
48730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			h->cache_num_builtins++;
488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
49030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	prev = NULL;
49130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
49230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			  add_chain, h, &prev);
49330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
49430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	qsort(h->cache_chain_heads + h->cache_num_builtins,
49530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	      h->cache_num_chains - h->cache_num_builtins,
49630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	      sizeof(struct chain_cache), alphasort);
49730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
49830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return 1;
49930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
50030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
50130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns cache ptr if found, otherwise NULL. */
50230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic struct chain_cache *
50330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellfind_label(const char *name, iptc_handle_t handle)
50430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
505849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	unsigned int i;
50630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
50730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (handle->cache_chain_heads == NULL
50830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    && !populate_cache(handle))
50930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
51030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
511849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	/* FIXME: Linear search through builtins, then binary --RR */
512849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	for (i = 0; i < handle->cache_num_chains; i++) {
513849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell		if (strcmp(handle->cache_chain_heads[i].name, name) == 0)
514849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell			return &handle->cache_chain_heads[i];
515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
517849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell	return NULL;
518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint iptc_is_chain(const char *chain, const iptc_handle_t handle)
522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
52330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return find_label(chain, handle) != NULL;
524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns the position of the final (ie. unconditional) element. */
527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_chain_end(const iptc_handle_t handle, unsigned int start)
529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int last_off, off;
531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	last_off = start;
534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(handle, start);
535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Terminate when we meet a error label or a hook entry. */
537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (off = start + e->next_offset;
538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     off < handle->entries.size;
539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     last_off = off, off += e->next_offset) {
540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry_target *t;
541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(handle, off);
544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit an entry point. */
546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (i = 0; i < NF_IP_NUMHOOKS; i++) {
547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if ((handle->info.valid_hooks & (1 << i))
548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && off == handle->info.hook_entry[i])
549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				return last_off;
550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit a user chain label */
553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t = ipt_get_target(e);
554228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0)
555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return last_off;
556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* SHOULD NEVER HAPPEN */
558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		handle->entries.size, off);
560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	abort();
561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
56330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */
564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
56530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_first_chain(iptc_handle_t *handle)
566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
56730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_heads == NULL
56830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    && !populate_cache(*handle))
569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
57130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	(*handle)->cache_chain_iteration
57230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		= &(*handle)->cache_chain_heads[0];
57330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
57430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (*handle)->cache_chain_iteration->name;
57530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
57630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
57730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains.  Returns NULL at end. */
57830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *
57930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_next_chain(iptc_handle_t *handle)
58030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
58130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	(*handle)->cache_chain_iteration++;
58230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
58330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
58430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    == (*handle)->cache_num_chains)
58530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
58630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
58730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (*handle)->cache_chain_iteration->name;
58830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
58930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
59030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */
59130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst struct ipt_entry *
59230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_first_rule(const char *chain, iptc_handle_t *handle)
59330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
59430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
59530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
59630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	c = find_label(chain, *handle);
59730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!c) {
59830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOENT;
59930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
60230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Empty chain: single return/policy rule */
60330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (c->start == c->end)
60430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
60530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
60630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	(*handle)->cache_rule_end = c->end;
60730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return c->start;
608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
61030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */
61130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst struct ipt_entry *
61230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle)
61330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
61430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((void *)prev + prev->next_offset
61530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	    == (void *)(*handle)->cache_rule_end)
61630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return NULL;
61730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
61830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	return (void *)prev + prev->next_offset;
61930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
62030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
62130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#if 0
622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_num_rules(const char *chain, iptc_handle_t *handle)
625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int off = 0;
627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *start, *end;
628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&off, chain, *handle)) {
631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	start = get_entry(*handle, off);
636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	end = get_entry(*handle, get_chain_end(*handle, off));
637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2index(*handle, end) - entry2index(*handle, start);
639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get n'th rule in this chain. */
642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst struct ipt_entry *iptc_get_rule(const char *chain,
643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      unsigned int n,
644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      iptc_handle_t *handle)
645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0, chainindex;
647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&pos, chain, *handle)) {
650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, pos));
655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return index2entry(*handle, chainindex + n);
657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
65830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif
659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
66030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic const char *
66130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelltarget_name(iptc_handle_t handle, const struct ipt_entry *ce)
662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int spos;
664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int labelidx;
665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *jumpto;
666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
66730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* To avoid const warnings */
66830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct ipt_entry *e = (struct ipt_entry *)ce;
66930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
670228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) != 0)
671228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		return ipt_get_target(e)->u.user.name;
672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Standard target: evaluate */
674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	spos = *(int *)ipt_get_target(e)->data;
675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (spos < 0) {
676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (spos == IPT_RETURN)
677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_RETURN;
678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_ACCEPT-1)
679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_ACCEPT;
680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_DROP-1)
681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_DROP;
6822f4e5d92c73906e0dc2ae42fee5c05740528e92bJames Morris		else if (spos == -NF_QUEUE-1)
683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_QUEUE;
684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			entry2offset(handle, e), handle->entries.size,
687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			spos);
688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	jumpto = get_entry(handle, spos);
692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fall through rule */
694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (jumpto == (void *)e + e->next_offset)
695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return "";
696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must point to head of a chain: ie. after error rule */
698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labelidx = entry2index(handle, jumpto) - 1;
699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return get_errorlabel(handle, index2offset(handle, labelidx));
700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns a pointer to the target name of this position. */
70330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *iptc_get_target(const struct ipt_entry *e,
704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    iptc_handle_t *handle)
705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Is this a built-in chain?  Actually returns hook + 1. */
710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_builtin(const char *chain, const iptc_handle_t handle)
712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((handle->info.valid_hooks & (1 << i))
717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && handle->hooknames[i]
718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && strcmp(handle->hooknames[i], chain) == 0)
719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return i+1;
720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the policy of a given built-in chain */
725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_policy(const char *chain,
727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_counters *counters,
728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		iptc_handle_t *handle)
729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int start;
731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int hook;
733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	hook = iptc_builtin(chain, *handle);
735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook != 0)
736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		start = (*handle)->info.hook_entry[hook-1];
737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, get_chain_end(*handle, start));
741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*counters = e->counters;
742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercorrect_verdict(struct ipt_entry *e,
748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned char *base,
749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int offset, int delta_offset)
750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t = (void *)ipt_get_target(e);
752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int curr = (unsigned char *)e - base;
753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Trap: insert of fall-through rule.  Don't change fall-through
755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   verdict to jump-over-next-rule. */
756228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0
757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && t->verdict > (int)offset
758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && !(curr == offset &&
759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		 t->verdict == curr + e->next_offset)) {
760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict += delta_offset;
761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Adjusts standard verdict jump positions after an insertion/deletion. */
767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherset_verdict(unsigned int offset, int delta_offset, iptc_handle_t *handle)
769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE((*handle)->entries.entries,
771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  (*handle)->entries.size,
772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  correct_verdict, (*handle)->entries.entries,
773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  offset, delta_offset);
774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
775175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* If prepend is set, then we are prepending to a chain: if the
780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * insertion position is an entry point, keep the entry point. */
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinsert_rules(unsigned int num_rules, unsigned int rules_size,
783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct ipt_entry *insert,
784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int offset, unsigned int num_rules_offset,
785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int prepend,
786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t newh;
789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo newinfo;
790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (offset >= (*handle)->entries.size) {
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newinfo = (*handle)->info;
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix up entry points. */
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Entry points to START of chain, so keep same if
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   inserting on at that point. */
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.hook_entry[i] > offset)
804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newinfo.hook_entry[i] += rules_size;
805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Underflow always points to END of chain (policy),
807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   so if something is inserted at same point, it
808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   should be advanced. */
809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.underflow[i] >= offset)
810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newinfo.underflow[i] += rules_size;
811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh = alloc_handle((*handle)->info.name,
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    (*handle)->info.size + rules_size,
815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    (*handle)->info.num_entries + num_rules);
816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newh)
817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->info = newinfo;
819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Copy pre... */
821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->entries.entries, (*handle)->entries.entries, offset);
822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... Insert new ... */
823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->entries.entries + offset, insert, rules_size);
824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... copy post */
825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->entries.entries + offset + rules_size,
826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.entries + offset,
827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size - offset);
828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move counter map. */
830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Copy pre... */
831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->counter_map, (*handle)->counter_map,
832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(struct counter_map) * num_rules_offset);
833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... copy post */
834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->counter_map + num_rules_offset + num_rules,
835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->counter_map + num_rules_offset,
836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(struct counter_map) * ((*handle)->new_number
837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					     - num_rules_offset));
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Set intermediates to no counter copy */
839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < num_rules; i++)
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		newh->counter_map[num_rules_offset+i]
841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->new_number = (*handle)->new_number + num_rules;
844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->entries.size = (*handle)->entries.size + rules_size;
845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->hooknames = (*handle)->hooknames;
846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
84730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_heads)
84830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		free((*handle)->cache_chain_heads);
849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(*handle);
850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = newh;
851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return set_verdict(offset, rules_size, handle);
853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdelete_rules(unsigned int num_rules, unsigned int rules_size,
857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int offset, unsigned int num_rules_offset,
858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (offset + rules_size > (*handle)->entries.size) {
863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix up entry points. */
868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* In practice, we never delete up to a hook entry,
870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   since the built-in chains are always first,
871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   so these two are never equal */
872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.hook_entry[i] >= offset + rules_size)
873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->info.hook_entry[i] -= rules_size;
874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if ((*handle)->info.hook_entry[i] > offset) {
875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				i, (*handle)->info.hook_entry[i], offset);
877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			abort();
878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Underflow points to policy (terminal) rule in
881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   built-in, so sequality is valid here (when deleting
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   the last rule). */
883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.underflow[i] >= offset + rules_size)
884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->info.underflow[i] -= rules_size;
885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if ((*handle)->info.underflow[i] > offset) {
886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				i, (*handle)->info.underflow[i], offset);
888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			abort();
889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move the rules down. */
893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memmove((*handle)->entries.entries + offset,
894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		(*handle)->entries.entries + offset + rules_size,
895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		(*handle)->entries.size - (offset + rules_size));
896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move the counter map down. */
898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memmove(&(*handle)->counter_map[num_rules_offset],
899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		&(*handle)->counter_map[num_rules_offset + num_rules],
900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sizeof(struct counter_map)
901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		* ((*handle)->new_number - (num_rules + num_rules_offset)));
902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix numbers */
904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->new_number -= num_rules;
905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->entries.size -= rules_size;
906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return set_verdict(offset, -(int)rules_size, handle);
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstandard_map(struct ipt_entry *e, int verdict)
912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)ipt_get_target(e);
916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
917228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (t->target.u.target_size != sizeof(struct ipt_standard_target)) {
918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
922228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->target.u.user.name, 0, IPT_FUNCTION_MAXNAMELEN);
923228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	strcpy(t->target.u.user.name, IPT_STANDARD_TARGET);
924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
9287e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermap_target(const iptc_handle_t handle,
931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   struct ipt_entry *e,
932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int offset,
933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   struct ipt_entry_target *old)
934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t = ipt_get_target(e);
936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*old = *t;
940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
942228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(t->u.user.name, "") == 0)
943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, offset + e->next_offset);
944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
945228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	else if (strcmp(t->u.user.name, IPTC_LABEL_ACCEPT) == 0)
946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_ACCEPT - 1);
947228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	else if (strcmp(t->u.user.name, IPTC_LABEL_DROP) == 0)
948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_DROP - 1);
949228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	else if (strcmp(t->u.user.name, IPTC_LABEL_QUEUE) == 0)
950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_QUEUE - 1);
951228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	else if (strcmp(t->u.user.name, IPTC_LABEL_RETURN) == 0)
952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, IPT_RETURN);
953228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	else if (iptc_builtin(t->u.user.name, handle)) {
954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
95930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		struct chain_cache *c;
960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
961228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		c = find_label(t->u.user.name, handle);
96230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		if (c)
96330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			return standard_map(e, entry2offset(handle, c->start));
964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset to all 0 for your memcmp convenience. */
968228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memset(t->u.user.name + strlen(t->u.user.name),
969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
970228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	       IPT_FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
974e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunmap_target(struct ipt_entry *e, struct ipt_entry_target *old)
976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t = ipt_get_target(e);
978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*t = *old;
982e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
986e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_insert_entry(const ipt_chainlabel chain,
987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_entry *e,
988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  unsigned int rulenum,
989e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
99130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int chainindex, offset;
992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
99330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
996e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_insert_entry;
99730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
998e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1000e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
100230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	chainindex = entry2index(*handle, c->start);
1003e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
100430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (index2entry(*handle, chainindex + rulenum) > c->end) {
1005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	offset = index2offset(*handle, chainindex + rulenum);
1009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Mapping target actually alters entry, but that's
1011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           transparent to the caller. */
1012e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!map_target(*handle, (struct ipt_entry *)e, offset, &old))
1013e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1014e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, offset,
1016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chainindex + rulenum, rulenum == 0, handle);
1017e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unmap_target((struct ipt_entry *)e, &old);
1018e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1019e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1021e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1022e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1023e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_replace_entry(const ipt_chainlabel chain,
1024e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   const struct ipt_entry *e,
1025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   unsigned int rulenum,
1026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   iptc_handle_t *handle)
1027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
102830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int chainindex, offset;
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
103030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_replace_entry;
1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
103530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	chainindex = entry2index(*handle, c->start);
1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (index2entry(*handle, chainindex + rulenum) >= c->end) {
1043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1045e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1046e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1047e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	offset = index2offset(*handle, chainindex + rulenum);
1048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace = delete and insert. */
1049e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
1050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  offset, chainindex + rulenum, handle))
1051e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!map_target(*handle, (struct ipt_entry *)e, offset, &old))
1054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1055e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, offset,
1057e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chainindex + rulenum, 1, handle);
1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unmap_target((struct ipt_entry *)e, &old);
1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1061e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1062e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Append entry `fw' to chain `chain'.  Equivalent to insert with
1063e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
1064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_append_entry(const ipt_chainlabel chain,
1066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_entry *e,
1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
1068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
106930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1070e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
1071e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1072e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1073e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_append_entry;
107430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1077e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1078e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
107930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!map_target(*handle, (struct ipt_entry *)e,
108030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			entry2offset(*handle, c->end), &old))
1081e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1082e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
108330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	ret = insert_rules(1, e->next_offset, e,
108430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   entry2offset(*handle, c->end),
108530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   entry2index(*handle, c->end),
1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   0, handle);
1087e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unmap_target((struct ipt_entry *)e, &old);
1088e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1089e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1092e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermatch_different(const struct ipt_entry_match *a,
1093edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *a_elems,
1094edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		const unsigned char *b_elems,
1095edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		unsigned char **maskptr)
1096e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1097e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const struct ipt_entry_match *b;
1098edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
110130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	b = (void *)b_elems + ((unsigned char *)a - a_elems);
1102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1103228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (a->u.match_size != b->u.match_size)
1104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1106228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(a->u.user.name, b->u.user.name) != 0)
1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1109edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += sizeof(*a);
1110edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1111228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	for (i = 0; i < a->u.match_size - sizeof(*a); i++)
1112edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1113edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell			return 1;
1114edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	*maskptr += i;
1115edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	return 0;
1116edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell}
1117edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1118edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int
1119edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russelltarget_different(const unsigned char *a_targdata,
1120edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *b_targdata,
1121edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 unsigned int tdatasize,
1122edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		 const unsigned char *mask)
1123edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{
1124edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned int i;
1125edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	for (i = 0; i < tdatasize; i++)
1126edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
112790e712a00913fe2a2f885142439c392392dc08a8Rusty Russell			return 1;
1128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1133edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellis_same(const struct ipt_entry *a, const struct ipt_entry *b,
1134edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned char *matchmask)
1135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *ta, *tb;
1138edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	unsigned char *mptr;
1139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1140edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	/* Always compare head structures: ignore mask here. */
1141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (a->ip.src.s_addr != b->ip.src.s_addr
1142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.dst.s_addr != b->ip.dst.s_addr
1143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.smsk.s_addr != b->ip.smsk.s_addr
1144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.smsk.s_addr != b->ip.smsk.s_addr
1145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.proto != b->ip.proto
1146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.flags != b->ip.flags
1147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.invflags != b->ip.invflags)
1148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++) {
1151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i])
1152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((a->ip.iniface[i] & a->ip.iniface_mask[i])
1154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    != (b->ip.iniface[i] & b->ip.iniface_mask[i]))
1155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i])
1157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((a->ip.outiface[i] & a->ip.outiface_mask[i])
1159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    != (b->ip.outiface[i] & b->ip.outiface_mask[i]))
1160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (a->nfcache != b->nfcache
1164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->target_offset != b->target_offset
1165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->next_offset != b->next_offset)
1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1168edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	mptr = matchmask + sizeof(struct ipt_entry);
1169edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr))
1170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ta = ipt_get_target((struct ipt_entry *)a);
1173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	tb = ipt_get_target((struct ipt_entry *)b);
1174228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (ta->u.target_size != tb->u.target_size)
1175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1176228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1178edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
1179ca92443e5a2b6430e334900058b341b440d385d9Marc Boucher	mptr += sizeof(*ta);
1180edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell	if (target_different(ta->data, tb->data,
1181228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			     ta->u.target_size - sizeof(*ta), mptr))
1182edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		return 0;
1183edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell
118490e712a00913fe2a2f885142439c392392dc08a8Rusty Russell   	return 1;
1185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the first rule in `chain' which matches `fw'. */
1188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_entry(const ipt_chainlabel chain,
1190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_entry *origfw,
1191edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		  unsigned char *matchmask,
1192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
1193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
119430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int offset;
119530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e, *fw;
1197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_entry;
119930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fw = malloc(origfw->next_offset);
1205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (fw == NULL) {
1206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
121030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	for (offset = entry2offset(*handle, c->start);
121130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	     offset < entry2offset(*handle, c->end);
121230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	     offset += e->next_offset) {
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry_target discard;
1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memcpy(fw, origfw, origfw->next_offset);
1216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* FIXME: handle this in is_same --RR */
1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!map_target(*handle, fw, offset, &discard)) {
1219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			free(fw);
1220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(*handle, offset);
1223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("Deleting:\n");
1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		dump_entry(newe);
1227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1228edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell		if (is_same(e, fw, matchmask)) {
1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			int ret;
1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			ret = delete_rules(1, e->next_offset,
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   offset, entry2index(*handle, e),
1232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   handle);
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			free(fw);
1234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return ret;
1235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(fw);
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
12417e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_num_entry(const ipt_chainlabel chain,
1246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      unsigned int rulenum,
1247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      iptc_handle_t *handle)
1248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int index;
1250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
125230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_num_entry;
125530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
126030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	index = entry2index(*handle, c->start) + rulenum;
1261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
126230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (index >= entry2index(*handle, c->end)) {
1263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = index2entry(*handle, index);
1268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e == NULL) {
1269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   index, handle);
1275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_check_packet(const ipt_chainlabel chain,
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      struct ipt_entry *entry,
1283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      iptc_handle_t *handle)
1284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
129330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int startindex, endindex;
129430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_flush_entries;
129830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
130230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	startindex = entry2index(*handle, c->start);
130330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	endindex = entry2index(*handle, c->end);
1304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(endindex - startindex,
130630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   (char *)c->end - (char *)c->start,
130730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   entry2offset(*handle, c->start), startindex,
1308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   handle);
1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
1315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, end;
131730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
13187e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
131930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
132430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	i = entry2index(*handle, c->start);
132530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	end = entry2index(*handle, c->end);
1326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (; i <= end; i++) {
1328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
1329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1331175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct {
1344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry head;
1345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_error_target name;
1346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry ret;
1347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_standard_target target;
1348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} newc;
1349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_create_chain;
1351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
135430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (find_label(chain, *handle)
1355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_DROP) == 0
1356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_ACCEPT) == 0
1357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_QUEUE) == 0
1358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_RETURN) == 0) {
1359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(chain)+1 > sizeof(ipt_chainlabel)) {
1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(&newc, 0, sizeof(newc));
1369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.head.target_offset = sizeof(struct ipt_entry);
1370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.head.next_offset
1371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= sizeof(struct ipt_entry) + sizeof(struct ipt_error_target);
1372228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	strcpy(newc.name.t.u.user.name, IPT_ERROR_TARGET);
1373228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	newc.name.t.u.target_size = sizeof(struct ipt_error_target);
1374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.name.error, chain);
1375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.ret.target_offset = sizeof(struct ipt_entry);
1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.ret.next_offset
1378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= sizeof(struct ipt_entry)+sizeof(struct ipt_standard_target);
1379228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	strcpy(newc.target.target.u.user.name, IPT_STANDARD_TARGET);
1380228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	newc.target.target.u.target_size = sizeof(struct ipt_standard_target);
1381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.target.verdict = IPT_RETURN;
1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Add just before terminal entry */
1384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(2, sizeof(newc), &newc.head,
1385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   index2offset(*handle, (*handle)->new_number - 1),
1386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   (*handle)->new_number - 1,
1387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   0, handle);
1388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercount_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref)
1393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1396228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) == 0) {
1397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t = (struct ipt_standard_target *)ipt_get_target(e);
1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict == offset)
1400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*ref)++;
1401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_references(unsigned int *ref, const ipt_chainlabel chain,
1409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    iptc_handle_t *handle)
1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
141130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
141330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1416e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1418e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*ref = 0;
1419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE((*handle)->entries.entries,
1420e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  (*handle)->entries.size,
142130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			  count_ref, entry2offset(*handle, c->start), ref);
1422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
1428e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
142930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int labelidx, labeloff;
1430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
143130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!iptc_get_references(&references, chain, handle))
1435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
14367e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_chain;
1438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (iptc_builtin(chain, *handle)) {
1440e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (references > 0) {
1445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EMLINK;
1446e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
144930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(chain, *handle))) {
1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
145430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((void *)c->start != c->end) {
1455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Need label index: preceeds chain start */
146030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	labelidx = entry2index(*handle, c->start) - 1;
1461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labeloff = index2offset(*handle, labelidx);
1462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(2,
1464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   get_entry(*handle, labeloff)->next_offset
146530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell			   + c->start->next_offset,
1466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   labeloff, labelidx, handle);
1467e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint iptc_rename_chain(const ipt_chainlabel oldname,
1472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      const ipt_chainlabel newname,
1473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      iptc_handle_t *handle)
1474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
147530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	unsigned int labeloff, labelidx;
147630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct chain_cache *c;
1477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_error_target *t;
1478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_rename_chain;
1480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT
1482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           RETURN. */
148330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (find_label(newname, *handle)
1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_DROP) == 0
1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_ACCEPT) == 0
1486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_RETURN) == 0) {
1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
149130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (!(c = find_label(oldname, *handle))
1492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || iptc_builtin(oldname, *handle)) {
1493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(newname)+1 > sizeof(ipt_chainlabel)) {
1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Need label index: preceeds chain start */
150330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	labelidx = entry2index(*handle, c->start) - 1;
1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labeloff = index2offset(*handle, labelidx);
1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_error_target *)
1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ipt_get_target(get_entry(*handle, labeloff));
1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->error, 0, sizeof(t->error));
1510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(t->error, newname);
1511175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_set_policy(const ipt_chainlabel chain,
1519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const ipt_chainlabel policy,
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		iptc_handle_t *handle)
1521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int hook;
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int policyoff;
1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1527c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	iptc_fn = iptc_set_policy;
1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Figure out which chain. */
1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	hook = iptc_builtin(chain, *handle);
1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook == 0) {
1531c8264991454b5e77279830736f80ea3153b6f814Marc Boucher		errno = ENOENT;
1532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		hook--;
1535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
1537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (policyoff != (*handle)->info.underflow[hook]) {
1538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       chain, policyoff, (*handle)->info.underflow[hook]);
1540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, policyoff);
1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)ipt_get_target(e);
1545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(policy, IPTC_LABEL_ACCEPT) == 0)
1547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_ACCEPT - 1;
1548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (strcmp(policy, IPTC_LABEL_DROP) == 0)
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_DROP - 1;
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->counter_map[entry2index(*handle, e)]
1555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
1556175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c: In function `iptc_commit':
1563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchersubtract_counters(struct ipt_counters *answer,
1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_counters *a,
1570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_counters *b)
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_commit(iptc_handle_t *handle)
1578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
1580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_replace *repl;
1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_counters_info *newcounters;
1582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t counterlen
1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= sizeof(struct ipt_counters_info)
1585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ sizeof(struct ipt_counters) * (*handle)->new_number;
1586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
1589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dump_entries(*handle);
1590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
1594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
1603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->counters = malloc(sizeof(struct ipt_counters)
1604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
1605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
1606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
16107e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
1613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
1614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_entries = (*handle)->new_number;
1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->size = (*handle)->entries.size;
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->hook_entry));
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->underflow, (*handle)->info.underflow,
1626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->underflow));
1627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
1628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->entries, (*handle)->entries.entries,
1630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size);
1631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_REPLACE, repl,
1633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       sizeof(*repl) + (*handle)->entries.size) < 0) {
1634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
1641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
1642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters->num_counters = (*handle)->new_number;
1643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < (*handle)->new_number; i++) {
1644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int mappos = (*handle)->counter_map[i].mappos;
1645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		switch ((*handle)->counter_map[i].maptype) {
1646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NOMAP:
1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i]
1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				= ((struct ipt_counters){ 0, 0 });
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NORMAL_MAP:
1652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: X + Y + Z.
1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in X + Y
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in replacement read.
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i] = repl->counters[mappos];
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_ZEROED:
1663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: Y + Z.
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in Y.
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in (replacement read - original read).
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			subtract_counters(&newcounters->counters[i],
1671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &repl->counters[mappos],
1672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &index2entry(*handle, i)->counters);
1673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16777e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell	if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_ADD_COUNTERS,
1678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       newcounters, counterlen) < 0) {
1679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
1686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
1687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
1688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
169030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if ((*handle)->cache_chain_heads)
169130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		free((*handle)->cache_chain_heads);
1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(*handle);
1693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = NULL;
1694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
1698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_raw_socket()
1700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
1702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
1706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_strerror(int err)
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
1712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  { { NULL, 0, "Incompatible with this kernel" },
1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
1716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOSYS, "Will be implemented real soon.  I promise." },
1717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOMEM, "Memory allocation problem" },
1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_init, EPERM, "Permission denied (you must be root)" },
1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_init, EINVAL, "Module is wrong version" },
1720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_chain, ENOTEMPTY, "Chain is not empty" },
1721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_chain, EINVAL, "Can't delete built-in chain" },
1722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_chain, EMLINK,
1723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_create_chain, EEXIST, "Chain already exists" },
1725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_insert_entry, E2BIG, "Index of insertion too big" },
1726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_replace_entry, E2BIG, "Index of replacement too big" },
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_num_entry, E2BIG, "Index of deletion too big" },
1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_insert_entry, ELOOP, "Loop found in table" },
1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_insert_entry, EINVAL, "Target problem" },
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
1731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_check_packet, EINVAL,
1732c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad arguments (does that interface exist?)" },
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_entry, ENOENT,
1735c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad rule (does a matching rule exist in that chain?)" },
1736c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	    { iptc_set_policy, ENOENT,
1737c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad built-in chain name" },
1738c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	    { iptc_set_policy, EINVAL,
1739c8264991454b5e77279830736f80ea3153b6f814Marc Boucher	      "Bad policy name" },
1740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOENT, "No extended target/match by that name" }
1741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
1742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/***************************** DEBUGGING ********************************/
1753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunconditional(const struct ipt_ip *ip)
1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(*ip)/sizeof(u_int32_t); i++)
1759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (((u_int32_t *)ip)[i])
1760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_match(const struct ipt_entry_match *m, unsigned int *off)
1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1768228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(m->u.match_size >= sizeof(struct ipt_entry_match));
1769228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(IPT_ALIGN(m->u.match_size) == m->u.match_size);
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1771228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	(*off) += m->u.match_size;
1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off,
1777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int user_offset, int *was_return,
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    iptc_handle_t h)
1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int toff;
1781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(e->target_offset >= sizeof(struct ipt_entry));
1784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(e->next_offset >= e->target_offset
1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       + sizeof(struct ipt_entry_target));
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	toff = sizeof(struct ipt_entry);
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_MATCH_ITERATE(e, check_match, &toff);
1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(toff == e->target_offset);
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)
1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ipt_get_target((struct ipt_entry *)e);
1793228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	/* next_offset will have to be multiple of entry alignment. */
1794228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(e->next_offset == IPT_ALIGN(e->next_offset));
1795228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(e->target_offset == IPT_ALIGN(e->target_offset));
1796228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(t->target.u.target_size == IPT_ALIGN(t->target.u.target_size));
1797228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(!iptc_is_chain(t->target.u.user.name, h));
1798228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell
1799228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0) {
1800228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		assert(t->target.u.target_size
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == IPT_ALIGN(sizeof(struct ipt_standard_target)));
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->verdict == -NF_DROP-1
1804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict == -NF_ACCEPT-1
1805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict == IPT_RETURN
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict < (int)h->entries.size);
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict >= 0) {
1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			struct ipt_entry *te = get_entry(h, t->verdict);
1810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			int idx;
1811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			idx = entry2index(h, te);
1813228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			assert(strcmp(ipt_get_target(te)->u.user.name,
1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      IPT_ERROR_TARGET)
1815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       != 0);
1816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(te != e);
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Prior node must be error node, or this node. */
1819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(t->verdict == entry2offset(h, e)+e->next_offset
1820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       || strcmp(ipt_get_target(index2entry(h, idx-1))
1821228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell					 ->u.user.name, IPT_ERROR_TARGET)
1822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       == 0);
1823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict == IPT_RETURN
1826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && unconditional(&e->ip)
1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && e->target_offset == sizeof(*e))
1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			*was_return = 1;
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			*was_return = 0;
1831228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	} else if (strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0) {
1832228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		assert(t->target.u.target_size
1833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == IPT_ALIGN(sizeof(struct ipt_error_target)));
1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* If this is in user area, previous must have been return */
1836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (*off > user_offset)
1837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(*was_return);
1838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*was_return = 0;
1840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else *was_return = 0;
1842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*off == user_offset)
1844228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		assert(strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0);
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*off) += e->next_offset;
1847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*i)++;
1848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
185130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#ifndef NDEBUG
1852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Do every conceivable sanity check on the handle */
1853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
1854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdo_check(iptc_handle_t h, unsigned int line)
1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, n;
1857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int user_offset; /* Offset of first user chain */
1858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int was_return;
1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(h->changed == 0 || h->changed == 1);
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(h->info.name, "filter") == 0) {
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.valid_hooks
1863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_LOCAL_IN
1864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_FORWARD
1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Hooks should be first three */
1868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0);
1869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_FORWARD] == n);
1873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, n);
1875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else if (strcmp(h->info.name, "nat") == 0) {
1880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.valid_hooks
1881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_PRE_ROUTING
1882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_POST_ROUTING
1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
1890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, n);
1892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else if (strcmp(h->info.name, "mangle") == 0) {
1897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.valid_hooks
1898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_PRE_ROUTING
1899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Hooks should be first three */
1902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
1911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* User chain == end of last builtin + policy entry */
1913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	user_offset = get_chain_end(h, user_offset);
1914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	user_offset += get_entry(h, user_offset)->next_offset;
1915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Overflows should be end of entry chains, and unconditional
1917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           policy nodes. */
1918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry *e;
1920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_standard_target *t;
1921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!(h->info.valid_hooks & (1 << i)))
1923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			continue;
1924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.underflow[i]
1925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == get_chain_end(h, h->info.hook_entry[i]));
1926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(h, get_chain_end(h, h->info.hook_entry[i]));
1928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(unconditional(&e->ip));
1929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(e->target_offset == sizeof(*e));
1930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(e->next_offset == sizeof(*e) + sizeof(*t));
1931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t = (struct ipt_standard_target *)ipt_get_target(e);
1932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1933228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		assert(strcmp(t->target.u.user.name, IPT_STANDARD_TARGET)==0);
1934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
1935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Hooks and underflows must be valid entries */
1937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		entry2index(h, get_entry(h, h->info.hook_entry[i]));
1938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		entry2index(h, get_entry(h, h->info.underflow[i]));
1939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(h->info.size
1942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       >= h->info.num_entries * (sizeof(struct ipt_entry)
1943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					 +sizeof(struct ipt_standard_target)));
1944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(h->entries.size
1946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       >= (h->new_number
1947e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   * (sizeof(struct ipt_entry)
1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      + sizeof(struct ipt_standard_target))));
1949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(strcmp(h->info.name, h->entries.name) == 0);
1950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	i = 0; n = 0;
1952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	was_return = 0;
1953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Check all the entries. */
1954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
1955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  check_entry, &i, &n, user_offset, &was_return, h);
1956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(i == h->new_number);
1958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(n == h->entries.size);
1959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Final entry must be error node */
1961228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1))
1962228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		      ->u.user.name,
1963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      IPT_ERROR_TARGET) == 0);
1964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
196530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif /*NDEBUG*/
1966