blob: 0fef235e45375fa0c035cb42e75e117696c78d1d [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 Schuymer64182a32004-01-21 20:39:54 +0000174
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000175 if (!e->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000176 ebt_print_bug("Couldn't load standard target");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000177 ((struct ebt_standard_target *)((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000178}
179
Bart De Schuymer6622a012005-01-19 21:09:05 +0000180/* Free up the memory of the table held in userspace, *replace can be reused */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000181void ebt_cleanup_replace(struct ebt_u_replace *replace)
182{
183 int i;
184 struct ebt_u_entries *entries;
185 struct ebt_u_chain_list *udc1, *udc2;
186 struct ebt_cntchanges *cc1, *cc2;
187 struct ebt_u_entry *u_e1, *u_e2;
188
189 replace->name[0] = '\0';
190 replace->valid_hooks = 0;
191 replace->nentries = 0;
192 replace->num_counters = 0;
193 replace->flags = 0;
194 replace->command = 0;
195 replace->selected_chain = -1;
196 if (replace->filename) {
197 free(replace->filename);
198 replace->filename = NULL;
199 }
200 if (replace->counters) {
201 free(replace->counters);
202 replace->counters = NULL;
203 }
204
205 i = -1;
206 while (1) {
207 i++;
208 entries = ebt_nr_to_chain(replace, i);
209 if (!entries) {
210 if (i < NF_BR_NUMHOOKS)
211 continue;
212 else
213 break;
214 }
215 entries->nentries = 0;
216 entries->counter_offset = 0;
217 u_e1 = entries->entries;
218 entries->entries = NULL;
219 while (u_e1) {
220 ebt_free_u_entry(u_e1);
221 u_e2 = u_e1->next;
222 free(u_e1);
223 u_e1 = u_e2;
224 }
225 }
226 udc1 = replace->udc;
227 while (udc1) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000228 free(udc1->udc);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000229 udc2 = udc1->next;
230 free(udc1);
231 udc1 = udc2;
232 }
233 replace->udc = NULL;
234 cc1 = replace->counterchanges;
235 while (cc1) {
236 cc2 = cc1->next;
237 free(cc2);
238 cc1 = cc2;
239 }
240 replace->counterchanges = NULL;
241}
242
Bart De Schuymer6622a012005-01-19 21:09:05 +0000243/* Should be called, e.g., between 2 rule adds */
244void ebt_reinit_extensions()
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000245{
246 struct ebt_u_match *m;
247 struct ebt_u_watcher *w;
248 struct ebt_u_target *t;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000249 int size;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000250
251 /* The init functions should determine by themselves whether they are
252 * called for the first time or not (when necessary). */
253 for (m = ebt_matches; m; m = m->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000254 size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000255 if (m->used) {
256 m->m = (struct ebt_entry_match *)malloc(size);
257 if (!m->m)
258 ebt_print_memory();
259 strcpy(m->m->u.name, m->name);
260 m->m->match_size = EBT_ALIGN(m->size);
261 m->used = 0;
262 m->flags = 0;
263 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000264 m->init(m->m);
265 }
266 for (w = ebt_watchers; w; w = w->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000267 size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000268 if (w->used) {
269 w->w = (struct ebt_entry_watcher *)malloc(size);
270 if (!w->w)
271 ebt_print_memory();
272 strcpy(w->w->u.name, w->name);
273 w->w->watcher_size = EBT_ALIGN(w->size);
274 w->used = 0;
275 w->flags = 0;
276 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000277 w->init(w->w);
278 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000279 for (t = ebt_targets; t; t = t->next) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000280 size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000281 if (t->used) {
282 t->t = (struct ebt_entry_target *)malloc(size);
283 if (!t->t)
284 ebt_print_memory();
285 strcpy(t->t->u.name, t->name);
286 t->t->target_size = EBT_ALIGN(t->size);
287 t->used = 0;
288 t->flags = 0;
289 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000290 t->init(t->t);
291 }
292}
293
Bart De Schuymer6622a012005-01-19 21:09:05 +0000294/* This doesn't free e, because the calling function might need e->next */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000295void ebt_free_u_entry(struct ebt_u_entry *e)
296{
297 struct ebt_u_match_list *m_l, *m_l2;
298 struct ebt_u_watcher_list *w_l, *w_l2;
299
300 m_l = e->m_list;
301 while (m_l) {
302 m_l2 = m_l->next;
303 free(m_l->m);
304 free(m_l);
305 m_l = m_l2;
306 }
307 w_l = e->w_list;
308 while (w_l) {
309 w_l2 = w_l->next;
310 free(w_l->w);
311 free(w_l);
312 w_l = w_l2;
313 }
314 free(e->t);
315}
316
Bart De Schuymer6622a012005-01-19 21:09:05 +0000317/* Blatently stolen (again) from iptables.c userspace program
318 * find out where the modprobe utility is located */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000319static char *get_modprobe(void)
320{
321 int procfile;
322 char *ret;
323
324 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
325 if (procfile < 0)
326 return NULL;
327
328 ret = malloc(1024);
329 if (ret) {
330 switch (read(procfile, ret, 1024)) {
331 case -1: goto fail;
332 case 1024: goto fail; /* Partial read. Wierd */
333 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000334 if (ret[strlen(ret)-1] == '\n')
335 ret[strlen(ret)-1] = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000336 close(procfile);
337 return ret;
338 }
339 fail:
340 free(ret);
341 close(procfile);
342 return NULL;
343}
344
345char *ebt_modprobe;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000346/* Try to load the kernel module */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000347int ebtables_insmod(const char *modname)
348{
349 char *buf = NULL;
350 char *argv[3];
351
352 /* If they don't explicitly set it, read out of kernel */
353 if (!ebt_modprobe) {
354 buf = get_modprobe();
355 if (!buf)
356 return -1;
357 ebt_modprobe = buf;
358 }
359
360 switch (fork()) {
361 case 0:
362 argv[0] = (char *)ebt_modprobe;
363 argv[1] = (char *)modname;
364 argv[2] = NULL;
365 execv(argv[0], argv);
366
Bart De Schuymer6622a012005-01-19 21:09:05 +0000367 /* Not usually reached */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000368 exit(0);
369 case -1:
370 return -1;
371
Bart De Schuymer6622a012005-01-19 21:09:05 +0000372 default: /* Parent */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000373 wait(NULL);
374 }
375
376 free(buf);
377 return 0;
378}
379
Bart De Schuymer6622a012005-01-19 21:09:05 +0000380/* Gives back a pointer to the chain base, based on nr.
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000381 * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain.
Bart De Schuymer6622a012005-01-19 21:09:05 +0000382 * Returns NULL on failure. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000383struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace,
384 int nr)
385{
386 if (nr == -1)
387 return NULL;
388 if (nr < NF_BR_NUMHOOKS)
389 return replace->hook_entry[nr];
390 else {
391 int i;
392 struct ebt_u_chain_list *cl = replace->udc;
393
394 i = nr - NF_BR_NUMHOOKS;
395 while (i > 0 && cl) {
396 cl = cl->next;
397 i--;
398 }
399 if (cl)
400 return cl->udc;
401 else
402 return NULL;
403 }
404}
405
Bart De Schuymer6622a012005-01-19 21:09:05 +0000406/* Gives back a pointer to the chain base of selected_chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000407struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace)
408{
409 return ebt_nr_to_chain(replace, replace->selected_chain);
410}
411
Bart De Schuymer6622a012005-01-19 21:09:05 +0000412/* Parse the chain name and return a pointer to the chain base.
413 * Returns NULL on failure. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000414struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
Bart De Schuymer6622a012005-01-19 21:09:05 +0000415 const char* arg)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000416{
417 int i;
418 struct ebt_u_chain_list *cl = replace->udc;
419
420 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
421 if (!(replace->valid_hooks & (1 << i)))
422 continue;
423 if (!strcmp(arg, replace->hook_entry[i]->name))
424 return replace->hook_entry[i];
425 }
426 while(cl) {
427 if (!strcmp(arg, cl->udc->name))
428 return cl->udc;
429 cl = cl->next;
430 }
431 return NULL;
432}
433
Bart De Schuymer6622a012005-01-19 21:09:05 +0000434/* Parse the chain name and return the corresponding chain nr
435 * returns -1 on failure */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000436int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg)
437{
438 int i;
439 struct ebt_u_chain_list *cl = replace->udc;
440
441 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
442 if (!(replace->valid_hooks & (1 << i)))
443 continue;
444 if (!strcmp(arg, replace->hook_entry[i]->name))
445 return i;
446 }
447 while(cl) {
448 if (!strcmp(arg, cl->udc->name))
449 return i;
450 i++;
451 cl = cl->next;
452 }
453 return -1;
454}
455
456 /*
457************
458************
459**COMMANDS**
460************
461************
462 */
463
Bart De Schuymer6622a012005-01-19 21:09:05 +0000464/* Change the policy of selected_chain.
465 * Handing a bad policy to this function is a bug. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000466void ebt_change_policy(struct ebt_u_replace *replace, int policy)
467{
468 struct ebt_u_entries *entries = ebt_to_chain(replace);
469
470 if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000471 ebt_print_bug("Wrong policy: %d", policy);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000472 entries->policy = policy;
473}
474
Bart De Schuymer6622a012005-01-19 21:09:05 +0000475/* Flush one chain or the complete table
476 * If selected_chain == -1: flush the complete table */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000477void ebt_flush_chains(struct ebt_u_replace *replace)
478{
479 int i, j, numdel;
480 struct ebt_u_entry *u_e, *tmp;
481 struct ebt_u_entries *entries = ebt_to_chain(replace);
482 struct ebt_cntchanges *cc = replace->counterchanges;
483 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
484
Bart De Schuymer6622a012005-01-19 21:09:05 +0000485 /* Flush whole table */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000486 if (!entries) {
487 if (replace->nentries == 0)
488 return;
489 replace->nentries = 0;
490
Bart De Schuymer6622a012005-01-19 21:09:05 +0000491 /* Free everything and zero (n)entries */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000492 i = -1;
493 while (1) {
494 i++;
495 entries = ebt_nr_to_chain(replace, i);
496 if (!entries) {
497 if (i < NF_BR_NUMHOOKS)
498 continue;
499 else
500 break;
501 }
502 entries->nentries = 0;
503 entries->counter_offset = 0;
504 u_e = entries->entries;
505 entries->entries = NULL;
506 while (u_e) {
507 ebt_free_u_entry(u_e);
508 tmp = u_e->next;
509 free(u_e);
510 u_e = tmp;
511 }
512 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000513 /* Update the counters */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000514 while (cc) {
515 if (cc->type == CNT_ADD) {
516 *prev_cc = cc->next;
517 free(cc);
518 cc = *prev_cc;
519 continue;
520 }
521 cc->type = CNT_DEL;
522 prev_cc = &(cc->next);
523 cc = cc->next;
524 }
525 return;
526 }
527
528 if (entries->nentries == 0)
529 return;
530 replace->nentries -= entries->nentries;
531 numdel = entries->nentries;
532
Bart De Schuymer6622a012005-01-19 21:09:05 +0000533 /* Delete the counters belonging to the specified chain,
534 * update counter_offset */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000535 i = -1;
536 while (1) {
537 i++;
538 entries = ebt_nr_to_chain(replace, i);
539 if (!entries) {
540 if (i < NF_BR_NUMHOOKS)
541 continue;
542 else
543 break;
544 }
545 if (i > replace->selected_chain) {
546 entries->counter_offset -= numdel;
547 continue;
548 }
549 j = entries->nentries;
550 while (j) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000551 /* Don't count deleted entries */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000552 if (cc->type == CNT_DEL)
553 goto letscontinue;
554 if (i == replace->selected_chain) {
555 if (cc->type == CNT_ADD) {
556 *prev_cc = cc->next;
557 free(cc);
558 cc = *prev_cc;
559 j--;
560 continue;
561 }
562 cc->type = CNT_DEL;
563 }
564 j--;
565letscontinue:
566 prev_cc = &(cc->next);
567 cc = cc->next;
568 }
569 }
570
571 entries = ebt_to_chain(replace);
572 entries->nentries = 0;
573 u_e = entries->entries;
574 while (u_e) {
575 ebt_free_u_entry(u_e);
576 tmp = u_e->next;
577 free(u_e);
578 u_e = tmp;
579 }
580 entries->entries = NULL;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000581}
582
Bart De Schuymer6622a012005-01-19 21:09:05 +0000583/* Returns the rule number on success (starting from 0), -1 on failure
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000584 *
585 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer6622a012005-01-19 21:09:05 +0000586 * to contain pointers to ebt_u_{match,watcher,target} */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000587int ebt_check_rule_exists(struct ebt_u_replace *replace,
588 struct ebt_u_entry *new_entry)
589{
590 struct ebt_u_entry *u_e;
591 struct ebt_u_match_list *m_l, *m_l2;
592 struct ebt_u_match *m;
593 struct ebt_u_watcher_list *w_l, *w_l2;
594 struct ebt_u_watcher *w;
595 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
596 struct ebt_u_entries *entries = ebt_to_chain(replace);
597 int i, j, k;
598
599 u_e = entries->entries;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000600 /* Check for an existing rule (if there are duplicate rules,
601 * take the first occurance) */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000602 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
603 if (!u_e)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000604 ebt_print_bug("Hmm, trouble");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000605 if (u_e->ethproto != new_entry->ethproto)
606 continue;
607 if (strcmp(u_e->in, new_entry->in))
608 continue;
609 if (strcmp(u_e->out, new_entry->out))
610 continue;
611 if (strcmp(u_e->logical_in, new_entry->logical_in))
612 continue;
613 if (strcmp(u_e->logical_out, new_entry->logical_out))
614 continue;
615 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer6622a012005-01-19 21:09:05 +0000616 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000617 continue;
618 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer6622a012005-01-19 21:09:05 +0000619 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000620 continue;
621 if (new_entry->bitmask != u_e->bitmask ||
Bart De Schuymer6622a012005-01-19 21:09:05 +0000622 new_entry->invflags != u_e->invflags)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000623 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000624 /* Compare all matches */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000625 m_l = new_entry->m_list;
626 j = 0;
627 while (m_l) {
628 m = (struct ebt_u_match *)(m_l->m);
629 m_l2 = u_e->m_list;
630 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
631 m_l2 = m_l2->next;
632 if (!m_l2 || !m->compare(m->m, m_l2->m))
633 goto letscontinue;
634 j++;
635 m_l = m_l->next;
636 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000637 /* Now be sure they have the same nr of matches */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000638 k = 0;
639 m_l = u_e->m_list;
640 while (m_l) {
641 k++;
642 m_l = m_l->next;
643 }
644 if (j != k)
645 continue;
646
Bart De Schuymer6622a012005-01-19 21:09:05 +0000647 /* Compare all watchers */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000648 w_l = new_entry->w_list;
649 j = 0;
650 while (w_l) {
651 w = (struct ebt_u_watcher *)(w_l->w);
652 w_l2 = u_e->w_list;
653 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
654 w_l2 = w_l2->next;
655 if (!w_l2 || !w->compare(w->w, w_l2->w))
656 goto letscontinue;
657 j++;
658 w_l = w_l->next;
659 }
660 k = 0;
661 w_l = u_e->w_list;
662 while (w_l) {
663 k++;
664 w_l = w_l->next;
665 }
666 if (j != k)
667 continue;
668 if (strcmp(t->t->u.name, u_e->t->u.name))
669 continue;
670 if (!t->compare(t->t, u_e->t))
671 continue;
672 return i;
Bart De Schuymeraef08942004-09-09 21:41:29 +0000673letscontinue:;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000674 }
675 return -1;
676}
677
678/* Add a rule, rule_nr is the rule to update
679 * rule_nr specifies where the rule should be inserted
680 * rule_nr > 0 : insert the rule right before the rule_nr'th rule
681 * (the first rule is rule 1)
682 * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule,
Bart De Schuymer6622a012005-01-19 21:09:05 +0000683 * where n denotes the number of rules in the chain
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000684 * rule_nr == 0: add a new rule at the end of the chain
685 *
686 * This function expects the ebt_{match,watcher,target} members of new_entry
687 * to contain pointers to ebt_u_{match,watcher,target} and updates these
Bart De Schuymer6622a012005-01-19 21:09:05 +0000688 * pointers so that they point to ebt_{match,watcher,target}, before adding
689 * the rule to the chain. Don't free() the ebt_{match,watcher,target} after a
690 * successful call to ebt_add_rule() */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000691void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
692 int rule_nr)
693{
694 int i, j;
695 struct ebt_u_entry **u_e;
696 struct ebt_u_match_list *m_l;
697 struct ebt_u_watcher_list *w_l;
698 struct ebt_u_entries *entries = ebt_to_chain(replace);
699 struct ebt_cntchanges *cc = replace->counterchanges, *new_cc;
700 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
701
702 if (rule_nr <= 0)
703 rule_nr += entries->nentries;
704 else
705 rule_nr--;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000706 if (rule_nr > entries->nentries || rule_nr < 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000707 ebt_print_error("The specified rule number is incorrect");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000708 return;
709 }
710 /* We're adding one rule */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000711 replace->nentries++;
712 entries->nentries++;
713
Bart De Schuymer6622a012005-01-19 21:09:05 +0000714 /* Handle counter stuff */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000715 for (i = 0; i < replace->selected_chain; i++) {
716 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
717 continue;
718 j = ebt_nr_to_chain(replace, i)->nentries;
719 while (j) {
720 if (cc->type != CNT_DEL)
721 j--;
722 prev_cc = &(cc->next);
723 cc = cc->next;
724 }
725 }
726 j = rule_nr;
727 while (j) {
728 if (cc->type != CNT_DEL)
729 j--;
730 prev_cc = &(cc->next);
731 cc = cc->next;
732 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000733 if (cc && cc->type == CNT_DEL)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000734 cc->type = CNT_OWRITE;
735 else {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000736 new_cc = (struct ebt_cntchanges *)
737 malloc(sizeof(struct ebt_cntchanges));
Bart De Schuymer6622a012005-01-19 21:09:05 +0000738 if (!new_cc)
739 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000740 new_cc->type = CNT_ADD;
741 new_cc->next = cc;
742 *prev_cc = new_cc;
743 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000744 /* Go to the right position in the chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000745 u_e = &entries->entries;
746 for (i = 0; i < rule_nr; i++)
747 u_e = &(*u_e)->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000748 /* Insert the rule */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000749 new_entry->next = *u_e;
750 *u_e = new_entry;
751
Bart De Schuymer6622a012005-01-19 21:09:05 +0000752 /* Put the ebt_{match, watcher, target} pointers in place */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000753 m_l = new_entry->m_list;
754 while (m_l) {
755 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
756 m_l = m_l->next;
757 }
758 w_l = new_entry->w_list;
759 while (w_l) {
760 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
761 w_l = w_l->next;
762 }
763 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000764 /* Update the counter_offset of chains behind this one */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000765 i = replace->selected_chain;
766 while (1) {
767 i++;
768 entries = ebt_nr_to_chain(replace, i);
769 if (!entries) {
770 if (i < NF_BR_NUMHOOKS)
771 continue;
772 else
773 break;
774 } else
775 entries->counter_offset++;
776 }
777}
778
Bart De Schuymer6622a012005-01-19 21:09:05 +0000779/* Delete a rule or rules
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000780 * begin == end == 0: delete the rule corresponding to new_entry
781 *
Bart De Schuymer6622a012005-01-19 21:09:05 +0000782 * The first rule has rule nr 1, the last rule has rule nr -1, etc.
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000783 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer6622a012005-01-19 21:09:05 +0000784 * to contain pointers to ebt_u_{match,watcher,target}. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000785void ebt_delete_rule(struct ebt_u_replace *replace,
786 struct ebt_u_entry *new_entry, int begin, int end)
787{
788 int i, j, nr_deletes;
789 struct ebt_u_entry **u_e, *u_e2;
790 struct ebt_u_entries *entries = ebt_to_chain(replace);
791 struct ebt_cntchanges *cc = replace->counterchanges;
792 struct ebt_cntchanges **prev_cc = &(replace->counterchanges);
793
794 if (begin < 0)
795 begin += entries->nentries + 1;
796 if (end < 0)
797 end += entries->nentries + 1;
798
Bart De Schuymer6622a012005-01-19 21:09:05 +0000799 if (begin < 0 || begin > end || end > entries->nentries) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000800 ebt_print_error("Sorry, wrong rule numbers");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000801 return;
802 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000803
804 if ((begin * end == 0) && (begin + end != 0))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000805 ebt_print_bug("begin and end should be either both zero, "
806 "either both non-zero");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000807 if (begin != 0 && end != 0) {
808 begin--;
809 end--;
810 } else {
811 begin = ebt_check_rule_exists(replace, new_entry);
812 end = begin;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000813 if (begin == -1) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000814 ebt_print_error("Sorry, rule does not exist");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000815 return;
816 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000817 }
818
Bart De Schuymer6622a012005-01-19 21:09:05 +0000819 /* We're deleting rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000820 nr_deletes = end - begin + 1;
821 replace->nentries -= nr_deletes;
822 entries->nentries -= nr_deletes;
823
Bart De Schuymer6622a012005-01-19 21:09:05 +0000824 /* Handle counter stuff */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000825 for (i = 0; i < replace->selected_chain; i++) {
826 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
827 continue;
828 j = ebt_nr_to_chain(replace, i)->nentries;
829 while (j) {
830 if (cc->type != CNT_DEL)
831 j--;
832 prev_cc = &(cc->next);
833 cc = cc->next;
834 }
835 }
836 j = begin;
837 while (j) {
838 if (cc->type != CNT_DEL)
839 j--;
840 prev_cc = &(cc->next);
841 cc = cc->next;
842 }
843 j = nr_deletes;
844 while (j) {
845 if (cc->type != CNT_DEL) {
846 j--;
847 if (cc->type == CNT_ADD) {
848 *prev_cc = cc->next;
849 free(cc);
850 cc = *prev_cc;
851 continue;
852 }
853 cc->type = CNT_DEL;
854 }
855 prev_cc = &(cc->next);
856 cc = cc->next;
857 }
858
Bart De Schuymer6622a012005-01-19 21:09:05 +0000859 /* Go to the right position in the chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000860 u_e = &entries->entries;
861 for (j = 0; j < begin; j++)
862 u_e = &(*u_e)->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000863 /* Remove the rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000864 j = nr_deletes;
865 while(j--) {
866 u_e2 = *u_e;
867 *u_e = (*u_e)->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000868 /* Free everything */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000869 ebt_free_u_entry(u_e2);
870 free(u_e2);
871 }
872
Bart De Schuymer6622a012005-01-19 21:09:05 +0000873 /* Update the counter_offset of chains behind this one */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000874 j = replace->selected_chain;
875 while (1) {
876 j++;
877 entries = ebt_nr_to_chain(replace, j);
878 if (!entries) {
879 if (j < NF_BR_NUMHOOKS)
880 continue;
881 else
882 break;
883 } else
884 entries->counter_offset -= nr_deletes;
885 }
886}
887
Bart De Schuymer6622a012005-01-19 21:09:05 +0000888/* Selected_chain == -1 : zero all counters
889 * Otherwise, zero the counters of selected_chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000890void ebt_zero_counters(struct ebt_u_replace *replace)
891{
892 struct ebt_u_entries *entries = ebt_to_chain(replace);
893 struct ebt_cntchanges *cc = replace->counterchanges;
894 int i, j;
895
896 if (!entries) {
897 while (cc) {
898 if (cc->type == CNT_NORM)
899 cc->type = CNT_ZERO;
900 cc = cc->next;
901 }
902 } else {
903 if (entries->nentries == 0)
904 return;
905
906 for (i = 0; i < replace->selected_chain; i++) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000907 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000908 continue;
909 j = ebt_nr_to_chain(replace, i)->nentries;
910 while (j) {
911 if (cc->type != CNT_DEL)
912 j--;
913 cc = cc->next;
914 }
915 }
916 j = entries->nentries;
917 while (j) {
918 if (cc->type != CNT_DEL) {
919 j--;
920 if (cc->type == CNT_NORM)
921 cc->type = CNT_ZERO;
922 }
923 cc = cc->next;
924 }
925 }
926}
927
Bart De Schuymer6622a012005-01-19 21:09:05 +0000928/* Add a new chain and specify its policy */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000929void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
930{
931 struct ebt_u_chain_list *cl, **cl2;
932
Bart De Schuymer6622a012005-01-19 21:09:05 +0000933 if (ebt_get_chainnr(replace, name) != -1) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000934 ebt_print_error("Chain %s already exists", optarg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000935 return;
936 } else if (ebt_find_target(name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000937 ebt_print_error("Target with name %s exists", optarg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000938 return;
939 } else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000940 ebt_print_error("Chain name length can't exceed %d",
941 EBT_CHAIN_MAXNAMELEN - 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000942 return;
943 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000944 cl = (struct ebt_u_chain_list *)
945 malloc(sizeof(struct ebt_u_chain_list));
946 if (!cl)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000947 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000948 cl->next = NULL;
949 cl->udc = (struct ebt_u_entries *)
950 malloc(sizeof(struct ebt_u_entries));
951 if (!cl->udc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000952 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000953 cl->udc->nentries = 0;
954 cl->udc->policy = policy;
955 cl->udc->counter_offset = replace->nentries;
956 cl->udc->hook_mask = 0;
957 strcpy(cl->udc->name, name);
958 cl->udc->entries = NULL;
959 cl->kernel_start = NULL;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000960 /* Put the new chain at the end */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000961 cl2 = &(replace->udc);
962 while (*cl2)
963 cl2 = &((*cl2)->next);
964 *cl2 = cl;
965}
966
Bart De Schuymer6622a012005-01-19 21:09:05 +0000967/* Selected_chain == -1: delete all non-referenced udc
968 * selected_chain < NF_BR_NUMHOOKS is illegal */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000969void ebt_delete_chain(struct ebt_u_replace *replace)
970{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000971 int chain_nr = replace->selected_chain, print_error = 1;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000972
973 if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000974 ebt_print_bug("You can't remove a standard chain");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000975 if (chain_nr == -1) {
976 print_error = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000977 replace->selected_chain = NF_BR_NUMHOOKS;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000978 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000979 do {
980 if (ebt_to_chain(replace) == NULL) {
981 if (chain_nr == -1)
982 break;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000983 ebt_print_bug("udc nr %d doesn't exist", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000984 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000985 /* If the chain is referenced, don't delete it,
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000986 * also decrement jumps to a chain behind the
Bart De Schuymer6622a012005-01-19 21:09:05 +0000987 * one we're deleting */
988 if (ebt_check_for_references(replace, print_error)) {
989 if (chain_nr != -1)
990 break;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000991 replace->selected_chain++;
992 continue;
993 }
994 decrease_chain_jumps(replace);
995 ebt_flush_chains(replace);
996 remove_udc(replace);
Bart De Schuymerc6c0dc32004-12-16 19:30:32 +0000997 } while (chain_nr == -1);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000998 replace->selected_chain = chain_nr; /* Put back to -1 */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000999}
1000
Bart De Schuymer6622a012005-01-19 21:09:05 +00001001/* Rename an existing chain. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001002void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
1003{
1004 struct ebt_u_entries *entries = ebt_to_chain(replace);
1005
1006 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001007 ebt_print_bug("ebt_rename_chain: entries == NULL");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001008 strcpy(entries->name, name);
1009}
1010
1011
1012 /*
1013*************************
1014*************************
1015**SPECIALIZED*FUNCTIONS**
1016*************************
1017*************************
1018 */
1019
1020
Bart De Schuymer6622a012005-01-19 21:09:05 +00001021/* Executes the final_check() function for all extensions used by the rule
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001022 * ebt_check_for_loops should have been executed earlier, to make sure the
Bart De Schuymer6622a012005-01-19 21:09:05 +00001023 * hook_mask is correct. The time argument to final_check() is set to 1,
1024 * meaning it's the second time the final_check() function is executed. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001025void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
1026 struct ebt_u_entries *entries)
1027{
1028 struct ebt_u_match_list *m_l;
1029 struct ebt_u_watcher_list *w_l;
1030 struct ebt_u_target *t;
1031 struct ebt_u_match *m;
1032 struct ebt_u_watcher *w;
1033
1034 m_l = e->m_list;
1035 w_l = e->w_list;
1036 while (m_l) {
1037 m = ebt_find_match(m_l->m->u.name);
1038 m->final_check(e, m_l->m, replace->name,
1039 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001040 if (ebt_errormsg[0] != '\0')
1041 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001042 m_l = m_l->next;
1043 }
1044 while (w_l) {
1045 w = ebt_find_watcher(w_l->w->u.name);
1046 w->final_check(e, w_l->w, replace->name,
1047 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001048 if (ebt_errormsg[0] != '\0')
1049 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001050 w_l = w_l->next;
1051 }
1052 t = ebt_find_target(e->t->u.name);
1053 t->final_check(e, e->t, replace->name,
1054 entries->hook_mask, 1);
1055}
1056
Bart De Schuymer6622a012005-01-19 21:09:05 +00001057/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1058 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1059int ebt_check_for_references(struct ebt_u_replace *replace, int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001060{
Bart De Schuymer6622a012005-01-19 21:09:05 +00001061 if (print_err)
1062 return iterate_entries(replace, 1);
1063 else
1064 return iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001065}
1066
Bart De Schuymer6622a012005-01-19 21:09:05 +00001067/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
1068 * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1069 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1070int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr,
1071 int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001072{
1073 int tmp = replace->selected_chain, ret;
1074
1075 replace->selected_chain = chain_nr;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001076 if (print_err)
1077 ret = iterate_entries(replace, 1);
1078 else
1079 ret = iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001080 replace->selected_chain = tmp;
1081 return ret;
1082}
1083
1084struct ebt_u_stack
1085{
1086 int chain_nr;
1087 int n;
1088 struct ebt_u_entry *e;
1089 struct ebt_u_entries *entries;
1090};
1091
Bart De Schuymer6622a012005-01-19 21:09:05 +00001092/* Checks for loops
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001093 * As a by-product, the hook_mask member of each chain is filled in
1094 * correctly. The check functions of the extensions need this hook_mask
Bart De Schuymer6622a012005-01-19 21:09:05 +00001095 * to know from which standard chains they can be called. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001096void ebt_check_for_loops(struct ebt_u_replace *replace)
1097{
1098 int chain_nr , i, j , k, sp = 0, verdict;
1099 struct ebt_u_entries *entries, *entries2;
1100 struct ebt_u_stack *stack = NULL;
1101 struct ebt_u_entry *e;
1102
1103 i = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001104 /* Initialize hook_mask to 0 */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001105 while (1) {
1106 i++;
1107 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
1108 continue;
1109 entries = ebt_nr_to_chain(replace, i);
1110 if (!entries)
1111 break;
1112 entries->hook_mask = 0;
1113 }
1114 if (i > NF_BR_NUMHOOKS) {
1115 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
1116 sizeof(struct ebt_u_stack));
1117 if (!stack)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001118 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001119 }
1120
Bart De Schuymer6622a012005-01-19 21:09:05 +00001121 /* Check for loops, starting from every base chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001122 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1123 if (!(replace->valid_hooks & (1 << i)))
1124 continue;
1125 entries = ebt_nr_to_chain(replace, i);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001126 /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain
1127 * (usefull in the final_check() funtions) */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001128 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
1129 chain_nr = i;
1130
1131 e = entries->entries;
1132 for (j = 0; j < entries->nentries; j++) {
1133 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
1134 goto letscontinue;
1135 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
1136 if (verdict < 0)
1137 goto letscontinue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001138 entries2 = ebt_nr_to_chain(replace, verdict + NF_BR_NUMHOOKS);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001139 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001140 /* Now see if we've been here before */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001141 for (k = 0; k < sp; k++)
Bart De Schuymer6622a012005-01-19 21:09:05 +00001142 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) {
1143 ebt_print_error("Loop from chain '%s' to chain '%s'",
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001144 ebt_nr_to_chain(replace, chain_nr)->name,
1145 ebt_nr_to_chain(replace, stack[k].chain_nr)->name);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001146 goto free_stack;
1147 }
1148 /* Jump to the chain, make sure we know how to get back */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001149 stack[sp].chain_nr = chain_nr;
1150 stack[sp].n = j;
1151 stack[sp].entries = entries;
1152 stack[sp].e = e;
1153 sp++;
1154 j = -1;
1155 e = entries2->entries;
1156 chain_nr = verdict + NF_BR_NUMHOOKS;
1157 entries = entries2;
1158 continue;
1159letscontinue:
1160 e = e->next;
1161 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001162 /* We are at the end of a standard chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001163 if (sp == 0)
1164 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001165 /* Go back to the chain one level higher */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001166 sp--;
1167 j = stack[sp].n;
1168 chain_nr = stack[sp].chain_nr;
1169 e = stack[sp].e;
1170 entries = stack[sp].entries;
1171 goto letscontinue;
1172 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001173free_stack:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001174 free(stack);
1175 return;
1176}
1177
Bart De Schuymer6622a012005-01-19 21:09:05 +00001178/* The user will use the match, so put it in new_entry. The ebt_u_match
1179 * pointer is put in the ebt_entry_match pointer. ebt_add_rule will
1180 * fill in the final value for new->m. Unless the rule is added to a chain,
1181 * the pointer will keep pointing to the ebt_u_match (until the new_entry
1182 * is freed). I know, I should use a union for these 2 pointer types... */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001183void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m)
1184{
1185 struct ebt_u_match_list **m_list, *new;
1186
1187 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
1188 new = (struct ebt_u_match_list *)
1189 malloc(sizeof(struct ebt_u_match_list));
1190 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001191 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001192 *m_list = new;
1193 new->next = NULL;
1194 new->m = (struct ebt_entry_match *)m;
1195}
1196
1197void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w)
1198{
1199 struct ebt_u_watcher_list **w_list;
1200 struct ebt_u_watcher_list *new;
1201
1202 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
1203 new = (struct ebt_u_watcher_list *)
1204 malloc(sizeof(struct ebt_u_watcher_list));
1205 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001206 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001207 *w_list = new;
1208 new->next = NULL;
1209 new->w = (struct ebt_entry_watcher *)w;
1210}
1211
1212
1213 /*
1214*******************
1215*******************
1216**OTHER*FUNCTIONS**
1217*******************
1218*******************
1219 */
1220
1221
Bart De Schuymer6622a012005-01-19 21:09:05 +00001222/* type = 0 => update chain jumps
1223 * type = 1 => check for reference, print error when referenced
1224 * type = 2 => check for reference, don't print error when referenced
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001225 *
Bart De Schuymer6622a012005-01-19 21:09:05 +00001226 * Returns 1 when type == 1 and the chain is referenced
1227 * returns 0 otherwise */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001228static int iterate_entries(struct ebt_u_replace *replace, int type)
1229{
1230 int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS;
1231 struct ebt_u_entries *entries;
1232 struct ebt_u_entry *e;
1233
1234 if (chain_nr < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001235 ebt_print_bug("iterate_entries: udc = %d < 0", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001236 while (1) {
1237 i++;
1238 entries = ebt_nr_to_chain(replace, i);
1239 if (!entries) {
1240 if (i < NF_BR_NUMHOOKS)
1241 continue;
1242 else
1243 break;
1244 }
1245 e = entries->entries;
1246 j = 0;
1247 while (e) {
1248 int chain_jmp;
1249
1250 j++;
1251 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1252 e = e->next;
1253 continue;
1254 }
Bart De Schuymer64182a32004-01-21 20:39:54 +00001255 chain_jmp = ((struct ebt_standard_target *)e->t)->
1256 verdict;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001257 switch (type) {
1258 case 1:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001259 case 2:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001260 if (chain_jmp == chain_nr) {
Bart De Schuymer6622a012005-01-19 21:09:05 +00001261 if (type == 2)
1262 return 1;
1263 ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d",
1264 ebt_nr_to_chain(replace, chain_nr + NF_BR_NUMHOOKS)->name, entries->name, j);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001265 return 1;
1266 }
1267 break;
1268 case 0:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001269 /* Adjust the chain jumps when necessary */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001270 if (chain_jmp > chain_nr)
1271 ((struct ebt_standard_target *)e->t)->verdict--;
1272 break;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001273 } /* End switch */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001274 e = e->next;
1275 }
1276 }
1277 return 0;
1278}
1279
1280static void decrease_chain_jumps(struct ebt_u_replace *replace)
1281{
1282 iterate_entries(replace, 0);
1283}
1284
Bart De Schuymer6622a012005-01-19 21:09:05 +00001285/* Selected_chain >= NF_BR_NUMHOOKS */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001286static void remove_udc(struct ebt_u_replace *replace)
1287{
1288 struct ebt_u_chain_list *cl, **cl2;
1289 struct ebt_u_entries *entries;
1290 struct ebt_u_entry *u_e, *tmp;
1291 int chain_nr = replace->selected_chain;
1292
1293 if (chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001294 ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr,
1295 NF_BR_NUMHOOKS);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001296 /* First free the rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001297 entries = ebt_nr_to_chain(replace, chain_nr);
1298 u_e = entries->entries;
1299 while (u_e) {
1300 ebt_free_u_entry(u_e);
1301 tmp = u_e->next;
1302 free(u_e);
1303 u_e = tmp;
1304 }
1305
1306 /* next, remove the chain */
1307 cl2 = &(replace->udc);
1308 while ((*cl2)->udc != entries)
1309 cl2 = &((*cl2)->next);
1310 cl = (*cl2);
1311 (*cl2) = (*cl2)->next;
1312 free(cl->udc);
1313 free(cl);
1314}
1315
Bart De Schuymer6622a012005-01-19 21:09:05 +00001316/* Used in initialization code of modules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001317void ebt_register_match(struct ebt_u_match *m)
1318{
1319 int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
1320 struct ebt_u_match **i;
1321
1322 m->m = (struct ebt_entry_match *)malloc(size);
1323 if (!m->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001324 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001325 strcpy(m->m->u.name, m->name);
1326 m->m->match_size = EBT_ALIGN(m->size);
1327 m->init(m->m);
1328
1329 for (i = &ebt_matches; *i; i = &((*i)->next));
1330 m->next = NULL;
1331 *i = m;
1332}
1333
1334void ebt_register_watcher(struct ebt_u_watcher *w)
1335{
1336 int size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
1337 struct ebt_u_watcher **i;
1338
1339 w->w = (struct ebt_entry_watcher *)malloc(size);
1340 if (!w->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001341 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001342 strcpy(w->w->u.name, w->name);
1343 w->w->watcher_size = EBT_ALIGN(w->size);
1344 w->init(w->w);
1345
1346 for (i = &ebt_watchers; *i; i = &((*i)->next));
1347 w->next = NULL;
1348 *i = w;
1349}
1350
1351void ebt_register_target(struct ebt_u_target *t)
1352{
1353 int size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
1354 struct ebt_u_target **i;
1355
1356 t->t = (struct ebt_entry_target *)malloc(size);
1357 if (!t->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001358 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001359 strcpy(t->t->u.name, t->name);
1360 t->t->target_size = EBT_ALIGN(t->size);
1361 t->init(t->t);
1362
1363 for (i = &ebt_targets; *i; i = &((*i)->next));
1364 t->next = NULL;
1365 *i = t;
1366}
1367
1368void ebt_register_table(struct ebt_u_table *t)
1369{
1370 t->next = ebt_tables;
1371 ebt_tables = t;
1372}
1373
1374void ebt_iterate_matches(void (*f)(struct ebt_u_match *))
1375{
1376 struct ebt_u_match *i;
1377
1378 for (i = ebt_matches; i; i = i->next)
1379 f(i);
1380}
1381
1382void ebt_iterate_watchers(void (*f)(struct ebt_u_watcher *))
1383{
1384 struct ebt_u_watcher *i;
1385
1386 for (i = ebt_watchers; i; i = i->next)
1387 f(i);
1388}
1389
1390void ebt_iterate_targets(void (*f)(struct ebt_u_target *))
1391{
1392 struct ebt_u_target *i;
1393
1394 for (i = ebt_targets; i; i = i->next)
1395 f(i);
1396}
1397
Bart De Schuymer6622a012005-01-19 21:09:05 +00001398/* Don't use this function, use ebt_print_bug() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001399void __ebt_print_bug(char *file, int line, char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001400{
1401 va_list l;
1402
1403 va_start(l, format);
1404 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
1405 vprintf(format, l);
1406 printf("\n");
1407 va_end(l);
1408 exit (-1);
1409}
1410
Bart De Schuymer6622a012005-01-19 21:09:05 +00001411/* The error messages are put in here when ebt_silent == 1
1412 * ebt_errormsg[0] == '\0' implies there was no error */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001413char ebt_errormsg[ERRORMSG_MAXLEN];
Bart De Schuymer6622a012005-01-19 21:09:05 +00001414/* When error messages should not be printed on the screen, after which
1415 * the program exit()s, set ebt_silent to 1. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001416int ebt_silent;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001417/* Don't use this function, use ebt_print_error() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001418void __ebt_print_error(char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001419{
1420 va_list l;
1421
1422 va_start(l, format);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001423 if (ebt_silent && ebt_errormsg[0] == '\0') {
1424 vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001425 va_end(l);
1426 } else {
1427 vprintf(format, l);
1428 printf("\n");
1429 va_end(l);
1430 exit (-1);
1431 }
1432}