libiptc.c revision c8264991454b5e77279830736f80ea3153b6f814
10f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson/* 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
113ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte/* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
123ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte   COPYING for details). */
13aae69bed019826ddec93f761514652a93d871e49Harald Welte
143ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte#include <assert.h>
15fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte#include <string.h>
163ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte#include <errno.h>
17fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte#include <stdlib.h>
180113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte#include <stdio.h>
19fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte#include <limits.h>
20fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Welte
21aae69bed019826ddec93f761514652a93d871e49Harald Welte#if !defined(__GLIBC__) || (__GLIBC__ < 2)
22aae69bed019826ddec93f761514652a93d871e49Harald Weltetypedef unsigned int socklen_t;
23aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
24aae69bed019826ddec93f761514652a93d871e49Harald Welte
25aae69bed019826ddec93f761514652a93d871e49Harald Welte#include <libiptc/libiptc.h>
263ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte#include <linux/netfilter_ipv4/ipt_limit.h>
2715920d160760535e51a57b3834eba45257cfa6d8Harald Welte
2815920d160760535e51a57b3834eba45257cfa6d8Harald Welte#define IP_VERSION	4
298b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt#define IP_OFFSET	0x1FFF
307cd002826d0f329620cb738bc4dc4760ef5e084aStephane Ouellette
31aae69bed019826ddec93f761514652a93d871e49Harald Welte#ifndef IPT_LIB_DIR
32aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IPT_LIB_DIR "/usr/local/lib/iptables"
33aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
34aae69bed019826ddec93f761514652a93d871e49Harald Welte
35aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int sockfd = -1;
36aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void *iptc_fn = NULL;
37aae69bed019826ddec93f761514652a93d871e49Harald Welte
38aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic const char *hooknames[]
39aae69bed019826ddec93f761514652a93d871e49Harald Welte= { [NF_IP_PRE_ROUTING]  "PREROUTING",
40aae69bed019826ddec93f761514652a93d871e49Harald Welte    [NF_IP_LOCAL_IN]     "INPUT",
41aae69bed019826ddec93f761514652a93d871e49Harald Welte    [NF_IP_FORWARD]      "FORWARD",
42aae69bed019826ddec93f761514652a93d871e49Harald Welte    [NF_IP_LOCAL_OUT]    "OUTPUT",
43aae69bed019826ddec93f761514652a93d871e49Harald Welte    [NF_IP_POST_ROUTING] "POSTROUTING"
4401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer};
4501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
4601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerstruct counter_map
4701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
4801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	enum {
4901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		COUNTER_MAP_NOMAP,
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_NORMAL_MAP,
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		COUNTER_MAP_ZEROED
520b63936140032deac44072951451bdf47b54296aPatrick McHardy	} maptype;
530b63936140032deac44072951451bdf47b54296aPatrick McHardy	unsigned int mappos;
540b63936140032deac44072951451bdf47b54296aPatrick McHardy};
550b63936140032deac44072951451bdf47b54296aPatrick McHardy
560b63936140032deac44072951451bdf47b54296aPatrick McHardy/* Convenience structures */
570b63936140032deac44072951451bdf47b54296aPatrick McHardystruct ipt_error_target
5810758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell{
590b63936140032deac44072951451bdf47b54296aPatrick McHardy	struct ipt_entry_target t;
6010758b743d6aa076ebe2c3e8f855e73826841e71Rusty Russell	char error[IPT_TABLE_MAXNAMELEN];
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
63aae69bed019826ddec93f761514652a93d871e49Harald Weltestruct iptc_handle
64aae69bed019826ddec93f761514652a93d871e49Harald Welte{
65aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Have changes been made? */
66aae69bed019826ddec93f761514652a93d871e49Harald Welte	int changed;
67aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Size in here reflects original state. */
68aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_getinfo info;
69aae69bed019826ddec93f761514652a93d871e49Harald Welte
70aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct counter_map *counter_map;
71aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Array of hook names */
72aae69bed019826ddec93f761514652a93d871e49Harald Welte	const char **hooknames;
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* This was taking us ~50 seconds to list 300 rules. */
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Cached: last find_label result */
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char cache_label_name[IPT_TABLE_MAXNAMELEN];
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int cache_label_return;
781cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte	unsigned int cache_label_offset;
791cef74d943055668b5e356eebea877fdaa1ce3e0Harald Welte
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Number in here reflects current state. */
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int new_number;
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_get_entries entries;
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
84aae69bed019826ddec93f761514652a93d871e49Harald Welte
85aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic void
86aae69bed019826ddec93f761514652a93d871e49Harald Welteset_changed(iptc_handle_t h)
87aae69bed019826ddec93f761514652a93d871e49Harald Welte{
88aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->cache_label_name[0] = '\0';
89aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->changed = 1;
90aae69bed019826ddec93f761514652a93d871e49Harald Welte}
91aae69bed019826ddec93f761514652a93d871e49Harald Welte
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void do_check(iptc_handle_t h, unsigned int line);
93aae69bed019826ddec93f761514652a93d871e49Harald Welte#define CHECK(h) do_check((h), __LINE__)
94aae69bed019826ddec93f761514652a93d871e49Harald Welte
95aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
96aae69bed019826ddec93f761514652a93d871e49Harald Welteget_number(const struct ipt_entry *i,
97aae69bed019826ddec93f761514652a93d871e49Harald Welte	   const struct ipt_entry *seek,
98aae69bed019826ddec93f761514652a93d871e49Harald Welte	   unsigned int *pos)
99aae69bed019826ddec93f761514652a93d871e49Harald Welte{
100aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (i == seek)
101aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
102aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*pos)++;
103aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
104aae69bed019826ddec93f761514652a93d871e49Harald Welte}
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int
107aae69bed019826ddec93f761514652a93d871e49Harald Welteentry2index(const iptc_handle_t h, const struct ipt_entry *seek)
10830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
109aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int pos = 0;
11079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
111aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
112aae69bed019826ddec93f761514652a93d871e49Harald Welte			      get_number, seek, &pos) == 0) {
113aae69bed019826ddec93f761514652a93d871e49Harald Welte		fprintf(stderr, "ERROR: offset %i not an entry!\n",
114aae69bed019826ddec93f761514652a93d871e49Harald Welte			(unsigned char *)seek - h->entries.entries);
115aae69bed019826ddec93f761514652a93d871e49Harald Welte		abort();
116aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
117aae69bed019826ddec93f761514652a93d871e49Harald Welte	return pos;
118aae69bed019826ddec93f761514652a93d871e49Harald Welte}
119aae69bed019826ddec93f761514652a93d871e49Harald Welte
120aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
121aae69bed019826ddec93f761514652a93d871e49Harald Welteget_entry_n(struct ipt_entry *i,
122aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int number,
123aae69bed019826ddec93f761514652a93d871e49Harald Welte	    unsigned int *pos,
124aae69bed019826ddec93f761514652a93d871e49Harald Welte	    struct ipt_entry **pe)
12530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
12630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (*pos == number) {
12779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		*pe = i;
128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
129175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt	}
130aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*pos)++;
131aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
132aae69bed019826ddec93f761514652a93d871e49Harald Welte}
133aae69bed019826ddec93f761514652a93d871e49Harald Welte
134aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic struct ipt_entry *
135aae69bed019826ddec93f761514652a93d871e49Harald Welteindex2entry(iptc_handle_t h, unsigned int index)
136aae69bed019826ddec93f761514652a93d871e49Harald Welte{
13748bde40e73b45ad134d32cde88b779fe509faf64Jesper Dangaard Brouer	unsigned int pos = 0;
13848bde40e73b45ad134d32cde88b779fe509faf64Jesper Dangaard Brouer	struct ipt_entry *ret = NULL;
13901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
14001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
14101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			  get_entry_n, index, &pos, &ret);
1424bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
1434bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	return ret;
1444bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer}
1454bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
1464bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerstatic inline struct ipt_entry *
14779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellget_entry(iptc_handle_t h, unsigned int offset)
148aae69bed019826ddec93f761514652a93d871e49Harald Welte{
149aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (struct ipt_entry *)(h->entries.entries + offset);
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1514bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
1524bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerstatic inline unsigned long
1534bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerentry2offset(const iptc_handle_t h, const struct ipt_entry *e)
1544bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer{
1554bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	return (unsigned char *)e - h->entries.entries;
156aae69bed019826ddec93f761514652a93d871e49Harald Welte}
157aae69bed019826ddec93f761514652a93d871e49Harald Welte
158aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic unsigned long
159aae69bed019826ddec93f761514652a93d871e49Harald Welteindex2offset(iptc_handle_t h, unsigned int index)
160aae69bed019826ddec93f761514652a93d871e49Harald Welte{
161aae69bed019826ddec93f761514652a93d871e49Harald Welte	return entry2offset(h, index2entry(h, index));
162aae69bed019826ddec93f761514652a93d871e49Harald Welte}
163aae69bed019826ddec93f761514652a93d871e49Harald Welte
164aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic const char *
165aae69bed019826ddec93f761514652a93d871e49Harald Welteget_errorlabel(iptc_handle_t h, unsigned int offset)
166aae69bed019826ddec93f761514652a93d871e49Harald Welte{
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
168aae69bed019826ddec93f761514652a93d871e49Harald Welte
169aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = get_entry(h, offset);
17030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) != 0) {
171aae69bed019826ddec93f761514652a93d871e49Harald Welte		fprintf(stderr, "ERROR: offset %u not an error node!\n",
172aae69bed019826ddec93f761514652a93d871e49Harald Welte			offset);
173aae69bed019826ddec93f761514652a93d871e49Harald Welte		abort();
174aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
175aae69bed019826ddec93f761514652a93d871e49Harald Welte
176aae69bed019826ddec93f761514652a93d871e49Harald Welte	return (const char *)ipt_get_target(e)->data;
177aae69bed019826ddec93f761514652a93d871e49Harald Welte}
17830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
179aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Allocate handle of given size */
180aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic iptc_handle_t
181175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellalloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
182aae69bed019826ddec93f761514652a93d871e49Harald Welte{
183aae69bed019826ddec93f761514652a93d871e49Harald Welte	size_t len;
184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t h;
185aae69bed019826ddec93f761514652a93d871e49Harald Welte
186910939897ea0cb9be2729a98c60a92e807aad5c3Jesper Dangaard Brouer	len = sizeof(struct iptc_handle)
187fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt		+ size
188175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell		+ num_rules * sizeof(struct counter_map);
189175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell
190175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell	if ((h = malloc(len)) == NULL) {
191175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell		errno = ENOMEM;
192380ba5f3074a16fbaa8869d9594962d58b5f8608Harald Welte		return NULL;
193fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	}
194849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell
19530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->changed = 0;
19630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->cache_label_name[0] = '\0';
19730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	h->counter_map = (void *)h
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		+ sizeof(struct iptc_handle)
199aae69bed019826ddec93f761514652a93d871e49Harald Welte		+ size;
200aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(h->info.name, tablename);
201aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(h->entries.name, tablename);
202aae69bed019826ddec93f761514652a93d871e49Harald Welte
203aae69bed019826ddec93f761514652a93d871e49Harald Welte	return h;
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
205aae69bed019826ddec93f761514652a93d871e49Harald Welte
20679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russelliptc_handle_t
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_init(const char *tablename)
208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_handle_t h;
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_getinfo info;
211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int tmp;
213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	socklen_t s;
214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
215aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = iptc_init;
216aae69bed019826ddec93f761514652a93d871e49Harald Welte
217aae69bed019826ddec93f761514652a93d871e49Harald Welte	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
218aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (sockfd < 0)
219aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
220aae69bed019826ddec93f761514652a93d871e49Harald Welte
221aae69bed019826ddec93f761514652a93d871e49Harald Welte	s = sizeof(info);
222aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strlen(tablename) >= IPT_TABLE_MAXNAMELEN) {
223aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EINVAL;
224aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
225aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
226aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(info.name, tablename);
227aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_INFO, &info, &s) < 0)
228aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
229aae69bed019826ddec93f761514652a93d871e49Harald Welte
230fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	if ((h = alloc_handle(info.name, info.size, info.num_entries))
231aae69bed019826ddec93f761514652a93d871e49Harald Welte	    == NULL)
232aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
233aae69bed019826ddec93f761514652a93d871e49Harald Welte
234aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Too hard --RR */
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
236fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dynlib = dlopen(pathname, RTLD_NOW);
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!dynlib) {
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
240aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
241aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
242a28d495285ad7dd9f286d63958cf20d74eec6bcbMartin Josefsson	h->hooknames = dlsym(dynlib, "hooknames");
243aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!h->hooknames) {
244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = ENOENT;
245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return NULL;
246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#else
248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	h->hooknames = hooknames;
249aae69bed019826ddec93f761514652a93d871e49Harald Welte#endif
250fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Initialize current state */
252aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->info = info;
253aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->new_number = h->info.num_entries;
254aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < h->info.num_entries; i++)
255aae69bed019826ddec93f761514652a93d871e49Harald Welte		h->counter_map[i]
256aae69bed019826ddec93f761514652a93d871e49Harald Welte			= ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
257fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
258aae69bed019826ddec93f761514652a93d871e49Harald Welte	h->entries.size = h->info.size;
259aae69bed019826ddec93f761514652a93d871e49Harald Welte
260aae69bed019826ddec93f761514652a93d871e49Harald Welte	tmp = sizeof(struct ipt_get_entries) + h->info.size;
261aae69bed019826ddec93f761514652a93d871e49Harald Welte
262aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_ENTRIES, &h->entries,
263fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt		       &tmp) < 0) {
264aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(h);
265aae69bed019826ddec93f761514652a93d871e49Harald Welte		return NULL;
266aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
267aae69bed019826ddec93f761514652a93d871e49Harald Welte
268aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(h);
269aae69bed019826ddec93f761514652a93d871e49Harald Welte	return h;
270fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt}
271aae69bed019826ddec93f761514652a93d871e49Harald Welte
272aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IP_PARTS_NATIVE(n)			\
273aae69bed019826ddec93f761514652a93d871e49Harald Welte(unsigned int)((n)>>24)&0xFF,			\
274aae69bed019826ddec93f761514652a93d871e49Harald Welte(unsigned int)((n)>>16)&0xFF,			\
275aae69bed019826ddec93f761514652a93d871e49Harald Welte(unsigned int)((n)>>8)&0xFF,			\
276aae69bed019826ddec93f761514652a93d871e49Harald Welte(unsigned int)((n)&0xFF)
277aae69bed019826ddec93f761514652a93d871e49Harald Welte
278aae69bed019826ddec93f761514652a93d871e49Harald Welte#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
279aae69bed019826ddec93f761514652a93d871e49Harald Welte
280aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
281aae69bed019826ddec93f761514652a93d871e49Harald Welteprint_match(const struct ipt_entry_match *m)
282aae69bed019826ddec93f761514652a93d871e49Harald Welte{
283aae69bed019826ddec93f761514652a93d871e49Harald Welte	printf("Match name: `%s'\n", m->u.name);
28401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return 0;
28501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
28601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
28701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerint
28801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerdump_entry(struct ipt_entry *e, const iptc_handle_t handle)
28901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
29001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	size_t i;
29101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	struct ipt_entry_target *t;
29201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
29301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Entry %u (%lu):\n", entry2index(handle, e),
29401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       entry2offset(handle, e));
29501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
29601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr));
29701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n",
29801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr));
29901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Interface: `%s'/", e->ip.iniface);
30001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	for (i = 0; i < IFNAMSIZ; i++)
30101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		printf("%c", e->ip.iniface_mask[i] ? 'X' : '.');
30201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("to `%s'/", e->ip.outiface);
30301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	for (i = 0; i < IFNAMSIZ; i++)
30401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		printf("%c", e->ip.outiface_mask[i] ? 'X' : '.');
30501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("\nProtocol: %u\n", e->ip.proto);
30601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Flags: %02X\n", e->ip.flags);
30701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Invflags: %02X\n", e->ip.invflags);
30801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Counters: %llu packets, %llu bytes\n",
30901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       e->counters.pcnt, e->counters.bcnt);
31001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Cache: %08X ", e->nfcache);
31101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_ALTERED) printf("ALTERED ");
31201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN ");
31301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_SRC) printf("IP_SRC ");
31401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_DST) printf("IP_DST ");
31501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN ");
31601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT ");
31701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_TOS) printf("IP_TOS ");
31801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO ");
31901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS ");
32001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS ");
32101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT ");
32201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT ");
3234bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN ");
3244bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	printf("\n");
3254bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
3264bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	IPT_MATCH_ITERATE(e, print_match);
3274bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
32801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	t = ipt_get_target(e);
32901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Target name: `%s' [%u]\n", t->u.name, t->target_size);
3304bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	if (strcmp(t->u.name, IPT_STANDARD_TARGET) == 0) {
331fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt		int pos = *(int *)t->data;
3324bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		if (pos < 0)
33301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			printf("verdict=%s\n",
33401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			       pos == -NF_ACCEPT-1 ? "NF_ACCEPT"
33501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			       : pos == -NF_DROP-1 ? "NF_DROP"
33601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			       : pos == -NF_QUEUE-1 ? "NF_QUEUE"
33701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			       : pos == IPT_RETURN ? "RETURN"
33801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			       : "UNKNOWN");
33901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		else
34001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			printf("verdict=%u\n", pos);
34101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	} else if (strcmp(t->u.name, IPT_ERROR_TARGET) == 0)
34201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		printf("error=`%s'\n", t->data);
34301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
34401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("\n");
34501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return 0;
34601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
34701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
34801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouervoid
34901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerdump_entries(const iptc_handle_t handle)
3504bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer{
3514bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	CHECK(handle);
35201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
35301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("libiptc v%s.  %u entries, %u bytes.\n",
35401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       NETFILTER_VERSION,
35501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       handle->new_number, handle->entries.size);
35601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Table `%s'\n", handle->info.name);
35701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
35801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       handle->info.hook_entry[NF_IP_PRE_ROUTING],
35901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       handle->info.hook_entry[NF_IP_LOCAL_IN],
3604bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.hook_entry[NF_IP_FORWARD],
3614bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.hook_entry[NF_IP_LOCAL_OUT],
3624bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.hook_entry[NF_IP_POST_ROUTING]);
3634bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
3644bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.underflow[NF_IP_PRE_ROUTING],
3654bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.underflow[NF_IP_LOCAL_IN],
3664bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.underflow[NF_IP_FORWARD],
3674bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.underflow[NF_IP_LOCAL_OUT],
3684bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	       handle->info.underflow[NF_IP_POST_ROUTING]);
3694bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
3704bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size,
3714bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer			  dump_entry, handle);
3724bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer}
3734bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
3744bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerstatic inline int
3754bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerfind_user_label(struct ipt_entry *e, unsigned int *off, const char *name)
3764bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer{
3774bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	/* Increment first: they want offset of entry AFTER label */
3784bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	(*off) += e->next_offset;
3794bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
3804bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) == 0
3814bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	    && strcmp(ipt_get_target(e)->data, name) == 0)
3824bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		return 1;
38301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
384dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt	return 0;
38501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
38601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
38701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Returns offset of label. */
38801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerstatic int
38901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerfind_label(unsigned int *off,
39001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	   const char *name,
39101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	   const iptc_handle_t handle)
39201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
39301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int i;
39401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
39501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Cached? */
39601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (handle->cache_label_name[0]
39701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	    && strcmp(name, handle->cache_label_name) == 0) {
39801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		*off = handle->cache_label_offset;
39901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return handle->cache_label_return;
40001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
40101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
40201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Builtin chain name? */
40301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	i = iptc_builtin(name, handle);
40401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (i != 0) {
40501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		*off = handle->info.hook_entry[i-1];
40601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return 1;
40701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
40801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
4094bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	/* User chain name? */
4104bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	*off = 0;
4114bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	if (IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size,
4124bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer			      find_user_label, off, name) != 0) {
4134bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		/* last error node doesn't count */
4144bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		if (*off != handle->entries.size) {
4154bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer			strcpy(handle->cache_label_name, name);
4164bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer			handle->cache_label_offset = *off;
4174bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer			handle->cache_label_return = 1;
41801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return 1;
41901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		}
42001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
42101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
42201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	strcpy(handle->cache_label_name, name);
42301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	handle->cache_label_return = 0;
42401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return 0;
42501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
42601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
42701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Does this chain exist? */
42801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerint iptc_is_chain(const char *chain, const iptc_handle_t handle)
42901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
43001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int dummy;
4314bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
4324bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	/* avoid infinite recursion */
4334bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer#if 0
434fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	CHECK(handle);
4354bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer#endif
4364bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
4374bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	return find_label(&dummy, chain, handle);
4384bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer}
4394bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
4404bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer/* Returns the position of the final (ie. unconditional) element. */
4414bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerstatic unsigned int
4424bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouerget_chain_end(const iptc_handle_t handle, unsigned int start)
443fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt{
4444bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	unsigned int last_off, off;
4454bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	struct ipt_entry *e;
4464bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
4474bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	last_off = start;
4484bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	e = get_entry(handle, start);
4494bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
4504bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	/* Terminate when we meet a error label or a hook entry. */
4514bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	for (off = start + e->next_offset;
4524bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	     off < handle->entries.size;
4534bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	     last_off = off, off += e->next_offset) {
4544bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		struct ipt_entry_target *t;
4554bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		unsigned int i;
4564bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
4574bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		e = get_entry(handle, off);
4584bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
45901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* We hit an entry point. */
46001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		for (i = 0; i < NF_IP_NUMHOOKS; i++) {
46101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			if ((handle->info.valid_hooks & (1 << i))
46201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			    && off == handle->info.hook_entry[i])
463fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt				return last_off;
46401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		}
46501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
46601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* We hit a user chain label */
46701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		t = ipt_get_target(e);
46801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if (strcmp(t->u.name, IPT_ERROR_TARGET) == 0)
46901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return last_off;
47001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
47101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* SHOULD NEVER HAPPEN */
47201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
47301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		handle->entries.size, off);
47401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	abort();
47501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
47601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
47701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Iterator functions to run through the chains; prev = NULL means
47801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer   first chain.  Returns NULL at end. */
47901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerconst char *
48001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Broueriptc_next_chain(const char *prev, iptc_handle_t *handle)
48101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
48201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int pos;
48301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int i;
48401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	struct ipt_entry *e;
48501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
48601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	CHECK(*handle);
48701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (!prev)
48801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		pos = 0;
48901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	else {
49001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if (!find_label(&pos, prev, *handle)) {
491fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt			errno = ENOENT;
49201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return NULL;
49301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		}
49401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		pos = get_chain_end(*handle, pos);
49501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* Next entry. */
49601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		e = get_entry(*handle, pos);
49701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		pos += e->next_offset;
49801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
49901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	e = get_entry(*handle, pos);
50001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
50101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Return names of entry points if it is one. */
50201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
50301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if (((*handle)->info.valid_hooks & (1 << i))
50401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		    && pos == (*handle)->info.hook_entry[i])
50501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return (*handle)->hooknames[i];
50601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
50701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* If this is the last element, iteration finished */
50801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (pos + e->next_offset == (*handle)->entries.size)
50901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return NULL;
51001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
51101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) != 0) {
51201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* SHOULD NEVER HAPPEN */
51301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		fprintf(stderr, "ERROR: position %u/%u not an error label\n",
51401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			pos, (*handle)->entries.size);
51501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		abort();
516fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	}
51701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
51801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return (const char *)ipt_get_target(e)->data;
51901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
52001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
52101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* How many rules in this chain? */
52201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerunsigned int
52301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Broueriptc_num_rules(const char *chain, iptc_handle_t *handle)
524fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt{
52501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int off = 0;
52601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	struct ipt_entry *start, *end;
52701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
52801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	CHECK(*handle);
52901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (!find_label(&off, chain, *handle)) {
53001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		errno = ENOENT;
53101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return (unsigned int)-1;
53201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
53301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
53401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	start = get_entry(*handle, off);
53501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	end = get_entry(*handle, get_chain_end(*handle, off));
53601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
53701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return entry2index(*handle, end) - entry2index(*handle, start);
53801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
539fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
54001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Get n'th rule in this chain. */
54101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerconst struct ipt_entry *iptc_get_rule(const char *chain,
54201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer				      unsigned int n,
54301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer				      iptc_handle_t *handle)
54401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
54501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int pos = 0, chainindex;
54601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
54701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	CHECK(*handle);
54801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (!find_label(&pos, chain, *handle)) {
54901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		errno = ENOENT;
55001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return NULL;
55101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
55201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
55301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	chainindex = entry2index(*handle, get_entry(*handle, pos));
55401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
55501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return index2entry(*handle, chainindex + n);
55601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
55701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
55801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerstatic const char *target_name(iptc_handle_t handle, struct ipt_entry *e)
55901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
56001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	int spos;
56101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int labelidx;
56201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	struct ipt_entry *jumpto;
56301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
56401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (strcmp(ipt_get_target(e)->u.name, IPT_STANDARD_TARGET) != 0)
56501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return ipt_get_target(e)->u.name;
56601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
56701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Standard target: evaluate */
56801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	spos = *(int *)ipt_get_target(e)->data;
56901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (spos < 0) {
57001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if (spos == IPT_RETURN)
57101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return IPTC_LABEL_RETURN;
57201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		else if (spos == -NF_ACCEPT-1)
57301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return IPTC_LABEL_ACCEPT;
57401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		else if (spos == -NF_DROP-1)
57501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return IPTC_LABEL_DROP;
57601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		else if (spos == -NF_QUEUE-1)
57701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			return IPTC_LABEL_QUEUE;
57801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
57901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
58001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			entry2offset(handle, e), handle->entries.size,
581fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt			spos);
58201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		abort();
58301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
58401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
58501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	jumpto = get_entry(handle, spos);
58601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
58701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Fall through rule */
58801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (jumpto == (void *)e + e->next_offset)
58901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return "";
59001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
59101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Must point to head of a chain: ie. after error rule */
59201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	labelidx = entry2index(handle, jumpto) - 1;
59301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return get_errorlabel(handle, index2offset(handle, labelidx));
59401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
59501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
59601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Returns a pointer to the target name of this position. */
59701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerconst char *iptc_get_target(const char *chain,
59801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			    unsigned int n,
59901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			    iptc_handle_t *handle)
60001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
60101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int pos = 0, chainindex;
60201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	struct ipt_entry *e;
603fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
60401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	CHECK(*handle);
60501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (!find_label(&pos, chain, *handle)) {
60601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		errno = ENOENT;
607dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt		return NULL;
60801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
609dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt
61001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	chainindex = entry2index(*handle, get_entry(*handle, pos));
61101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	e = index2entry(*handle, chainindex + n);
61201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
61301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return target_name(*handle, e);
61401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
61501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
61601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Is this a built-in chain?  Actually returns hook + 1. */
61701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerint
61801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Broueriptc_builtin(const char *chain, const iptc_handle_t handle)
61901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
62001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int i;
62101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
62201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
62301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if ((handle->info.valid_hooks & (1 << i))
62401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		    && handle->hooknames[i]
625dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt		    && strcmp(handle->hooknames[i], chain) == 0)
626dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			return i+1;
62701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
62801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return 0;
62901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
63001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
63101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer/* Get the policy of a given built-in chain */
632dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardtconst char *
633dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardtiptc_get_policy(const char *chain,
63401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		struct ipt_counters *counters,
63501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		iptc_handle_t *handle)
63601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
63701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int start;
63801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	struct ipt_entry *e;
63901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	int hook;
64001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
64101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	CHECK(*handle);
642aae69bed019826ddec93f761514652a93d871e49Harald Welte	hook = iptc_builtin(chain, *handle);
643aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (hook != 0)
644aae69bed019826ddec93f761514652a93d871e49Harald Welte		start = (*handle)->info.hook_entry[hook-1];
645aae69bed019826ddec93f761514652a93d871e49Harald Welte	else
646910939897ea0cb9be2729a98c60a92e807aad5c3Jesper Dangaard Brouer		return NULL;
647aae69bed019826ddec93f761514652a93d871e49Harald Welte
648aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = get_entry(*handle, get_chain_end(*handle, start));
649aae69bed019826ddec93f761514652a93d871e49Harald Welte	*counters = e->counters;
650aae69bed019826ddec93f761514652a93d871e49Harald Welte
651aae69bed019826ddec93f761514652a93d871e49Harald Welte	return target_name(*handle, e);
652aae69bed019826ddec93f761514652a93d871e49Harald Welte}
653aae69bed019826ddec93f761514652a93d871e49Harald Welte
654aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int
655aae69bed019826ddec93f761514652a93d871e49Harald Weltecorrect_verdict(struct ipt_entry *e,
656aae69bed019826ddec93f761514652a93d871e49Harald Welte		unsigned char *base,
657aae69bed019826ddec93f761514652a93d871e49Harald Welte		unsigned int offset, int delta_offset)
658aae69bed019826ddec93f761514652a93d871e49Harald Welte{
659aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_standard_target *t = (void *)ipt_get_target(e);
660aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int curr = (unsigned char *)e - base;
661aae69bed019826ddec93f761514652a93d871e49Harald Welte
662aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Trap: insert of fall-through rule.  Don't change fall-through
663aae69bed019826ddec93f761514652a93d871e49Harald Welte	   verdict to jump-over-next-rule. */
664aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0
665aae69bed019826ddec93f761514652a93d871e49Harald Welte	    && t->verdict > (int)offset
666a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	    && !(curr == offset &&
667a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		 t->verdict == curr + e->next_offset)) {
668a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		t->verdict += delta_offset;
669a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	}
670a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson
671a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	return 0;
672a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson}
673a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson
674a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson/* Adjusts standard verdict jump positions after an insertion/deletion. */
675a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefssonstatic int
676a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefssonset_verdict(unsigned int offset, int delta_offset, iptc_handle_t *handle)
677a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson{
678a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	IPT_ENTRY_ITERATE((*handle)->entries.entries,
679a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson			  (*handle)->entries.size,
680a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson			  correct_verdict, (*handle)->entries.entries,
681aae69bed019826ddec93f761514652a93d871e49Harald Welte			  offset, delta_offset);
682aae69bed019826ddec93f761514652a93d871e49Harald Welte
683fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	set_changed(*handle);
684aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
685aae69bed019826ddec93f761514652a93d871e49Harald Welte}
6864bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
6874bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer/* If prepend is set, then we are prepending to a chain: if the
688aae69bed019826ddec93f761514652a93d871e49Harald Welte * insertion position is an entry point, keep the entry point. */
689aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int
690aae69bed019826ddec93f761514652a93d871e49Harald Welteinsert_rules(unsigned int num_rules, unsigned int rules_size,
691aae69bed019826ddec93f761514652a93d871e49Harald Welte	     const struct ipt_entry *insert,
6924bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	     unsigned int offset, unsigned int num_rules_offset,
6934bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	     int prepend,
6944bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	     iptc_handle_t *handle)
6954bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer{
6964bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	iptc_handle_t newh;
6974bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	struct ipt_getinfo newinfo;
6984bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	unsigned int i;
6994bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
7004bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	if (offset >= (*handle)->entries.size) {
7014bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		errno = EINVAL;
702aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
7034bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	}
7044bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
7054bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	newinfo = (*handle)->info;
706aae69bed019826ddec93f761514652a93d871e49Harald Welte
7074bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	/* Fix up entry points. */
708aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
709aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Entry points to START of chain, so keep same if
710aae69bed019826ddec93f761514652a93d871e49Harald Welte                   inserting on at that point. */
711aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((*handle)->info.hook_entry[i] > offset)
71201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			newinfo.hook_entry[i] += rules_size;
713aae69bed019826ddec93f761514652a93d871e49Harald Welte
714aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Underflow always points to END of chain (policy),
715fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt		   so if something is inserted at same point, it
716aae69bed019826ddec93f761514652a93d871e49Harald Welte		   should be advanced. */
717aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((*handle)->info.underflow[i] >= offset)
71801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			newinfo.underflow[i] += rules_size;
71901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
72001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
721aae69bed019826ddec93f761514652a93d871e49Harald Welte	newh = alloc_handle((*handle)->info.name,
722aae69bed019826ddec93f761514652a93d871e49Harald Welte			    (*handle)->info.size + rules_size,
723aae69bed019826ddec93f761514652a93d871e49Harald Welte			    (*handle)->info.num_entries + num_rules);
724aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!newh)
72501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return 0;
726aae69bed019826ddec93f761514652a93d871e49Harald Welte	newh->info = newinfo;
727aae69bed019826ddec93f761514652a93d871e49Harald Welte
72801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Copy pre... */
72901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	memcpy(newh->entries.entries, (*handle)->entries.entries, offset);
730aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* ... Insert new ... */
731aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(newh->entries.entries + offset, insert, rules_size);
732aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* ... copy post */
733aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(newh->entries.entries + offset + rules_size,
73401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       (*handle)->entries.entries + offset,
73501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       (*handle)->entries.size - offset);
73601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
73701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Move counter map. */
73801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Copy pre... */
73901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	memcpy(newh->counter_map, (*handle)->counter_map,
74001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       sizeof(struct counter_map) * num_rules_offset);
74101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* ... copy post */
74201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	memcpy(newh->counter_map + num_rules_offset + num_rules,
74301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       (*handle)->counter_map + num_rules_offset,
74401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       sizeof(struct counter_map) * ((*handle)->new_number
74501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer					     - num_rules_offset));
74601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Set intermediates to no counter copy */
74701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	for (i = 0; i < num_rules; i++)
74801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		newh->counter_map[num_rules_offset+i]
74901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
75001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
75101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	newh->new_number = (*handle)->new_number + num_rules;
75201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	newh->entries.size = (*handle)->entries.size + rules_size;
75301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	newh->hooknames = (*handle)->hooknames;
75401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
75501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	free(*handle);
75601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	*handle = newh;
75701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
75801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return set_verdict(offset, rules_size, handle);
75901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
76001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
76101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerstatic int
76201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouerdelete_rules(unsigned int num_rules, unsigned int rules_size,
76301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	     unsigned int offset, unsigned int num_rules_offset,
76401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	     iptc_handle_t *handle)
76501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer{
76601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	unsigned int i;
76701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
76801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (offset + rules_size > (*handle)->entries.size) {
76901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		errno = EINVAL;
77001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return 0;
77101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	}
77201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
77301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Fix up entry points. */
77401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
77501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* In practice, we never delete up to a hook entry,
77601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		   since the built-in chains are always first,
77701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		   so these two are never equal */
77801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if ((*handle)->info.hook_entry[i] >= offset + rules_size)
77901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			(*handle)->info.hook_entry[i] -= rules_size;
78001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		else if ((*handle)->info.hook_entry[i] > offset) {
78101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
78201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer				i, (*handle)->info.hook_entry[i], offset);
78301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer			abort();
78401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		}
78501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer
78601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* Underflow points to policy (terminal) rule in
787aae69bed019826ddec93f761514652a93d871e49Harald Welte                   built-in, so sequality is valid here (when deleting
788aae69bed019826ddec93f761514652a93d871e49Harald Welte                   the last rule). */
789aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((*handle)->info.underflow[i] >= offset + rules_size)
790aae69bed019826ddec93f761514652a93d871e49Harald Welte			(*handle)->info.underflow[i] -= rules_size;
791aae69bed019826ddec93f761514652a93d871e49Harald Welte		else if ((*handle)->info.underflow[i] > offset) {
792aae69bed019826ddec93f761514652a93d871e49Harald Welte			fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
793aae69bed019826ddec93f761514652a93d871e49Harald Welte				i, (*handle)->info.underflow[i], offset);
794aae69bed019826ddec93f761514652a93d871e49Harald Welte			abort();
795aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
796aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
797aae69bed019826ddec93f761514652a93d871e49Harald Welte
798aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Move the rules down. */
799aae69bed019826ddec93f761514652a93d871e49Harald Welte	memmove((*handle)->entries.entries + offset,
800aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->entries.entries + offset + rules_size,
801aae69bed019826ddec93f761514652a93d871e49Harald Welte		(*handle)->entries.size - (offset + rules_size));
802aae69bed019826ddec93f761514652a93d871e49Harald Welte
803aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Move the counter map down. */
804aae69bed019826ddec93f761514652a93d871e49Harald Welte	memmove(&(*handle)->counter_map[num_rules_offset],
805aae69bed019826ddec93f761514652a93d871e49Harald Welte		&(*handle)->counter_map[num_rules_offset + num_rules],
806aae69bed019826ddec93f761514652a93d871e49Harald Welte		sizeof(struct counter_map)
807aae69bed019826ddec93f761514652a93d871e49Harald Welte		* ((*handle)->new_number - (num_rules + num_rules_offset)));
808aae69bed019826ddec93f761514652a93d871e49Harald Welte
809aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Fix numbers */
810aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->new_number -= num_rules;
811aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->entries.size -= rules_size;
812fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
813aae69bed019826ddec93f761514652a93d871e49Harald Welte	return set_verdict(offset, -(int)rules_size, handle);
814aae69bed019826ddec93f761514652a93d871e49Harald Welte}
815aae69bed019826ddec93f761514652a93d871e49Harald Welte
816aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int
817aae69bed019826ddec93f761514652a93d871e49Harald Weltestandard_map(struct ipt_entry *e, int verdict)
818aae69bed019826ddec93f761514652a93d871e49Harald Welte{
819aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_standard_target *t;
820aae69bed019826ddec93f761514652a93d871e49Harald Welte
821aae69bed019826ddec93f761514652a93d871e49Harald Welte	t = (struct ipt_standard_target *)ipt_get_target(e);
822aae69bed019826ddec93f761514652a93d871e49Harald Welte
823aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (t->target.target_size != IPT_ALIGN(sizeof(struct ipt_standard_target))) {
824aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EINVAL;
825aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
826aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
827aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* memset for memcmp convenience on delete/replace */
828aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(t->target.u.name, 0, IPT_FUNCTION_MAXNAMELEN);
829aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(t->target.u.name, IPT_STANDARD_TARGET);
830aae69bed019826ddec93f761514652a93d871e49Harald Welte	t->verdict = verdict;
831aae69bed019826ddec93f761514652a93d871e49Harald Welte
832aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
833aae69bed019826ddec93f761514652a93d871e49Harald Welte}
834aae69bed019826ddec93f761514652a93d871e49Harald Welte
835aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic int
8368d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefssonmap_target(const iptc_handle_t handle,
837aae69bed019826ddec93f761514652a93d871e49Harald Welte	   struct ipt_entry *e,
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   unsigned int offset,
839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   struct ipt_entry_target *old)
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t = ipt_get_target(e);
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
843ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	/* Save old target (except data, which we don't change, except for
844fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	   standard case, where we don't care). */
845ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	*old = *t;
846ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
84701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Maybe it's empty (=> fall through) */
84801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	if (strcmp(t->u.name, "") == 0)
84901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return standard_map(e, offset + e->next_offset);
85001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* Maybe it's a standard target name... */
85101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	else if (strcmp(t->u.name, IPTC_LABEL_ACCEPT) == 0)
85201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return standard_map(e, -NF_ACCEPT - 1);
85301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	else if (strcmp(t->u.name, IPTC_LABEL_DROP) == 0)
85401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return standard_map(e, -NF_DROP - 1);
85501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	else if (strcmp(t->u.name, IPTC_LABEL_QUEUE) == 0)
85601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return standard_map(e, -NF_QUEUE - 1);
85701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	else if (strcmp(t->u.name, IPTC_LABEL_RETURN) == 0)
85801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return standard_map(e, IPT_RETURN);
85901444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	else if (iptc_builtin(t->u.name, handle)) {
86001444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		/* Can't jump to builtins. */
86101444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		errno = EINVAL;
86201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		return 0;
86301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	} else {
864ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte		/* Maybe it's an existing chain name. */
8659d3ed77341361674994f584ff69a61f31a342739Olaf Rempel		unsigned int exists;
8669d3ed77341361674994f584ff69a61f31a342739Olaf Rempel
86701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer		if (find_label(&exists, t->u.name, handle))
868feca0578a5d035122b4b7cdb8d44d6cca819f35cRobert de Barth			return standard_map(e, exists);
8699d3ed77341361674994f584ff69a61f31a342739Olaf Rempel	}
8709d3ed77341361674994f584ff69a61f31a342739Olaf Rempel
8719d3ed77341361674994f584ff69a61f31a342739Olaf Rempel	/* Must be a module?  If not, kernel will reject... */
87201444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	/* memset to all 0 for your memcmp convenience. */
87301444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	memset(t->u.name + strlen(t->u.name),
87401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       0,
87501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	       IPT_FUNCTION_MAXNAMELEN - strlen(t->u.name));
87601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	return 1;
87701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer}
878ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
879ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Weltestatic void
880ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welteunmap_target(struct ipt_entry *e, struct ipt_entry_target *old)
881ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte{
882ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	struct ipt_entry_target *t = ipt_get_target(e);
883ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte
884ec30b6c4d3ebb09d2c05e44f3904428893ef13bdHarald Welte	/* Save old target (except data, which we don't change, except for
885aae69bed019826ddec93f761514652a93d871e49Harald Welte	   standard case, where we don't care). */
886aae69bed019826ddec93f761514652a93d871e49Harald Welte	*t = *old;
887fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt}
888aae69bed019826ddec93f761514652a93d871e49Harald Welte
889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
8901336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouerint
8911336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Broueriptc_insert_entry(const ipt_chainlabel chain,
8921336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		  const struct ipt_entry *e,
893aae69bed019826ddec93f761514652a93d871e49Harald Welte		  unsigned int rulenum,
894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		  iptc_handle_t *handle)
895aae69bed019826ddec93f761514652a93d871e49Harald Welte{
896aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int chainoff, chainindex, offset;
897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target old;
8981336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	int ret;
8991336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer
9001336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	CHECK(*handle);
9011336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	iptc_fn = iptc_insert_entry;
9021336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	if (!find_label(&chainoff, chain, *handle)) {
9031336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		errno = ENOENT;
9041336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		return 0;
9051336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	}
9061336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer
9074bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	chainindex = entry2index(*handle, get_entry(*handle, chainoff));
908526d3e138635e33773d1ca16477052a04f53f5bdJesper Dangaard Brouer
909526d3e138635e33773d1ca16477052a04f53f5bdJesper Dangaard Brouer	if (index2entry(*handle, chainindex + rulenum)
9101336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	    > get_entry(*handle, get_chain_end(*handle, chainoff))) {
9114bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		errno = E2BIG;
9121336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer		return 0;
9134bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	}
9144bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	offset = index2offset(*handle, chainindex + rulenum);
9154bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
9164bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	/* Mapping target actually alters entry, but that's
9174bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer           transparent to the caller. */
9184bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	if (!map_target(*handle, (struct ipt_entry *)e, offset, &old))
9194bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer		return 0;
9204bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer
9214bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	ret = insert_rules(1, e->next_offset, e, offset,
9224bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer			   chainindex + rulenum, rulenum == 0, handle);
9231336451ead58d608618ff5b0a251d132b73f9866Jesper Dangaard Brouer	unmap_target((struct ipt_entry *)e, &old);
924d8cb787ab44e9d2de4fd3b04fcaa370c9918fc5dJesper Dangaard Brouer	CHECK(*handle);
925aae69bed019826ddec93f761514652a93d871e49Harald Welte	return ret;
926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
928aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Atomically replace rule `rulenum' in `chain' with `fw'. */
929aae69bed019826ddec93f761514652a93d871e49Harald Welteint
930fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardtiptc_replace_entry(const ipt_chainlabel chain,
931aae69bed019826ddec93f761514652a93d871e49Harald Welte		   const struct ipt_entry *e,
932aae69bed019826ddec93f761514652a93d871e49Harald Welte		   unsigned int rulenum,
933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   iptc_handle_t *handle)
934aae69bed019826ddec93f761514652a93d871e49Harald Welte{
935aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int chainoff, chainindex, offset;
936aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_entry_target old;
937aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
938aae69bed019826ddec93f761514652a93d871e49Harald Welte
939aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
940aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = iptc_replace_entry;
941aae69bed019826ddec93f761514652a93d871e49Harald Welte
942aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!find_label(&chainoff, chain, *handle)) {
943aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
944aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
945aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
946aae69bed019826ddec93f761514652a93d871e49Harald Welte
947aae69bed019826ddec93f761514652a93d871e49Harald Welte	chainindex = entry2index(*handle, get_entry(*handle, chainoff));
948aae69bed019826ddec93f761514652a93d871e49Harald Welte
949aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (index2entry(*handle, chainindex + rulenum)
950aae69bed019826ddec93f761514652a93d871e49Harald Welte	    >= get_entry(*handle, get_chain_end(*handle, chainoff))) {
951aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = E2BIG;
952aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
953aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
954aae69bed019826ddec93f761514652a93d871e49Harald Welte
955aae69bed019826ddec93f761514652a93d871e49Harald Welte	offset = index2offset(*handle, chainindex + rulenum);
956aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Replace = delete and insert. */
957aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
958aae69bed019826ddec93f761514652a93d871e49Harald Welte			  offset, chainindex + rulenum, handle))
959aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
960aae69bed019826ddec93f761514652a93d871e49Harald Welte
961aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!map_target(*handle, (struct ipt_entry *)e, offset, &old))
96248bde40e73b45ad134d32cde88b779fe509faf64Jesper Dangaard Brouer		return 0;
963aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
964aae69bed019826ddec93f761514652a93d871e49Harald Welte
965aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = insert_rules(1, e->next_offset, e, offset,
966aae69bed019826ddec93f761514652a93d871e49Harald Welte			   chainindex + rulenum, 1, handle);
967aae69bed019826ddec93f761514652a93d871e49Harald Welte	unmap_target((struct ipt_entry *)e, &old);
968aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
969aae69bed019826ddec93f761514652a93d871e49Harald Welte	return ret;
970aae69bed019826ddec93f761514652a93d871e49Harald Welte}
971aae69bed019826ddec93f761514652a93d871e49Harald Welte
972aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Append entry `fw' to chain `chain'.  Equivalent to insert with
973aae69bed019826ddec93f761514652a93d871e49Harald Welte   rulenum = length of chain. */
974aae69bed019826ddec93f761514652a93d871e49Harald Welteint
975aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_append_entry(const ipt_chainlabel chain,
976aae69bed019826ddec93f761514652a93d871e49Harald Welte		  const struct ipt_entry *e,
977aae69bed019826ddec93f761514652a93d871e49Harald Welte		  iptc_handle_t *handle)
978aae69bed019826ddec93f761514652a93d871e49Harald Welte{
979aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int startoff, endoff;
980aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_entry_target old;
981aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
982aae69bed019826ddec93f761514652a93d871e49Harald Welte
983aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
984aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = iptc_append_entry;
985aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!find_label(&startoff, chain, *handle)) {
986aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
987aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
988aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
989aae69bed019826ddec93f761514652a93d871e49Harald Welte
990aae69bed019826ddec93f761514652a93d871e49Harald Welte	endoff = get_chain_end(*handle, startoff);
991aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!map_target(*handle, (struct ipt_entry *)e, endoff, &old))
992aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
993aae69bed019826ddec93f761514652a93d871e49Harald Welte
994aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = insert_rules(1, e->next_offset, e, endoff,
995aae69bed019826ddec93f761514652a93d871e49Harald Welte			   entry2index(*handle, get_entry(*handle, endoff)),
996aae69bed019826ddec93f761514652a93d871e49Harald Welte			   0, handle);
997aae69bed019826ddec93f761514652a93d871e49Harald Welte	unmap_target((struct ipt_entry *)e, &old);
998aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
999aae69bed019826ddec93f761514652a93d871e49Harald Welte	return ret;
1000aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1001aae69bed019826ddec93f761514652a93d871e49Harald Welte
1002aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
1003aae69bed019826ddec93f761514652a93d871e49Harald Weltematch_different(const struct ipt_entry_match *a,
1004aae69bed019826ddec93f761514652a93d871e49Harald Welte		const unsigned char *a_elems,
1005aae69bed019826ddec93f761514652a93d871e49Harald Welte		const unsigned char *b_elems,
1006aae69bed019826ddec93f761514652a93d871e49Harald Welte		unsigned char **maskptr)
1007aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1008aae69bed019826ddec93f761514652a93d871e49Harald Welte	const struct ipt_entry_match *b;
1009aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i;
1010aae69bed019826ddec93f761514652a93d871e49Harald Welte
1011aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Offset of b is the same as a. */
1012aae69bed019826ddec93f761514652a93d871e49Harald Welte	b = (void *)b_elems + ((unsigned char *)a-a_elems);
1013aae69bed019826ddec93f761514652a93d871e49Harald Welte
1014aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (a->match_size != b->match_size)
1015aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
1016aae69bed019826ddec93f761514652a93d871e49Harald Welte
1017aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(a->u.name, b->u.name) != 0)
1018aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 1;
1019aae69bed019826ddec93f761514652a93d871e49Harald Welte
1020aae69bed019826ddec93f761514652a93d871e49Harald Welte	*maskptr += sizeof(*a);
1021aae69bed019826ddec93f761514652a93d871e49Harald Welte
1022aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < a->match_size - sizeof(*a); i++)
1023aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1024aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 1;
102552c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson	*maskptr += i;
102652c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson	return 0;
102752c380208a87191a8c25608d2c501c0dc32aa9adMartin Josefsson}
1028aae69bed019826ddec93f761514652a93d871e49Harald Welte
1029aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
1030aae69bed019826ddec93f761514652a93d871e49Harald Weltetarget_different(const unsigned char *a_targdata,
10318d1b38a064d146c77eb8fc951717663e1a713cfcMartin Josefsson		 const unsigned char *b_targdata,
1032aae69bed019826ddec93f761514652a93d871e49Harald Welte		 unsigned int tdatasize,
1033aae69bed019826ddec93f761514652a93d871e49Harald Welte		 const unsigned char *mask)
1034aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1035aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i;
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < tdatasize; i++)
1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
1038aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 1;
1039aae69bed019826ddec93f761514652a93d871e49Harald Welte
1040fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	return 0;
1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1042aae69bed019826ddec93f761514652a93d871e49Harald Welte
1043aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
1044aae69bed019826ddec93f761514652a93d871e49Harald Welteis_same(const struct ipt_entry *a, const struct ipt_entry *b,
1045aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned char *matchmask)
10464bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer{
10474bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	unsigned int i;
10484bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	struct ipt_entry_target *ta, *tb;
10494bae3f1001028ee283a5e1fcea4a561b0068f95dJesper Dangaard Brouer	unsigned char *mptr;
1050aae69bed019826ddec93f761514652a93d871e49Harald Welte
1051aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Always compare head structures: ignore mask here. */
1052aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (a->ip.src.s_addr != b->ip.src.s_addr
1053aae69bed019826ddec93f761514652a93d871e49Harald Welte	    || a->ip.dst.s_addr != b->ip.dst.s_addr
105401444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	    || a->ip.smsk.s_addr != b->ip.smsk.s_addr
105501444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	    || a->ip.smsk.s_addr != b->ip.smsk.s_addr
105601444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	    || a->ip.proto != b->ip.proto
105701444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	    || a->ip.flags != b->ip.flags
105801444da4cb70417d2dc2643e2d48c70de7ff8e96Jesper Dangaard Brouer	    || a->ip.invflags != b->ip.invflags)
1059aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1060aae69bed019826ddec93f761514652a93d871e49Harald Welte
1061aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < IFNAMSIZ; i++) {
1062aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i])
1063dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			return 0;
1064aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((a->ip.iniface[i] & a->ip.iniface_mask[i])
1065aae69bed019826ddec93f761514652a93d871e49Harald Welte		    != (b->ip.iniface[i] & b->ip.iniface_mask[i]))
1066aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 0;
1067aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i])
1068aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 0;
1069aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((a->ip.outiface[i] & a->ip.outiface_mask[i])
1070dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt		    != (b->ip.outiface[i] & b->ip.outiface_mask[i]))
1071dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt			return 0;
1072aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1073dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt
1074dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt	if (a->nfcache != b->nfcache
1075aae69bed019826ddec93f761514652a93d871e49Harald Welte	    || a->target_offset != b->target_offset
1076aae69bed019826ddec93f761514652a93d871e49Harald Welte	    || a->next_offset != b->next_offset)
1077aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1078aae69bed019826ddec93f761514652a93d871e49Harald Welte
10790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	mptr = matchmask + sizeof(struct ipt_entry);
10809e03380e9f78ae347ae4f3f041c4eca50348f2e8Harald Welte	if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr))
1081aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1082aae69bed019826ddec93f761514652a93d871e49Harald Welte
1083aae69bed019826ddec93f761514652a93d871e49Harald Welte	ta = ipt_get_target((struct ipt_entry *)a);
1084aae69bed019826ddec93f761514652a93d871e49Harald Welte	tb = ipt_get_target((struct ipt_entry *)b);
1085aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (ta->target_size != tb->target_size)
1086aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1087aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(ta->u.name, tb->u.name) != 0)
1088aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1089aae69bed019826ddec93f761514652a93d871e49Harald Welte
1090aae69bed019826ddec93f761514652a93d871e49Harald Welte	mptr += sizeof(*ta);
1091aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (target_different(ta->data, tb->data,
1092aae69bed019826ddec93f761514652a93d871e49Harald Welte			     ta->target_size - sizeof(*ta), mptr))
1093aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1094aae69bed019826ddec93f761514652a93d871e49Harald Welte
1095aae69bed019826ddec93f761514652a93d871e49Harald Welte   	return 1;
1096aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1097aae69bed019826ddec93f761514652a93d871e49Harald Welte
1098aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Delete the first rule in `chain' which matches `fw'. */
1099aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1100aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_delete_entry(const ipt_chainlabel chain,
1101aae69bed019826ddec93f761514652a93d871e49Harald Welte		  const struct ipt_entry *origfw,
1102aae69bed019826ddec93f761514652a93d871e49Harald Welte		  unsigned char *matchmask,
1103aae69bed019826ddec93f761514652a93d871e49Harald Welte		  iptc_handle_t *handle)
1104aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1105aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset, lastoff;
1106aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_entry *e, *fw;
1107aae69bed019826ddec93f761514652a93d871e49Harald Welte
1108aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1109aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = iptc_delete_entry;
1110aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!find_label(&offset, chain, *handle)) {
1111fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt		errno = ENOENT;
11120113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
1113aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1114aae69bed019826ddec93f761514652a93d871e49Harald Welte
1115aae69bed019826ddec93f761514652a93d871e49Harald Welte	fw = malloc(origfw->next_offset);
1116aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (fw == NULL) {
1117aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOMEM;
1118aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1119aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1120aae69bed019826ddec93f761514652a93d871e49Harald Welte	lastoff = get_chain_end(*handle, offset);
1121aae69bed019826ddec93f761514652a93d871e49Harald Welte
1122aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (; offset < lastoff; offset += e->next_offset) {
1123aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct ipt_entry_target discard;
1124aae69bed019826ddec93f761514652a93d871e49Harald Welte
1125aae69bed019826ddec93f761514652a93d871e49Harald Welte		memcpy(fw, origfw, origfw->next_offset);
1126aae69bed019826ddec93f761514652a93d871e49Harald Welte
1127aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* FIXME: handle this in is_same --RR */
1128aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (!map_target(*handle, fw, offset, &discard)) {
1129aae69bed019826ddec93f761514652a93d871e49Harald Welte			free(fw);
1130aae69bed019826ddec93f761514652a93d871e49Harald Welte			return 0;
1131aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1132aae69bed019826ddec93f761514652a93d871e49Harald Welte		e = get_entry(*handle, offset);
1133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0
1135aae69bed019826ddec93f761514652a93d871e49Harald Welte		printf("Deleting:\n");
1136fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt		dump_entry(newe);
11373ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte#endif
1138aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (is_same(e, fw, matchmask)) {
1139aae69bed019826ddec93f761514652a93d871e49Harald Welte			int ret;
1140aae69bed019826ddec93f761514652a93d871e49Harald Welte			ret = delete_rules(1, e->next_offset,
1141aae69bed019826ddec93f761514652a93d871e49Harald Welte					   offset, entry2index(*handle, e),
1142aae69bed019826ddec93f761514652a93d871e49Harald Welte					   handle);
1143aae69bed019826ddec93f761514652a93d871e49Harald Welte			free(fw);
1144aae69bed019826ddec93f761514652a93d871e49Harald Welte			CHECK(*handle);
1145aae69bed019826ddec93f761514652a93d871e49Harald Welte			return ret;
1146aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
1147aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1148aae69bed019826ddec93f761514652a93d871e49Harald Welte
1149aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(fw);
1150aae69bed019826ddec93f761514652a93d871e49Harald Welte	errno = ENOENT;
1151aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
1152aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1153aae69bed019826ddec93f761514652a93d871e49Harald Welte
1154aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Delete the rule in position `rulenum' in `chain'. */
1155aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1156aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_delete_num_entry(const ipt_chainlabel chain,
1157aae69bed019826ddec93f761514652a93d871e49Harald Welte		      unsigned int rulenum,
1158aae69bed019826ddec93f761514652a93d871e49Harald Welte		      iptc_handle_t *handle)
1159aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1160aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int chainstart;
1161aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int index;
1162aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
1163aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_entry *e;
1164aae69bed019826ddec93f761514652a93d871e49Harald Welte
1165aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1166aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = iptc_delete_num_entry;
1167aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!find_label(&chainstart, chain, *handle)) {
1168aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1169aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1170aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1171aae69bed019826ddec93f761514652a93d871e49Harald Welte
1172aae69bed019826ddec93f761514652a93d871e49Harald Welte	index = entry2index(*handle, get_entry(*handle, chainstart))
1173aae69bed019826ddec93f761514652a93d871e49Harald Welte		+ rulenum;
1174aae69bed019826ddec93f761514652a93d871e49Harald Welte
1175aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (index
1176aae69bed019826ddec93f761514652a93d871e49Harald Welte	    >= entry2index(*handle,
1177aae69bed019826ddec93f761514652a93d871e49Harald Welte			  get_entry(*handle,
1178aae69bed019826ddec93f761514652a93d871e49Harald Welte				    get_chain_end(*handle, chainstart)))) {
1179aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = E2BIG;
1180aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
11813ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte	}
11823ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte
1183aae69bed019826ddec93f761514652a93d871e49Harald Welte	e = index2entry(*handle, index);
1184fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	if (e == NULL) {
1185efa8fc2123a2a9fc229ab471edd2b2688ce1da3aHarald Welte		errno = EINVAL;
11863ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte		return 0;
1187aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1188aae69bed019826ddec93f761514652a93d871e49Harald Welte
1189aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
1190aae69bed019826ddec93f761514652a93d871e49Harald Welte			   index, handle);
1191aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1192aae69bed019826ddec93f761514652a93d871e49Harald Welte	return ret;
1193aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1194aae69bed019826ddec93f761514652a93d871e49Harald Welte
1195aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1196aae69bed019826ddec93f761514652a93d871e49Harald Welte   NULL and sets errno. */
1197aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *
1198aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_check_packet(const ipt_chainlabel chain,
1199aae69bed019826ddec93f761514652a93d871e49Harald Welte			      struct ipt_entry *entry,
1200aae69bed019826ddec93f761514652a93d871e49Harald Welte			      iptc_handle_t *handle)
1201aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1202aae69bed019826ddec93f761514652a93d871e49Harald Welte	errno = ENOSYS;
1203aae69bed019826ddec93f761514652a93d871e49Harald Welte	return NULL;
1204aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1205aae69bed019826ddec93f761514652a93d871e49Harald Welte
1206aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Flushes the entries in the given chain (ie. empties chain). */
1207aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1208aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
1209aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1210aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int startoff, endoff, startindex, endindex;
1211aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
1212aae69bed019826ddec93f761514652a93d871e49Harald Welte
1213aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1214aae69bed019826ddec93f761514652a93d871e49Harald Welte	iptc_fn = iptc_flush_entries;
1215aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!find_label(&startoff, chain, *handle)) {
12163ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte		errno = ENOENT;
12173ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte		return 0;
1218aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1219fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	endoff = get_chain_end(*handle, startoff);
1220aae69bed019826ddec93f761514652a93d871e49Harald Welte	startindex = entry2index(*handle, get_entry(*handle, startoff));
1221aae69bed019826ddec93f761514652a93d871e49Harald Welte	endindex = entry2index(*handle, get_entry(*handle, endoff));
1222aae69bed019826ddec93f761514652a93d871e49Harald Welte
1223aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = delete_rules(endindex - startindex,
12243ea8f40262386e6b1445a617841f28702fe74d9dHarald Welte			   endoff - startoff, startoff, startindex,
1225aae69bed019826ddec93f761514652a93d871e49Harald Welte			   handle);
1226aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1227aae69bed019826ddec93f761514652a93d871e49Harald Welte	return ret;
1228aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1229aae69bed019826ddec93f761514652a93d871e49Harald Welte
1230aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Zeroes the counters in a chain. */
1231aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1232aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
1233aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1234aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i, end;
1235aae69bed019826ddec93f761514652a93d871e49Harald Welte
1236aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1237aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!find_label(&i, chain, *handle)) {
1238aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1239aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1240aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1241aae69bed019826ddec93f761514652a93d871e49Harald Welte	end = get_chain_end(*handle, i);
1242fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
12430113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	i = entry2index(*handle, get_entry(*handle, i));
1244aae69bed019826ddec93f761514652a93d871e49Harald Welte	end = entry2index(*handle, get_entry(*handle, end));
1245aae69bed019826ddec93f761514652a93d871e49Harald Welte
12460113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (; i <= end; i++) {
1247aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
1248aae69bed019826ddec93f761514652a93d871e49Harald Welte			(*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1249aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1250aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1251aae69bed019826ddec93f761514652a93d871e49Harald Welte
12520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	CHECK(*handle);
12530113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return 1;
1254aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1255aae69bed019826ddec93f761514652a93d871e49Harald Welte
1256aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Creates a new chain. */
1257aae69bed019826ddec93f761514652a93d871e49Harald Welte/* To create a chain, create two rules: error node and unconditional
1258aae69bed019826ddec93f761514652a93d871e49Harald Welte * return. */
1259aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1260aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
1261aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1262aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int pos;
1263aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
12640113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	struct {
1265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry head;
1266aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct ipt_error_target name;
1267aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct ipt_entry ret;
1268aae69bed019826ddec93f761514652a93d871e49Harald Welte		struct ipt_standard_target target;
1269aae69bed019826ddec93f761514652a93d871e49Harald Welte	} newc;
1270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1271fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	CHECK(*handle);
12720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	iptc_fn = iptc_create_chain;
1273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT,
1275fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt           QUEUE, RETURN. */
1276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (find_label(&pos, chain, *handle)
1277aae69bed019826ddec93f761514652a93d871e49Harald Welte	    || strcmp(chain, IPTC_LABEL_DROP) == 0
1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(chain, IPTC_LABEL_ACCEPT) == 0
1279aae69bed019826ddec93f761514652a93d871e49Harald Welte	    || strcmp(chain, IPTC_LABEL_QUEUE) == 0
1280aae69bed019826ddec93f761514652a93d871e49Harald Welte	    || strcmp(chain, IPTC_LABEL_RETURN) == 0) {
1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EEXIST;
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1284aae69bed019826ddec93f761514652a93d871e49Harald Welte
1285aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strlen(chain)+1 > sizeof(ipt_chainlabel)) {
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		errno = EINVAL;
1287aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
12880371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte	}
1289aae69bed019826ddec93f761514652a93d871e49Harald Welte
1290aae69bed019826ddec93f761514652a93d871e49Harald Welte	memset(&newc, 0, sizeof(newc));
1291aae69bed019826ddec93f761514652a93d871e49Harald Welte	newc.head.target_offset = sizeof(struct ipt_entry);
1292aae69bed019826ddec93f761514652a93d871e49Harald Welte	newc.head.next_offset
12930371c0c5eb17c81e8dd44c4aa31b58318e9b7b72Harald Welte		= sizeof(struct ipt_entry) + sizeof(struct ipt_error_target);
1294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.name.t.u.name, IPT_ERROR_TARGET);
1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.name.t.target_size = sizeof(struct ipt_error_target);
1296aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(newc.name.error, chain);
1297aae69bed019826ddec93f761514652a93d871e49Harald Welte
1298aae69bed019826ddec93f761514652a93d871e49Harald Welte	newc.ret.target_offset = sizeof(struct ipt_entry);
1299aae69bed019826ddec93f761514652a93d871e49Harald Welte	newc.ret.next_offset
1300aae69bed019826ddec93f761514652a93d871e49Harald Welte		= sizeof(struct ipt_entry)+sizeof(struct ipt_standard_target);
1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newc.target.target.u.name, IPT_STANDARD_TARGET);
1302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newc.target.target.target_size = sizeof(struct ipt_standard_target);
1303aae69bed019826ddec93f761514652a93d871e49Harald Welte	newc.target.verdict = IPT_RETURN;
1304fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
130579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	/* Add just before terminal entry */
1306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	ret = insert_rules(2, sizeof(newc), &newc.head,
1307fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt			   index2offset(*handle, (*handle)->new_number - 1),
130879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			   (*handle)->new_number - 1,
1309efa8fc2123a2a9fc229ab471edd2b2688ce1da3aHarald Welte			   0, handle);
1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	CHECK(*handle);
1311175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt	return ret;
1312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
131379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
1314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1315841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefssoncount_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref)
1316841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
1317841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	struct ipt_standard_target *t;
1318841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
1319175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt	if (strcmp(ipt_get_target(e)->u.name, IPT_STANDARD_TARGET) == 0) {
1320175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt		t = (struct ipt_standard_target *)ipt_get_target(e);
1321175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt
1322175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt		if (t->verdict == offset)
1323175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt			(*ref)++;
13242f93205b375ee9f5a383f8041749a9b989012dd0Patrick McHardy	}
1325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1326841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	return 0;
1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1328664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates
1329175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt/* Get the number of references to this chain. */
1330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
1331664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Patesiptc_get_references(unsigned int *ref, const ipt_chainlabel chain,
1332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    iptc_handle_t *handle)
1333aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1334aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int offset;
1335aae69bed019826ddec93f761514652a93d871e49Harald Welte
13360113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	CHECK(*handle);
1337841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (!find_label(&offset, chain, *handle)) {
1338175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt		errno = ENOENT;
1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1340841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	}
1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*ref = 0;
1343175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt	IPT_ENTRY_ITERATE((*handle)->entries.entries,
1344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			  (*handle)->entries.size,
13450113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			  count_ref, offset, ref);
1346aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
134879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
1349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */
1350175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardtint
1351aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
1352aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1353aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int chainoff, labelidx, labeloff;
1354aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int references;
1355aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_entry *e;
1356aae69bed019826ddec93f761514652a93d871e49Harald Welte	int ret;
1357aae69bed019826ddec93f761514652a93d871e49Harald Welte
1358aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1359aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!iptc_get_references(&references, chain, handle))
1360aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1361aae69bed019826ddec93f761514652a93d871e49Harald Welte
1362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_delete_chain;
1363aae69bed019826ddec93f761514652a93d871e49Harald Welte
1364aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (iptc_builtin(chain, *handle)) {
1365aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EINVAL;
1366aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
13677e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell	}
1368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (references > 0) {
1370aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = EMLINK;
13711c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		return 0;
13722f93205b375ee9f5a383f8041749a9b989012dd0Patrick McHardy	}
13732f93205b375ee9f5a383f8041749a9b989012dd0Patrick McHardy
13742f93205b375ee9f5a383f8041749a9b989012dd0Patrick McHardy	if (!find_label(&chainoff, chain, *handle)) {
1375aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1378841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson
13791c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	e = get_entry(*handle, chainoff);
1380841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson	if (get_chain_end(*handle, chainoff) != chainoff) {
1381aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOTEMPTY;
1382aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1383664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	}
1384175f451104532f3054b1824695d16a4ee1d8ea34Jan Engelhardt
1385aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Need label index: preceeds chain start */
13861c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	labelidx = entry2index(*handle, e) - 1;
1387aae69bed019826ddec93f761514652a93d871e49Harald Welte	labeloff = index2offset(*handle, labelidx);
1388aae69bed019826ddec93f761514652a93d871e49Harald Welte
1389aae69bed019826ddec93f761514652a93d871e49Harald Welte	ret = delete_rules(2,
1390aae69bed019826ddec93f761514652a93d871e49Harald Welte			   get_entry(*handle, labeloff)->next_offset
1391aae69bed019826ddec93f761514652a93d871e49Harald Welte			   + e->next_offset,
1392aae69bed019826ddec93f761514652a93d871e49Harald Welte			   labeloff, labelidx, handle);
1393aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1394aae69bed019826ddec93f761514652a93d871e49Harald Welte	return ret;
1395aae69bed019826ddec93f761514652a93d871e49Harald Welte}
13961c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
1397aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Renames a chain. */
13981c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardtint iptc_rename_chain(const ipt_chainlabel oldname,
13991c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		      const ipt_chainlabel newname,
1400841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson		      iptc_handle_t *handle)
1401841e4aed2349046eb2c0b1375139c06569a93bd0Martin Josefsson{
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int chainoff, labeloff, labelidx;
140379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	struct ipt_error_target *t;
1404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1405228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	CHECK(*handle);
1406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_rename_chain;
1407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* find_label doesn't cover built-in targets: DROP, ACCEPT
1409fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt           RETURN. */
141079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (find_label(&chainoff, newname, *handle)
1411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_DROP) == 0
1412fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	    || strcmp(newname, IPTC_LABEL_ACCEPT) == 0
1413e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(newname, IPTC_LABEL_RETURN) == 0) {
1414664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates		errno = EEXIST;
1415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
141697fb2f1579f0794377db1dca7c5bb07fade1a0dcPatrick McHardy	}
1417e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell
14188b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	if (!find_label(&chainoff, oldname, *handle)
1419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || iptc_builtin(oldname, *handle)) {
1420d73af64b9d28a5b0309104232c848e8ca8ab6956Jan Engelhardt		errno = ENOENT;
142167088e73ce7707229c56987868f112051defca5aRusty Russell		return 0;
142267088e73ce7707229c56987868f112051defca5aRusty Russell	}
142367088e73ce7707229c56987868f112051defca5aRusty Russell
142467088e73ce7707229c56987868f112051defca5aRusty Russell	if (strlen(newname)+1 > sizeof(ipt_chainlabel)) {
142567088e73ce7707229c56987868f112051defca5aRusty Russell		errno = EINVAL;
1426d73af64b9d28a5b0309104232c848e8ca8ab6956Jan Engelhardt		return 0;
142767088e73ce7707229c56987868f112051defca5aRusty Russell	}
142867088e73ce7707229c56987868f112051defca5aRusty Russell
142967088e73ce7707229c56987868f112051defca5aRusty Russell	/* Need label index: preceeds chain start */
143067088e73ce7707229c56987868f112051defca5aRusty Russell	labelidx = entry2index(*handle, get_entry(*handle, chainoff)) - 1;
143167088e73ce7707229c56987868f112051defca5aRusty Russell	labeloff = index2offset(*handle, labelidx);
1432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1433aae69bed019826ddec93f761514652a93d871e49Harald Welte	t = (struct ipt_error_target *)
143479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		ipt_get_target(get_entry(*handle, labeloff));
14350113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(t->error, 0, sizeof(t->error));
1437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(t->error, newname);
1438fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	set_changed(*handle);
1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1440664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	CHECK(*handle);
1441aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1444fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt/* Sets the policy on a built-in chain. */
1445aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1446aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_set_policy(const ipt_chainlabel chain,
1447aae69bed019826ddec93f761514652a93d871e49Harald Welte		const ipt_chainlabel policy,
1448aae69bed019826ddec93f761514652a93d871e49Harald Welte		iptc_handle_t *handle)
1449aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1450aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int hook;
1451aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int policyoff;
1452aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_entry *e;
1453aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct ipt_standard_target *t;
1454e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
145530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	CHECK(*handle);
1456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptc_fn = iptc_set_policy;
14571c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	/* Figure out which chain. */
1458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	hook = iptc_builtin(chain, *handle);
14591c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	if (hook == 0) {
1460aae69bed019826ddec93f761514652a93d871e49Harald Welte		errno = ENOENT;
1461aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1462aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else
1463aae69bed019826ddec93f761514652a93d871e49Harald Welte		hook--;
1464aae69bed019826ddec93f761514652a93d871e49Harald Welte
14651c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
1466aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (policyoff != (*handle)->info.underflow[hook]) {
14670113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
1468aae69bed019826ddec93f761514652a93d871e49Harald Welte		       chain, policyoff, (*handle)->info.underflow[hook]);
14690113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		return 0;
14701c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	}
14711c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
147230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	e = get_entry(*handle, policyoff);
1473aae69bed019826ddec93f761514652a93d871e49Harald Welte	t = (struct ipt_standard_target *)ipt_get_target(e);
1474aae69bed019826ddec93f761514652a93d871e49Harald Welte
147530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	if (strcmp(policy, IPTC_LABEL_ACCEPT) == 0)
147630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		t->verdict = -NF_ACCEPT - 1;
147730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	else if (strcmp(policy, IPTC_LABEL_DROP) == 0)
147830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		t->verdict = -NF_DROP - 1;
14791c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	else {
148030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = EINVAL;
14811c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		return 0;
1482aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1483aae69bed019826ddec93f761514652a93d871e49Harald Welte	(*handle)->counter_map[entry2index(*handle, e)]
148430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		= ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
1485aae69bed019826ddec93f761514652a93d871e49Harald Welte	set_changed(*handle);
1486aae69bed019826ddec93f761514652a93d871e49Harald Welte
148730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	CHECK(*handle);
1488aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
148930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
14901c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
1491aae69bed019826ddec93f761514652a93d871e49Harald Welte/* Without this, on gcc 2.7.2.3, we get:
1492aae69bed019826ddec93f761514652a93d871e49Harald Welte   libiptc.c: In function `iptc_commit':
1493aae69bed019826ddec93f761514652a93d871e49Harald Welte   libiptc.c:833: fixed or forbidden register was spilled.
149430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell   This may be due to a compiler bug or to impossible asm
149530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell   statements or clauses.
149630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell*/
149779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void
14981c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardtsubtract_counters(struct ipt_counters *answer,
149930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		  const struct ipt_counters *a,
1500aae69bed019826ddec93f761514652a93d871e49Harald Welte		  const struct ipt_counters *b)
1501aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1502aae69bed019826ddec93f761514652a93d871e49Harald Welte	answer->pcnt = a->pcnt - b->pcnt;
1503aae69bed019826ddec93f761514652a93d871e49Harald Welte	answer->bcnt = a->bcnt - b->bcnt;
150430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}
1505aae69bed019826ddec93f761514652a93d871e49Harald Welte
1506aae69bed019826ddec93f761514652a93d871e49Harald Welteint
15071c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardtiptc_commit(iptc_handle_t *handle)
150830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{
150930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Replace, then map back the counters. */
151030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	struct ipt_replace *repl;
1511e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_counters_info *newcounters;
1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
151330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	size_t counterlen
1514aae69bed019826ddec93f761514652a93d871e49Harald Welte		= sizeof(struct ipt_counters_info)
1515aae69bed019826ddec93f761514652a93d871e49Harald Welte		+ sizeof(struct ipt_counters) * (*handle)->new_number;
151630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell
1517aae69bed019826ddec93f761514652a93d871e49Harald Welte	CHECK(*handle);
1518aae69bed019826ddec93f761514652a93d871e49Harald Welte#if 0
1519aae69bed019826ddec93f761514652a93d871e49Harald Welte	dump_entries(*handle);
15201c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt#endif
1521aae69bed019826ddec93f761514652a93d871e49Harald Welte
152230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	/* Don't commit if nothing changed. */
1523aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!(*handle)->changed)
1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		goto finished;
1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
152630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	repl = malloc(sizeof(*repl) + (*handle)->entries.size);
152779dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	if (!repl) {
15281c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		errno = ENOMEM;
152930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		return 0;
1530aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1531aae69bed019826ddec93f761514652a93d871e49Harald Welte
1532664c0a30b7963040da2e7a7e86dc56a0f1a829b5Derrik Pates	/* These are the old counters we will get from kernel */
15331c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	repl->counters = malloc(sizeof(struct ipt_counters)
1534aae69bed019826ddec93f761514652a93d871e49Harald Welte				* (*handle)->info.num_entries);
15351c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	if (!repl->counters) {
1536aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
153730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell		errno = ENOMEM;
1538aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1539aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
15401c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
1541aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* These are the counters we're going to put back, later. */
154230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	newcounters = malloc(counterlen);
1543aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (!newcounters) {
1544aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl->counters);
1545aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
15461c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		errno = ENOMEM;
1547aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
15481c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	}
15491c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
1550aae69bed019826ddec93f761514652a93d871e49Harald Welte	strcpy(repl->name, (*handle)->info.name);
1551aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->num_entries = (*handle)->new_number;
1552aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->size = (*handle)->entries.size;
1553aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(repl->hook_entry, (*handle)->info.hook_entry,
15541c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	       sizeof(repl->hook_entry));
1555aae69bed019826ddec93f761514652a93d871e49Harald Welte	memcpy(repl->underflow, (*handle)->info.underflow,
1556aae69bed019826ddec93f761514652a93d871e49Harald Welte	       sizeof(repl->underflow));
1557aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->num_counters = (*handle)->info.num_entries;
1558aae69bed019826ddec93f761514652a93d871e49Harald Welte	repl->valid_hooks = (*handle)->info.valid_hooks;
155930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	memcpy(repl->entries, (*handle)->entries.entries,
156030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell	       (*handle)->entries.size);
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
156233690a1aec0b6309ff90066ca56285b6e43013f2Jan Engelhardt	if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_REPLACE, repl,
15631c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		       sizeof(*repl) + (*handle)->entries.size) < 0) {
1564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		free(repl->counters);
1565aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
1566aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(newcounters);
15671c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		return 0;
1568aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
15691c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
1570aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Put counters back. */
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(newcounters->name, (*handle)->info.name);
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	newcounters->num_counters = (*handle)->new_number;
1573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < (*handle)->new_number; i++) {
1574aae69bed019826ddec93f761514652a93d871e49Harald Welte		unsigned int mappos = (*handle)->counter_map[i].mappos;
1575aae69bed019826ddec93f761514652a93d871e49Harald Welte		switch ((*handle)->counter_map[i].maptype) {
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_NOMAP:
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			newcounters->counters[i]
157833690a1aec0b6309ff90066ca56285b6e43013f2Jan Engelhardt				= ((struct ipt_counters){ 0, 0 });
15791c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt			break;
1580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1581aae69bed019826ddec93f761514652a93d871e49Harald Welte		case COUNTER_MAP_NORMAL_MAP:
1582aae69bed019826ddec93f761514652a93d871e49Harald Welte			/* Original read: X.
1583aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * Atomic read on replacement: X + Y.
1584aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * Currently in kernel: Z.
1585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Want in kernel: X + Y + Z.
15861c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt			 * => Add in X + Y
1587aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * => Add in replacement read.
15881c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt			 */
1589aae69bed019826ddec93f761514652a93d871e49Harald Welte			newcounters->counters[i] = repl->counters[mappos];
1590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case COUNTER_MAP_ZEROED:
1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Original read: X.
1594aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * Atomic read on replacement: X + Y.
1595aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * Currently in kernel: Z.
1596aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * Want in kernel: Y + Z.
1597aae69bed019826ddec93f761514652a93d871e49Harald Welte			 * => Add in Y.
1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * => Add in (replacement read - original read).
1599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1600aae69bed019826ddec93f761514652a93d871e49Harald Welte			subtract_counters(&newcounters->counters[i],
160133690a1aec0b6309ff90066ca56285b6e43013f2Jan Engelhardt					  &repl->counters[mappos],
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					  &index2entry(*handle, i)->counters);
1603aae69bed019826ddec93f761514652a93d871e49Harald Welte			break;
1604aae69bed019826ddec93f761514652a93d871e49Harald Welte		}
160579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	}
1606aae69bed019826ddec93f761514652a93d871e49Harald Welte
1607aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_ADD_COUNTERS,
160879dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	       newcounters, counterlen) < 0) {
1609aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl->counters);
1610aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(repl);
1611aae69bed019826ddec93f761514652a93d871e49Harald Welte		free(newcounters);
1612aae69bed019826ddec93f761514652a93d871e49Harald Welte		return 0;
1613aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
1614aae69bed019826ddec93f761514652a93d871e49Harald Welte
1615aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(repl->counters);
1616aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(repl);
1617aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(newcounters);
1618aae69bed019826ddec93f761514652a93d871e49Harald Welte
1619aae69bed019826ddec93f761514652a93d871e49Harald Welte finished:
1620aae69bed019826ddec93f761514652a93d871e49Harald Welte	free(*handle);
1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = NULL;
1622aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1623aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */
1626aae69bed019826ddec93f761514652a93d871e49Harald Welteint
1627aae69bed019826ddec93f761514652a93d871e49Harald Welteiptc_get_raw_socket()
16281c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt{
1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return sockfd;
1630aae69bed019826ddec93f761514652a93d871e49Harald Welte}
1631e45c71321e77735a1d66b180f8a29bea33aeb1b0Rusty Russell
1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */
1633aae69bed019826ddec93f761514652a93d871e49Harald Welteconst char *
16340113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welteiptc_strerror(int err)
1635aae69bed019826ddec93f761514652a93d871e49Harald Welte{
1636aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i;
1637aae69bed019826ddec93f761514652a93d871e49Harald Welte	struct table_struct {
1638aae69bed019826ddec93f761514652a93d871e49Harald Welte		void *fn;
1639aae69bed019826ddec93f761514652a93d871e49Harald Welte		int err;
1640aae69bed019826ddec93f761514652a93d871e49Harald Welte		const char *message;
1641aae69bed019826ddec93f761514652a93d871e49Harald Welte	} table [] =
1642aae69bed019826ddec93f761514652a93d871e49Harald Welte	  { { NULL, 0, "Incompatible with this kernel" },
1643aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
1644aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { NULL, ENOSYS, "Will be implemented real soon.  I promise." },
1645aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { NULL, ENOMEM, "Memory allocation problem" },
1646aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_init, EPERM, "Permission denied (you must be root)" },
1647aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_init, EINVAL, "Module is wrong version" },
1648aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_delete_chain, ENOTEMPTY, "Chain is not empty" },
1649aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_delete_chain, EINVAL, "Can't delete built-in chain" },
1650aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_delete_chain, EMLINK,
1651aae69bed019826ddec93f761514652a93d871e49Harald Welte	      "Can't delete chain with references left" },
16520113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    { iptc_create_chain, EEXIST, "Chain already exists" },
1653aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_insert_entry, E2BIG, "Index of insertion too big" },
1654aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_replace_entry, E2BIG, "Index of replacement too big" },
1655aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_delete_num_entry, E2BIG, "Index of deletion too big" },
1656aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_insert_entry, ELOOP, "Loop found in table" },
1657fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt	    { iptc_insert_entry, EINVAL, "Target problem" },
1658aae69bed019826ddec93f761514652a93d871e49Harald Welte	    /* EINVAL for CHECK probably means bad interface. */
1659aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_check_packet, EINVAL,
1660aae69bed019826ddec93f761514652a93d871e49Harald Welte	      "Bad arguments (does that interface exist?)" },
1661aae69bed019826ddec93f761514652a93d871e49Harald Welte	    /* ENOENT for DELETE probably means no matching rule */
16620113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    { iptc_delete_entry, ENOENT,
1663aae69bed019826ddec93f761514652a93d871e49Harald Welte	      "Bad rule (does a matching rule exist in that chain?)" },
1664aae69bed019826ddec93f761514652a93d871e49Harald Welte	    { iptc_set_policy, ENOENT,
1665aae69bed019826ddec93f761514652a93d871e49Harald Welte	      "Bad built-in chain name" },
1666b0f3d2d7261be3fe256a66abcc237241fea43a02Martin Josefsson	    { iptc_set_policy, EINVAL,
16670113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	      "Bad policy name" },
16680113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	    { NULL, ENOENT, "No extended target/match by that name" }
1669aae69bed019826ddec93f761514652a93d871e49Harald Welte	  };
16700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
16710113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1672aae69bed019826ddec93f761514652a93d871e49Harald Welte		if ((!table[i].fn || table[i].fn == iptc_fn)
1673aae69bed019826ddec93f761514652a93d871e49Harald Welte		    && table[i].err == err)
1674aae69bed019826ddec93f761514652a93d871e49Harald Welte			return table[i].message;
1675aae69bed019826ddec93f761514652a93d871e49Harald Welte	}
16761c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
16770113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return strerror(err);
1678aae69bed019826ddec93f761514652a93d871e49Harald Welte}
16790113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1680aae69bed019826ddec93f761514652a93d871e49Harald Welte/***************************** DEBUGGING ********************************/
1681fbc85236a6140918ab1d0fb0e07e2d72da46ce45Harald Weltestatic inline int
1682aae69bed019826ddec93f761514652a93d871e49Harald Welteunconditional(const struct ipt_ip *ip)
16830113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte{
16841c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	unsigned int i;
1685aae69bed019826ddec93f761514652a93d871e49Harald Welte
1686aae69bed019826ddec93f761514652a93d871e49Harald Welte	for (i = 0; i < sizeof(*ip)/sizeof(u_int32_t); i++)
1687aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (((u_int32_t *)ip)[i])
16880113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte			return 0;
16890113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1690aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 1;
1691aae69bed019826ddec93f761514652a93d871e49Harald Welte}
16920113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1693aae69bed019826ddec93f761514652a93d871e49Harald Weltestatic inline int
16940113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Weltecheck_match(const struct ipt_entry_match *m, unsigned int *off)
1695aae69bed019826ddec93f761514652a93d871e49Harald Welte{
16960113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	assert(m->match_size >= sizeof(struct ipt_entry_match));
1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*off) += m->match_size;
1699aae69bed019826ddec93f761514652a93d871e49Harald Welte	return 0;
1700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1701aae69bed019826ddec93f761514652a93d871e49Harald Welte
170279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic inline int
1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off,
170479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	    unsigned int user_offset, int *was_return,
1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    iptc_handle_t h)
170667088e73ce7707229c56987868f112051defca5aRusty Russell{
17078c700900e2a0cf87d7917cb62578583a60ad1210Philip Blundell	unsigned int toff;
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_standard_target *t;
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(e->target_offset >= sizeof(struct ipt_entry));
1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(e->next_offset >= e->target_offset
171279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	       + sizeof(struct ipt_entry_target));
171379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	toff = sizeof(struct ipt_entry);
1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_MATCH_ITERATE(e, check_match, &toff);
1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1716aae69bed019826ddec93f761514652a93d871e49Harald Welte	assert(toff == e->target_offset);
1717aae69bed019826ddec93f761514652a93d871e49Harald Welte
1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = (struct ipt_standard_target *)
1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ipt_get_target((struct ipt_entry *)e);
17207e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell	assert(t->target.target_size == e->next_offset - e->target_offset);
1721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(!iptc_is_chain(t->target.u.name, h));
1722fd1873110f8e57be578df17fc9d03536b10f4f73Jan Engelhardt
1723aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0) {
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->target.target_size
1725aae69bed019826ddec93f761514652a93d871e49Harald Welte		       == IPT_ALIGN(sizeof(struct ipt_standard_target)));
17260113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(t->verdict == -NF_DROP-1
1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       || t->verdict == -NF_ACCEPT-1
1729aae69bed019826ddec93f761514652a93d871e49Harald Welte		       || t->verdict == IPT_RETURN
1730aae69bed019826ddec93f761514652a93d871e49Harald Welte		       || t->verdict < (int)h->entries.size);
1731aae69bed019826ddec93f761514652a93d871e49Harald Welte
1732aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (t->verdict >= 0) {
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			struct ipt_entry *te = get_entry(h, t->verdict);
173479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			int idx;
1735aae69bed019826ddec93f761514652a93d871e49Harald Welte
173679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			idx = entry2index(h, te);
1737aae69bed019826ddec93f761514652a93d871e49Harald Welte			assert(strcmp(ipt_get_target(te)->u.name,
173867088e73ce7707229c56987868f112051defca5aRusty Russell				      IPT_ERROR_TARGET)
1739aae69bed019826ddec93f761514652a93d871e49Harald Welte			       != 0);
174079dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			assert(te != e);
1741aae69bed019826ddec93f761514652a93d871e49Harald Welte
174279dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell			/* Prior node must be error node, or this node. */
1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(t->verdict == entry2offset(h, e)+e->next_offset
1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       || strcmp(ipt_get_target(index2entry(h, idx-1))
1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					 ->u.name, IPT_ERROR_TARGET)
1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       == 0);
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1748aae69bed019826ddec93f761514652a93d871e49Harald Welte
1749aae69bed019826ddec93f761514652a93d871e49Harald Welte		if (t->verdict == IPT_RETURN
1750aae69bed019826ddec93f761514652a93d871e49Harald Welte		    && unconditional(&e->ip)
1751aae69bed019826ddec93f761514652a93d871e49Harald Welte		    && e->target_offset == sizeof(*e))
1752aae69bed019826ddec93f761514652a93d871e49Harald Welte			*was_return = 1;
1753aae69bed019826ddec93f761514652a93d871e49Harald Welte		else
1754aae69bed019826ddec93f761514652a93d871e49Harald Welte			*was_return = 0;
1755aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if (strcmp(t->target.u.name, IPT_ERROR_TARGET) == 0) {
1756aae69bed019826ddec93f761514652a93d871e49Harald Welte		assert(t->target.target_size
1757aae69bed019826ddec93f761514652a93d871e49Harald Welte		       == IPT_ALIGN(sizeof(struct ipt_error_target)));
1758aae69bed019826ddec93f761514652a93d871e49Harald Welte
1759aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* If this is in user area, previous must have been return */
1760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (*off > user_offset)
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			assert(*was_return);
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
17633aef54dce4f9bbe0b466478fd33a1d3131efbbb8Rusty Russell		*was_return = 0;
1764228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	}
1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else *was_return = 0;
17663aef54dce4f9bbe0b466478fd33a1d3131efbbb8Rusty Russell
1767733e54b8250576d6a1e0ab5621ef5b144abdf018Rusty Russell	if (*off == user_offset)
1768aae69bed019826ddec93f761514652a93d871e49Harald Welte		assert(strcmp(t->target.u.name, IPT_ERROR_TARGET) == 0);
1769aae69bed019826ddec93f761514652a93d871e49Harald Welte
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*off) += e->next_offset;
1771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	(*i)++;
17720113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	return 0;
1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
177479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
177579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell/* Do every conceivable sanity check on the handle */
177679dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russellstatic void
17771c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardtdo_check(iptc_handle_t h, unsigned int line)
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1779aae69bed019826ddec93f761514652a93d871e49Harald Welte	unsigned int i, n;
1780eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	unsigned int user_offset; /* Offset of first user chain */
1781eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson	int was_return;
1782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
178379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	assert(h->changed == 0 || h->changed == 1);
1784aae69bed019826ddec93f761514652a93d871e49Harald Welte	if (strcmp(h->info.name, "filter") == 0) {
17851c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		assert(h->info.valid_hooks
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		       == (1 << NF_IP_LOCAL_IN
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_FORWARD
1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   | 1 << NF_IP_LOCAL_OUT));
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1790eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		/* Hooks should be first three */
1791eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0);
1792eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson
1793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n += get_entry(h, n)->next_offset;
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_FORWARD] == n);
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1797631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		n = get_chain_end(h, n);
1798631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		n += get_entry(h, n)->next_offset;
1799631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1800631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson
1801eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1802a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson	} else if (strcmp(h->info.name, "nat") == 0) {
1803631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		assert(h->info.valid_hooks
1804a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson		       == (1 << NF_IP_PRE_ROUTING
1805a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson			   | 1 << NF_IP_POST_ROUTING
1806a5616dcfafd33fa46a03a8c270e5e09b2fba7cb1Martin Josefsson			   | 1 << NF_IP_LOCAL_OUT));
1807631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson
1808631f3619b7fb597f5e1c8f61c7178d64be7c144fMartin Josefsson		assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
1809eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson
1810aae69bed019826ddec93f761514652a93d871e49Harald Welte		n = get_chain_end(h, 0);
1811aae69bed019826ddec93f761514652a93d871e49Harald Welte		n += get_entry(h, n)->next_offset;
1812aae69bed019826ddec93f761514652a93d871e49Harald Welte		assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n);
1813aae69bed019826ddec93f761514652a93d871e49Harald Welte
1814aae69bed019826ddec93f761514652a93d871e49Harald Welte		n = get_chain_end(h, n);
1815aae69bed019826ddec93f761514652a93d871e49Harald Welte		n += get_entry(h, n)->next_offset;
1816aae69bed019826ddec93f761514652a93d871e49Harald Welte		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1817aae69bed019826ddec93f761514652a93d871e49Harald Welte
18181c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1819aae69bed019826ddec93f761514652a93d871e49Harald Welte	} else if (strcmp(h->info.name, "mangle") == 0) {
18200113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		assert(h->info.valid_hooks
1821aae69bed019826ddec93f761514652a93d871e49Harald Welte		       == (1 << NF_IP_PRE_ROUTING
1822aae69bed019826ddec93f761514652a93d871e49Harald Welte			   | 1 << NF_IP_LOCAL_OUT));
1823eb066cc4fb75a616400eaf38dfa31c052c76cf5cMartin Josefsson
1824aae69bed019826ddec93f761514652a93d871e49Harald Welte		/* Hooks should be first three */
1825aae69bed019826ddec93f761514652a93d871e49Harald Welte		assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0);
18261c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt
1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		n = get_chain_end(h, 0);
1828aae69bed019826ddec93f761514652a93d871e49Harald Welte		n += get_entry(h, n)->next_offset;
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n);
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT];
1832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
183379dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		abort();
183479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell
183579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	/* User chain == end of last builtin + policy entry */
18361c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	user_offset = get_chain_end(h, user_offset);
1837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	user_offset += get_entry(h, user_offset)->next_offset;
1838aae69bed019826ddec93f761514652a93d871e49Harald Welte
1839aae69bed019826ddec93f761514652a93d871e49Harald Welte	/* Overflows should be end of entry chains, and unconditional
1840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           policy nodes. */
184179dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct ipt_entry *e;
18431c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt		struct ipt_standard_target *t;
1844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!(h->info.valid_hooks & (1 << i)))
1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			continue;
1847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(h->info.underflow[i]
18480f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		       == get_chain_end(h, h->info.hook_entry[i]));
1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		e = get_entry(h, get_chain_end(h, h->info.hook_entry[i]));
1851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(unconditional(&e->ip));
1852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		assert(e->target_offset == sizeof(*e));
18530f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		assert(e->next_offset == sizeof(*e) + sizeof(*t));
18540f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		t = (struct ipt_standard_target *)ipt_get_target(e);
18550f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson
18560f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		assert(strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0);
18570f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1);
18580f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson
18590f9b8b158bb71b96c6b2908f5bf7bb9670ff4eb0Martin Josefsson		/* Hooks and underflows must be valid entries */
1860aae69bed019826ddec93f761514652a93d871e49Harald Welte		entry2index(h, get_entry(h, h->info.hook_entry[i]));
1861aae69bed019826ddec93f761514652a93d871e49Harald Welte		entry2index(h, get_entry(h, h->info.underflow[i]));
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1863aae69bed019826ddec93f761514652a93d871e49Harald Welte
1864aae69bed019826ddec93f761514652a93d871e49Harald Welte	assert(h->info.size
1865aae69bed019826ddec93f761514652a93d871e49Harald Welte	       >= h->info.num_entries * (sizeof(struct ipt_entry)
1866aae69bed019826ddec93f761514652a93d871e49Harald Welte					 +sizeof(struct ipt_standard_target)));
1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
18681c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	assert(h->entries.size
1869aae69bed019826ddec93f761514652a93d871e49Harald Welte	       >= (h->new_number
18700113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte		   * (sizeof(struct ipt_entry)
1871aae69bed019826ddec93f761514652a93d871e49Harald Welte		      + sizeof(struct ipt_standard_target))));
1872aae69bed019826ddec93f761514652a93d871e49Harald Welte	assert(strcmp(h->info.name, h->entries.name) == 0);
1873aae69bed019826ddec93f761514652a93d871e49Harald Welte
1874aae69bed019826ddec93f761514652a93d871e49Harald Welte	i = 0; n = 0;
18750113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	was_return = 0;
18761c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt	/* Check all the entries. */
1877aae69bed019826ddec93f761514652a93d871e49Harald Welte	IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size,
1878aae69bed019826ddec93f761514652a93d871e49Harald Welte			  check_entry, &i, &n, user_offset, &was_return, h);
1879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	assert(i == h->new_number);
18810113fe75ff05e09e6f3d251534d9ae32e9aa717cHarald Welte	assert(n == h->entries.size);
1882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Final entry must be error node */
188479dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell	assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1))->u.name,
188579dee0702b18c8ea1d1f7a2b1f6b29349466986bRusty Russell		      IPT_ERROR_TARGET) == 0);
18861c9015b2cb483678f153121255e10ec0bbfde3e6Jan Engelhardt}
1887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher