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