use library constructor instead of obsolete _init
[iptables.git] / libiptc2 / libiptc.cvs.c
1 /* Library which manipulates firewall rules.  Version $Revision: 1.40 $ */
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                                 if (i+1 >= h->cache_num_chains)
483                                         continue;
484                                 start = &h->cache_chain_heads[i+1];
485                                 size = (h->cache_num_chains-i)
486                                         * sizeof(struct chain_cache);
487                                 memmove(cc, start, size);
488
489                                 /* iterate over same index again, since
490                                  * it is now a different chain */
491                                 i--;
492                                 continue;
493                         }
494                 }
495
496                 if (cc->start_off > offset)
497                         cc->start_off += delta;
498
499                 if (cc->end_off >= offset)
500                         cc->end_off += delta;
501         }
502         /* HW_FIXME: sorting might be needed, but just in case a new chain was
503          * added */
504
505         return 1;
506 }
507
508 static int
509 add_chain_cache(TC_HANDLE_T h, const char *name, unsigned int start_off,
510                 unsigned int end_off)
511 {
512         struct chain_cache *ccs = realloc(h->cache_chain_heads, 
513                                           (h->new_number / 2 + 4 + 1)
514                                            * sizeof(struct chain_cache));
515         struct chain_cache *newcc;
516         
517         if (!ccs)
518                 return 0;
519
520         h->cache_chain_heads = ccs;
521         newcc = &h->cache_chain_heads[h->cache_num_chains];
522         h->cache_num_chains++;
523
524         strncpy(newcc->name, name, TABLE_MAXNAMELEN-1);
525         newcc->start_off = start_off;
526         newcc->end_off = end_off;
527
528         return 1;
529 }
530
531 /* Returns cache ptr if found, otherwise NULL. */
532 static struct chain_cache *
533 find_label(const char *name, TC_HANDLE_T handle)
534 {
535         unsigned int i;
536
537         if (handle->cache_chain_heads == NULL
538             && !populate_cache(handle))
539                 return NULL;
540
541         /* FIXME: Linear search through builtins, then binary --RR */
542         for (i = 0; i < handle->cache_num_chains; i++) {
543                 if (strcmp(handle->cache_chain_heads[i].name, name) == 0)
544                         return &handle->cache_chain_heads[i];
545         }
546
547         return NULL;
548 }
549
550 /* Does this chain exist? */
551 int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
552 {
553         return find_label(chain, handle) != NULL;
554 }
555
556 /* Returns the position of the final (ie. unconditional) element. */
557 static unsigned int
558 get_chain_end(const TC_HANDLE_T handle, unsigned int start)
559 {
560         unsigned int last_off, off;
561         STRUCT_ENTRY *e;
562
563         last_off = start;
564         e = get_entry(handle, start);
565
566         /* Terminate when we meet a error label or a hook entry. */
567         for (off = start + e->next_offset;
568              off < handle->entries.size;
569              last_off = off, off += e->next_offset) {
570                 STRUCT_ENTRY_TARGET *t;
571                 unsigned int i;
572
573                 e = get_entry(handle, off);
574
575                 /* We hit an entry point. */
576                 for (i = 0; i < NUMHOOKS; i++) {
577                         if ((handle->info.valid_hooks & (1 << i))
578                             && off == handle->info.hook_entry[i])
579                                 return last_off;
580                 }
581
582                 /* We hit a user chain label */
583                 t = GET_TARGET(e);
584                 if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
585                         return last_off;
586         }
587         /* SHOULD NEVER HAPPEN */
588         fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
589                 handle->entries.size, off);
590         abort();
591 }
592
593 /* Iterator functions to run through the chains. */
594 const char *
595 TC_FIRST_CHAIN(TC_HANDLE_T *handle)
596 {
597         if ((*handle)->cache_chain_heads == NULL
598             && !populate_cache(*handle))
599                 return NULL;
600
601         (*handle)->cache_chain_iteration
602                 = &(*handle)->cache_chain_heads[0];
603
604         return (*handle)->cache_chain_iteration->name;
605 }
606
607 /* Iterator functions to run through the chains.  Returns NULL at end. */
608 const char *
609 TC_NEXT_CHAIN(TC_HANDLE_T *handle)
610 {
611         (*handle)->cache_chain_iteration++;
612
613         if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
614             == (*handle)->cache_num_chains)
615                 return NULL;
616
617         return (*handle)->cache_chain_iteration->name;
618 }
619
620 /* Get first rule in the given chain: NULL for empty chain. */
621 const STRUCT_ENTRY *
622 TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
623 {
624         struct chain_cache *c;
625
626         c = find_label(chain, *handle);
627         if (!c) {
628                 errno = ENOENT;
629                 return NULL;
630         }
631
632         /* Empty chain: single return/policy rule */
633         if (c->start_off == c->end_off)
634                 return NULL;
635
636         (*handle)->cache_rule_end = offset2entry(*handle, c->end_off);
637         return offset2entry(*handle, c->start_off);
638 }
639
640 /* Returns NULL when rules run out. */
641 const STRUCT_ENTRY *
642 TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
643 {
644         if ((void *)prev + prev->next_offset
645             == (void *)(*handle)->cache_rule_end)
646                 return NULL;
647
648         return (void *)prev + prev->next_offset;
649 }
650
651 #if 0
652 /* How many rules in this chain? */
653 unsigned int
654 TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
655 {
656         unsigned int off = 0;
657         STRUCT_ENTRY *start, *end;
658
659         CHECK(*handle);
660         if (!find_label(&off, chain, *handle)) {
661                 errno = ENOENT;
662                 return (unsigned int)-1;
663         }
664
665         start = get_entry(*handle, off);
666         end = get_entry(*handle, get_chain_end(*handle, off));
667
668         return entry2index(*handle, end) - entry2index(*handle, start);
669 }
670
671 /* Get n'th rule in this chain. */
672 const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
673                                 unsigned int n,
674                                 TC_HANDLE_T *handle)
675 {
676         unsigned int pos = 0, chainindex;
677
678         CHECK(*handle);
679         if (!find_label(&pos, chain, *handle)) {
680                 errno = ENOENT;
681                 return NULL;
682         }
683
684         chainindex = entry2index(*handle, get_entry(*handle, pos));
685
686         return index2entry(*handle, chainindex + n);
687 }
688 #endif
689
690 static const char *
691 target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
692 {
693         int spos;
694         unsigned int labelidx;
695         STRUCT_ENTRY *jumpto;
696
697         /* To avoid const warnings */
698         STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
699
700         if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
701                 return GET_TARGET(e)->u.user.name;
702
703         /* Standard target: evaluate */
704         spos = *(int *)GET_TARGET(e)->data;
705         if (spos < 0) {
706                 if (spos == RETURN)
707                         return LABEL_RETURN;
708                 else if (spos == -NF_ACCEPT-1)
709                         return LABEL_ACCEPT;
710                 else if (spos == -NF_DROP-1)
711                         return LABEL_DROP;
712                 else if (spos == -NF_QUEUE-1)
713                         return LABEL_QUEUE;
714
715                 fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
716                         entry2offset(handle, e), handle->entries.size,
717                         spos);
718                 abort();
719         }
720
721         jumpto = get_entry(handle, spos);
722
723         /* Fall through rule */
724         if (jumpto == (void *)e + e->next_offset)
725                 return "";
726
727         /* Must point to head of a chain: ie. after error rule */
728         labelidx = entry2index(handle, jumpto) - 1;
729         return get_errorlabel(handle, index2offset(handle, labelidx));
730 }
731
732 /* Returns a pointer to the target name of this position. */
733 const char *TC_GET_TARGET(const STRUCT_ENTRY *e,
734                           TC_HANDLE_T *handle)
735 {
736         return target_name(*handle, e);
737 }
738
739 /* Is this a built-in chain?  Actually returns hook + 1. */
740 int
741 TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
742 {
743         unsigned int i;
744
745         for (i = 0; i < NUMHOOKS; i++) {
746                 if ((handle->info.valid_hooks & (1 << i))
747                     && handle->hooknames[i]
748                     && strcmp(handle->hooknames[i], chain) == 0)
749                         return i+1;
750         }
751         return 0;
752 }
753
754 /* Get the policy of a given built-in chain */
755 const char *
756 TC_GET_POLICY(const char *chain,
757               STRUCT_COUNTERS *counters,
758               TC_HANDLE_T *handle)
759 {
760         unsigned int start;
761         STRUCT_ENTRY *e;
762         int hook;
763
764         hook = TC_BUILTIN(chain, *handle);
765         if (hook != 0)
766                 start = (*handle)->info.hook_entry[hook-1];
767         else
768                 return NULL;
769
770         e = get_entry(*handle, get_chain_end(*handle, start));
771         *counters = e->counters;
772
773         return target_name(*handle, e);
774 }
775
776 static inline int
777 correct_verdict(STRUCT_ENTRY *e,
778                 char *base,
779                 unsigned int offset, int delta_offset)
780 {
781         STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
782         unsigned int curr = (char *)e - base;
783
784         /* Trap: insert of fall-through rule.  Don't change fall-through
785            verdict to jump-over-next-rule. */
786         if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0
787             && t->verdict > (int)offset
788             && !(curr == offset &&
789                  t->verdict == curr + e->next_offset)) {
790                 t->verdict += delta_offset;
791         }
792
793         return 0;
794 }
795
796 /* Adjusts standard verdict jump positions after an insertion/deletion. */
797 static int
798 set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
799 {
800         ENTRY_ITERATE((*handle)->entries.entrytable,
801                       (*handle)->entries.size,
802                       correct_verdict, (char *)(*handle)->entries.entrytable,
803                       offset, delta_offset);
804
805         set_changed(*handle);
806         return 1;
807 }
808
809 /* If prepend is set, then we are prepending to a chain: if the
810  * insertion position is an entry point, keep the entry point. */
811 static int
812 insert_rules(unsigned int num_rules, unsigned int rules_size,
813              const STRUCT_ENTRY *insert,
814              unsigned int offset, unsigned int num_rules_offset,
815              int prepend,
816              TC_HANDLE_T *handle)
817 {
818         TC_HANDLE_T newh;
819         STRUCT_GETINFO newinfo;
820         unsigned int i;
821
822         if (offset >= (*handle)->entries.size) {
823                 errno = EINVAL;
824                 return 0;
825         }
826
827         newinfo = (*handle)->info;
828
829         /* Fix up entry points. */
830         for (i = 0; i < NUMHOOKS; i++) {
831                 /* Entry points to START of chain, so keep same if
832                    inserting on at that point. */
833                 if ((*handle)->info.hook_entry[i] > offset)
834                         newinfo.hook_entry[i] += rules_size;
835
836                 /* Underflow always points to END of chain (policy),
837                    so if something is inserted at same point, it
838                    should be advanced. */
839                 if ((*handle)->info.underflow[i] >= offset)
840                         newinfo.underflow[i] += rules_size;
841         }
842
843         newh = alloc_handle((*handle)->info.name,
844                             (*handle)->entries.size + rules_size,
845                             (*handle)->new_number + num_rules);
846         if (!newh)
847                 return 0;
848         newh->info = newinfo;
849
850         /* Copy pre... */
851         memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset);
852         /* ... Insert new ... */
853         memcpy((char *)newh->entries.entrytable + offset, insert, rules_size);
854         /* ... copy post */
855         memcpy((char *)newh->entries.entrytable + offset + rules_size,
856                (char *)(*handle)->entries.entrytable + offset,
857                (*handle)->entries.size - offset);
858
859         /* Move counter map. */
860         /* Copy pre... */
861         memcpy(newh->counter_map, (*handle)->counter_map,
862                sizeof(struct counter_map) * num_rules_offset);
863         /* ... copy post */
864         memcpy(newh->counter_map + num_rules_offset + num_rules,
865                (*handle)->counter_map + num_rules_offset,
866                sizeof(struct counter_map) * ((*handle)->new_number
867                                              - num_rules_offset));
868         /* Set intermediates to no counter copy */
869         for (i = 0; i < num_rules; i++)
870                 newh->counter_map[num_rules_offset+i]
871                         = ((struct counter_map){ COUNTER_MAP_SET, 0 });
872
873         newh->new_number = (*handle)->new_number + num_rules;
874         newh->entries.size = (*handle)->entries.size + rules_size;
875         newh->hooknames = (*handle)->hooknames;
876
877         newh->cache_chain_heads = (*handle)->cache_chain_heads;
878         newh->cache_num_builtins = (*handle)->cache_num_builtins;
879         newh->cache_num_chains = (*handle)->cache_num_chains;
880         newh->cache_rule_end = (*handle)->cache_rule_end;
881         newh->cache_chain_iteration = (*handle)->cache_chain_iteration;
882         if (!correct_cache(newh, offset, rules_size)) {
883                 free(newh);
884                 return 0;
885         }
886
887         free(*handle);
888         *handle = newh;
889
890         return set_verdict(offset, rules_size, handle);
891 }
892
893 static int
894 delete_rules(unsigned int num_rules, unsigned int rules_size,
895              unsigned int offset, unsigned int num_rules_offset,
896              TC_HANDLE_T *handle)
897 {
898         unsigned int i;
899
900         if (offset + rules_size > (*handle)->entries.size) {
901                 errno = EINVAL;
902                 return 0;
903         }
904
905         /* Fix up entry points. */
906         for (i = 0; i < NUMHOOKS; i++) {
907                 /* In practice, we never delete up to a hook entry,
908                    since the built-in chains are always first,
909                    so these two are never equal */
910                 if ((*handle)->info.hook_entry[i] >= offset + rules_size)
911                         (*handle)->info.hook_entry[i] -= rules_size;
912                 else if ((*handle)->info.hook_entry[i] > offset) {
913                         fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
914                                 i, (*handle)->info.hook_entry[i], offset);
915                         abort();
916                 }
917
918                 /* Underflow points to policy (terminal) rule in
919                    built-in, so sequality is valid here (when deleting
920                    the last rule). */
921                 if ((*handle)->info.underflow[i] >= offset + rules_size)
922                         (*handle)->info.underflow[i] -= rules_size;
923                 else if ((*handle)->info.underflow[i] > offset) {
924                         fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
925                                 i, (*handle)->info.underflow[i], offset);
926                         abort();
927                 }
928         }
929
930         /* Move the rules down. */
931         memmove((char *)(*handle)->entries.entrytable + offset,
932                 (char *)(*handle)->entries.entrytable + offset + rules_size,
933                 (*handle)->entries.size - (offset + rules_size));
934
935         /* Move the counter map down. */
936         memmove(&(*handle)->counter_map[num_rules_offset],
937                 &(*handle)->counter_map[num_rules_offset + num_rules],
938                 sizeof(struct counter_map)
939                 * ((*handle)->new_number - (num_rules + num_rules_offset)));
940
941         /* Fix numbers */
942         (*handle)->new_number -= num_rules;
943         (*handle)->entries.size -= rules_size;
944
945         /* Fix the chain cache */
946         if (!correct_cache(*handle, offset, -(int)rules_size))
947                 return 0;
948
949         return set_verdict(offset, -(int)rules_size, handle);
950 }
951
952 static int
953 standard_map(STRUCT_ENTRY *e, int verdict)
954 {
955         STRUCT_STANDARD_TARGET *t;
956
957         t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
958
959         if (t->target.u.target_size
960             != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
961                 errno = EINVAL;
962                 return 0;
963         }
964         /* memset for memcmp convenience on delete/replace */
965         memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
966         strcpy(t->target.u.user.name, STANDARD_TARGET);
967         t->verdict = verdict;
968
969         return 1;
970 }
971
972 static int
973 map_target(const TC_HANDLE_T handle,
974            STRUCT_ENTRY *e,
975            unsigned int offset,
976            STRUCT_ENTRY_TARGET *old)
977 {
978         STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
979
980         /* Save old target (except data, which we don't change, except for
981            standard case, where we don't care). */
982         *old = *t;
983
984         /* Maybe it's empty (=> fall through) */
985         if (strcmp(t->u.user.name, "") == 0)
986                 return standard_map(e, offset + e->next_offset);
987         /* Maybe it's a standard target name... */
988         else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
989                 return standard_map(e, -NF_ACCEPT - 1);
990         else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
991                 return standard_map(e, -NF_DROP - 1);
992         else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
993                 return standard_map(e, -NF_QUEUE - 1);
994         else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
995                 return standard_map(e, RETURN);
996         else if (TC_BUILTIN(t->u.user.name, handle)) {
997                 /* Can't jump to builtins. */
998                 errno = EINVAL;
999                 return 0;
1000         } else {
1001                 /* Maybe it's an existing chain name. */
1002                 struct chain_cache *c;
1003
1004                 c = find_label(t->u.user.name, handle);
1005                 if (c)
1006                         return standard_map(e, c->start_off);
1007         }
1008
1009         /* Must be a module?  If not, kernel will reject... */
1010         /* memset to all 0 for your memcmp convenience. */
1011         memset(t->u.user.name + strlen(t->u.user.name),
1012                0,
1013                FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
1014         return 1;
1015 }
1016
1017 static void
1018 unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
1019 {
1020         STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1021
1022         /* Save old target (except data, which we don't change, except for
1023            standard case, where we don't care). */
1024         *t = *old;
1025 }
1026
1027 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1028 int
1029 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
1030                 const STRUCT_ENTRY *e,
1031                 unsigned int rulenum,
1032                 TC_HANDLE_T *handle)
1033 {
1034         unsigned int chainindex, offset;
1035         STRUCT_ENTRY_TARGET old;
1036         struct chain_cache *c;
1037         STRUCT_ENTRY *tmp;
1038         int ret;
1039
1040         iptc_fn = TC_INSERT_ENTRY;
1041         if (!(c = find_label(chain, *handle))) {
1042                 errno = ENOENT;
1043                 return 0;
1044         }
1045
1046         chainindex = offset2index(*handle, c->start_off);
1047
1048         tmp = index2entry(*handle, chainindex + rulenum);
1049         if (!tmp || tmp > offset2entry(*handle, c->end_off)) {
1050                 errno = E2BIG;
1051                 return 0;
1052         }
1053         offset = index2offset(*handle, chainindex + rulenum);
1054
1055         /* Mapping target actually alters entry, but that's
1056            transparent to the caller. */
1057         if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
1058                 return 0;
1059
1060         ret = insert_rules(1, e->next_offset, e, offset,
1061                            chainindex + rulenum, rulenum == 0, handle);
1062         unmap_target((STRUCT_ENTRY *)e, &old);
1063         return ret;
1064 }
1065
1066 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
1067 int
1068 TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
1069                  const STRUCT_ENTRY *e,
1070                  unsigned int rulenum,
1071                  TC_HANDLE_T *handle)
1072 {
1073         unsigned int chainindex, offset;
1074         STRUCT_ENTRY_TARGET old;
1075         struct chain_cache *c;
1076         STRUCT_ENTRY *tmp;
1077         int ret;
1078
1079         iptc_fn = TC_REPLACE_ENTRY;
1080
1081         if (!(c = find_label(chain, *handle))) {
1082                 errno = ENOENT;
1083                 return 0;
1084         }
1085
1086         chainindex = offset2index(*handle, c->start_off);
1087
1088         tmp = index2entry(*handle, chainindex + rulenum);
1089         if (!tmp || tmp >= offset2entry(*handle, c->end_off)) {
1090                 errno = E2BIG;
1091                 return 0;
1092         }
1093
1094         offset = index2offset(*handle, chainindex + rulenum);
1095         /* Replace = delete and insert. */
1096         if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
1097                           offset, chainindex + rulenum, handle))
1098                 return 0;
1099
1100         if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
1101                 return 0;
1102
1103         ret = insert_rules(1, e->next_offset, e, offset,
1104                            chainindex + rulenum, 1, handle);
1105         unmap_target((STRUCT_ENTRY *)e, &old);
1106         return ret;
1107 }
1108
1109 /* Append entry `fw' to chain `chain'.  Equivalent to insert with
1110    rulenum = length of chain. */
1111 int
1112 TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
1113                 const STRUCT_ENTRY *e,
1114                 TC_HANDLE_T *handle)
1115 {
1116         struct chain_cache *c;
1117         STRUCT_ENTRY_TARGET old;
1118         int ret;
1119
1120         iptc_fn = TC_APPEND_ENTRY;
1121         if (!(c = find_label(chain, *handle))) {
1122                 errno = ENOENT;
1123                 return 0;
1124         }
1125
1126         if (!map_target(*handle, (STRUCT_ENTRY *)e,
1127                         c->end_off, &old))
1128                 return 0;
1129
1130         ret = insert_rules(1, e->next_offset, e, c->end_off, 
1131                            offset2index(*handle, c->end_off), 0, handle);
1132         unmap_target((STRUCT_ENTRY *)e, &old);
1133         return ret;
1134 }
1135
1136 static inline int
1137 match_different(const STRUCT_ENTRY_MATCH *a,
1138                 const unsigned char *a_elems,
1139                 const unsigned char *b_elems,
1140                 unsigned char **maskptr)
1141 {
1142         const STRUCT_ENTRY_MATCH *b;
1143         unsigned int i;
1144
1145         /* Offset of b is the same as a. */
1146         b = (void *)b_elems + ((unsigned char *)a - a_elems);
1147
1148         if (a->u.match_size != b->u.match_size)
1149                 return 1;
1150
1151         if (strcmp(a->u.user.name, b->u.user.name) != 0)
1152                 return 1;
1153
1154         *maskptr += ALIGN(sizeof(*a));
1155
1156         for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1157                 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1158                         return 1;
1159         *maskptr += i;
1160         return 0;
1161 }
1162
1163 static inline int
1164 target_different(const unsigned char *a_targdata,
1165                  const unsigned char *b_targdata,
1166                  unsigned int tdatasize,
1167                  const unsigned char *mask)
1168 {
1169         unsigned int i;
1170         for (i = 0; i < tdatasize; i++)
1171                 if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
1172                         return 1;
1173
1174         return 0;
1175 }
1176
1177 static int
1178 is_same(const STRUCT_ENTRY *a,
1179         const STRUCT_ENTRY *b,
1180         unsigned char *matchmask);
1181
1182 /* Delete the first rule in `chain' which matches `fw'. */
1183 int
1184 TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
1185                 const STRUCT_ENTRY *origfw,
1186                 unsigned char *matchmask,
1187                 TC_HANDLE_T *handle)
1188 {
1189         unsigned int offset;
1190         struct chain_cache *c;
1191         STRUCT_ENTRY *e, *fw;
1192
1193         iptc_fn = TC_DELETE_ENTRY;
1194         if (!(c = find_label(chain, *handle))) {
1195                 errno = ENOENT;
1196                 return 0;
1197         }
1198
1199         fw = malloc(origfw->next_offset);
1200         if (fw == NULL) {
1201                 errno = ENOMEM;
1202                 return 0;
1203         }
1204
1205         for (offset = c->start_off; offset < c->end_off;
1206              offset += e->next_offset) {
1207                 STRUCT_ENTRY_TARGET discard;
1208
1209                 memcpy(fw, origfw, origfw->next_offset);
1210
1211                 /* FIXME: handle this in is_same --RR */
1212                 if (!map_target(*handle, fw, offset, &discard)) {
1213                         free(fw);
1214                         return 0;
1215                 }
1216                 e = get_entry(*handle, offset);
1217
1218 #if 0
1219                 printf("Deleting:\n");
1220                 dump_entry(newe);
1221 #endif
1222                 if (is_same(e, fw, matchmask)) {
1223                         int ret;
1224                         ret = delete_rules(1, e->next_offset,
1225                                            offset, entry2index(*handle, e),
1226                                            handle);
1227                         free(fw);
1228                         return ret;
1229                 }
1230         }
1231
1232         free(fw);
1233         errno = ENOENT;
1234         return 0;
1235 }
1236
1237 /* Delete the rule in position `rulenum' in `chain'. */
1238 int
1239 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
1240                     unsigned int rulenum,
1241                     TC_HANDLE_T *handle)
1242 {
1243         unsigned int index;
1244         int ret;
1245         STRUCT_ENTRY *e;
1246         struct chain_cache *c;
1247
1248         iptc_fn = TC_DELETE_NUM_ENTRY;
1249         if (!(c = find_label(chain, *handle))) {
1250                 errno = ENOENT;
1251                 return 0;
1252         }
1253
1254         index = offset2index(*handle, c->start_off) + rulenum;
1255
1256         if (index >= offset2index(*handle, c->end_off)) {
1257                 errno = E2BIG;
1258                 return 0;
1259         }
1260
1261         e = index2entry(*handle, index);
1262         if (e == NULL) {
1263                 errno = EINVAL;
1264                 return 0;
1265         }
1266
1267         ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
1268                            index, handle);
1269         return ret;
1270 }
1271
1272 /* Check the packet `fw' on chain `chain'.  Returns the verdict, or
1273    NULL and sets errno. */
1274 const char *
1275 TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
1276                 STRUCT_ENTRY *entry,
1277                 TC_HANDLE_T *handle)
1278 {
1279         errno = ENOSYS;
1280         return NULL;
1281 }
1282
1283 /* Flushes the entries in the given chain (ie. empties chain). */
1284 int
1285 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1286 {
1287         unsigned int startindex, endindex;
1288         STRUCT_ENTRY *startentry, *endentry;
1289         struct chain_cache *c;
1290         int ret;
1291
1292         iptc_fn = TC_FLUSH_ENTRIES;
1293         if (!(c = find_label(chain, *handle))) {
1294                 errno = ENOENT;
1295                 return 0;
1296         }
1297         startindex = offset2index(*handle, c->start_off);
1298         endindex = offset2index(*handle, c->end_off);
1299         startentry = offset2entry(*handle, c->start_off);
1300         endentry = offset2entry(*handle, c->end_off);
1301
1302         ret = delete_rules(endindex - startindex,
1303                            (char *)endentry - (char *)startentry,
1304                            c->start_off, startindex,
1305                            handle);
1306         return ret;
1307 }
1308
1309 /* Zeroes the counters in a chain. */
1310 int
1311 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1312 {
1313         unsigned int i, end;
1314         struct chain_cache *c;
1315
1316         if (!(c = find_label(chain, *handle))) {
1317                 errno = ENOENT;
1318                 return 0;
1319         }
1320
1321         i = offset2index(*handle, c->start_off);
1322         end = offset2index(*handle, c->end_off);
1323
1324         for (; i <= end; i++) {
1325                 if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
1326                         (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1327         }
1328         set_changed(*handle);
1329
1330         return 1;
1331 }
1332
1333 STRUCT_COUNTERS *
1334 TC_READ_COUNTER(const IPT_CHAINLABEL chain,
1335                 unsigned int rulenum,
1336                 TC_HANDLE_T *handle)
1337 {
1338         STRUCT_ENTRY *e;
1339         struct chain_cache *c;
1340         unsigned int chainindex, end;
1341
1342         iptc_fn = TC_READ_COUNTER;
1343         CHECK(*handle);
1344
1345         if (!(c = find_label(chain, *handle))) {
1346                 errno = ENOENT;
1347                 return NULL;
1348         }
1349
1350         chainindex = offset2index(*handle, c->start_off);
1351         end = offset2index(*handle, c->end_off);
1352
1353         if (chainindex + rulenum > end) {
1354                 errno = E2BIG;
1355                 return NULL;
1356         }
1357
1358         e = index2entry(*handle, chainindex + rulenum);
1359
1360         return &e->counters;
1361 }
1362
1363 int
1364 TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
1365                 unsigned int rulenum,
1366                 TC_HANDLE_T *handle)
1367 {
1368         STRUCT_ENTRY *e;
1369         struct chain_cache *c;
1370         unsigned int chainindex, end;
1371         
1372         iptc_fn = TC_ZERO_COUNTER;
1373         CHECK(*handle);
1374
1375         if (!(c = find_label(chain, *handle))) {
1376                 errno = ENOENT;
1377                 return 0;
1378         }
1379
1380         chainindex = offset2index(*handle, c->start_off);
1381         end = offset2index(*handle, c->end_off);
1382
1383         if (chainindex + rulenum > end) {
1384                 errno = E2BIG;
1385                 return 0;
1386         }
1387
1388         e = index2entry(*handle, chainindex + rulenum);
1389
1390         if ((*handle)->counter_map[chainindex + rulenum].maptype
1391                         == COUNTER_MAP_NORMAL_MAP) {
1392                 (*handle)->counter_map[chainindex + rulenum].maptype
1393                          = COUNTER_MAP_ZEROED;
1394         }
1395
1396         set_changed(*handle);
1397
1398         return 1;
1399 }
1400
1401 int 
1402 TC_SET_COUNTER(const IPT_CHAINLABEL chain,
1403                unsigned int rulenum,
1404                STRUCT_COUNTERS *counters,
1405                TC_HANDLE_T *handle)
1406 {
1407         STRUCT_ENTRY *e;
1408         struct chain_cache *c;
1409         unsigned int chainindex, end;
1410
1411         iptc_fn = TC_SET_COUNTER;
1412         CHECK(*handle);
1413
1414         if (!(c = find_label(chain, *handle))) {
1415                 errno = ENOENT;
1416                 return 0;
1417         }
1418
1419         chainindex = offset2index(*handle, c->start_off);
1420         end = offset2index(*handle, c->end_off);
1421
1422         if (chainindex + rulenum > end) {
1423                 errno = E2BIG;
1424                 return 0;
1425         }
1426
1427         e = index2entry(*handle, chainindex + rulenum);
1428
1429         (*handle)->counter_map[chainindex + rulenum].maptype
1430                 = COUNTER_MAP_SET;
1431
1432         memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
1433
1434         set_changed(*handle);
1435
1436         return 1;
1437 }
1438
1439 /* Creates a new chain. */
1440 /* To create a chain, create two rules: error node and unconditional
1441  * return. */
1442 int
1443 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1444 {
1445         int ret;
1446         struct {
1447                 STRUCT_ENTRY head;
1448                 struct ipt_error_target name;
1449                 STRUCT_ENTRY ret;
1450                 STRUCT_STANDARD_TARGET target;
1451         } newc;
1452         unsigned int destination;
1453
1454         iptc_fn = TC_CREATE_CHAIN;
1455
1456         /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1457            QUEUE, RETURN. */
1458         if (find_label(chain, *handle)
1459             || strcmp(chain, LABEL_DROP) == 0
1460             || strcmp(chain, LABEL_ACCEPT) == 0
1461             || strcmp(chain, LABEL_QUEUE) == 0
1462             || strcmp(chain, LABEL_RETURN) == 0) {
1463                 errno = EEXIST;
1464                 return 0;
1465         }
1466
1467         if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1468                 errno = EINVAL;
1469                 return 0;
1470         }
1471
1472         memset(&newc, 0, sizeof(newc));
1473         newc.head.target_offset = sizeof(STRUCT_ENTRY);
1474         newc.head.next_offset
1475                 = sizeof(STRUCT_ENTRY)
1476                 + ALIGN(sizeof(struct ipt_error_target));
1477         strcpy(newc.name.t.u.user.name, ERROR_TARGET);
1478         newc.name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target));
1479         strcpy(newc.name.error, chain);
1480
1481         newc.ret.target_offset = sizeof(STRUCT_ENTRY);
1482         newc.ret.next_offset
1483                 = sizeof(STRUCT_ENTRY)
1484                 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1485         strcpy(newc.target.target.u.user.name, STANDARD_TARGET);
1486         newc.target.target.u.target_size
1487                 = ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1488         newc.target.verdict = RETURN;
1489
1490         destination = index2offset(*handle, (*handle)->new_number -1);
1491
1492         /* Add just before terminal entry */
1493         ret = insert_rules(2, sizeof(newc), &newc.head,
1494                            destination,
1495                            (*handle)->new_number - 1,
1496                            0, handle);
1497
1498         set_changed(*handle);
1499
1500         /* add chain cache info for this chain */
1501         add_chain_cache(*handle, chain, 
1502                         destination+newc.head.next_offset, 
1503                         destination+newc.head.next_offset);
1504
1505         return ret;
1506 }
1507
1508 static int
1509 count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
1510 {
1511         STRUCT_STANDARD_TARGET *t;
1512
1513         if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) {
1514                 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1515
1516                 if (t->verdict == offset)
1517                         (*ref)++;
1518         }
1519
1520         return 0;
1521 }
1522
1523 /* Get the number of references to this chain. */
1524 int
1525 TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
1526                   TC_HANDLE_T *handle)
1527 {
1528         struct chain_cache *c;
1529
1530         if (!(c = find_label(chain, *handle))) {
1531                 errno = ENOENT;
1532                 return 0;
1533         }
1534
1535         *ref = 0;
1536         ENTRY_ITERATE((*handle)->entries.entrytable,
1537                       (*handle)->entries.size,
1538                       count_ref, c->start_off, ref);
1539         return 1;
1540 }
1541
1542 /* Deletes a chain. */
1543 int
1544 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1545 {
1546         unsigned int labelidx, labeloff;
1547         unsigned int references;
1548         struct chain_cache *c;
1549         int ret;
1550         STRUCT_ENTRY *start;
1551
1552         if (!TC_GET_REFERENCES(&references, chain, handle))
1553                 return 0;
1554
1555         iptc_fn = TC_DELETE_CHAIN;
1556
1557         if (TC_BUILTIN(chain, *handle)) {
1558                 errno = EINVAL;
1559                 return 0;
1560         }
1561
1562         if (references > 0) {
1563                 errno = EMLINK;
1564                 return 0;
1565         }
1566
1567         if (!(c = find_label(chain, *handle))) {
1568                 errno = ENOENT;
1569                 return 0;
1570         }
1571
1572         if (c->start_off != c->end_off) {
1573                 errno = ENOTEMPTY;
1574                 return 0;
1575         }
1576
1577         /* Need label index: preceeds chain start */
1578         labelidx = offset2index(*handle, c->start_off) - 1;
1579         labeloff = index2offset(*handle, labelidx);
1580
1581         start = offset2entry(*handle, c->start_off);
1582
1583         ret = delete_rules(2,
1584                            get_entry(*handle, labeloff)->next_offset
1585                            + start->next_offset,
1586                            labeloff, labelidx, handle);
1587         return ret;
1588 }
1589
1590 /* Renames a chain. */
1591 int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
1592                     const IPT_CHAINLABEL newname,
1593                     TC_HANDLE_T *handle)
1594 {
1595         unsigned int labeloff, labelidx;
1596         struct chain_cache *c;
1597         struct ipt_error_target *t;
1598
1599         iptc_fn = TC_RENAME_CHAIN;
1600
1601         /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1602            QUEUE, RETURN. */
1603         if (find_label(newname, *handle)
1604             || strcmp(newname, LABEL_DROP) == 0
1605             || strcmp(newname, LABEL_ACCEPT) == 0
1606             || strcmp(newname, LABEL_QUEUE) == 0
1607             || strcmp(newname, LABEL_RETURN) == 0) {
1608                 errno = EEXIST;
1609                 return 0;
1610         }
1611
1612         if (!(c = find_label(oldname, *handle))
1613             || TC_BUILTIN(oldname, *handle)) {
1614                 errno = ENOENT;
1615                 return 0;
1616         }
1617
1618         if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1619                 errno = EINVAL;
1620                 return 0;
1621         }
1622
1623         /* Need label index: preceeds chain start */
1624         labelidx = offset2index(*handle, c->start_off) - 1;
1625         labeloff = index2offset(*handle, labelidx);
1626
1627         t = (struct ipt_error_target *)
1628                 GET_TARGET(get_entry(*handle, labeloff));
1629
1630         memset(t->error, 0, sizeof(t->error));
1631         strcpy(t->error, newname);
1632
1633         /* update chain cache */
1634         memset(c->name, 0, sizeof(c->name));
1635         strcpy(c->name, newname);
1636
1637         set_changed(*handle);
1638
1639         return 1;
1640 }
1641
1642 /* Sets the policy on a built-in chain. */
1643 int
1644 TC_SET_POLICY(const IPT_CHAINLABEL chain,
1645               const IPT_CHAINLABEL policy,
1646               STRUCT_COUNTERS *counters,
1647               TC_HANDLE_T *handle)
1648 {
1649         unsigned int hook;
1650         unsigned int policyoff, ctrindex;
1651         STRUCT_ENTRY *e;
1652         STRUCT_STANDARD_TARGET *t;
1653
1654         iptc_fn = TC_SET_POLICY;
1655         /* Figure out which chain. */
1656         hook = TC_BUILTIN(chain, *handle);
1657         if (hook == 0) {
1658                 errno = ENOENT;
1659                 return 0;
1660         } else
1661                 hook--;
1662
1663         policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
1664         if (policyoff != (*handle)->info.underflow[hook]) {
1665                 printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
1666                        chain, policyoff, (*handle)->info.underflow[hook]);
1667                 return 0;
1668         }
1669
1670         e = get_entry(*handle, policyoff);
1671         t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1672
1673         if (strcmp(policy, LABEL_ACCEPT) == 0)
1674                 t->verdict = -NF_ACCEPT - 1;
1675         else if (strcmp(policy, LABEL_DROP) == 0)
1676                 t->verdict = -NF_DROP - 1;
1677         else {
1678                 errno = EINVAL;
1679                 return 0;
1680         }
1681
1682         ctrindex = entry2index(*handle, e);
1683
1684         if (counters) {
1685                 /* set byte and packet counters */
1686                 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
1687
1688                 (*handle)->counter_map[ctrindex].maptype
1689                         = COUNTER_MAP_SET;
1690
1691         } else {
1692                 (*handle)->counter_map[ctrindex]
1693                         = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
1694         }
1695
1696         set_changed(*handle);
1697
1698         return 1;
1699 }
1700
1701 /* Without this, on gcc 2.7.2.3, we get:
1702    libiptc.c: In function `TC_COMMIT':
1703    libiptc.c:833: fixed or forbidden register was spilled.
1704    This may be due to a compiler bug or to impossible asm
1705    statements or clauses.
1706 */
1707 static void
1708 subtract_counters(STRUCT_COUNTERS *answer,
1709                   const STRUCT_COUNTERS *a,
1710                   const STRUCT_COUNTERS *b)
1711 {
1712         answer->pcnt = a->pcnt - b->pcnt;
1713         answer->bcnt = a->bcnt - b->bcnt;
1714 }
1715
1716 int
1717 TC_COMMIT(TC_HANDLE_T *handle)
1718 {
1719         /* Replace, then map back the counters. */
1720         STRUCT_REPLACE *repl;
1721         STRUCT_COUNTERS_INFO *newcounters;
1722         unsigned int i;
1723         size_t counterlen;
1724
1725         CHECK(*handle);
1726
1727         counterlen = sizeof(STRUCT_COUNTERS_INFO)
1728                         + sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
1729
1730 #if 0
1731         TC_DUMP_ENTRIES(*handle);
1732 #endif
1733
1734         /* Don't commit if nothing changed. */
1735         if (!(*handle)->changed)
1736                 goto finished;
1737
1738         repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1739         if (!repl) {
1740                 errno = ENOMEM;
1741                 return 0;
1742         }
1743
1744         /* These are the old counters we will get from kernel */
1745         repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1746                                 * (*handle)->info.num_entries);
1747         if (!repl->counters) {
1748                 free(repl);
1749                 errno = ENOMEM;
1750                 return 0;
1751         }
1752
1753         /* These are the counters we're going to put back, later. */
1754         newcounters = malloc(counterlen);
1755         if (!newcounters) {
1756                 free(repl->counters);
1757                 free(repl);
1758                 errno = ENOMEM;
1759                 return 0;
1760         }
1761
1762         strcpy(repl->name, (*handle)->info.name);
1763         repl->num_entries = (*handle)->new_number;
1764         repl->size = (*handle)->entries.size;
1765         memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1766                sizeof(repl->hook_entry));
1767         memcpy(repl->underflow, (*handle)->info.underflow,
1768                sizeof(repl->underflow));
1769         repl->num_counters = (*handle)->info.num_entries;
1770         repl->valid_hooks = (*handle)->info.valid_hooks;
1771         memcpy(repl->entries, (*handle)->entries.entrytable,
1772                (*handle)->entries.size);
1773
1774         if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
1775                        sizeof(*repl) + (*handle)->entries.size) < 0) {
1776                 free(repl->counters);
1777                 free(repl);
1778                 free(newcounters);
1779                 return 0;
1780         }
1781
1782         /* Put counters back. */
1783         strcpy(newcounters->name, (*handle)->info.name);
1784         newcounters->num_counters = (*handle)->new_number;
1785         for (i = 0; i < (*handle)->new_number; i++) {
1786                 unsigned int mappos = (*handle)->counter_map[i].mappos;
1787                 switch ((*handle)->counter_map[i].maptype) {
1788                 case COUNTER_MAP_NOMAP:
1789                         newcounters->counters[i]
1790                                 = ((STRUCT_COUNTERS){ 0, 0 });
1791                         break;
1792
1793                 case COUNTER_MAP_NORMAL_MAP:
1794                         /* Original read: X.
1795                          * Atomic read on replacement: X + Y.
1796                          * Currently in kernel: Z.
1797                          * Want in kernel: X + Y + Z.
1798                          * => Add in X + Y
1799                          * => Add in replacement read.
1800                          */
1801                         newcounters->counters[i] = repl->counters[mappos];
1802                         break;
1803
1804                 case COUNTER_MAP_ZEROED:
1805                         /* Original read: X.
1806                          * Atomic read on replacement: X + Y.
1807                          * Currently in kernel: Z.
1808                          * Want in kernel: Y + Z.
1809                          * => Add in Y.
1810                          * => Add in (replacement read - original read).
1811                          */
1812                         subtract_counters(&newcounters->counters[i],
1813                                           &repl->counters[mappos],
1814                                           &index2entry(*handle, i)->counters);
1815                         break;
1816
1817                 case COUNTER_MAP_SET:
1818                         /* Want to set counter (iptables-restore) */
1819
1820                         memcpy(&newcounters->counters[i],
1821                                &index2entry(*handle, i)->counters,
1822                                sizeof(STRUCT_COUNTERS));
1823
1824                         break;
1825                 }
1826         }
1827
1828 #ifdef KERNEL_64_USERSPACE_32
1829         {
1830                 /* Kernel will think that pointer should be 64-bits, and get
1831                    padding.  So we accomodate here (assumption: alignment of
1832                    `counters' is on 64-bit boundary). */
1833                 u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
1834                 if ((unsigned long)&newcounters->counters % 8 != 0) {
1835                         fprintf(stderr,
1836                                 "counters alignment incorrect! Mail rusty!\n");
1837                         abort();
1838                 }
1839                 *kernptr = newcounters->counters;
1840         }
1841 #endif /* KERNEL_64_USERSPACE_32 */
1842
1843         if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
1844                        newcounters, counterlen) < 0) {
1845                 free(repl->counters);
1846                 free(repl);
1847                 free(newcounters);
1848                 return 0;
1849         }
1850
1851         free(repl->counters);
1852         free(repl);
1853         free(newcounters);
1854
1855  finished:
1856         TC_FREE(handle);
1857         return 1;
1858 }
1859
1860 /* Get raw socket. */
1861 int
1862 TC_GET_RAW_SOCKET()
1863 {
1864         return sockfd;
1865 }
1866
1867 /* Translates errno numbers into more human-readable form than strerror. */
1868 const char *
1869 TC_STRERROR(int err)
1870 {
1871         unsigned int i;
1872         struct table_struct {
1873                 void *fn;
1874                 int err;
1875                 const char *message;
1876         } table [] =
1877           { { TC_INIT, EPERM, "Permission denied (you must be root)" },
1878             { TC_INIT, EINVAL, "Module is wrong version" },
1879             { TC_INIT, ENOENT, 
1880                     "Table does not exist (do you need to insmod?)" },
1881             { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
1882             { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
1883             { TC_DELETE_CHAIN, EMLINK,
1884               "Can't delete chain with references left" },
1885             { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
1886             { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
1887             { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
1888             { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
1889             { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
1890             { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
1891             { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
1892             { TC_INSERT_ENTRY, EINVAL, "Target problem" },
1893             /* EINVAL for CHECK probably means bad interface. */
1894             { TC_CHECK_PACKET, EINVAL,
1895               "Bad arguments (does that interface exist?)" },
1896             { TC_CHECK_PACKET, ENOSYS,
1897               "Checking will most likely never get implemented" },
1898             /* ENOENT for DELETE probably means no matching rule */
1899             { TC_DELETE_ENTRY, ENOENT,
1900               "Bad rule (does a matching rule exist in that chain?)" },
1901             { TC_SET_POLICY, ENOENT,
1902               "Bad built-in chain name" },
1903             { TC_SET_POLICY, EINVAL,
1904               "Bad policy name" },
1905
1906             { NULL, 0, "Incompatible with this kernel" },
1907             { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
1908             { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
1909             { NULL, ENOMEM, "Memory allocation problem" },
1910             { NULL, ENOENT, "No chain/target/match by that name" },
1911           };
1912
1913         for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1914                 if ((!table[i].fn || table[i].fn == iptc_fn)
1915                     && table[i].err == err)
1916                         return table[i].message;
1917         }
1918
1919         return strerror(err);
1920 }