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