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