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