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