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