blob: ff1e14c44a3686235637715852be9ba8a23a7e11 [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;
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000895 struct ebt_u_entry *next;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000896 int i, j;
897
898 if (!entries) {
899 while (cc) {
900 if (cc->type == CNT_NORM)
901 cc->type = CNT_ZERO;
902 cc = cc->next;
903 }
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000904 i = -1;
905 while (1) {
906 i++;
907 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
908 continue;
909 entries = ebt_nr_to_chain(replace, i);
910 if (!entries) {
911 if (i < NF_BR_NUMHOOKS)
912 ebt_print_bug("i < NF_BR_NUMHOOKS");
913 break;
914 }
915 next = entries->entries;
916 while (next) {
917 next->cnt.bcnt = next->cnt.pcnt = 0;
918 next = next->next;
919 }
920 }
921
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000922 } else {
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000923 next = entries->entries;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000924 if (entries->nentries == 0)
925 return;
926
927 for (i = 0; i < replace->selected_chain; i++) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000928 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000929 continue;
930 j = ebt_nr_to_chain(replace, i)->nentries;
931 while (j) {
932 if (cc->type != CNT_DEL)
933 j--;
934 cc = cc->next;
935 }
936 }
937 j = entries->nentries;
938 while (j) {
939 if (cc->type != CNT_DEL) {
940 j--;
941 if (cc->type == CNT_NORM)
942 cc->type = CNT_ZERO;
943 }
944 cc = cc->next;
945 }
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000946 while (next) {
947 next->cnt.bcnt = next->cnt.pcnt = 0;
948 next = next->next;
949 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000950 }
951}
952
Bart De Schuymer6622a012005-01-19 21:09:05 +0000953/* Add a new chain and specify its policy */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000954void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
955{
956 struct ebt_u_chain_list *cl, **cl2;
957
Bart De Schuymer6622a012005-01-19 21:09:05 +0000958 if (ebt_get_chainnr(replace, name) != -1) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000959 ebt_print_error("Chain %s already exists", optarg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000960 return;
961 } else if (ebt_find_target(name)) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000962 ebt_print_error("Target with name %s exists", optarg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000963 return;
964 } else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000965 ebt_print_error("Chain name length can't exceed %d",
966 EBT_CHAIN_MAXNAMELEN - 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000967 return;
968 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000969 cl = (struct ebt_u_chain_list *)
970 malloc(sizeof(struct ebt_u_chain_list));
971 if (!cl)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000972 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000973 cl->next = NULL;
974 cl->udc = (struct ebt_u_entries *)
975 malloc(sizeof(struct ebt_u_entries));
976 if (!cl->udc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000977 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000978 cl->udc->nentries = 0;
979 cl->udc->policy = policy;
980 cl->udc->counter_offset = replace->nentries;
981 cl->udc->hook_mask = 0;
982 strcpy(cl->udc->name, name);
983 cl->udc->entries = NULL;
984 cl->kernel_start = NULL;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000985 /* Put the new chain at the end */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000986 cl2 = &(replace->udc);
987 while (*cl2)
988 cl2 = &((*cl2)->next);
989 *cl2 = cl;
990}
991
Bart De Schuymer6622a012005-01-19 21:09:05 +0000992/* Selected_chain == -1: delete all non-referenced udc
993 * selected_chain < NF_BR_NUMHOOKS is illegal */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000994void ebt_delete_chain(struct ebt_u_replace *replace)
995{
Bart De Schuymer6622a012005-01-19 21:09:05 +0000996 int chain_nr = replace->selected_chain, print_error = 1;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000997
998 if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000999 ebt_print_bug("You can't remove a standard chain");
Bart De Schuymer6622a012005-01-19 21:09:05 +00001000 if (chain_nr == -1) {
1001 print_error = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001002 replace->selected_chain = NF_BR_NUMHOOKS;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001003 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001004 do {
1005 if (ebt_to_chain(replace) == NULL) {
1006 if (chain_nr == -1)
1007 break;
Bart De Schuymer64182a32004-01-21 20:39:54 +00001008 ebt_print_bug("udc nr %d doesn't exist", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001009 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001010 /* If the chain is referenced, don't delete it,
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001011 * also decrement jumps to a chain behind the
Bart De Schuymer6622a012005-01-19 21:09:05 +00001012 * one we're deleting */
1013 if (ebt_check_for_references(replace, print_error)) {
1014 if (chain_nr != -1)
1015 break;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001016 replace->selected_chain++;
1017 continue;
1018 }
1019 decrease_chain_jumps(replace);
1020 ebt_flush_chains(replace);
1021 remove_udc(replace);
Bart De Schuymerc6c0dc32004-12-16 19:30:32 +00001022 } while (chain_nr == -1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001023 replace->selected_chain = chain_nr; /* Put back to -1 */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001024}
1025
Bart De Schuymer6622a012005-01-19 21:09:05 +00001026/* Rename an existing chain. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001027void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
1028{
1029 struct ebt_u_entries *entries = ebt_to_chain(replace);
1030
1031 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001032 ebt_print_bug("ebt_rename_chain: entries == NULL");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001033 strcpy(entries->name, name);
1034}
1035
1036
1037 /*
1038*************************
1039*************************
1040**SPECIALIZED*FUNCTIONS**
1041*************************
1042*************************
1043 */
1044
1045
Bart De Schuymer6622a012005-01-19 21:09:05 +00001046/* Executes the final_check() function for all extensions used by the rule
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001047 * ebt_check_for_loops should have been executed earlier, to make sure the
Bart De Schuymer6622a012005-01-19 21:09:05 +00001048 * hook_mask is correct. The time argument to final_check() is set to 1,
1049 * meaning it's the second time the final_check() function is executed. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001050void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
1051 struct ebt_u_entries *entries)
1052{
1053 struct ebt_u_match_list *m_l;
1054 struct ebt_u_watcher_list *w_l;
1055 struct ebt_u_target *t;
1056 struct ebt_u_match *m;
1057 struct ebt_u_watcher *w;
1058
1059 m_l = e->m_list;
1060 w_l = e->w_list;
1061 while (m_l) {
1062 m = ebt_find_match(m_l->m->u.name);
1063 m->final_check(e, m_l->m, replace->name,
1064 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001065 if (ebt_errormsg[0] != '\0')
1066 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001067 m_l = m_l->next;
1068 }
1069 while (w_l) {
1070 w = ebt_find_watcher(w_l->w->u.name);
1071 w->final_check(e, w_l->w, replace->name,
1072 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001073 if (ebt_errormsg[0] != '\0')
1074 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001075 w_l = w_l->next;
1076 }
1077 t = ebt_find_target(e->t->u.name);
1078 t->final_check(e, e->t, replace->name,
1079 entries->hook_mask, 1);
1080}
1081
Bart De Schuymer6622a012005-01-19 21:09:05 +00001082/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1083 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1084int ebt_check_for_references(struct ebt_u_replace *replace, int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001085{
Bart De Schuymer6622a012005-01-19 21:09:05 +00001086 if (print_err)
1087 return iterate_entries(replace, 1);
1088 else
1089 return iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001090}
1091
Bart De Schuymer6622a012005-01-19 21:09:05 +00001092/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
1093 * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1094 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1095int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr,
1096 int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001097{
1098 int tmp = replace->selected_chain, ret;
1099
1100 replace->selected_chain = chain_nr;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001101 if (print_err)
1102 ret = iterate_entries(replace, 1);
1103 else
1104 ret = iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001105 replace->selected_chain = tmp;
1106 return ret;
1107}
1108
1109struct ebt_u_stack
1110{
1111 int chain_nr;
1112 int n;
1113 struct ebt_u_entry *e;
1114 struct ebt_u_entries *entries;
1115};
1116
Bart De Schuymer6622a012005-01-19 21:09:05 +00001117/* Checks for loops
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001118 * As a by-product, the hook_mask member of each chain is filled in
1119 * correctly. The check functions of the extensions need this hook_mask
Bart De Schuymer6622a012005-01-19 21:09:05 +00001120 * to know from which standard chains they can be called. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001121void ebt_check_for_loops(struct ebt_u_replace *replace)
1122{
1123 int chain_nr , i, j , k, sp = 0, verdict;
1124 struct ebt_u_entries *entries, *entries2;
1125 struct ebt_u_stack *stack = NULL;
1126 struct ebt_u_entry *e;
1127
1128 i = -1;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001129 /* Initialize hook_mask to 0 */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001130 while (1) {
1131 i++;
1132 if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
1133 continue;
1134 entries = ebt_nr_to_chain(replace, i);
1135 if (!entries)
1136 break;
1137 entries->hook_mask = 0;
1138 }
1139 if (i > NF_BR_NUMHOOKS) {
1140 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
1141 sizeof(struct ebt_u_stack));
1142 if (!stack)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001143 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001144 }
1145
Bart De Schuymer6622a012005-01-19 21:09:05 +00001146 /* Check for loops, starting from every base chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001147 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1148 if (!(replace->valid_hooks & (1 << i)))
1149 continue;
1150 entries = ebt_nr_to_chain(replace, i);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001151 /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain
1152 * (usefull in the final_check() funtions) */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001153 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
1154 chain_nr = i;
1155
1156 e = entries->entries;
1157 for (j = 0; j < entries->nentries; j++) {
1158 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
1159 goto letscontinue;
1160 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
1161 if (verdict < 0)
1162 goto letscontinue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001163 entries2 = ebt_nr_to_chain(replace, verdict + NF_BR_NUMHOOKS);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001164 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001165 /* Now see if we've been here before */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001166 for (k = 0; k < sp; k++)
Bart De Schuymer6622a012005-01-19 21:09:05 +00001167 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) {
1168 ebt_print_error("Loop from chain '%s' to chain '%s'",
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001169 ebt_nr_to_chain(replace, chain_nr)->name,
1170 ebt_nr_to_chain(replace, stack[k].chain_nr)->name);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001171 goto free_stack;
1172 }
1173 /* Jump to the chain, make sure we know how to get back */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001174 stack[sp].chain_nr = chain_nr;
1175 stack[sp].n = j;
1176 stack[sp].entries = entries;
1177 stack[sp].e = e;
1178 sp++;
1179 j = -1;
1180 e = entries2->entries;
1181 chain_nr = verdict + NF_BR_NUMHOOKS;
1182 entries = entries2;
1183 continue;
1184letscontinue:
1185 e = e->next;
1186 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001187 /* We are at the end of a standard chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001188 if (sp == 0)
1189 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001190 /* Go back to the chain one level higher */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001191 sp--;
1192 j = stack[sp].n;
1193 chain_nr = stack[sp].chain_nr;
1194 e = stack[sp].e;
1195 entries = stack[sp].entries;
1196 goto letscontinue;
1197 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001198free_stack:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001199 free(stack);
1200 return;
1201}
1202
Bart De Schuymer6622a012005-01-19 21:09:05 +00001203/* The user will use the match, so put it in new_entry. The ebt_u_match
1204 * pointer is put in the ebt_entry_match pointer. ebt_add_rule will
1205 * fill in the final value for new->m. Unless the rule is added to a chain,
1206 * the pointer will keep pointing to the ebt_u_match (until the new_entry
1207 * is freed). I know, I should use a union for these 2 pointer types... */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001208void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m)
1209{
1210 struct ebt_u_match_list **m_list, *new;
1211
1212 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
1213 new = (struct ebt_u_match_list *)
1214 malloc(sizeof(struct ebt_u_match_list));
1215 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001216 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001217 *m_list = new;
1218 new->next = NULL;
1219 new->m = (struct ebt_entry_match *)m;
1220}
1221
1222void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w)
1223{
1224 struct ebt_u_watcher_list **w_list;
1225 struct ebt_u_watcher_list *new;
1226
1227 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
1228 new = (struct ebt_u_watcher_list *)
1229 malloc(sizeof(struct ebt_u_watcher_list));
1230 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001231 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001232 *w_list = new;
1233 new->next = NULL;
1234 new->w = (struct ebt_entry_watcher *)w;
1235}
1236
1237
1238 /*
1239*******************
1240*******************
1241**OTHER*FUNCTIONS**
1242*******************
1243*******************
1244 */
1245
1246
Bart De Schuymer6622a012005-01-19 21:09:05 +00001247/* type = 0 => update chain jumps
1248 * type = 1 => check for reference, print error when referenced
1249 * type = 2 => check for reference, don't print error when referenced
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001250 *
Bart De Schuymer6622a012005-01-19 21:09:05 +00001251 * Returns 1 when type == 1 and the chain is referenced
1252 * returns 0 otherwise */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001253static int iterate_entries(struct ebt_u_replace *replace, int type)
1254{
1255 int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS;
1256 struct ebt_u_entries *entries;
1257 struct ebt_u_entry *e;
1258
1259 if (chain_nr < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001260 ebt_print_bug("iterate_entries: udc = %d < 0", chain_nr);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001261 while (1) {
1262 i++;
1263 entries = ebt_nr_to_chain(replace, i);
1264 if (!entries) {
1265 if (i < NF_BR_NUMHOOKS)
1266 continue;
1267 else
1268 break;
1269 }
1270 e = entries->entries;
1271 j = 0;
1272 while (e) {
1273 int chain_jmp;
1274
1275 j++;
1276 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1277 e = e->next;
1278 continue;
1279 }
Bart De Schuymer64182a32004-01-21 20:39:54 +00001280 chain_jmp = ((struct ebt_standard_target *)e->t)->
1281 verdict;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001282 switch (type) {
1283 case 1:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001284 case 2:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001285 if (chain_jmp == chain_nr) {
Bart De Schuymer6622a012005-01-19 21:09:05 +00001286 if (type == 2)
1287 return 1;
1288 ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d",
1289 ebt_nr_to_chain(replace, chain_nr + NF_BR_NUMHOOKS)->name, entries->name, j);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001290 return 1;
1291 }
1292 break;
1293 case 0:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001294 /* Adjust the chain jumps when necessary */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001295 if (chain_jmp > chain_nr)
1296 ((struct ebt_standard_target *)e->t)->verdict--;
1297 break;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001298 } /* End switch */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001299 e = e->next;
1300 }
1301 }
1302 return 0;
1303}
1304
1305static void decrease_chain_jumps(struct ebt_u_replace *replace)
1306{
1307 iterate_entries(replace, 0);
1308}
1309
Bart De Schuymer6622a012005-01-19 21:09:05 +00001310/* Selected_chain >= NF_BR_NUMHOOKS */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001311static void remove_udc(struct ebt_u_replace *replace)
1312{
1313 struct ebt_u_chain_list *cl, **cl2;
1314 struct ebt_u_entries *entries;
1315 struct ebt_u_entry *u_e, *tmp;
1316 int chain_nr = replace->selected_chain;
1317
1318 if (chain_nr < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001319 ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr,
1320 NF_BR_NUMHOOKS);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001321 /* First free the rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001322 entries = ebt_nr_to_chain(replace, chain_nr);
1323 u_e = entries->entries;
1324 while (u_e) {
1325 ebt_free_u_entry(u_e);
1326 tmp = u_e->next;
1327 free(u_e);
1328 u_e = tmp;
1329 }
1330
1331 /* next, remove the chain */
1332 cl2 = &(replace->udc);
1333 while ((*cl2)->udc != entries)
1334 cl2 = &((*cl2)->next);
1335 cl = (*cl2);
1336 (*cl2) = (*cl2)->next;
1337 free(cl->udc);
1338 free(cl);
1339}
1340
Bart De Schuymer6622a012005-01-19 21:09:05 +00001341/* Used in initialization code of modules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001342void ebt_register_match(struct ebt_u_match *m)
1343{
1344 int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
1345 struct ebt_u_match **i;
1346
1347 m->m = (struct ebt_entry_match *)malloc(size);
1348 if (!m->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001349 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001350 strcpy(m->m->u.name, m->name);
1351 m->m->match_size = EBT_ALIGN(m->size);
1352 m->init(m->m);
1353
1354 for (i = &ebt_matches; *i; i = &((*i)->next));
1355 m->next = NULL;
1356 *i = m;
1357}
1358
1359void ebt_register_watcher(struct ebt_u_watcher *w)
1360{
1361 int size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
1362 struct ebt_u_watcher **i;
1363
1364 w->w = (struct ebt_entry_watcher *)malloc(size);
1365 if (!w->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001366 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001367 strcpy(w->w->u.name, w->name);
1368 w->w->watcher_size = EBT_ALIGN(w->size);
1369 w->init(w->w);
1370
1371 for (i = &ebt_watchers; *i; i = &((*i)->next));
1372 w->next = NULL;
1373 *i = w;
1374}
1375
1376void ebt_register_target(struct ebt_u_target *t)
1377{
1378 int size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
1379 struct ebt_u_target **i;
1380
1381 t->t = (struct ebt_entry_target *)malloc(size);
1382 if (!t->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001383 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001384 strcpy(t->t->u.name, t->name);
1385 t->t->target_size = EBT_ALIGN(t->size);
1386 t->init(t->t);
1387
1388 for (i = &ebt_targets; *i; i = &((*i)->next));
1389 t->next = NULL;
1390 *i = t;
1391}
1392
1393void ebt_register_table(struct ebt_u_table *t)
1394{
1395 t->next = ebt_tables;
1396 ebt_tables = t;
1397}
1398
1399void ebt_iterate_matches(void (*f)(struct ebt_u_match *))
1400{
1401 struct ebt_u_match *i;
1402
1403 for (i = ebt_matches; i; i = i->next)
1404 f(i);
1405}
1406
1407void ebt_iterate_watchers(void (*f)(struct ebt_u_watcher *))
1408{
1409 struct ebt_u_watcher *i;
1410
1411 for (i = ebt_watchers; i; i = i->next)
1412 f(i);
1413}
1414
1415void ebt_iterate_targets(void (*f)(struct ebt_u_target *))
1416{
1417 struct ebt_u_target *i;
1418
1419 for (i = ebt_targets; i; i = i->next)
1420 f(i);
1421}
1422
Bart De Schuymer6622a012005-01-19 21:09:05 +00001423/* Don't use this function, use ebt_print_bug() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001424void __ebt_print_bug(char *file, int line, char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001425{
1426 va_list l;
1427
1428 va_start(l, format);
1429 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
1430 vprintf(format, l);
1431 printf("\n");
1432 va_end(l);
1433 exit (-1);
1434}
1435
Bart De Schuymer6622a012005-01-19 21:09:05 +00001436/* The error messages are put in here when ebt_silent == 1
1437 * ebt_errormsg[0] == '\0' implies there was no error */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001438char ebt_errormsg[ERRORMSG_MAXLEN];
Bart De Schuymer6622a012005-01-19 21:09:05 +00001439/* When error messages should not be printed on the screen, after which
1440 * the program exit()s, set ebt_silent to 1. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001441int ebt_silent;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001442/* Don't use this function, use ebt_print_error() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001443void __ebt_print_error(char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001444{
1445 va_list l;
1446
1447 va_start(l, format);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001448 if (ebt_silent && ebt_errormsg[0] == '\0') {
1449 vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001450 va_end(l);
1451 } else {
1452 vprintf(format, l);
Bart De Schuymer87889eb2005-01-24 22:25:27 +00001453 printf(".\n");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001454 va_end(l);
1455 exit (-1);
1456 }
1457}