blob: a4232fda4d7984dc94e39da5e35bb5593e88edb5 [file] [log] [blame]
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001
2/*
3 * libebtc.c, January 2004
4 *
5 * Contains the functions with which to make a table in userspace.
6 *
7 * Author: Bart De Schuymer
8 *
9 * This code is stongly inspired on the iptables code which is
10 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include <getopt.h>
28#include <string.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <stdarg.h>
32#include <netinet/ether.h>
33#include "include/ebtables_u.h"
34#include "include/ethernetdb.h"
35#include <unistd.h>
36#include <fcntl.h>
37#include <sys/wait.h>
38
39static void decrease_chain_jumps(struct ebt_u_replace *replace);
40static void remove_udc(struct ebt_u_replace *replace);
41static int iterate_entries(struct ebt_u_replace *replace, int type);
42
43/*
44 * The standard names
45 */
46const char *ebt_hooknames[NF_BR_NUMHOOKS] =
47{
48 [NF_BR_PRE_ROUTING]"PREROUTING",
49 [NF_BR_LOCAL_IN]"INPUT",
50 [NF_BR_FORWARD]"FORWARD",
51 [NF_BR_LOCAL_OUT]"OUTPUT",
52 [NF_BR_POST_ROUTING]"POSTROUTING",
53 [NF_BR_BROUTING]"BROUTING"
54};
55
56/*
57 * The four target names
58 */
59const char* ebt_standard_targets[NUM_STANDARD_TARGETS] =
60{
61 "ACCEPT",
62 "DROP",
63 "CONTINUE",
64 "RETURN",
65};
66
67/*
68 * The lists of supported tables, matches, watchers and targets
69 */
70struct ebt_u_table *ebt_tables;
71struct ebt_u_match *ebt_matches;
72struct ebt_u_watcher *ebt_watchers;
73struct ebt_u_target *ebt_targets;
74
75/*
76 * Find the right structure belonging to a name
77 */
78struct ebt_u_target *ebt_find_target(const char *name)
79{
80 struct ebt_u_target *t = ebt_targets;
81
82 while(t && strcmp(t->name, name))
83 t = t->next;
84 return t;
85}
86
87struct ebt_u_match *ebt_find_match(const char *name)
88{
89 struct ebt_u_match *m = ebt_matches;
90
91 while(m && strcmp(m->name, name))
92 m = m->next;
93 return m;
94}
95
96struct ebt_u_watcher *ebt_find_watcher(const char *name)
97{
98 struct ebt_u_watcher *w = ebt_watchers;
99
100 while(w && strcmp(w->name, name))
101 w = w->next;
102 return w;
103}
104
105struct ebt_u_table *ebt_find_table(const char *name)
106{
107 struct ebt_u_table *t = ebt_tables;
108
109 while (t && strcmp(t->name, name))
110 t = t->next;
111 return t;
112}
113
114/*
115 * Prints all registered extensions
116 */
117void ebt_list_extensions()
118{
119 struct ebt_u_table *tbl = ebt_tables;
120 struct ebt_u_target *t = ebt_targets;
121 struct ebt_u_match *m = ebt_matches;
122 struct ebt_u_watcher *w = ebt_watchers;
123
124 PRINT_VERSION;
125 printf("Supported userspace extensions:\n\nSupported tables:\n");
126 while(tbl) {
127 printf("%s\n", tbl->name);
128 tbl = tbl->next;
129 }
130 printf("\nSupported targets:\n");
131 while(t) {
132 printf("%s\n", t->name);
133 t = t->next;
134 }
135 printf("\nSupported matches:\n");
136 while(m) {
137 printf("%s\n", m->name);
138 m = m->next;
139 }
140 printf("\nSupported watchers:\n");
141 while(w) {
142 printf("%s\n", w->name);
143 w = w->next;
144 }
145 exit(0);
146}
147
148/*
149 * Get the table from the kernel or from a binary file
Bart De Schuymer64182a32004-01-21 20:39:54 +0000150 * init: 1 = ask the kernel for the initial contents of a table, i.e. the
151 * way it looks when the table is insmod'ed
152 * 0 = get the current data in the table
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000153 */
154void ebt_get_kernel_table(struct ebt_u_replace *replace,
Bart De Schuymer64182a32004-01-21 20:39:54 +0000155 struct ebt_u_table *table, int init)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000156{
157 if ( !(table = ebt_find_table(replace->name)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000158 ebt_print_error("Bad table name");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000159 /*
160 * get the kernel's information
161 */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000162 if (ebt_get_table(replace, init)) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000163 ebtables_insmod("ebtables");
Bart De Schuymer64182a32004-01-21 20:39:54 +0000164 if (ebt_get_table(replace, init))
165 ebt_print_error("The kernel doesn't support the "
166 "ebtables %s table", replace->name);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000167 }
168 /*
169 * when listing a table contained in a file, we don't demand that
Bart De Schuymer64182a32004-01-21 20:39:54 +0000170 * the user knows the table's name, so we update table if necessary
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000171 */
172 if ( !(table = ebt_find_table(replace->name)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +0000173 ebt_print_error("Bad table name");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000174}
175
176/*
177 * Put sane values into a new entry
178 */
179void ebt_initialize_entry(struct ebt_u_entry *e)
180{
181 e->bitmask = EBT_NOPROTO;
182 e->invflags = 0;
183 e->ethproto = 0;
184 strcpy(e->in, "");
185 strcpy(e->out, "");
186 strcpy(e->logical_in, "");
187 strcpy(e->logical_out, "");
188 e->m_list = NULL;
189 e->w_list = NULL;
190 e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000191
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000192 if (!e->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000193 ebt_print_bug("Couldn't load standard target");
194 ((struct ebt_standard_target *)
195 ((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000196}
197
198/*
199 * replace is reborn, i.e. rebirth of replace
200 */
201void ebt_cleanup_replace(struct ebt_u_replace *replace)
202{
203 int i;
204 struct ebt_u_entries *entries;
205 struct ebt_u_chain_list *udc1, *udc2;
206 struct ebt_cntchanges *cc1, *cc2;
207 struct ebt_u_entry *u_e1, *u_e2;
208
209 replace->name[0] = '\0';
210 replace->valid_hooks = 0;
211 replace->nentries = 0;
212 replace->num_counters = 0;
213 replace->flags = 0;
214 replace->command = 0;
215 replace->selected_chain = -1;
216 if (replace->filename) {
217 free(replace->filename);
218 replace->filename = NULL;
219 }
220 if (replace->counters) {
221 free(replace->counters);
222 replace->counters = NULL;
223 }
224
225 i = -1;
226 while (1) {
227 i++;
228 entries = ebt_nr_to_chain(replace, i);
229 if (!entries) {
230 if (i < NF_BR_NUMHOOKS)
231 continue;
232 else
233 break;
234 }
235 entries->nentries = 0;
236 entries->counter_offset = 0;
237 u_e1 = entries->entries;
238 entries->entries = NULL;
239 while (u_e1) {
240 ebt_free_u_entry(u_e1);
241 u_e2 = u_e1->next;
242 free(u_e1);
243 u_e1 = u_e2;
244 }
245 }
246 udc1 = replace->udc;
247 while (udc1) {
248 udc2 = udc1->next;
249 free(udc1);
250 udc1 = udc2;
251 }
252 replace->udc = NULL;
253 cc1 = replace->counterchanges;
254 while (cc1) {
255 cc2 = cc1->next;
256 free(cc2);
257 cc1 = cc2;
258 }
259 replace->counterchanges = NULL;
260}
261
262/*
263 * Should be called between 2 rule adds, f.e.
264 */
265void ebt_reinit_extensions(struct ebt_u_replace *replace)
266{
267 struct ebt_u_match *m;
268 struct ebt_u_watcher *w;
269 struct ebt_u_target *t;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000270 int size;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000271
272 /* The init functions should determine by themselves whether they are
273 * called for the first time or not (when necessary). */
274 for (m = ebt_matches; m; m = m->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000275 size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
276 if (m->m)
277 free(m->m);
278 m->m = (struct ebt_entry_match *)malloc(size);
279 if (!m->m)
280 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000281 m->used = 0;
282 m->flags = 0;
283 m->init(m->m);
284 }
285 for (w = ebt_watchers; w; w = w->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000286 size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
287 if (w->w)
288 free(w->w);
289 w->w = (struct ebt_entry_watcher *)malloc(size);
290 if (!w->w)
291 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000292 w->used = 0;
293 w->flags = 0;
294 w->init(w->w);
295 }
296 for (t = ebt_targets; m; t = t->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000297 size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
298 if (t->t)
299 free(t->t);
300 t->t = (struct ebt_entry_target *)malloc(size);
301 if (!t->t)
302 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000303 t->used = 0;
304 t->flags = 0;
305 t->init(t->t);
306 }
307}
308
309/*
310 * This doesn't free e, becoz the calling function might need e->next
311 */
312void ebt_free_u_entry(struct ebt_u_entry *e)
313{
314 struct ebt_u_match_list *m_l, *m_l2;
315 struct ebt_u_watcher_list *w_l, *w_l2;
316
317 m_l = e->m_list;
318 while (m_l) {
319 m_l2 = m_l->next;
320 free(m_l->m);
321 free(m_l);
322 m_l = m_l2;
323 }
324 w_l = e->w_list;
325 while (w_l) {
326 w_l2 = w_l->next;
327 free(w_l->w);
328 free(w_l);
329 w_l = w_l2;
330 }
331 free(e->t);
332}
333
334/*
335 * Blatently stolen (again) from iptables.c userspace program
336 * find out where the modprobe utility is located
337 */
338static char *get_modprobe(void)
339{
340 int procfile;
341 char *ret;
342
343 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
344 if (procfile < 0)
345 return NULL;
346
347 ret = malloc(1024);
348 if (ret) {
349 switch (read(procfile, ret, 1024)) {
350 case -1: goto fail;
351 case 1024: goto fail; /* Partial read. Wierd */
352 }
353 if (ret[strlen(ret)-1]=='\n')
354 ret[strlen(ret)-1]=0;
355 close(procfile);
356 return ret;
357 }
358 fail:
359 free(ret);
360 close(procfile);
361 return NULL;
362}
363
364char *ebt_modprobe;
365/*
366 * Try to load the kernel module
367 */
368int ebtables_insmod(const char *modname)
369{
370 char *buf = NULL;
371 char *argv[3];
372
373 /* If they don't explicitly set it, read out of kernel */
374 if (!ebt_modprobe) {
375 buf = get_modprobe();
376 if (!buf)
377 return -1;
378 ebt_modprobe = buf;
379 }
380
381 switch (fork()) {
382 case 0:
383 argv[0] = (char *)ebt_modprobe;
384 argv[1] = (char *)modname;
385 argv[2] = NULL;
386 execv(argv[0], argv);
387
388 /* not usually reached */
389 exit(0);
390 case -1:
391 return -1;
392
393 default: /* parent */
394 wait(NULL);
395 }
396
397 free(buf);
398 return 0;
399}
400
401/*
402 * Gives back a pointer to the chain base, based on nr.
403 * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain.
404 * Returns NULL on failure.
405 */
406struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace,
407 int nr)
408{
409 if (nr == -1)
410 return NULL;
411 if (nr < NF_BR_NUMHOOKS)
412 return replace->hook_entry[nr];
413 else {
414 int i;
415 struct ebt_u_chain_list *cl = replace->udc;
416
417 i = nr - NF_BR_NUMHOOKS;
418 while (i > 0 && cl) {
419 cl = cl->next;
420 i--;
421 }
422 if (cl)
423 return cl->udc;
424 else
425 return NULL;
426 }
427}
428
429/*
430 * Gives back a pointer to the chain base of selected_chain
431 */
432struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace)
433{
434 return ebt_nr_to_chain(replace, replace->selected_chain);
435}
436
437/*
438 * Parse the chain name and return a pointer to the chain base.
439 * Returns NULL on failure.
440 */
441struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
442 const char* arg)
443{
444 int i;
445 struct ebt_u_chain_list *cl = replace->udc;
446
447 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
448 if (!(replace->valid_hooks & (1 << i)))
449 continue;
450 if (!strcmp(arg, replace->hook_entry[i]->name))
451 return replace->hook_entry[i];
452 }
453 while(cl) {
454 if (!strcmp(arg, cl->udc->name))
455 return cl->udc;
456 cl = cl->next;
457 }
458 return NULL;
459}
460
461/*
462 * Parse the chain name and return the corresponding chain nr
463 * returns -1 on failure
464 */
465int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg)
466{
467 int i;
468 struct ebt_u_chain_list *cl = replace->udc;
469
470 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
471 if (!(replace->valid_hooks & (1 << i)))
472 continue;
473 if (!strcmp(arg, replace->hook_entry[i]->name))
474 return i;
475 }
476 while(cl) {
477 if (!strcmp(arg, cl->udc->name))
478 return i;
479 i++;
480 cl = cl->next;
481 }
482 return -1;
483}
484
485 /*
486************
487************
488**COMMANDS**
489************
490************
491 */
492
493/*
494 * Chainge the policy of selected_chain.
495 * No sanity checks are done.
496 */
497void ebt_change_policy(struct ebt_u_replace *replace, int policy)
498{
499 struct ebt_u_entries *entries = ebt_to_chain(replace);
500
501 if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000502 ebt_print_bug("wrong policy: %d", policy);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000503 entries->policy = policy;
504}
505
506/*
507 * Flush one chain or the complete table
508 * If selected_chain == -1: flush the complete table
509 */
510void ebt_flush_chains(struct ebt_u_replace *replace)
511{
512 int i, j, numdel;
513 struct ebt_u_entry *u_e, *tmp;
514 struct ebt_u_entries *entries = ebt_to_chain(replace);
515 struct ebt_cntchanges *cc = replace->counterchanges;
516 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
517
518 /*
519 * flush whole table
520 */
521 if (!entries) {
522 if (replace->nentries == 0)
523 return;
524 replace->nentries = 0;
525
526 /*
527 * free everything and zero (n)entries
528 */
529 i = -1;
530 while (1) {
531 i++;
532 entries = ebt_nr_to_chain(replace, i);
533 if (!entries) {
534 if (i < NF_BR_NUMHOOKS)
535 continue;
536 else
537 break;
538 }
539 entries->nentries = 0;
540 entries->counter_offset = 0;
541 u_e = entries->entries;
542 entries->entries = NULL;
543 while (u_e) {
544 ebt_free_u_entry(u_e);
545 tmp = u_e->next;
546 free(u_e);
547 u_e = tmp;
548 }
549 }
550 /*
551 * update the counters
552 */
553 while (cc) {
554 if (cc->type == CNT_ADD) {
555 *prev_cc = cc->next;
556 free(cc);
557 cc = *prev_cc;
558 continue;
559 }
560 cc->type = CNT_DEL;
561 prev_cc = &(cc->next);
562 cc = cc->next;
563 }
564 return;
565 }
566
567 if (entries->nentries == 0)
568 return;
569 replace->nentries -= entries->nentries;
570 numdel = entries->nentries;
571
572 /*
573 * delete the counters belonging to the specified chain,
574 * update counter_offset
575 */
576 i = -1;
577 while (1) {
578 i++;
579 entries = ebt_nr_to_chain(replace, i);
580 if (!entries) {
581 if (i < NF_BR_NUMHOOKS)
582 continue;
583 else
584 break;
585 }
586 if (i > replace->selected_chain) {
587 entries->counter_offset -= numdel;
588 continue;
589 }
590 j = entries->nentries;
591 while (j) {
592 /* don't count deleted entries */
593 if (cc->type == CNT_DEL)
594 goto letscontinue;
595 if (i == replace->selected_chain) {
596 if (cc->type == CNT_ADD) {
597 *prev_cc = cc->next;
598 free(cc);
599 cc = *prev_cc;
600 j--;
601 continue;
602 }
603 cc->type = CNT_DEL;
604 }
605 j--;
606letscontinue:
607 prev_cc = &(cc->next);
608 cc = cc->next;
609 }
610 }
611
612 entries = ebt_to_chain(replace);
613 entries->nentries = 0;
614 u_e = entries->entries;
615 while (u_e) {
616 ebt_free_u_entry(u_e);
617 tmp = u_e->next;
618 free(u_e);
619 u_e = tmp;
620 }
621 entries->entries = NULL;
622 return;
623}
624
625/*
626 * returns the rule number on success (starting from 0), -1 on failure
627 *
628 * This function expects the ebt_{match,watcher,target} members of new_entry
629 * to contain pointers to ebt_u_{match,watcher,target}.
630 */
631int ebt_check_rule_exists(struct ebt_u_replace *replace,
632 struct ebt_u_entry *new_entry)
633{
634 struct ebt_u_entry *u_e;
635 struct ebt_u_match_list *m_l, *m_l2;
636 struct ebt_u_match *m;
637 struct ebt_u_watcher_list *w_l, *w_l2;
638 struct ebt_u_watcher *w;
639 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
640 struct ebt_u_entries *entries = ebt_to_chain(replace);
641 int i, j, k;
642
643 u_e = entries->entries;
644 /*
645 * check for an existing rule (if there are duplicate rules,
646 * take the first occurance)
647 */
648 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
649 if (!u_e)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000650 ebt_print_bug("Hmm, trouble");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000651 if (u_e->ethproto != new_entry->ethproto)
652 continue;
653 if (strcmp(u_e->in, new_entry->in))
654 continue;
655 if (strcmp(u_e->out, new_entry->out))
656 continue;
657 if (strcmp(u_e->logical_in, new_entry->logical_in))
658 continue;
659 if (strcmp(u_e->logical_out, new_entry->logical_out))
660 continue;
661 if (new_entry->bitmask & EBT_SOURCEMAC &&
662 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
663 continue;
664 if (new_entry->bitmask & EBT_DESTMAC &&
665 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
666 continue;
667 if (new_entry->bitmask != u_e->bitmask ||
668 new_entry->invflags != u_e->invflags)
669 continue;
670 /*
671 * compare all matches
672 */
673 m_l = new_entry->m_list;
674 j = 0;
675 while (m_l) {
676 m = (struct ebt_u_match *)(m_l->m);
677 m_l2 = u_e->m_list;
678 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
679 m_l2 = m_l2->next;
680 if (!m_l2 || !m->compare(m->m, m_l2->m))
681 goto letscontinue;
682 j++;
683 m_l = m_l->next;
684 }
685 /*
686 * now be sure they have the same nr of matches
687 */
688 k = 0;
689 m_l = u_e->m_list;
690 while (m_l) {
691 k++;
692 m_l = m_l->next;
693 }
694 if (j != k)
695 continue;
696
697 /*
698 * compare all watchers
699 */
700 w_l = new_entry->w_list;
701 j = 0;
702 while (w_l) {
703 w = (struct ebt_u_watcher *)(w_l->w);
704 w_l2 = u_e->w_list;
705 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
706 w_l2 = w_l2->next;
707 if (!w_l2 || !w->compare(w->w, w_l2->w))
708 goto letscontinue;
709 j++;
710 w_l = w_l->next;
711 }
712 k = 0;
713 w_l = u_e->w_list;
714 while (w_l) {
715 k++;
716 w_l = w_l->next;
717 }
718 if (j != k)
719 continue;
720 if (strcmp(t->t->u.name, u_e->t->u.name))
721 continue;
722 if (!t->compare(t->t, u_e->t))
723 continue;
724 return i;
Bart De Schuymeraef08942004-09-09 21:41:29 +0000725letscontinue:;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000726 }
727 return -1;
728}
729
730/* Add a rule, rule_nr is the rule to update
731 * rule_nr specifies where the rule should be inserted
732 * rule_nr > 0 : insert the rule right before the rule_nr'th rule
733 * (the first rule is rule 1)
734 * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule,
735 * where n denotes the number of rule in the chain
736 * rule_nr == 0: add a new rule at the end of the chain
737 *
738 * This function expects the ebt_{match,watcher,target} members of new_entry
739 * to contain pointers to ebt_u_{match,watcher,target} and updates these
740 * pointers before adding the rule to the chain.
741 */
742void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
743 int rule_nr)
744{
745 int i, j;
746 struct ebt_u_entry **u_e;
747 struct ebt_u_match_list *m_l;
748 struct ebt_u_watcher_list *w_l;
749 struct ebt_u_entries *entries = ebt_to_chain(replace);
750 struct ebt_cntchanges *cc = replace->counterchanges, *new_cc;
751 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
752
753 if (rule_nr <= 0)
754 rule_nr += entries->nentries;
755 else
756 rule_nr--;
757 if (rule_nr > entries->nentries || rule_nr < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000758 ebt_print_error("The specified rule number is incorrect");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000759 /*
760 * we're adding one rule
761 */
762 replace->nentries++;
763 entries->nentries++;
764
765 /*
766 * handle counter stuff
767 */
768 for (i = 0; i < replace->selected_chain; i++) {
769 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
770 continue;
771 j = ebt_nr_to_chain(replace, i)->nentries;
772 while (j) {
773 if (cc->type != CNT_DEL)
774 j--;
775 prev_cc = &(cc->next);
776 cc = cc->next;
777 }
778 }
779 j = rule_nr;
780 while (j) {
781 if (cc->type != CNT_DEL)
782 j--;
783 prev_cc = &(cc->next);
784 cc = cc->next;
785 }
786 if (cc && cc->type == CNT_DEL) /* The add is victorious and conquers
787 * the delete */
788 cc->type = CNT_OWRITE;
789 else {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000790 new_cc = (struct ebt_cntchanges *)
791 malloc(sizeof(struct ebt_cntchanges));
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000792 new_cc->type = CNT_ADD;
793 new_cc->next = cc;
794 *prev_cc = new_cc;
795 }
796
797 /*
798 * go to the right position in the chain
799 */
800 u_e = &entries->entries;
801 for (i = 0; i < rule_nr; i++)
802 u_e = &(*u_e)->next;
803 /*
804 * insert the rule
805 */
806 new_entry->next = *u_e;
807 *u_e = new_entry;
808
809 /*
810 * put the ebt_[match, watcher, target] pointers in place
811 */
812 m_l = new_entry->m_list;
813 while (m_l) {
814 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
815 m_l = m_l->next;
816 }
817 w_l = new_entry->w_list;
818 while (w_l) {
819 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
820 w_l = w_l->next;
821 }
822 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
823
824 /*
825 * update the counter_offset of chains behind this one
826 */
827 i = replace->selected_chain;
828 while (1) {
829 i++;
830 entries = ebt_nr_to_chain(replace, i);
831 if (!entries) {
832 if (i < NF_BR_NUMHOOKS)
833 continue;
834 else
835 break;
836 } else
837 entries->counter_offset++;
838 }
839}
840
841/*
842 * Delete a rule or rules
843 * begin == end == 0: delete the rule corresponding to new_entry
844 *
845 * the first rule has rule nr 1, the last rule has rule nr -1, etc.
846 * This function expects the ebt_{match,watcher,target} members of new_entry
847 * to contain pointers to ebt_u_{match,watcher,target}.
848 */
849void ebt_delete_rule(struct ebt_u_replace *replace,
850 struct ebt_u_entry *new_entry, int begin, int end)
851{
852 int i, j, nr_deletes;
853 struct ebt_u_entry **u_e, *u_e2;
854 struct ebt_u_entries *entries = ebt_to_chain(replace);
855 struct ebt_cntchanges *cc = replace->counterchanges;
856 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
857
858 if (begin < 0)
859 begin += entries->nentries + 1;
860 if (end < 0)
861 end += entries->nentries + 1;
862
863 if (begin < 0 || begin > end || end > entries->nentries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000864 ebt_print_error("Sorry, wrong rule numbers");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000865
866 if ((begin * end == 0) && (begin + end != 0))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000867 ebt_print_bug("begin and end should be either both zero, "
868 "either both non-zero");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000869 if (begin != 0 && end != 0) {
870 begin--;
871 end--;
872 } else {
873 begin = ebt_check_rule_exists(replace, new_entry);
874 end = begin;
875 if (begin == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000876 ebt_print_error("Sorry, rule does not exist");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000877 }
878
879 /*
880 * we're deleting rules
881 */
882 nr_deletes = end - begin + 1;
883 replace->nentries -= nr_deletes;
884 entries->nentries -= nr_deletes;
885
886 /*
887 * handle counter stuff
888 */
889 for (i = 0; i < replace->selected_chain; i++) {
890 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
891 continue;
892 j = ebt_nr_to_chain(replace, i)->nentries;
893 while (j) {
894 if (cc->type != CNT_DEL)
895 j--;
896 prev_cc = &(cc->next);
897 cc = cc->next;
898 }
899 }
900 j = begin;
901 while (j) {
902 if (cc->type != CNT_DEL)
903 j--;
904 prev_cc = &(cc->next);
905 cc = cc->next;
906 }
907 j = nr_deletes;
908 while (j) {
909 if (cc->type != CNT_DEL) {
910 j--;
911 if (cc->type == CNT_ADD) {
912 *prev_cc = cc->next;
913 free(cc);
914 cc = *prev_cc;
915 continue;
916 }
917 cc->type = CNT_DEL;
918 }
919 prev_cc = &(cc->next);
920 cc = cc->next;
921 }
922
923 /*
924 * go to the right position in the chain
925 */
926 u_e = &entries->entries;
927 for (j = 0; j < begin; j++)
928 u_e = &(*u_e)->next;
929 /*
930 * remove the rules
931 */
932 j = nr_deletes;
933 while(j--) {
934 u_e2 = *u_e;
935 *u_e = (*u_e)->next;
936 /* free everything */
937 ebt_free_u_entry(u_e2);
938 free(u_e2);
939 }
940
941 /*
942 * update the counter_offset of chains behind this one
943 */
944 j = replace->selected_chain;
945 while (1) {
946 j++;
947 entries = ebt_nr_to_chain(replace, j);
948 if (!entries) {
949 if (j < NF_BR_NUMHOOKS)
950 continue;
951 else
952 break;
953 } else
954 entries->counter_offset -= nr_deletes;
955 }
956}
957
958/*
959 * Selected_chain == -1 : zero all counters
960 * else, zero the counters of selected_chain
961 */
962void ebt_zero_counters(struct ebt_u_replace *replace)
963{
964 struct ebt_u_entries *entries = ebt_to_chain(replace);
965 struct ebt_cntchanges *cc = replace->counterchanges;
966 int i, j;
967
968 if (!entries) {
969 while (cc) {
970 if (cc->type == CNT_NORM)
971 cc->type = CNT_ZERO;
972 cc = cc->next;
973 }
974 } else {
975 if (entries->nentries == 0)
976 return;
977
978 for (i = 0; i < replace->selected_chain; i++) {
979 if (i < NF_BR_NUMHOOKS &&
980 !(replace->valid_hooks & (1 << i)))
981 continue;
982 j = ebt_nr_to_chain(replace, i)->nentries;
983 while (j) {
984 if (cc->type != CNT_DEL)
985 j--;
986 cc = cc->next;
987 }
988 }
989 j = entries->nentries;
990 while (j) {
991 if (cc->type != CNT_DEL) {
992 j--;
993 if (cc->type == CNT_NORM)
994 cc->type = CNT_ZERO;
995 }
996 cc = cc->next;
997 }
998 }
999}
1000
1001/*
1002 * Add a new chain and specify its policy
1003 */
1004void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
1005{
1006 struct ebt_u_chain_list *cl, **cl2;
1007
1008 if (ebt_get_chainnr(replace, name) != -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001009 ebt_print_error("Chain %s already exists", optarg);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001010 if (ebt_find_target(name))
Bart De Schuymer64182a32004-01-21 20:39:54 +00001011 ebt_print_error("Target with name %s exists", optarg);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001012 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001013 ebt_print_error("Chain name length can't exceed %d",
1014 EBT_CHAIN_MAXNAMELEN - 1);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001015 cl = (struct ebt_u_chain_list *)
1016 malloc(sizeof(struct ebt_u_chain_list));
1017 if (!cl)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001018 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001019 cl->next = NULL;
1020 cl->udc = (struct ebt_u_entries *)
1021 malloc(sizeof(struct ebt_u_entries));
1022 if (!cl->udc)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001023 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001024 cl->udc->nentries = 0;
1025 cl->udc->policy = policy;
1026 cl->udc->counter_offset = replace->nentries;
1027 cl->udc->hook_mask = 0;
1028 strcpy(cl->udc->name, name);
1029 cl->udc->entries = NULL;
1030 cl->kernel_start = NULL;
1031 /*
1032 * put the new chain at the end
1033 */
1034 cl2 = &(replace->udc);
1035 while (*cl2)
1036 cl2 = &((*cl2)->next);
1037 *cl2 = cl;
1038}
1039
1040/*
1041 * Selected_chain == -1: delete all non-referenced udc
1042 * selected_chain < NF_BR_NUMHOOKS is illegal
1043 */
1044void ebt_delete_chain(struct ebt_u_replace *replace)
1045{
1046 int chain_nr = replace->selected_chain;
1047
1048 if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001049 ebt_print_bug("You can't remove a standard chain");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001050 if (chain_nr == -1)
1051 replace->selected_chain = NF_BR_NUMHOOKS;
1052 do {
1053 if (ebt_to_chain(replace) == NULL) {
1054 if (chain_nr == -1)
1055 break;
Bart De Schuymer64182a32004-01-21 20:39:54 +00001056 ebt_print_bug("udc nr %d doesn't exist", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001057 }
1058 /*
1059 * if the chain is referenced, don't delete it,
1060 * also decrement jumps to a chain behind the
1061 * one we're deleting
1062 */
1063 if (ebt_check_for_references(replace)) {
1064 replace->selected_chain++;
1065 continue;
1066 }
1067 decrease_chain_jumps(replace);
1068 ebt_flush_chains(replace);
1069 remove_udc(replace);
1070 } while (chain_nr != -1);
1071 replace->selected_chain = chain_nr;
1072}
1073
1074/*
1075 * Rename an existing chain.
1076 */
1077void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
1078{
1079 struct ebt_u_entries *entries = ebt_to_chain(replace);
1080
1081 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001082 ebt_print_bug("ebt_rename_chain: entries == NULL");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001083 strcpy(entries->name, name);
1084}
1085
1086
1087 /*
1088*************************
1089*************************
1090**SPECIALIZED*FUNCTIONS**
1091*************************
1092*************************
1093 */
1094
1095
1096/*
1097 * executes the final_check() function for all extensions used by the rule
1098 * ebt_check_for_loops should have been executed earlier, to make sure the
1099 * hook_mask is correct.
1100 */
1101void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
1102 struct ebt_u_entries *entries)
1103{
1104 struct ebt_u_match_list *m_l;
1105 struct ebt_u_watcher_list *w_l;
1106 struct ebt_u_target *t;
1107 struct ebt_u_match *m;
1108 struct ebt_u_watcher *w;
1109
1110 m_l = e->m_list;
1111 w_l = e->w_list;
1112 while (m_l) {
1113 m = ebt_find_match(m_l->m->u.name);
1114 m->final_check(e, m_l->m, replace->name,
1115 entries->hook_mask, 1);
1116 m_l = m_l->next;
1117 }
1118 while (w_l) {
1119 w = ebt_find_watcher(w_l->w->u.name);
1120 w->final_check(e, w_l->w, replace->name,
1121 entries->hook_mask, 1);
1122 w_l = w_l->next;
1123 }
1124 t = ebt_find_target(e->t->u.name);
1125 t->final_check(e, e->t, replace->name,
1126 entries->hook_mask, 1);
1127}
1128
1129/*
1130 * returns 1 when the chain is referenced,
1131 * 0 when it isn't.
1132 */
1133int ebt_check_for_references(struct ebt_u_replace *replace)
1134{
1135 return iterate_entries(replace, 1);
1136}
1137
1138/*
1139 * chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
1140 * returns 1 when the chain is referenced,
1141 * 0 when it isn't.
1142 */
1143int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr)
1144{
1145 int tmp = replace->selected_chain, ret;
1146
1147 replace->selected_chain = chain_nr;
1148 ret = iterate_entries(replace, 1);
1149 replace->selected_chain = tmp;
1150 return ret;
1151}
1152
1153struct ebt_u_stack
1154{
1155 int chain_nr;
1156 int n;
1157 struct ebt_u_entry *e;
1158 struct ebt_u_entries *entries;
1159};
1160
1161/*
1162 * Checks for loops
1163 * As a by-product, the hook_mask member of each chain is filled in
1164 * correctly. The check functions of the extensions need this hook_mask
1165 * to know from which standard chains they can be called.
1166 */
1167void ebt_check_for_loops(struct ebt_u_replace *replace)
1168{
1169 int chain_nr , i, j , k, sp = 0, verdict;
1170 struct ebt_u_entries *entries, *entries2;
1171 struct ebt_u_stack *stack = NULL;
1172 struct ebt_u_entry *e;
1173
1174 i = -1;
1175 /*
1176 * initialize hook_mask to 0
1177 */
1178 while (1) {
1179 i++;
1180 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
1181 continue;
1182 entries = ebt_nr_to_chain(replace, i);
1183 if (!entries)
1184 break;
1185 entries->hook_mask = 0;
1186 }
1187 if (i > NF_BR_NUMHOOKS) {
1188 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
1189 sizeof(struct ebt_u_stack));
1190 if (!stack)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001191 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001192 }
1193
1194 /*
1195 * check for loops, starting from every base chain
1196 */
1197 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1198 if (!(replace->valid_hooks & (1 << i)))
1199 continue;
1200 entries = ebt_nr_to_chain(replace, i);
1201 /*
1202 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
1203 * (usefull in the final_check() funtions)
1204 */
1205 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
1206 chain_nr = i;
1207
1208 e = entries->entries;
1209 for (j = 0; j < entries->nentries; j++) {
1210 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
1211 goto letscontinue;
1212 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
1213 if (verdict < 0)
1214 goto letscontinue;
1215 entries2 = ebt_nr_to_chain(replace,
1216 verdict + NF_BR_NUMHOOKS);
1217 entries2->hook_mask |= entries->hook_mask;
1218 /*
1219 * now see if we've been here before
1220 */
1221 for (k = 0; k < sp; k++)
1222 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001223 ebt_print_error("Loop from chain %s to chain %s",
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001224 ebt_nr_to_chain(replace, chain_nr)->name,
1225 ebt_nr_to_chain(replace, stack[k].chain_nr)->name);
1226 /*
1227 * jump to the chain, make sure we know how to get back
1228 */
1229 stack[sp].chain_nr = chain_nr;
1230 stack[sp].n = j;
1231 stack[sp].entries = entries;
1232 stack[sp].e = e;
1233 sp++;
1234 j = -1;
1235 e = entries2->entries;
1236 chain_nr = verdict + NF_BR_NUMHOOKS;
1237 entries = entries2;
1238 continue;
1239letscontinue:
1240 e = e->next;
1241 }
1242 /*
1243 * we are at the end of a standard chain
1244 */
1245 if (sp == 0)
1246 continue;
1247 /*
1248 * go back to the chain one level higher
1249 */
1250 sp--;
1251 j = stack[sp].n;
1252 chain_nr = stack[sp].chain_nr;
1253 e = stack[sp].e;
1254 entries = stack[sp].entries;
1255 goto letscontinue;
1256 }
1257 free(stack);
1258 return;
1259}
1260
1261/*
1262 * the user will use the match, so put it in new_entry
1263 */
1264void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m)
1265{
1266 struct ebt_u_match_list **m_list, *new;
1267
1268 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
1269 new = (struct ebt_u_match_list *)
1270 malloc(sizeof(struct ebt_u_match_list));
1271 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001272 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001273 *m_list = new;
1274 new->next = NULL;
1275 new->m = (struct ebt_entry_match *)m;
1276}
1277
1278void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w)
1279{
1280 struct ebt_u_watcher_list **w_list;
1281 struct ebt_u_watcher_list *new;
1282
1283 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
1284 new = (struct ebt_u_watcher_list *)
1285 malloc(sizeof(struct ebt_u_watcher_list));
1286 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001287 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001288 *w_list = new;
1289 new->next = NULL;
1290 new->w = (struct ebt_entry_watcher *)w;
1291}
1292
1293
1294 /*
1295*******************
1296*******************
1297**OTHER*FUNCTIONS**
1298*******************
1299*******************
1300 */
1301
1302
1303/*
1304 * type = 0 => update chain jumps
1305 * type = 1 => check for reference
1306 *
1307 * returns 1 when type == 1 and the chain is referenced
1308 * returns 0 otherwise
1309 */
1310static int iterate_entries(struct ebt_u_replace *replace, int type)
1311{
1312 int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS;
1313 struct ebt_u_entries *entries;
1314 struct ebt_u_entry *e;
1315
1316 if (chain_nr < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001317 ebt_print_bug("iterate_entries: udc = %d < 0", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001318 while (1) {
1319 i++;
1320 entries = ebt_nr_to_chain(replace, i);
1321 if (!entries) {
1322 if (i < NF_BR_NUMHOOKS)
1323 continue;
1324 else
1325 break;
1326 }
1327 e = entries->entries;
1328 j = 0;
1329 while (e) {
1330 int chain_jmp;
1331
1332 j++;
1333 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1334 e = e->next;
1335 continue;
1336 }
Bart De Schuymer64182a32004-01-21 20:39:54 +00001337 chain_jmp = ((struct ebt_standard_target *)e->t)->
1338 verdict;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001339 switch (type) {
1340 case 1:
1341 if (chain_jmp == chain_nr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +00001342 ebt_print_error("Can't delete the chain, it's "
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001343 "referenced in chain %s, rule %d",
1344 entries->name, j);
1345 return 1;
1346 }
1347 break;
1348 case 0:
1349 /* adjust the chain jumps when necessary */
1350 if (chain_jmp > chain_nr)
1351 ((struct ebt_standard_target *)e->t)->verdict--;
1352 break;
1353 } /* end switch */
1354 e = e->next;
1355 }
1356 }
1357 return 0;
1358}
1359
1360static void decrease_chain_jumps(struct ebt_u_replace *replace)
1361{
1362 iterate_entries(replace, 0);
1363}
1364
1365/*
1366 * selected_chain >= NF_BR_NUMHOOKS
1367 */
1368static void remove_udc(struct ebt_u_replace *replace)
1369{
1370 struct ebt_u_chain_list *cl, **cl2;
1371 struct ebt_u_entries *entries;
1372 struct ebt_u_entry *u_e, *tmp;
1373 int chain_nr = replace->selected_chain;
1374
1375 if (chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001376 ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr,
1377 NF_BR_NUMHOOKS);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001378 /* first free the rules */
1379 entries = ebt_nr_to_chain(replace, chain_nr);
1380 u_e = entries->entries;
1381 while (u_e) {
1382 ebt_free_u_entry(u_e);
1383 tmp = u_e->next;
1384 free(u_e);
1385 u_e = tmp;
1386 }
1387
1388 /* next, remove the chain */
1389 cl2 = &(replace->udc);
1390 while ((*cl2)->udc != entries)
1391 cl2 = &((*cl2)->next);
1392 cl = (*cl2);
1393 (*cl2) = (*cl2)->next;
1394 free(cl->udc);
1395 free(cl);
1396}
1397
1398
1399/*
1400 * used in initialization code of modules
1401 */
1402void ebt_register_match(struct ebt_u_match *m)
1403{
1404 int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
1405 struct ebt_u_match **i;
1406
1407 m->m = (struct ebt_entry_match *)malloc(size);
1408 if (!m->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001409 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001410 strcpy(m->m->u.name, m->name);
1411 m->m->match_size = EBT_ALIGN(m->size);
1412 m->init(m->m);
1413
1414 for (i = &ebt_matches; *i; i = &((*i)->next));
1415 m->next = NULL;
1416 *i = m;
1417}
1418
1419void ebt_register_watcher(struct ebt_u_watcher *w)
1420{
1421 int size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
1422 struct ebt_u_watcher **i;
1423
1424 w->w = (struct ebt_entry_watcher *)malloc(size);
1425 if (!w->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001426 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001427 strcpy(w->w->u.name, w->name);
1428 w->w->watcher_size = EBT_ALIGN(w->size);
1429 w->init(w->w);
1430
1431 for (i = &ebt_watchers; *i; i = &((*i)->next));
1432 w->next = NULL;
1433 *i = w;
1434}
1435
1436void ebt_register_target(struct ebt_u_target *t)
1437{
1438 int size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
1439 struct ebt_u_target **i;
1440
1441 t->t = (struct ebt_entry_target *)malloc(size);
1442 if (!t->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001443 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001444 strcpy(t->t->u.name, t->name);
1445 t->t->target_size = EBT_ALIGN(t->size);
1446 t->init(t->t);
1447
1448 for (i = &ebt_targets; *i; i = &((*i)->next));
1449 t->next = NULL;
1450 *i = t;
1451}
1452
1453void ebt_register_table(struct ebt_u_table *t)
1454{
1455 t->next = ebt_tables;
1456 ebt_tables = t;
1457}
1458
1459void ebt_iterate_matches(void (*f)(struct ebt_u_match *))
1460{
1461 struct ebt_u_match *i;
1462
1463 for (i = ebt_matches; i; i = i->next)
1464 f(i);
1465}
1466
1467void ebt_iterate_watchers(void (*f)(struct ebt_u_watcher *))
1468{
1469 struct ebt_u_watcher *i;
1470
1471 for (i = ebt_watchers; i; i = i->next)
1472 f(i);
1473}
1474
1475void ebt_iterate_targets(void (*f)(struct ebt_u_target *))
1476{
1477 struct ebt_u_target *i;
1478
1479 for (i = ebt_targets; i; i = i->next)
1480 f(i);
1481}
1482
1483/*
Bart De Schuymer64182a32004-01-21 20:39:54 +00001484 * Don't use this function, use ebt_print_bug()
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001485 */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001486void __ebt_print_bug(char *file, int line, char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001487{
1488 va_list l;
1489
1490 va_start(l, format);
1491 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
1492 vprintf(format, l);
1493 printf("\n");
1494 va_end(l);
1495 exit (-1);
1496}
1497
1498/*
1499 * The error messages are put in here when ebt_silent == 1
1500 * ebt_errormsg[0] == '\0' implies there was no error
1501 */
1502char ebt_errormsg[ERRORMSG_MAXLEN];
1503/*
1504 * When error messages should not be printed on the screen, after which
1505 * the program exit()s, set ebt_silent to 1.
1506 */
1507int ebt_silent;
1508/*
Bart De Schuymer64182a32004-01-21 20:39:54 +00001509 * Don't use this function, use ebt_print_error()
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001510 */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001511void __ebt_print_error(char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001512{
1513 va_list l;
1514
1515 va_start(l, format);
1516 if (ebt_silent) {
1517 snprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
1518 va_end(l);
1519 } else {
1520 vprintf(format, l);
1521 printf("\n");
1522 va_end(l);
1523 exit (-1);
1524 }
1525}