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