libiptc.c revision 90e712a00913fe2a2f885142439c392392dc08a8
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>
1990e712a00913fe2a2f885142439c392392dc08a8Rusty Russell#include <linux/netfilter_ipv4/ipt_limit.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>
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_VERSION	4
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_OFFSET	0x1FFF
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1;
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL;
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[]
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher= { [NF_IP_PRE_ROUTING]  "PREROUTING",
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_LOCAL_IN]     "INPUT",
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_FORWARD]      "FORWARD",
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_LOCAL_OUT]    "OUTPUT",
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    [NF_IP_POST_ROUTING] "POSTROUTING"
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	enum {
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NOMAP,
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_ZEROED
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} maptype;
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int mappos;
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Convenience structures */
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct ipt_error_target
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target t;
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char error[IPT_TABLE_MAXNAMELEN];
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptc_handle
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Have changes been made? */
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int changed;
66e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Size in here reflects original state. */
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo info;
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct counter_map *counter_map;
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Array of hook names */
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char **hooknames;
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
73175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	/* This was taking us ~50 seconds to list 300 rules. */
74175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	/* Cached: last find_label result */
75175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	char cache_label_name[IPT_TABLE_MAXNAMELEN];
76175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	int cache_label_return;
77175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	unsigned int cache_label_offset;
78175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Number in here reflects current state. */
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int new_number;
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_get_entries entries;
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
84175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void
85175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellset_changed(iptc_handle_t h)
86175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{
87175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->cache_label_name[0] = '\0';
88175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->changed = 1;
89175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell}
90175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void do_check(iptc_handle_t h, unsigned int line);
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CHECK(h) do_check((h), __LINE__)
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_number(const struct ipt_entry *i,
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   const struct ipt_entry *seek,
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int *pos)
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i == seek)
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherentry2index(const iptc_handle_t h, const struct ipt_entry *seek)
107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      get_number, seek, &pos) == 0) {
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %i not an entry!\n",
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(unsigned char *)seek - h->entries.entries);
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return pos;
117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_entry_n(struct ipt_entry *i,
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int number,
122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int *pos,
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    struct ipt_entry **pe)
124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*pos == number) {
126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*pe = i;
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*pos)++;
130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct ipt_entry *
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherindex2entry(iptc_handle_t h, unsigned int index)
135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0;
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *ret = NULL;
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  get_entry_n, index, &pos, &ret);
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline struct ipt_entry *
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_entry(iptc_handle_t h, unsigned int offset)
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (struct ipt_entry *)(h->entries.entries + offset);
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline unsigned long
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherentry2offset(const iptc_handle_t h, const struct ipt_entry *e)
153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (unsigned char *)e - h->entries.entries;
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned long
158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherindex2offset(iptc_handle_t h, unsigned int index)
159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2offset(h, index2entry(h, index));
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_errorlabel(iptc_handle_t h, unsigned int offset)
165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(h, offset);
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) != 0) {
170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: offset %u not an error node!\n",
171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			offset);
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (const char *)ipt_get_target(e)->data;
176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */
179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic iptc_handle_t
180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheralloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t len;
183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t h;
184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	len = sizeof(struct iptc_handle)
186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ num_rules * sizeof(struct counter_map);
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = malloc(len)) == NULL) {
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->changed = 0;
195175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	h->cache_label_name[0] = '\0';
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->counter_map = (void *)h
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ sizeof(struct iptc_handle)
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ size;
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->info.name, tablename);
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(h->entries.name, tablename);
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_handle_t
206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_init(const char *tablename)
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t h;
209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo info;
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_init;
215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (sockfd < 0)
218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	s = sizeof(info);
221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(tablename) >= IPT_TABLE_MAXNAMELEN) {
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(info.name, tablename);
226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_INFO, &info, &s) < 0)
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((h = alloc_handle(info.name, info.size, info.num_entries))
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    == NULL)
231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Too hard --RR */
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dynlib = dlopen(pathname, RTLD_NOW);
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!dynlib) {
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = dlsym(dynlib, "hooknames");
242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!h->hooknames) {
243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#else
247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = hooknames;
248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->info = info;
252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->new_number = h->info.num_entries;
253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < h->info.num_entries; i++)
254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		h->counter_map[i]
255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			= ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->entries.size = h->info.size;
258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	tmp = sizeof(struct ipt_get_entries) + h->info.size;
260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_ENTRIES, &h->entries,
262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       &tmp) < 0) {
263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(h);
264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2667e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(h);
268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return h;
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS_NATIVE(n)			\
272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>24)&0xFF,			\
273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>16)&0xFF,			\
274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>8)&0xFF,			\
275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)&0xFF)
276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_match(const struct ipt_entry_match *m)
281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Match name: `%s'\n", m->u.name);
283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdump_entry(struct ipt_entry *e, const iptc_handle_t handle)
288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t i;
290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t;
291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Entry %u (%lu):\n", entry2index(handle, e),
293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       entry2offset(handle, e));
294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr));
296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr));
298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Interface: `%s'/", e->ip.iniface);
299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++)
300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%c", e->ip.iniface_mask[i] ? 'X' : '.');
301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("to `%s'/", e->ip.outiface);
302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++)
303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%c", e->ip.outiface_mask[i] ? 'X' : '.');
304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\nProtocol: %u\n", e->ip.proto);
305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Flags: %02X\n", e->ip.flags);
306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Invflags: %02X\n", e->ip.invflags);
307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Counters: %llu packets, %llu bytes\n",
308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       e->counters.pcnt, e->counters.bcnt);
309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Cache: %08X ", e->nfcache);
310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_ALTERED) printf("ALTERED ");
311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN ");
312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_SRC) printf("IP_SRC ");
313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_DST) printf("IP_DST ");
314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN ");
315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT ");
316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_TOS) printf("IP_TOS ");
317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO ");
318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS ");
319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS ");
320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT ");
321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT ");
322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN ");
323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_MATCH_ITERATE(e, print_match);
326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = ipt_get_target(e);
328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Target name: `%s' [%u]\n", t->u.name, t->target_size);
329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(t->u.name, IPT_STANDARD_TARGET) == 0) {
330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int pos = *(int *)t->data;
331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (pos < 0)
332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("verdict=%s\n",
333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       pos == -NF_ACCEPT-1 ? "NF_ACCEPT"
334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : pos == -NF_DROP-1 ? "NF_DROP"
335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : pos == -NF_QUEUE-1 ? "NF_QUEUE"
336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : pos == IPT_RETURN ? "RETURN"
337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       : "UNKNOWN");
338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("verdict=%u\n", pos);
340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else if (strcmp(t->u.name, IPT_ERROR_TARGET) == 0)
341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("error=`%s'\n", t->data);
342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdump_entries(const iptc_handle_t handle)
349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("libiptc v%s.  %u entries, %u bytes.\n",
353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       NETFILTER_VERSION,
354e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->new_number, handle->entries.size);
355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Table `%s'\n", handle->info.name);
356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_PRE_ROUTING],
358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_LOCAL_IN],
359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_FORWARD],
360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_LOCAL_OUT],
361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.hook_entry[NF_IP_POST_ROUTING]);
362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_PRE_ROUTING],
364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_LOCAL_IN],
365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_FORWARD],
366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_LOCAL_OUT],
367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       handle->info.underflow[NF_IP_POST_ROUTING]);
368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size,
370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  dump_entry, handle);
371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
372e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
373e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfind_user_label(struct ipt_entry *e, unsigned int *off, const char *name)
375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Increment first: they want offset of entry AFTER label */
377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*off) += e->next_offset;
378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) == 0
380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && strcmp(ipt_get_target(e)->data, name) == 0)
381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns offset of label. */
387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfind_label(unsigned int *off,
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   const char *name,
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   const iptc_handle_t handle)
391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
394175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	/* Cached? */
395175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	if (handle->cache_label_name[0]
396175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	    && strcmp(name, handle->cache_label_name) == 0) {
397175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell		*off = handle->cache_label_offset;
398175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell		return handle->cache_label_return;
399175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	}
400175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Builtin chain name? */
402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	i = iptc_builtin(name, handle);
403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i != 0) {
404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*off = handle->info.hook_entry[i-1];
405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* User chain name? */
409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*off = 0;
410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size,
411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      find_user_label, off, name) != 0) {
412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* last error node doesn't count */
413175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell		if (*off != handle->entries.size) {
414175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell			strcpy(handle->cache_label_name, name);
415175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell			handle->cache_label_offset = *off;
416175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell			handle->cache_label_return = 1;
417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 1;
418175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell		}
419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
420e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
421175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	strcpy(handle->cache_label_name, name);
422175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	handle->cache_label_return = 0;
423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */
427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint iptc_is_chain(const char *chain, const iptc_handle_t handle)
428e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
429e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int dummy;
430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
431e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* avoid infinite recursion */
432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(handle);
434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return find_label(&dummy, chain, handle);
437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns the position of the final (ie. unconditional) element. */
440e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_chain_end(const iptc_handle_t handle, unsigned int start)
442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int last_off, off;
444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
446e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	last_off = start;
447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(handle, start);
448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Terminate when we meet a error label or a hook entry. */
450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (off = start + e->next_offset;
451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     off < handle->entries.size;
452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     last_off = off, off += e->next_offset) {
453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry_target *t;
454e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(handle, off);
457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit an entry point. */
459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (i = 0; i < NF_IP_NUMHOOKS; i++) {
460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if ((handle->info.valid_hooks & (1 << i))
461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && off == handle->info.hook_entry[i])
462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				return last_off;
463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We hit a user chain label */
466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t = ipt_get_target(e);
467e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (strcmp(t->u.name, IPT_ERROR_TARGET) == 0)
468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return last_off;
469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* SHOULD NEVER HAPPEN */
471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		handle->entries.size, off);
473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	abort();
474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Iterator functions to run through the chains; prev = NULL means
477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   first chain.  Returns NULL at end. */
478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_next_chain(const char *prev, iptc_handle_t *handle)
480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos;
482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
483e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!prev)
487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		pos = 0;
488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!find_label(&pos, prev, *handle)) {
490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			errno = ENOENT;
491e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return NULL;
492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		pos = get_chain_end(*handle, pos);
494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Next entry. */
495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(*handle, pos);
496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		pos += e->next_offset;
497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, pos);
499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Return names of entry points if it is one. */
501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (((*handle)->info.valid_hooks & (1 << i))
503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && pos == (*handle)->info.hook_entry[i])
504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return (*handle)->hooknames[i];
505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* If this is the last element, iteration finished */
507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (pos + e->next_offset == (*handle)->entries.size)
508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) != 0) {
511e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* SHOULD NEVER HAPPEN */
512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: position %u/%u not an error label\n",
513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			pos, (*handle)->entries.size);
514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (const char *)ipt_get_target(e)->data;
518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */
521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int
522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_num_rules(const char *chain, iptc_handle_t *handle)
523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int off = 0;
525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *start, *end;
526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&off, chain, *handle)) {
529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (unsigned int)-1;
531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	start = get_entry(*handle, off);
534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	end = get_entry(*handle, get_chain_end(*handle, off));
535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return entry2index(*handle, end) - entry2index(*handle, start);
537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get n'th rule in this chain. */
540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst struct ipt_entry *iptc_get_rule(const char *chain,
541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      unsigned int n,
542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      iptc_handle_t *handle)
543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0, chainindex;
545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&pos, chain, *handle)) {
548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, pos));
553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return index2entry(*handle, chainindex + n);
555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *target_name(iptc_handle_t handle, struct ipt_entry *e)
558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int spos;
560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int labelidx;
561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *jumpto;
562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(ipt_get_target(e)->u.name, IPT_STANDARD_TARGET) != 0)
564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return ipt_get_target(e)->u.name;
565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Standard target: evaluate */
567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	spos = *(int *)ipt_get_target(e)->data;
568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (spos < 0) {
569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (spos == IPT_RETURN)
570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_RETURN;
571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_ACCEPT-1)
572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_ACCEPT;
573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (spos == -NF_DROP-1)
574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_DROP;
5752f4e5d92c73906e0dc2ae42fee5c05740528e92bJames Morris		else if (spos == -NF_QUEUE-1)
576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return IPTC_LABEL_QUEUE;
577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			entry2offset(handle, e), handle->entries.size,
580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			spos);
581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	jumpto = get_entry(handle, spos);
585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fall through rule */
587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (jumpto == (void *)e + e->next_offset)
588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return "";
589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must point to head of a chain: ie. after error rule */
591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labelidx = entry2index(handle, jumpto) - 1;
592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return get_errorlabel(handle, index2offset(handle, labelidx));
593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns a pointer to the target name of this position. */
596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *iptc_get_target(const char *chain,
597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    unsigned int n,
598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    iptc_handle_t *handle)
599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos = 0, chainindex;
601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&pos, chain, *handle)) {
605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, pos));
610e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = index2entry(*handle, chainindex + n);
611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Is this a built-in chain?  Actually returns hook + 1. */
616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_builtin(const char *chain, const iptc_handle_t handle)
618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((handle->info.valid_hooks & (1 << i))
623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && handle->hooknames[i]
624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && strcmp(handle->hooknames[i], chain) == 0)
625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return i+1;
626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the policy of a given built-in chain */
631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_policy(const char *chain,
633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_counters *counters,
634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		iptc_handle_t *handle)
635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int start;
637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int hook;
639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	hook = iptc_builtin(chain, *handle);
642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook != 0)
643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		start = (*handle)->info.hook_entry[hook-1];
644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, get_chain_end(*handle, start));
648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*counters = e->counters;
649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return target_name(*handle, e);
651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercorrect_verdict(struct ipt_entry *e,
655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned char *base,
656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int offset, int delta_offset)
657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t = (void *)ipt_get_target(e);
659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int curr = (unsigned char *)e - base;
660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Trap: insert of fall-through rule.  Don't change fall-through
662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   verdict to jump-over-next-rule. */
663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0
664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && t->verdict > (int)offset
665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    && !(curr == offset &&
666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		 t->verdict == curr + e->next_offset)) {
667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict += delta_offset;
668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Adjusts standard verdict jump positions after an insertion/deletion. */
674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherset_verdict(unsigned int offset, int delta_offset, iptc_handle_t *handle)
676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE((*handle)->entries.entries,
678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  (*handle)->entries.size,
679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  correct_verdict, (*handle)->entries.entries,
680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  offset, delta_offset);
681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
682175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* If prepend is set, then we are prepending to a chain: if the
687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * insertion position is an entry point, keep the entry point. */
688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinsert_rules(unsigned int num_rules, unsigned int rules_size,
690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct ipt_entry *insert,
691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int offset, unsigned int num_rules_offset,
692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int prepend,
693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t newh;
696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo newinfo;
697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (offset >= (*handle)->entries.size) {
700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newinfo = (*handle)->info;
705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix up entry points. */
707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Entry points to START of chain, so keep same if
709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   inserting on at that point. */
710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.hook_entry[i] > offset)
711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newinfo.hook_entry[i] += rules_size;
712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Underflow always points to END of chain (policy),
714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   so if something is inserted at same point, it
715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   should be advanced. */
716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.underflow[i] >= offset)
717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newinfo.underflow[i] += rules_size;
718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh = alloc_handle((*handle)->info.name,
721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    (*handle)->info.size + rules_size,
722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    (*handle)->info.num_entries + num_rules);
723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newh)
724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->info = newinfo;
726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Copy pre... */
728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->entries.entries, (*handle)->entries.entries, offset);
729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... Insert new ... */
730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->entries.entries + offset, insert, rules_size);
731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... copy post */
732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->entries.entries + offset + rules_size,
733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.entries + offset,
734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size - offset);
735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move counter map. */
737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Copy pre... */
738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->counter_map, (*handle)->counter_map,
739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(struct counter_map) * num_rules_offset);
740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* ... copy post */
741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(newh->counter_map + num_rules_offset + num_rules,
742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->counter_map + num_rules_offset,
743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(struct counter_map) * ((*handle)->new_number
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					     - num_rules_offset));
745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Set intermediates to no counter copy */
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < num_rules; i++)
747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		newh->counter_map[num_rules_offset+i]
748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->new_number = (*handle)->new_number + num_rules;
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->entries.size = (*handle)->entries.size + rules_size;
752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newh->hooknames = (*handle)->hooknames;
753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(*handle);
755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = newh;
756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return set_verdict(offset, rules_size, handle);
758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdelete_rules(unsigned int num_rules, unsigned int rules_size,
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int offset, unsigned int num_rules_offset,
763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (offset + rules_size > (*handle)->entries.size) {
768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix up entry points. */
773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* In practice, we never delete up to a hook entry,
775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   since the built-in chains are always first,
776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   so these two are never equal */
777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.hook_entry[i] >= offset + rules_size)
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->info.hook_entry[i] -= rules_size;
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if ((*handle)->info.hook_entry[i] > offset) {
780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				i, (*handle)->info.hook_entry[i], offset);
782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			abort();
783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Underflow points to policy (terminal) rule in
786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   built-in, so sequality is valid here (when deleting
787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                   the last rule). */
788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->info.underflow[i] >= offset + rules_size)
789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->info.underflow[i] -= rules_size;
790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if ((*handle)->info.underflow[i] > offset) {
791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				i, (*handle)->info.underflow[i], offset);
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			abort();
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move the rules down. */
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memmove((*handle)->entries.entries + offset,
799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		(*handle)->entries.entries + offset + rules_size,
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		(*handle)->entries.size - (offset + rules_size));
801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Move the counter map down. */
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memmove(&(*handle)->counter_map[num_rules_offset],
804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		&(*handle)->counter_map[num_rules_offset + num_rules],
805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sizeof(struct counter_map)
806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		* ((*handle)->new_number - (num_rules + num_rules_offset)));
807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix numbers */
809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->new_number -= num_rules;
810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->entries.size -= rules_size;
811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return set_verdict(offset, -(int)rules_size, handle);
813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstandard_map(struct ipt_entry *e, int verdict)
817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)ipt_get_target(e);
821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (t->target.target_size != IPT_ALIGN(sizeof(struct ipt_standard_target))) {
823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset for memcmp convenience on delete/replace */
827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->target.u.name, 0, IPT_FUNCTION_MAXNAMELEN);
828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(t->target.u.name, IPT_STANDARD_TARGET);
829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t->verdict = verdict;
830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
8337e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermap_target(const iptc_handle_t handle,
836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   struct ipt_entry *e,
837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int offset,
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   struct ipt_entry_target *old)
839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t = ipt_get_target(e);
841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*old = *t;
845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's empty (=> fall through) */
847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(t->u.name, "") == 0)
848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, offset + e->next_offset);
849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Maybe it's a standard target name... */
850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (strcmp(t->u.name, IPTC_LABEL_ACCEPT) == 0)
851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_ACCEPT - 1);
852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (strcmp(t->u.name, IPTC_LABEL_DROP) == 0)
853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_DROP - 1);
854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (strcmp(t->u.name, IPTC_LABEL_QUEUE) == 0)
855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, -NF_QUEUE - 1);
856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (strcmp(t->u.name, IPTC_LABEL_RETURN) == 0)
857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return standard_map(e, IPT_RETURN);
858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (iptc_builtin(t->u.name, handle)) {
859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Can't jump to builtins. */
860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Maybe it's an existing chain name. */
864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int exists;
865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (find_label(&exists, t->u.name, handle))
867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return standard_map(e, exists);
868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Must be a module?  If not, kernel will reject... */
871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memset to all 0 for your memcmp convenience. */
872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->u.name + strlen(t->u.name),
873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       0,
874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       IPT_FUNCTION_MAXNAMELEN - strlen(t->u.name));
875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunmap_target(struct ipt_entry *e, struct ipt_entry_target *old)
880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t = ipt_get_target(e);
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Save old target (except data, which we don't change, except for
884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   standard case, where we don't care). */
885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*t = *old;
886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_insert_entry(const ipt_chainlabel chain,
891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_entry *e,
892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  unsigned int rulenum,
893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int chainoff, chainindex, offset;
896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_insert_entry;
901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&chainoff, chain, *handle)) {
902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, chainoff));
907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (index2entry(*handle, chainindex + rulenum)
909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    > get_entry(*handle, get_chain_end(*handle, chainoff))) {
910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	offset = index2offset(*handle, chainindex + rulenum);
914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Mapping target actually alters entry, but that's
916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           transparent to the caller. */
917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!map_target(*handle, (struct ipt_entry *)e, offset, &old))
918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, offset,
921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chainindex + rulenum, rulenum == 0, handle);
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unmap_target((struct ipt_entry *)e, &old);
923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */
928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_replace_entry(const ipt_chainlabel chain,
930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   const struct ipt_entry *e,
931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   unsigned int rulenum,
932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   iptc_handle_t *handle)
933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int chainoff, chainindex, offset;
935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_replace_entry;
940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&chainoff, chain, *handle)) {
942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	chainindex = entry2index(*handle, get_entry(*handle, chainoff));
947e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (index2entry(*handle, chainindex + rulenum)
949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    >= get_entry(*handle, get_chain_end(*handle, chainoff))) {
950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	offset = index2offset(*handle, chainindex + rulenum);
955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace = delete and insert. */
956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  offset, chainindex + rulenum, handle))
958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!map_target(*handle, (struct ipt_entry *)e, offset, &old))
961e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, offset,
965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chainindex + rulenum, 1, handle);
966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unmap_target((struct ipt_entry *)e, &old);
967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Append entry `fw' to chain `chain'.  Equivalent to insert with
972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   rulenum = length of chain. */
973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
974e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_append_entry(const ipt_chainlabel chain,
975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_entry *e,
976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int startoff, endoff;
979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
982e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_append_entry;
984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&startoff, chain, *handle)) {
985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
986e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
989e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	endoff = get_chain_end(*handle, startoff);
990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!map_target(*handle, (struct ipt_entry *)e, endoff, &old))
991e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
993e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(1, e->next_offset, e, endoff,
994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   entry2index(*handle, get_entry(*handle, endoff)),
995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   0, handle);
996e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unmap_target((struct ipt_entry *)e, &old);
997e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
998e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1000e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1002e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermatch_different(const struct ipt_entry_match *a,
1003e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *a_elems,
1004e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *b_elems)
1005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const struct ipt_entry_match *b;
1007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Offset of b is the same as a. */
100990e712a00913fe2a2f885142439c392392dc08a8Rusty Russell	b = (void *)b_elems + ((char *)a-a_elems);
1010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (a->match_size != b->match_size)
1012e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1013e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1014e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(a->u.name, b->u.name) != 0)
1015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
101790e712a00913fe2a2f885142439c392392dc08a8Rusty Russell	/* FIXME: This is really, really gross --RR */
101890e712a00913fe2a2f885142439c392392dc08a8Rusty Russell        if (strcmp(a->u.name,"limit") == 0) {
101990e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		/* Special case, the kernel writes in this data, so we
102090e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		 *  need to make sure that we only check the parts
102190e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		 *  that are user specified */
102290e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		if (((struct ipt_rateinfo *)a->data)->avg
102390e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		    != ((struct ipt_rateinfo *)b->data)->avg
102490e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		    || ((struct ipt_rateinfo *)a->data)->burst
102590e712a00913fe2a2f885142439c392392dc08a8Rusty Russell		    != ((struct ipt_rateinfo *)b->data)->burst)
102690e712a00913fe2a2f885142439c392392dc08a8Rusty Russell			return 1;
102790e712a00913fe2a2f885142439c392392dc08a8Rusty Russell        } else if (memcmp(a->data, b->data, a->match_size - sizeof(*a)) != 0)
1028e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1030e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheris_same(const struct ipt_entry *a, const struct ipt_entry *b)
1035e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *ta, *tb;
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (a->ip.src.s_addr != b->ip.src.s_addr
1040e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.dst.s_addr != b->ip.dst.s_addr
1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.smsk.s_addr != b->ip.smsk.s_addr
1042e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.smsk.s_addr != b->ip.smsk.s_addr
1043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.proto != b->ip.proto
1044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.flags != b->ip.flags
1045e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->ip.invflags != b->ip.invflags)
1046e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1047e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < IFNAMSIZ; i++) {
1049e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i])
1050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1051e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((a->ip.iniface[i] & a->ip.iniface_mask[i])
1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    != (b->ip.iniface[i] & b->ip.iniface_mask[i]))
1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i])
1055e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((a->ip.outiface[i] & a->ip.outiface_mask[i])
1057e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    != (b->ip.outiface[i] & b->ip.outiface_mask[i]))
1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1061e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (a->nfcache != b->nfcache
1062e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->target_offset != b->target_offset
1063e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || a->next_offset != b->next_offset)
1064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems))
1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1069e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ta = ipt_get_target((struct ipt_entry *)a);
1070e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	tb = ipt_get_target((struct ipt_entry *)b);
1071e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (ta->target_size != tb->target_size)
1072e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1073e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(ta->u.name, tb->u.name) != 0)
1074e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
107590e712a00913fe2a2f885142439c392392dc08a8Rusty Russell
107690e712a00913fe2a2f885142439c392392dc08a8Rusty Russell        /* FIXME: If kernel modifies these, then we never match --RR */
107790e712a00913fe2a2f885142439c392392dc08a8Rusty Russell
107890e712a00913fe2a2f885142439c392392dc08a8Rusty Russell        if (memcmp(ta->data, tb->data, ta->target_size - sizeof(*ta)) != 0)
107990e712a00913fe2a2f885142439c392392dc08a8Rusty Russell            return 0;
108090e712a00913fe2a2f885142439c392392dc08a8Rusty Russell
108190e712a00913fe2a2f885142439c392392dc08a8Rusty Russell   	return 1;
1082e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1083e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1084e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the first rule in `chain' which matches `fw'. */
1085e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_entry(const ipt_chainlabel chain,
1087e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_entry *origfw,
1088e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
1089e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int offset, lastoff;
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e, *fw;
1092e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1093e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1094e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_entry;
1095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&offset, chain, *handle)) {
1096e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1097e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1098e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fw = malloc(origfw->next_offset);
1101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (fw == NULL) {
1102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	lastoff = get_chain_end(*handle, offset);
1106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (; offset < lastoff; offset += e->next_offset) {
1108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry_target discard;
1109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memcpy(fw, origfw, origfw->next_offset);
1111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* FIXME: handle this in is_same --RR */
1113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!map_target(*handle, fw, offset, &discard)) {
1114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			free(fw);
1115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(*handle, offset);
1118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
1120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("Deleting:\n");
1121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		dump_entry(newe);
1122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (is_same(e, fw)) {
1124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			int ret;
1125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			ret = delete_rules(1, e->next_offset,
1126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   offset, entry2index(*handle, e),
1127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   handle);
1128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			free(fw);
1129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			CHECK(*handle);
1130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return ret;
1131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(fw);
1135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
11377e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */
1140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_num_entry(const ipt_chainlabel chain,
1142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      unsigned int rulenum,
1143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      iptc_handle_t *handle)
1144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int chainstart;
1146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int index;
1147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
1149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_num_entry;
1152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&chainstart, chain, *handle)) {
1153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	index = entry2index(*handle, get_entry(*handle, chainstart))
1158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ rulenum;
1159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (index
1161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    >= entry2index(*handle,
1162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  get_entry(*handle,
1163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    get_chain_end(*handle, chainstart)))) {
1164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = E2BIG;
1165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = index2entry(*handle, index);
1169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (e == NULL) {
1170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
1175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   index, handle);
1176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   NULL and sets errno. */
1182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
1183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_check_packet(const ipt_chainlabel chain,
1184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      struct ipt_entry *entry,
1185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			      iptc_handle_t *handle)
1186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOSYS;
1188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
1189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */
1192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
1194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int startoff, endoff, startindex, endindex;
1196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_flush_entries;
1200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&startoff, chain, *handle)) {
1201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	endoff = get_chain_end(*handle, startoff);
1205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	startindex = entry2index(*handle, get_entry(*handle, startoff));
1206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	endindex = entry2index(*handle, get_entry(*handle, endoff));
1207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(endindex - startindex,
1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   endoff - startoff, startoff, startindex,
1210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   handle);
1211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */
1216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, end;
12207e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&i, chain, *handle)) {
1223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	end = get_chain_end(*handle, i);
1227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	i = entry2index(*handle, get_entry(*handle, i));
1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	end = entry2index(*handle, get_entry(*handle, end));
1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (; i <= end; i++) {
1232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1235175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */
1242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional
1243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */
1244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
1246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int pos;
1248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct {
1250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry head;
1251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_error_target name;
1252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry ret;
1253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_standard_target target;
1254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} newc;
1255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_create_chain;
1258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           QUEUE, RETURN. */
1261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (find_label(&pos, chain, *handle)
1262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_DROP) == 0
1263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_ACCEPT) == 0
1264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_QUEUE) == 0
1265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_RETURN) == 0) {
1266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(chain)+1 > sizeof(ipt_chainlabel)) {
1271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(&newc, 0, sizeof(newc));
1276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.head.target_offset = sizeof(struct ipt_entry);
1277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.head.next_offset
1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= sizeof(struct ipt_entry) + sizeof(struct ipt_error_target);
1279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.name.t.u.name, IPT_ERROR_TARGET);
1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.name.t.target_size = sizeof(struct ipt_error_target);
1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.name.error, chain);
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.ret.target_offset = sizeof(struct ipt_entry);
1284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.ret.next_offset
1285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= sizeof(struct ipt_entry)+sizeof(struct ipt_standard_target);
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.target.target.u.name, IPT_STANDARD_TARGET);
1287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.target.target.target_size = sizeof(struct ipt_standard_target);
1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.target.verdict = IPT_RETURN;
1289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Add just before terminal entry */
1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(2, sizeof(newc), &newc.head,
1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   index2offset(*handle, (*handle)->new_number - 1),
1293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   (*handle)->new_number - 1,
1294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   0, handle);
1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercount_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref)
1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(ipt_get_target(e)->u.name, IPT_STANDARD_TARGET) == 0) {
1305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t = (struct ipt_standard_target *)ipt_get_target(e);
1306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict == offset)
1308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*ref)++;
1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */
1315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_references(unsigned int *ref, const ipt_chainlabel chain,
1317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    iptc_handle_t *handle)
1318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int offset;
1320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&offset, chain, *handle)) {
1323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*ref = 0;
1328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE((*handle)->entries.entries,
1329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  (*handle)->entries.size,
1330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  count_ref, offset, ref);
1331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
1337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int chainoff, labelidx, labeloff;
1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int references;
1340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret;
1342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!iptc_get_references(&references, chain, handle))
1345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
13467e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_chain;
1348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (iptc_builtin(chain, *handle)) {
1350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1354e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (references > 0) {
1355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EMLINK;
1356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&chainoff, chain, *handle)) {
1360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, chainoff);
1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (get_chain_end(*handle, chainoff) != chainoff) {
1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOTEMPTY;
1367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Need label index: preceeds chain start */
1371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labelidx = entry2index(*handle, e) - 1;
1372e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labeloff = index2offset(*handle, labelidx);
1373e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = delete_rules(2,
1375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   get_entry(*handle, labeloff)->next_offset
1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   + e->next_offset,
1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   labeloff, labelidx, handle);
1378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */
1383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint iptc_rename_chain(const ipt_chainlabel oldname,
1384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      const ipt_chainlabel newname,
1385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      iptc_handle_t *handle)
1386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int chainoff, labeloff, labelidx;
1388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_error_target *t;
1389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_rename_chain;
1392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT
1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           RETURN. */
1395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (find_label(&chainoff, newname, *handle)
1396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_DROP) == 0
1397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_ACCEPT) == 0
1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_RETURN) == 0) {
1399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!find_label(&chainoff, oldname, *handle)
1404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || iptc_builtin(oldname, *handle)) {
1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
1406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(newname)+1 > sizeof(ipt_chainlabel)) {
1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1413e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Need label index: preceeds chain start */
1415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labelidx = entry2index(*handle, get_entry(*handle, chainoff)) - 1;
1416e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	labeloff = index2offset(*handle, labelidx);
1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1418e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_error_target *)
1419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ipt_get_target(get_entry(*handle, labeloff));
1420e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->error, 0, sizeof(t->error));
1422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(t->error, newname);
1423175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1428e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1429e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */
1430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1431e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_set_policy(const ipt_chainlabel chain,
1432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const ipt_chainlabel policy,
1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		iptc_handle_t *handle)
1434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int hook;
1436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int policyoff;
1437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
1438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1440e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Figure out which chain. */
1442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	hook = iptc_builtin(chain, *handle);
1443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (hook == 0) {
1444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1446e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		hook--;
1448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (policyoff != (*handle)->info.underflow[hook]) {
1451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       chain, policyoff, (*handle)->info.underflow[hook]);
1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1454e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e = get_entry(*handle, policyoff);
1457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)ipt_get_target(e);
1458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(policy, IPTC_LABEL_ACCEPT) == 0)
1460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_ACCEPT - 1;
1461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (strcmp(policy, IPTC_LABEL_DROP) == 0)
1462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t->verdict = -NF_DROP - 1;
1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1467e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*handle)->counter_map[entry2index(*handle, e)]
1468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
1469175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	set_changed(*handle);
1470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get:
1476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c: In function `iptc_commit':
1477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   libiptc.c:833: fixed or forbidden register was spilled.
1478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   This may be due to a compiler bug or to impossible asm
1479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   statements or clauses.
1480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
1481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
1482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchersubtract_counters(struct ipt_counters *answer,
1483e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_counters *a,
1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  const struct ipt_counters *b)
1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->pcnt = a->pcnt - b->pcnt;
1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	answer->bcnt = a->bcnt - b->bcnt;
1488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1491e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_commit(iptc_handle_t *handle)
1492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Replace, then map back the counters. */
1494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_replace *repl;
1495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_counters_info *newcounters;
1496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size_t counterlen
1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= sizeof(struct ipt_counters_info)
1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ sizeof(struct ipt_counters) * (*handle)->new_number;
1500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
1503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dump_entries(*handle);
1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't commit if nothing changed. */
1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(*handle)->changed)
1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1511e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl) {
1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the old counters we will get from kernel */
1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->counters = malloc(sizeof(struct ipt_counters)
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				* (*handle)->info.num_entries);
1519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!repl->counters) {
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
15247e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* These are the counters we're going to put back, later. */
1526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters = malloc(counterlen);
1527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!newcounters) {
1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOMEM;
1531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(repl->name, (*handle)->info.name);
1535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_entries = (*handle)->new_number;
1536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->size = (*handle)->entries.size;
1537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->hook_entry));
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->underflow, (*handle)->info.underflow,
1540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       sizeof(repl->underflow));
1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->num_counters = (*handle)->info.num_entries;
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	repl->valid_hooks = (*handle)->info.valid_hooks;
1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(repl->entries, (*handle)->entries.entries,
1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       (*handle)->entries.size);
1545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_REPLACE, repl,
1547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       sizeof(*repl) + (*handle)->entries.size) < 0) {
1548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Put counters back. */
1555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
1556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters->num_counters = (*handle)->new_number;
1557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < (*handle)->new_number; i++) {
1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int mappos = (*handle)->counter_map[i].mappos;
1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		switch ((*handle)->counter_map[i].maptype) {
1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NOMAP:
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i]
1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				= ((struct ipt_counters){ 0, 0 });
1563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NORMAL_MAP:
1566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: X + Y + Z.
1570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in X + Y
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in replacement read.
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i] = repl->counters[mappos];
1574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_ZEROED:
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Atomic read on replacement: X + Y.
1579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Currently in kernel: Z.
1580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: Y + Z.
1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in Y.
1582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in (replacement read - original read).
1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			subtract_counters(&newcounters->counters[i],
1585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &repl->counters[mappos],
1586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &index2entry(*handle, i)->counters);
1587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
15917e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell	if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_ADD_COUNTERS,
1592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       newcounters, counterlen) < 0) {
1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl);
1595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(newcounters);
1596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl->counters);
1600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(repl);
1601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(newcounters);
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished:
1604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	free(*handle);
1605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = NULL;
1606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
1610e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_raw_socket()
1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
1614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *
1618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_strerror(int err)
1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct table_struct {
1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		void *fn;
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int err;
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		const char *message;
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} table [] =
1626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  { { NULL, 0, "Incompatible with this kernel" },
1627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
1628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOSYS, "Will be implemented real soon.  I promise." },
1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOMEM, "Memory allocation problem" },
1630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_init, EPERM, "Permission denied (you must be root)" },
1631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_init, EINVAL, "Module is wrong version" },
1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_chain, ENOTEMPTY, "Chain is not empty" },
1633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_chain, EINVAL, "Can't delete built-in chain" },
1634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_chain, EMLINK,
1635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "Can't delete chain with references left" },
1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_create_chain, EEXIST, "Chain already exists" },
1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_insert_entry, E2BIG, "Index of insertion too big" },
1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_replace_entry, E2BIG, "Index of replacement too big" },
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_num_entry, E2BIG, "Index of deletion too big" },
1640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_insert_entry, ELOOP, "Loop found in table" },
1641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_insert_entry, EINVAL, "Target problem" },
1642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* EINVAL for CHECK probably means bad interface. */
1643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_check_packet, EINVAL,
1644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "bad arguments (does that interface exist?)" },
1645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    /* ENOENT for DELETE probably means no matching rule */
1646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { iptc_delete_entry, ENOENT,
1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      "bad rule (does a matching rule exist in that chain?)" },
1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    { NULL, ENOENT, "No extended target/match by that name" }
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	  };
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((!table[i].fn || table[i].fn == iptc_fn)
1653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && table[i].err == err)
1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return table[i].message;
1655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return strerror(err);
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/***************************** DEBUGGING ********************************/
1661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunconditional(const struct ipt_ip *ip)
1663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(*ip)/sizeof(u_int32_t); i++)
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (((u_int32_t *)ip)[i])
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return 0;
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 1;
1671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_match(const struct ipt_entry_match *m, unsigned int *off)
1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(m->match_size >= sizeof(struct ipt_entry_match));
1677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*off) += m->match_size;
1679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int
1683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off,
1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    unsigned int user_offset, int *was_return,
1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    iptc_handle_t h)
1686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int toff;
1688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(e->target_offset >= sizeof(struct ipt_entry));
1691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(e->next_offset >= e->target_offset
1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       + sizeof(struct ipt_entry_target));
1693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	toff = sizeof(struct ipt_entry);
1694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_MATCH_ITERATE(e, check_match, &toff);
1695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(toff == e->target_offset);
1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)
1699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ipt_get_target((struct ipt_entry *)e);
1700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(t->target.target_size == e->next_offset - e->target_offset);
1701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(!iptc_is_chain(t->target.u.name, h));
1702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0) {
1704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->target.target_size
1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == IPT_ALIGN(sizeof(struct ipt_standard_target)));
1706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->verdict == -NF_DROP-1
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict == -NF_ACCEPT-1
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict == IPT_RETURN
1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict < (int)h->entries.size);
1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict >= 0) {
1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			struct ipt_entry *te = get_entry(h, t->verdict);
1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			int idx;
1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			idx = entry2index(h, te);
1717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(strcmp(ipt_get_target(te)->u.name,
1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      IPT_ERROR_TARGET)
1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       != 0);
1720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(te != e);
1721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Prior node must be error node, or this node. */
1723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(t->verdict == entry2offset(h, e)+e->next_offset
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       || strcmp(ipt_get_target(index2entry(h, idx-1))
1725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					 ->u.name, IPT_ERROR_TARGET)
1726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       == 0);
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (t->verdict == IPT_RETURN
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && unconditional(&e->ip)
1731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && e->target_offset == sizeof(*e))
1732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			*was_return = 1;
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			*was_return = 0;
1735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else if (strcmp(t->target.u.name, IPT_ERROR_TARGET) == 0) {
1736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->target.target_size
1737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == IPT_ALIGN(sizeof(struct ipt_error_target)));
1738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* If this is in user area, previous must have been return */
1740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (*off > user_offset)
1741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(*was_return);
1742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*was_return = 0;
1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else *was_return = 0;
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*off == user_offset)
1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(strcmp(t->target.u.name, IPT_ERROR_TARGET) == 0);
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*off) += e->next_offset;
1751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*i)++;
1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Do every conceivable sanity check on the handle */
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdo_check(iptc_handle_t h, unsigned int line)
1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, n;
1760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int user_offset; /* Offset of first user chain */
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int was_return;
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(h->changed == 0 || h->changed == 1);
1764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(h->info.name, "filter") == 0) {
1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.valid_hooks
1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_LOCAL_IN
1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_FORWARD
1768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Hooks should be first three */
1771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0);
1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_FORWARD] == n);
1776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, n);
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else if (strcmp(h->info.name, "nat") == 0) {
1783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.valid_hooks
1784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_PRE_ROUTING
1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_POST_ROUTING
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
1793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, n);
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else if (strcmp(h->info.name, "mangle") == 0) {
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.valid_hooks
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_PRE_ROUTING
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Hooks should be first three */
1805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		abort();
1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* User chain == end of last builtin + policy entry */
1816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	user_offset = get_chain_end(h, user_offset);
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	user_offset += get_entry(h, user_offset)->next_offset;
1818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Overflows should be end of entry chains, and unconditional
1820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           policy nodes. */
1821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry *e;
1823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_standard_target *t;
1824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!(h->info.valid_hooks & (1 << i)))
1826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			continue;
1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.underflow[i]
1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == get_chain_end(h, h->info.hook_entry[i]));
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(h, get_chain_end(h, h->info.hook_entry[i]));
1831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(unconditional(&e->ip));
1832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(e->target_offset == sizeof(*e));
1833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(e->next_offset == sizeof(*e) + sizeof(*t));
1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		t = (struct ipt_standard_target *)ipt_get_target(e);
1835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0);
1837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
1838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Hooks and underflows must be valid entries */
1840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		entry2index(h, get_entry(h, h->info.hook_entry[i]));
1841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		entry2index(h, get_entry(h, h->info.underflow[i]));
1842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(h->info.size
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       >= h->info.num_entries * (sizeof(struct ipt_entry)
1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					 +sizeof(struct ipt_standard_target)));
1847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(h->entries.size
1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       >= (h->new_number
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   * (sizeof(struct ipt_entry)
1851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      + sizeof(struct ipt_standard_target))));
1852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(strcmp(h->info.name, h->entries.name) == 0);
1853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	i = 0; n = 0;
1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	was_return = 0;
1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Check all the entries. */
1857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
1858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  check_entry, &i, &n, user_offset, &was_return, h);
1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(i == h->new_number);
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(n == h->entries.size);
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Final entry must be error node */
1864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1))->u.name,
1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      IPT_ERROR_TARGET) == 0);
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1867