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