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