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