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