blob: 03b7bfee2954cb1fe04a6598cb1dfc4becc2e0eb [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
Bart De Schuymer6622a012005-01-19 21:09:05 +000043/* The standard names */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000044const char *ebt_hooknames[NF_BR_NUMHOOKS] =
45{
46 [NF_BR_PRE_ROUTING]"PREROUTING",
47 [NF_BR_LOCAL_IN]"INPUT",
48 [NF_BR_FORWARD]"FORWARD",
49 [NF_BR_LOCAL_OUT]"OUTPUT",
50 [NF_BR_POST_ROUTING]"POSTROUTING",
51 [NF_BR_BROUTING]"BROUTING"
52};
53
Bart De Schuymer6622a012005-01-19 21:09:05 +000054/* The four target names */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000055const char* ebt_standard_targets[NUM_STANDARD_TARGETS] =
56{
57 "ACCEPT",
58 "DROP",
59 "CONTINUE",
60 "RETURN",
61};
62
Bart De Schuymer6622a012005-01-19 21:09:05 +000063/* The lists of supported tables, matches, watchers and targets */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000064struct ebt_u_table *ebt_tables;
65struct ebt_u_match *ebt_matches;
66struct ebt_u_watcher *ebt_watchers;
67struct ebt_u_target *ebt_targets;
68
Bart De Schuymer6622a012005-01-19 21:09:05 +000069/* Find the right structure belonging to a name */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000070struct ebt_u_target *ebt_find_target(const char *name)
71{
72 struct ebt_u_target *t = ebt_targets;
73
Bart De Schuymer6622a012005-01-19 21:09:05 +000074 while (t && strcmp(t->name, name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000075 t = t->next;
76 return t;
77}
78
79struct ebt_u_match *ebt_find_match(const char *name)
80{
81 struct ebt_u_match *m = ebt_matches;
82
Bart De Schuymer6622a012005-01-19 21:09:05 +000083 while (m && strcmp(m->name, name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000084 m = m->next;
85 return m;
86}
87
88struct ebt_u_watcher *ebt_find_watcher(const char *name)
89{
90 struct ebt_u_watcher *w = ebt_watchers;
91
Bart De Schuymer6622a012005-01-19 21:09:05 +000092 while (w && strcmp(w->name, name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000093 w = w->next;
94 return w;
95}
96
97struct ebt_u_table *ebt_find_table(const char *name)
98{
99 struct ebt_u_table *t = ebt_tables;
100
101 while (t && strcmp(t->name, name))
102 t = t->next;
103 return t;
104}
105
Bart De Schuymer6622a012005-01-19 21:09:05 +0000106/* Prints all registered extensions */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000107void ebt_list_extensions()
108{
109 struct ebt_u_table *tbl = ebt_tables;
110 struct ebt_u_target *t = ebt_targets;
111 struct ebt_u_match *m = ebt_matches;
112 struct ebt_u_watcher *w = ebt_watchers;
113
114 PRINT_VERSION;
115 printf("Supported userspace extensions:\n\nSupported tables:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000116 while (tbl) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000117 printf("%s\n", tbl->name);
118 tbl = tbl->next;
119 }
120 printf("\nSupported targets:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000121 while (t) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000122 printf("%s\n", t->name);
123 t = t->next;
124 }
125 printf("\nSupported matches:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000126 while (m) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000127 printf("%s\n", m->name);
128 m = m->next;
129 }
130 printf("\nSupported watchers:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000131 while (w) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000132 printf("%s\n", w->name);
133 w = w->next;
134 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000135}
136
Bart De Schuymer6622a012005-01-19 21:09:05 +0000137/* Get the table from the kernel or from a binary file
Bart De Schuymer64182a32004-01-21 20:39:54 +0000138 * init: 1 = ask the kernel for the initial contents of a table, i.e. the
139 * way it looks when the table is insmod'ed
Bart De Schuymer6622a012005-01-19 21:09:05 +0000140 * 0 = get the current data in the table */
141int ebt_get_kernel_table(struct ebt_u_replace *replace, int init)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000142{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000143 if (!ebt_find_table(replace->name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000144 ebt_print_error("Bad table name");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000145 return -1;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000146 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000147 /* Get the kernel's information */
148 if (ebt_get_table(replace, init)) {
149 if (ebt_errormsg[0] != '\0')
150 return -1;
151 ebtables_insmod("ebtables");
152 if (ebt_get_table(replace, init)) {
153 ebt_print_error("The kernel doesn't support the ebtables %s table", replace->name);
154 return -1;
155 }
156 }
157 return 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000158}
159
Bart De Schuymer6622a012005-01-19 21:09:05 +0000160/* Put sane values into a new entry */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000161void ebt_initialize_entry(struct ebt_u_entry *e)
162{
163 e->bitmask = EBT_NOPROTO;
164 e->invflags = 0;
165 e->ethproto = 0;
166 strcpy(e->in, "");
167 strcpy(e->out, "");
168 strcpy(e->logical_in, "");
169 strcpy(e->logical_out, "");
170 e->m_list = NULL;
171 e->w_list = NULL;
172 e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000173 ebt_find_target(EBT_STANDARD_TARGET)->used = 1;
Bart De Schuymerd2ced822005-01-23 19:19:00 +0000174 e->cnt.pcnt = e->cnt.bcnt = 0;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000175
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000176 if (!e->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000177 ebt_print_bug("Couldn't load standard target");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000178 ((struct ebt_standard_target *)((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000179}
180
Bart De Schuymer6622a012005-01-19 21:09:05 +0000181/* Free up the memory of the table held in userspace, *replace can be reused */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000182void ebt_cleanup_replace(struct ebt_u_replace *replace)
183{
184 int i;
185 struct ebt_u_entries *entries;
186 struct ebt_u_chain_list *udc1, *udc2;
187 struct ebt_cntchanges *cc1, *cc2;
188 struct ebt_u_entry *u_e1, *u_e2;
189
190 replace->name[0] = '\0';
191 replace->valid_hooks = 0;
192 replace->nentries = 0;
193 replace->num_counters = 0;
194 replace->flags = 0;
195 replace->command = 0;
196 replace->selected_chain = -1;
197 if (replace->filename) {
198 free(replace->filename);
199 replace->filename = NULL;
200 }
201 if (replace->counters) {
202 free(replace->counters);
203 replace->counters = NULL;
204 }
205
206 i = -1;
207 while (1) {
208 i++;
209 entries = ebt_nr_to_chain(replace, i);
210 if (!entries) {
211 if (i < NF_BR_NUMHOOKS)
212 continue;
213 else
214 break;
215 }
216 entries->nentries = 0;
217 entries->counter_offset = 0;
218 u_e1 = entries->entries;
219 entries->entries = NULL;
220 while (u_e1) {
221 ebt_free_u_entry(u_e1);
222 u_e2 = u_e1->next;
223 free(u_e1);
224 u_e1 = u_e2;
225 }
226 }
227 udc1 = replace->udc;
228 while (udc1) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000229 free(udc1->udc);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000230 udc2 = udc1->next;
231 free(udc1);
232 udc1 = udc2;
233 }
234 replace->udc = NULL;
235 cc1 = replace->counterchanges;
236 while (cc1) {
237 cc2 = cc1->next;
238 free(cc2);
239 cc1 = cc2;
240 }
241 replace->counterchanges = NULL;
242}
243
Bart De Schuymer6622a012005-01-19 21:09:05 +0000244/* Should be called, e.g., between 2 rule adds */
245void ebt_reinit_extensions()
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000246{
247 struct ebt_u_match *m;
248 struct ebt_u_watcher *w;
249 struct ebt_u_target *t;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000250 int size;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000251
252 /* The init functions should determine by themselves whether they are
253 * called for the first time or not (when necessary). */
254 for (m = ebt_matches; m; m = m->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000255 size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000256 if (m->used) {
257 m->m = (struct ebt_entry_match *)malloc(size);
258 if (!m->m)
259 ebt_print_memory();
260 strcpy(m->m->u.name, m->name);
261 m->m->match_size = EBT_ALIGN(m->size);
262 m->used = 0;
263 m->flags = 0;
264 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000265 m->init(m->m);
266 }
267 for (w = ebt_watchers; w; w = w->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000268 size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000269 if (w->used) {
270 w->w = (struct ebt_entry_watcher *)malloc(size);
271 if (!w->w)
272 ebt_print_memory();
273 strcpy(w->w->u.name, w->name);
274 w->w->watcher_size = EBT_ALIGN(w->size);
275 w->used = 0;
276 w->flags = 0;
277 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000278 w->init(w->w);
279 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000280 for (t = ebt_targets; t; t = t->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000281 size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000282 if (t->used) {
283 t->t = (struct ebt_entry_target *)malloc(size);
284 if (!t->t)
285 ebt_print_memory();
286 strcpy(t->t->u.name, t->name);
287 t->t->target_size = EBT_ALIGN(t->size);
288 t->used = 0;
289 t->flags = 0;
290 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000291 t->init(t->t);
292 }
293}
294
Bart De Schuymer6622a012005-01-19 21:09:05 +0000295/* This doesn't free e, because the calling function might need e->next */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000296void ebt_free_u_entry(struct ebt_u_entry *e)
297{
298 struct ebt_u_match_list *m_l, *m_l2;
299 struct ebt_u_watcher_list *w_l, *w_l2;
300
301 m_l = e->m_list;
302 while (m_l) {
303 m_l2 = m_l->next;
304 free(m_l->m);
305 free(m_l);
306 m_l = m_l2;
307 }
308 w_l = e->w_list;
309 while (w_l) {
310 w_l2 = w_l->next;
311 free(w_l->w);
312 free(w_l);
313 w_l = w_l2;
314 }
315 free(e->t);
316}
317
Bart De Schuymer6622a012005-01-19 21:09:05 +0000318/* Blatently stolen (again) from iptables.c userspace program
319 * find out where the modprobe utility is located */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000320static char *get_modprobe(void)
321{
322 int procfile;
323 char *ret;
324
325 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
326 if (procfile < 0)
327 return NULL;
328
329 ret = malloc(1024);
330 if (ret) {
331 switch (read(procfile, ret, 1024)) {
332 case -1: goto fail;
333 case 1024: goto fail; /* Partial read. Wierd */
334 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000335 if (ret[strlen(ret)-1] == '\n')
336 ret[strlen(ret)-1] = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000337 close(procfile);
338 return ret;
339 }
340 fail:
341 free(ret);
342 close(procfile);
343 return NULL;
344}
345
346char *ebt_modprobe;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000347/* Try to load the kernel module */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000348int ebtables_insmod(const char *modname)
349{
350 char *buf = NULL;
351 char *argv[3];
352
353 /* If they don't explicitly set it, read out of kernel */
354 if (!ebt_modprobe) {
355 buf = get_modprobe();
356 if (!buf)
357 return -1;
358 ebt_modprobe = buf;
359 }
360
361 switch (fork()) {
362 case 0:
363 argv[0] = (char *)ebt_modprobe;
364 argv[1] = (char *)modname;
365 argv[2] = NULL;
366 execv(argv[0], argv);
367
Bart De Schuymer6622a012005-01-19 21:09:05 +0000368 /* Not usually reached */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000369 exit(0);
370 case -1:
371 return -1;
372
Bart De Schuymer6622a012005-01-19 21:09:05 +0000373 default: /* Parent */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000374 wait(NULL);
375 }
376
377 free(buf);
378 return 0;
379}
380
Bart De Schuymer6622a012005-01-19 21:09:05 +0000381/* Gives back a pointer to the chain base, based on nr.
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000382 * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain.
Bart De Schuymer6622a012005-01-19 21:09:05 +0000383 * Returns NULL on failure. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000384struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace,
385 int nr)
386{
387 if (nr == -1)
388 return NULL;
389 if (nr < NF_BR_NUMHOOKS)
390 return replace->hook_entry[nr];
391 else {
392 int i;
393 struct ebt_u_chain_list *cl = replace->udc;
394
395 i = nr - NF_BR_NUMHOOKS;
396 while (i > 0 && cl) {
397 cl = cl->next;
398 i--;
399 }
400 if (cl)
401 return cl->udc;
402 else
403 return NULL;
404 }
405}
406
Bart De Schuymer6622a012005-01-19 21:09:05 +0000407/* Gives back a pointer to the chain base of selected_chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000408struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace)
409{
410 return ebt_nr_to_chain(replace, replace->selected_chain);
411}
412
Bart De Schuymer6622a012005-01-19 21:09:05 +0000413/* Parse the chain name and return a pointer to the chain base.
414 * Returns NULL on failure. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000415struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
Bart De Schuymer6622a012005-01-19 21:09:05 +0000416 const char* arg)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000417{
418 int i;
419 struct ebt_u_chain_list *cl = replace->udc;
420
421 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
422 if (!(replace->valid_hooks & (1 << i)))
423 continue;
424 if (!strcmp(arg, replace->hook_entry[i]->name))
425 return replace->hook_entry[i];
426 }
427 while(cl) {
428 if (!strcmp(arg, cl->udc->name))
429 return cl->udc;
430 cl = cl->next;
431 }
432 return NULL;
433}
434
Bart De Schuymer6622a012005-01-19 21:09:05 +0000435/* Parse the chain name and return the corresponding chain nr
436 * returns -1 on failure */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000437int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg)
438{
439 int i;
440 struct ebt_u_chain_list *cl = replace->udc;
441
442 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
443 if (!(replace->valid_hooks & (1 << i)))
444 continue;
445 if (!strcmp(arg, replace->hook_entry[i]->name))
446 return i;
447 }
448 while(cl) {
449 if (!strcmp(arg, cl->udc->name))
450 return i;
451 i++;
452 cl = cl->next;
453 }
454 return -1;
455}
456
457 /*
458************
459************
460**COMMANDS**
461************
462************
463 */
464
Bart De Schuymer6622a012005-01-19 21:09:05 +0000465/* Change the policy of selected_chain.
466 * Handing a bad policy to this function is a bug. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000467void ebt_change_policy(struct ebt_u_replace *replace, int policy)
468{
469 struct ebt_u_entries *entries = ebt_to_chain(replace);
470
471 if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000472 ebt_print_bug("Wrong policy: %d", policy);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000473 entries->policy = policy;
474}
475
Bart De Schuymer6622a012005-01-19 21:09:05 +0000476/* Flush one chain or the complete table
477 * If selected_chain == -1: flush the complete table */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000478void ebt_flush_chains(struct ebt_u_replace *replace)
479{
480 int i, j, numdel;
481 struct ebt_u_entry *u_e, *tmp;
482 struct ebt_u_entries *entries = ebt_to_chain(replace);
483 struct ebt_cntchanges *cc = replace->counterchanges;
484 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
485
Bart De Schuymer6622a012005-01-19 21:09:05 +0000486 /* Flush whole table */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000487 if (!entries) {
488 if (replace->nentries == 0)
489 return;
490 replace->nentries = 0;
491
Bart De Schuymer6622a012005-01-19 21:09:05 +0000492 /* Free everything and zero (n)entries */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000493 i = -1;
494 while (1) {
495 i++;
496 entries = ebt_nr_to_chain(replace, i);
497 if (!entries) {
498 if (i < NF_BR_NUMHOOKS)
499 continue;
500 else
501 break;
502 }
503 entries->nentries = 0;
504 entries->counter_offset = 0;
505 u_e = entries->entries;
506 entries->entries = NULL;
507 while (u_e) {
508 ebt_free_u_entry(u_e);
509 tmp = u_e->next;
510 free(u_e);
511 u_e = tmp;
512 }
513 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000514 /* Update the counters */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000515 while (cc) {
516 if (cc->type == CNT_ADD) {
517 *prev_cc = cc->next;
518 free(cc);
519 cc = *prev_cc;
520 continue;
521 }
522 cc->type = CNT_DEL;
523 prev_cc = &(cc->next);
524 cc = cc->next;
525 }
526 return;
527 }
528
529 if (entries->nentries == 0)
530 return;
531 replace->nentries -= entries->nentries;
532 numdel = entries->nentries;
533
Bart De Schuymer6622a012005-01-19 21:09:05 +0000534 /* Delete the counters belonging to the specified chain,
535 * update counter_offset */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000536 i = -1;
537 while (1) {
538 i++;
539 entries = ebt_nr_to_chain(replace, i);
540 if (!entries) {
541 if (i < NF_BR_NUMHOOKS)
542 continue;
543 else
544 break;
545 }
546 if (i > replace->selected_chain) {
547 entries->counter_offset -= numdel;
548 continue;
549 }
550 j = entries->nentries;
551 while (j) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000552 /* Don't count deleted entries */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000553 if (cc->type == CNT_DEL)
554 goto letscontinue;
555 if (i == replace->selected_chain) {
556 if (cc->type == CNT_ADD) {
557 *prev_cc = cc->next;
558 free(cc);
559 cc = *prev_cc;
560 j--;
561 continue;
562 }
563 cc->type = CNT_DEL;
564 }
565 j--;
566letscontinue:
567 prev_cc = &(cc->next);
568 cc = cc->next;
569 }
570 }
571
572 entries = ebt_to_chain(replace);
573 entries->nentries = 0;
574 u_e = entries->entries;
575 while (u_e) {
576 ebt_free_u_entry(u_e);
577 tmp = u_e->next;
578 free(u_e);
579 u_e = tmp;
580 }
581 entries->entries = NULL;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000582}
583
Bart De Schuymer6622a012005-01-19 21:09:05 +0000584/* Returns the rule number on success (starting from 0), -1 on failure
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000585 *
586 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer6622a012005-01-19 21:09:05 +0000587 * to contain pointers to ebt_u_{match,watcher,target} */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000588int ebt_check_rule_exists(struct ebt_u_replace *replace,
589 struct ebt_u_entry *new_entry)
590{
591 struct ebt_u_entry *u_e;
592 struct ebt_u_match_list *m_l, *m_l2;
593 struct ebt_u_match *m;
594 struct ebt_u_watcher_list *w_l, *w_l2;
595 struct ebt_u_watcher *w;
596 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
597 struct ebt_u_entries *entries = ebt_to_chain(replace);
598 int i, j, k;
599
600 u_e = entries->entries;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000601 /* Check for an existing rule (if there are duplicate rules,
602 * take the first occurance) */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000603 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
604 if (!u_e)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000605 ebt_print_bug("Hmm, trouble");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000606 if (u_e->ethproto != new_entry->ethproto)
607 continue;
608 if (strcmp(u_e->in, new_entry->in))
609 continue;
610 if (strcmp(u_e->out, new_entry->out))
611 continue;
612 if (strcmp(u_e->logical_in, new_entry->logical_in))
613 continue;
614 if (strcmp(u_e->logical_out, new_entry->logical_out))
615 continue;
616 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer6622a012005-01-19 21:09:05 +0000617 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000618 continue;
619 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer6622a012005-01-19 21:09:05 +0000620 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000621 continue;
622 if (new_entry->bitmask != u_e->bitmask ||
Bart De Schuymer6622a012005-01-19 21:09:05 +0000623 new_entry->invflags != u_e->invflags)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000624 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000625 /* Compare all matches */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000626 m_l = new_entry->m_list;
627 j = 0;
628 while (m_l) {
629 m = (struct ebt_u_match *)(m_l->m);
630 m_l2 = u_e->m_list;
631 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
632 m_l2 = m_l2->next;
633 if (!m_l2 || !m->compare(m->m, m_l2->m))
634 goto letscontinue;
635 j++;
636 m_l = m_l->next;
637 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000638 /* Now be sure they have the same nr of matches */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000639 k = 0;
640 m_l = u_e->m_list;
641 while (m_l) {
642 k++;
643 m_l = m_l->next;
644 }
645 if (j != k)
646 continue;
647
Bart De Schuymer6622a012005-01-19 21:09:05 +0000648 /* Compare all watchers */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000649 w_l = new_entry->w_list;
650 j = 0;
651 while (w_l) {
652 w = (struct ebt_u_watcher *)(w_l->w);
653 w_l2 = u_e->w_list;
654 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
655 w_l2 = w_l2->next;
656 if (!w_l2 || !w->compare(w->w, w_l2->w))
657 goto letscontinue;
658 j++;
659 w_l = w_l->next;
660 }
661 k = 0;
662 w_l = u_e->w_list;
663 while (w_l) {
664 k++;
665 w_l = w_l->next;
666 }
667 if (j != k)
668 continue;
669 if (strcmp(t->t->u.name, u_e->t->u.name))
670 continue;
671 if (!t->compare(t->t, u_e->t))
672 continue;
673 return i;
Bart De Schuymeraef08942004-09-09 21:41:29 +0000674letscontinue:;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000675 }
676 return -1;
677}
678
679/* Add a rule, rule_nr is the rule to update
680 * rule_nr specifies where the rule should be inserted
681 * rule_nr > 0 : insert the rule right before the rule_nr'th rule
682 * (the first rule is rule 1)
683 * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule,
Bart De Schuymer6622a012005-01-19 21:09:05 +0000684 * where n denotes the number of rules in the chain
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000685 * rule_nr == 0: add a new rule at the end of the chain
686 *
687 * This function expects the ebt_{match,watcher,target} members of new_entry
688 * to contain pointers to ebt_u_{match,watcher,target} and updates these
Bart De Schuymer6622a012005-01-19 21:09:05 +0000689 * pointers so that they point to ebt_{match,watcher,target}, before adding
690 * the rule to the chain. Don't free() the ebt_{match,watcher,target} after a
691 * successful call to ebt_add_rule() */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000692void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
693 int rule_nr)
694{
695 int i, j;
696 struct ebt_u_entry **u_e;
697 struct ebt_u_match_list *m_l;
698 struct ebt_u_watcher_list *w_l;
699 struct ebt_u_entries *entries = ebt_to_chain(replace);
700 struct ebt_cntchanges *cc = replace->counterchanges, *new_cc;
701 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
702
703 if (rule_nr <= 0)
704 rule_nr += entries->nentries;
705 else
706 rule_nr--;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000707 if (rule_nr > entries->nentries || rule_nr < 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000708 ebt_print_error("The specified rule number is incorrect");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000709 return;
710 }
711 /* We're adding one rule */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000712 replace->nentries++;
713 entries->nentries++;
714
Bart De Schuymer6622a012005-01-19 21:09:05 +0000715 /* Handle counter stuff */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000716 for (i = 0; i < replace->selected_chain; i++) {
717 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
718 continue;
719 j = ebt_nr_to_chain(replace, i)->nentries;
720 while (j) {
721 if (cc->type != CNT_DEL)
722 j--;
723 prev_cc = &(cc->next);
724 cc = cc->next;
725 }
726 }
727 j = rule_nr;
728 while (j) {
729 if (cc->type != CNT_DEL)
730 j--;
731 prev_cc = &(cc->next);
732 cc = cc->next;
733 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000734 if (cc && cc->type == CNT_DEL)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000735 cc->type = CNT_OWRITE;
736 else {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000737 new_cc = (struct ebt_cntchanges *)
738 malloc(sizeof(struct ebt_cntchanges));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000739 if (!new_cc)
740 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000741 new_cc->type = CNT_ADD;
742 new_cc->next = cc;
743 *prev_cc = new_cc;
744 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000745 /* Go to the right position in the chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000746 u_e = &entries->entries;
747 for (i = 0; i < rule_nr; i++)
748 u_e = &(*u_e)->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000749 /* Insert the rule */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000750 new_entry->next = *u_e;
751 *u_e = new_entry;
752
Bart De Schuymer6622a012005-01-19 21:09:05 +0000753 /* Put the ebt_{match, watcher, target} pointers in place */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000754 m_l = new_entry->m_list;
755 while (m_l) {
756 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
757 m_l = m_l->next;
758 }
759 w_l = new_entry->w_list;
760 while (w_l) {
761 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
762 w_l = w_l->next;
763 }
764 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000765 /* Update the counter_offset of chains behind this one */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000766 i = replace->selected_chain;
767 while (1) {
768 i++;
769 entries = ebt_nr_to_chain(replace, i);
770 if (!entries) {
771 if (i < NF_BR_NUMHOOKS)
772 continue;
773 else
774 break;
775 } else
776 entries->counter_offset++;
777 }
778}
779
Bart De Schuymer6622a012005-01-19 21:09:05 +0000780/* Delete a rule or rules
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000781 * begin == end == 0: delete the rule corresponding to new_entry
782 *
Bart De Schuymer6622a012005-01-19 21:09:05 +0000783 * The first rule has rule nr 1, the last rule has rule nr -1, etc.
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000784 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer6622a012005-01-19 21:09:05 +0000785 * to contain pointers to ebt_u_{match,watcher,target}. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000786void ebt_delete_rule(struct ebt_u_replace *replace,
787 struct ebt_u_entry *new_entry, int begin, int end)
788{
789 int i, j, nr_deletes;
790 struct ebt_u_entry **u_e, *u_e2;
791 struct ebt_u_entries *entries = ebt_to_chain(replace);
792 struct ebt_cntchanges *cc = replace->counterchanges;
793 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
794
795 if (begin < 0)
796 begin += entries->nentries + 1;
797 if (end < 0)
798 end += entries->nentries + 1;
799
Bart De Schuymer6622a012005-01-19 21:09:05 +0000800 if (begin < 0 || begin > end || end > entries->nentries) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000801 ebt_print_error("Sorry, wrong rule numbers");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000802 return;
803 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000804
805 if ((begin * end == 0) && (begin + end != 0))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000806 ebt_print_bug("begin and end should be either both zero, "
807 "either both non-zero");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000808 if (begin != 0 && end != 0) {
809 begin--;
810 end--;
811 } else {
812 begin = ebt_check_rule_exists(replace, new_entry);
813 end = begin;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000814 if (begin == -1) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000815 ebt_print_error("Sorry, rule does not exist");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000816 return;
817 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000818 }
819
Bart De Schuymer6622a012005-01-19 21:09:05 +0000820 /* We're deleting rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000821 nr_deletes = end - begin + 1;
822 replace->nentries -= nr_deletes;
823 entries->nentries -= nr_deletes;
824
Bart De Schuymer6622a012005-01-19 21:09:05 +0000825 /* Handle counter stuff */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000826 for (i = 0; i < replace->selected_chain; i++) {
827 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
828 continue;
829 j = ebt_nr_to_chain(replace, i)->nentries;
830 while (j) {
831 if (cc->type != CNT_DEL)
832 j--;
833 prev_cc = &(cc->next);
834 cc = cc->next;
835 }
836 }
837 j = begin;
838 while (j) {
839 if (cc->type != CNT_DEL)
840 j--;
841 prev_cc = &(cc->next);
842 cc = cc->next;
843 }
844 j = nr_deletes;
845 while (j) {
846 if (cc->type != CNT_DEL) {
847 j--;
848 if (cc->type == CNT_ADD) {
849 *prev_cc = cc->next;
850 free(cc);
851 cc = *prev_cc;
852 continue;
853 }
854 cc->type = CNT_DEL;
855 }
856 prev_cc = &(cc->next);
857 cc = cc->next;
858 }
859
Bart De Schuymer6622a012005-01-19 21:09:05 +0000860 /* Go to the right position in the chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000861 u_e = &entries->entries;
862 for (j = 0; j < begin; j++)
863 u_e = &(*u_e)->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000864 /* Remove the rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000865 j = nr_deletes;
866 while(j--) {
867 u_e2 = *u_e;
868 *u_e = (*u_e)->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000869 /* Free everything */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000870 ebt_free_u_entry(u_e2);
871 free(u_e2);
872 }
873
Bart De Schuymer6622a012005-01-19 21:09:05 +0000874 /* Update the counter_offset of chains behind this one */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000875 j = replace->selected_chain;
876 while (1) {
877 j++;
878 entries = ebt_nr_to_chain(replace, j);
879 if (!entries) {
880 if (j < NF_BR_NUMHOOKS)
881 continue;
882 else
883 break;
884 } else
885 entries->counter_offset -= nr_deletes;
886 }
887}
888
Bart De Schuymer6622a012005-01-19 21:09:05 +0000889/* Selected_chain == -1 : zero all counters
890 * Otherwise, zero the counters of selected_chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000891void ebt_zero_counters(struct ebt_u_replace *replace)
892{
893 struct ebt_u_entries *entries = ebt_to_chain(replace);
894 struct ebt_cntchanges *cc = replace->counterchanges;
895 int i, j;
896
897 if (!entries) {
898 while (cc) {
899 if (cc->type == CNT_NORM)
900 cc->type = CNT_ZERO;
901 cc = cc->next;
902 }
903 } else {
904 if (entries->nentries == 0)
905 return;
906
907 for (i = 0; i < replace->selected_chain; i++) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000908 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000909 continue;
910 j = ebt_nr_to_chain(replace, i)->nentries;
911 while (j) {
912 if (cc->type != CNT_DEL)
913 j--;
914 cc = cc->next;
915 }
916 }
917 j = entries->nentries;
918 while (j) {
919 if (cc->type != CNT_DEL) {
920 j--;
921 if (cc->type == CNT_NORM)
922 cc->type = CNT_ZERO;
923 }
924 cc = cc->next;
925 }
926 }
927}
928
Bart De Schuymer6622a012005-01-19 21:09:05 +0000929/* Add a new chain and specify its policy */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000930void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
931{
932 struct ebt_u_chain_list *cl, **cl2;
933
Bart De Schuymer6622a012005-01-19 21:09:05 +0000934 if (ebt_get_chainnr(replace, name) != -1) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000935 ebt_print_error("Chain %s already exists", optarg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000936 return;
937 } else if (ebt_find_target(name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000938 ebt_print_error("Target with name %s exists", optarg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000939 return;
940 } else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000941 ebt_print_error("Chain name length can't exceed %d",
942 EBT_CHAIN_MAXNAMELEN - 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000943 return;
944 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000945 cl = (struct ebt_u_chain_list *)
946 malloc(sizeof(struct ebt_u_chain_list));
947 if (!cl)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000948 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000949 cl->next = NULL;
950 cl->udc = (struct ebt_u_entries *)
951 malloc(sizeof(struct ebt_u_entries));
952 if (!cl->udc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000953 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000954 cl->udc->nentries = 0;
955 cl->udc->policy = policy;
956 cl->udc->counter_offset = replace->nentries;
957 cl->udc->hook_mask = 0;
958 strcpy(cl->udc->name, name);
959 cl->udc->entries = NULL;
960 cl->kernel_start = NULL;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000961 /* Put the new chain at the end */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000962 cl2 = &(replace->udc);
963 while (*cl2)
964 cl2 = &((*cl2)->next);
965 *cl2 = cl;
966}
967
Bart De Schuymer6622a012005-01-19 21:09:05 +0000968/* Selected_chain == -1: delete all non-referenced udc
969 * selected_chain < NF_BR_NUMHOOKS is illegal */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000970void ebt_delete_chain(struct ebt_u_replace *replace)
971{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000972 int chain_nr = replace->selected_chain, print_error = 1;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000973
974 if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000975 ebt_print_bug("You can't remove a standard chain");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000976 if (chain_nr == -1) {
977 print_error = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000978 replace->selected_chain = NF_BR_NUMHOOKS;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000979 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000980 do {
981 if (ebt_to_chain(replace) == NULL) {
982 if (chain_nr == -1)
983 break;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000984 ebt_print_bug("udc nr %d doesn't exist", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000985 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000986 /* If the chain is referenced, don't delete it,
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000987 * also decrement jumps to a chain behind the
Bart De Schuymer6622a012005-01-19 21:09:05 +0000988 * one we're deleting */
989 if (ebt_check_for_references(replace, print_error)) {
990 if (chain_nr != -1)
991 break;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000992 replace->selected_chain++;
993 continue;
994 }
995 decrease_chain_jumps(replace);
996 ebt_flush_chains(replace);
997 remove_udc(replace);
Bart De Schuymerc6c0dc32004-12-16 19:30:32 +0000998 } while (chain_nr == -1);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000999 replace->selected_chain = chain_nr; /* Put back to -1 */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001000}
1001
Bart De Schuymer6622a012005-01-19 21:09:05 +00001002/* Rename an existing chain. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001003void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
1004{
1005 struct ebt_u_entries *entries = ebt_to_chain(replace);
1006
1007 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001008 ebt_print_bug("ebt_rename_chain: entries == NULL");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001009 strcpy(entries->name, name);
1010}
1011
1012
1013 /*
1014*************************
1015*************************
1016**SPECIALIZED*FUNCTIONS**
1017*************************
1018*************************
1019 */
1020
1021
Bart De Schuymer6622a012005-01-19 21:09:05 +00001022/* Executes the final_check() function for all extensions used by the rule
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001023 * ebt_check_for_loops should have been executed earlier, to make sure the
Bart De Schuymer6622a012005-01-19 21:09:05 +00001024 * hook_mask is correct. The time argument to final_check() is set to 1,
1025 * meaning it's the second time the final_check() function is executed. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001026void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
1027 struct ebt_u_entries *entries)
1028{
1029 struct ebt_u_match_list *m_l;
1030 struct ebt_u_watcher_list *w_l;
1031 struct ebt_u_target *t;
1032 struct ebt_u_match *m;
1033 struct ebt_u_watcher *w;
1034
1035 m_l = e->m_list;
1036 w_l = e->w_list;
1037 while (m_l) {
1038 m = ebt_find_match(m_l->m->u.name);
1039 m->final_check(e, m_l->m, replace->name,
1040 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001041 if (ebt_errormsg[0] != '\0')
1042 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001043 m_l = m_l->next;
1044 }
1045 while (w_l) {
1046 w = ebt_find_watcher(w_l->w->u.name);
1047 w->final_check(e, w_l->w, replace->name,
1048 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001049 if (ebt_errormsg[0] != '\0')
1050 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001051 w_l = w_l->next;
1052 }
1053 t = ebt_find_target(e->t->u.name);
1054 t->final_check(e, e->t, replace->name,
1055 entries->hook_mask, 1);
1056}
1057
Bart De Schuymer6622a012005-01-19 21:09:05 +00001058/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1059 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1060int ebt_check_for_references(struct ebt_u_replace *replace, int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001061{
Bart De Schuymer6622a012005-01-19 21:09:05 +00001062 if (print_err)
1063 return iterate_entries(replace, 1);
1064 else
1065 return iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001066}
1067
Bart De Schuymer6622a012005-01-19 21:09:05 +00001068/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
1069 * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1070 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1071int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr,
1072 int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001073{
1074 int tmp = replace->selected_chain, ret;
1075
1076 replace->selected_chain = chain_nr;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001077 if (print_err)
1078 ret = iterate_entries(replace, 1);
1079 else
1080 ret = iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001081 replace->selected_chain = tmp;
1082 return ret;
1083}
1084
1085struct ebt_u_stack
1086{
1087 int chain_nr;
1088 int n;
1089 struct ebt_u_entry *e;
1090 struct ebt_u_entries *entries;
1091};
1092
Bart De Schuymer6622a012005-01-19 21:09:05 +00001093/* Checks for loops
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001094 * As a by-product, the hook_mask member of each chain is filled in
1095 * correctly. The check functions of the extensions need this hook_mask
Bart De Schuymer6622a012005-01-19 21:09:05 +00001096 * to know from which standard chains they can be called. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001097void ebt_check_for_loops(struct ebt_u_replace *replace)
1098{
1099 int chain_nr , i, j , k, sp = 0, verdict;
1100 struct ebt_u_entries *entries, *entries2;
1101 struct ebt_u_stack *stack = NULL;
1102 struct ebt_u_entry *e;
1103
1104 i = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001105 /* Initialize hook_mask to 0 */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001106 while (1) {
1107 i++;
1108 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
1109 continue;
1110 entries = ebt_nr_to_chain(replace, i);
1111 if (!entries)
1112 break;
1113 entries->hook_mask = 0;
1114 }
1115 if (i > NF_BR_NUMHOOKS) {
1116 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
1117 sizeof(struct ebt_u_stack));
1118 if (!stack)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001119 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001120 }
1121
Bart De Schuymer6622a012005-01-19 21:09:05 +00001122 /* Check for loops, starting from every base chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001123 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1124 if (!(replace->valid_hooks & (1 << i)))
1125 continue;
1126 entries = ebt_nr_to_chain(replace, i);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001127 /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain
1128 * (usefull in the final_check() funtions) */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001129 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
1130 chain_nr = i;
1131
1132 e = entries->entries;
1133 for (j = 0; j < entries->nentries; j++) {
1134 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
1135 goto letscontinue;
1136 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
1137 if (verdict < 0)
1138 goto letscontinue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001139 entries2 = ebt_nr_to_chain(replace, verdict + NF_BR_NUMHOOKS);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001140 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001141 /* Now see if we've been here before */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001142 for (k = 0; k < sp; k++)
Bart De Schuymer6622a012005-01-19 21:09:05 +00001143 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) {
1144 ebt_print_error("Loop from chain '%s' to chain '%s'",
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001145 ebt_nr_to_chain(replace, chain_nr)->name,
1146 ebt_nr_to_chain(replace, stack[k].chain_nr)->name);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001147 goto free_stack;
1148 }
1149 /* Jump to the chain, make sure we know how to get back */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001150 stack[sp].chain_nr = chain_nr;
1151 stack[sp].n = j;
1152 stack[sp].entries = entries;
1153 stack[sp].e = e;
1154 sp++;
1155 j = -1;
1156 e = entries2->entries;
1157 chain_nr = verdict + NF_BR_NUMHOOKS;
1158 entries = entries2;
1159 continue;
1160letscontinue:
1161 e = e->next;
1162 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001163 /* We are at the end of a standard chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001164 if (sp == 0)
1165 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001166 /* Go back to the chain one level higher */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001167 sp--;
1168 j = stack[sp].n;
1169 chain_nr = stack[sp].chain_nr;
1170 e = stack[sp].e;
1171 entries = stack[sp].entries;
1172 goto letscontinue;
1173 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001174free_stack:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001175 free(stack);
1176 return;
1177}
1178
Bart De Schuymer6622a012005-01-19 21:09:05 +00001179/* The user will use the match, so put it in new_entry. The ebt_u_match
1180 * pointer is put in the ebt_entry_match pointer. ebt_add_rule will
1181 * fill in the final value for new->m. Unless the rule is added to a chain,
1182 * the pointer will keep pointing to the ebt_u_match (until the new_entry
1183 * is freed). I know, I should use a union for these 2 pointer types... */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001184void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m)
1185{
1186 struct ebt_u_match_list **m_list, *new;
1187
1188 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
1189 new = (struct ebt_u_match_list *)
1190 malloc(sizeof(struct ebt_u_match_list));
1191 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001192 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001193 *m_list = new;
1194 new->next = NULL;
1195 new->m = (struct ebt_entry_match *)m;
1196}
1197
1198void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w)
1199{
1200 struct ebt_u_watcher_list **w_list;
1201 struct ebt_u_watcher_list *new;
1202
1203 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
1204 new = (struct ebt_u_watcher_list *)
1205 malloc(sizeof(struct ebt_u_watcher_list));
1206 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001207 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001208 *w_list = new;
1209 new->next = NULL;
1210 new->w = (struct ebt_entry_watcher *)w;
1211}
1212
1213
1214 /*
1215*******************
1216*******************
1217**OTHER*FUNCTIONS**
1218*******************
1219*******************
1220 */
1221
1222
Bart De Schuymer6622a012005-01-19 21:09:05 +00001223/* type = 0 => update chain jumps
1224 * type = 1 => check for reference, print error when referenced
1225 * type = 2 => check for reference, don't print error when referenced
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001226 *
Bart De Schuymer6622a012005-01-19 21:09:05 +00001227 * Returns 1 when type == 1 and the chain is referenced
1228 * returns 0 otherwise */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001229static int iterate_entries(struct ebt_u_replace *replace, int type)
1230{
1231 int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS;
1232 struct ebt_u_entries *entries;
1233 struct ebt_u_entry *e;
1234
1235 if (chain_nr < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001236 ebt_print_bug("iterate_entries: udc = %d < 0", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001237 while (1) {
1238 i++;
1239 entries = ebt_nr_to_chain(replace, i);
1240 if (!entries) {
1241 if (i < NF_BR_NUMHOOKS)
1242 continue;
1243 else
1244 break;
1245 }
1246 e = entries->entries;
1247 j = 0;
1248 while (e) {
1249 int chain_jmp;
1250
1251 j++;
1252 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1253 e = e->next;
1254 continue;
1255 }
Bart De Schuymer64182a32004-01-21 20:39:54 +00001256 chain_jmp = ((struct ebt_standard_target *)e->t)->
1257 verdict;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001258 switch (type) {
1259 case 1:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001260 case 2:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001261 if (chain_jmp == chain_nr) {
Bart De Schuymer6622a012005-01-19 21:09:05 +00001262 if (type == 2)
1263 return 1;
1264 ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d",
1265 ebt_nr_to_chain(replace, chain_nr + NF_BR_NUMHOOKS)->name, entries->name, j);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001266 return 1;
1267 }
1268 break;
1269 case 0:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001270 /* Adjust the chain jumps when necessary */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001271 if (chain_jmp > chain_nr)
1272 ((struct ebt_standard_target *)e->t)->verdict--;
1273 break;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001274 } /* End switch */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001275 e = e->next;
1276 }
1277 }
1278 return 0;
1279}
1280
1281static void decrease_chain_jumps(struct ebt_u_replace *replace)
1282{
1283 iterate_entries(replace, 0);
1284}
1285
Bart De Schuymer6622a012005-01-19 21:09:05 +00001286/* Selected_chain >= NF_BR_NUMHOOKS */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001287static void remove_udc(struct ebt_u_replace *replace)
1288{
1289 struct ebt_u_chain_list *cl, **cl2;
1290 struct ebt_u_entries *entries;
1291 struct ebt_u_entry *u_e, *tmp;
1292 int chain_nr = replace->selected_chain;
1293
1294 if (chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001295 ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr,
1296 NF_BR_NUMHOOKS);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001297 /* First free the rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001298 entries = ebt_nr_to_chain(replace, chain_nr);
1299 u_e = entries->entries;
1300 while (u_e) {
1301 ebt_free_u_entry(u_e);
1302 tmp = u_e->next;
1303 free(u_e);
1304 u_e = tmp;
1305 }
1306
1307 /* next, remove the chain */
1308 cl2 = &(replace->udc);
1309 while ((*cl2)->udc != entries)
1310 cl2 = &((*cl2)->next);
1311 cl = (*cl2);
1312 (*cl2) = (*cl2)->next;
1313 free(cl->udc);
1314 free(cl);
1315}
1316
Bart De Schuymer6622a012005-01-19 21:09:05 +00001317/* Used in initialization code of modules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001318void ebt_register_match(struct ebt_u_match *m)
1319{
1320 int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
1321 struct ebt_u_match **i;
1322
1323 m->m = (struct ebt_entry_match *)malloc(size);
1324 if (!m->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001325 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001326 strcpy(m->m->u.name, m->name);
1327 m->m->match_size = EBT_ALIGN(m->size);
1328 m->init(m->m);
1329
1330 for (i = &ebt_matches; *i; i = &((*i)->next));
1331 m->next = NULL;
1332 *i = m;
1333}
1334
1335void ebt_register_watcher(struct ebt_u_watcher *w)
1336{
1337 int size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
1338 struct ebt_u_watcher **i;
1339
1340 w->w = (struct ebt_entry_watcher *)malloc(size);
1341 if (!w->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001342 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001343 strcpy(w->w->u.name, w->name);
1344 w->w->watcher_size = EBT_ALIGN(w->size);
1345 w->init(w->w);
1346
1347 for (i = &ebt_watchers; *i; i = &((*i)->next));
1348 w->next = NULL;
1349 *i = w;
1350}
1351
1352void ebt_register_target(struct ebt_u_target *t)
1353{
1354 int size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
1355 struct ebt_u_target **i;
1356
1357 t->t = (struct ebt_entry_target *)malloc(size);
1358 if (!t->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001359 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001360 strcpy(t->t->u.name, t->name);
1361 t->t->target_size = EBT_ALIGN(t->size);
1362 t->init(t->t);
1363
1364 for (i = &ebt_targets; *i; i = &((*i)->next));
1365 t->next = NULL;
1366 *i = t;
1367}
1368
1369void ebt_register_table(struct ebt_u_table *t)
1370{
1371 t->next = ebt_tables;
1372 ebt_tables = t;
1373}
1374
1375void ebt_iterate_matches(void (*f)(struct ebt_u_match *))
1376{
1377 struct ebt_u_match *i;
1378
1379 for (i = ebt_matches; i; i = i->next)
1380 f(i);
1381}
1382
1383void ebt_iterate_watchers(void (*f)(struct ebt_u_watcher *))
1384{
1385 struct ebt_u_watcher *i;
1386
1387 for (i = ebt_watchers; i; i = i->next)
1388 f(i);
1389}
1390
1391void ebt_iterate_targets(void (*f)(struct ebt_u_target *))
1392{
1393 struct ebt_u_target *i;
1394
1395 for (i = ebt_targets; i; i = i->next)
1396 f(i);
1397}
1398
Bart De Schuymer6622a012005-01-19 21:09:05 +00001399/* Don't use this function, use ebt_print_bug() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001400void __ebt_print_bug(char *file, int line, char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001401{
1402 va_list l;
1403
1404 va_start(l, format);
1405 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
1406 vprintf(format, l);
1407 printf("\n");
1408 va_end(l);
1409 exit (-1);
1410}
1411
Bart De Schuymer6622a012005-01-19 21:09:05 +00001412/* The error messages are put in here when ebt_silent == 1
1413 * ebt_errormsg[0] == '\0' implies there was no error */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001414char ebt_errormsg[ERRORMSG_MAXLEN];
Bart De Schuymer6622a012005-01-19 21:09:05 +00001415/* When error messages should not be printed on the screen, after which
1416 * the program exit()s, set ebt_silent to 1. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001417int ebt_silent;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001418/* Don't use this function, use ebt_print_error() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001419void __ebt_print_error(char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001420{
1421 va_list l;
1422
1423 va_start(l, format);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001424 if (ebt_silent && ebt_errormsg[0] == '\0') {
1425 vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001426 va_end(l);
1427 } else {
1428 vprintf(format, l);
1429 printf("\n");
1430 va_end(l);
1431 exit (-1);
1432 }
1433}