blob: 4a9a79d8f0ab4365fc5dff96089faa4774eddd9f [file] [log] [blame]
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001/*
2 * libebtc.c, January 2004
3 *
4 * Contains the functions with which to make a table in userspace.
5 *
6 * Author: Bart De Schuymer
7 *
8 * This code is stongly inspired on the iptables code which is
9 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000026#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <stdarg.h>
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000030#include "include/ebtables_u.h"
31#include "include/ethernetdb.h"
32#include <unistd.h>
33#include <fcntl.h>
34#include <sys/wait.h>
Bart De Schuymer8b5594d2011-06-19 18:59:23 +000035#include <errno.h>
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000036
37static void decrease_chain_jumps(struct ebt_u_replace *replace);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000038static int iterate_entries(struct ebt_u_replace *replace, int type);
39
Bart De Schuymer6622a012005-01-19 21:09:05 +000040/* The standard names */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000041const char *ebt_hooknames[NF_BR_NUMHOOKS] =
42{
43 [NF_BR_PRE_ROUTING]"PREROUTING",
44 [NF_BR_LOCAL_IN]"INPUT",
45 [NF_BR_FORWARD]"FORWARD",
46 [NF_BR_LOCAL_OUT]"OUTPUT",
47 [NF_BR_POST_ROUTING]"POSTROUTING",
48 [NF_BR_BROUTING]"BROUTING"
49};
50
Bart De Schuymer6622a012005-01-19 21:09:05 +000051/* The four target names */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000052const char* ebt_standard_targets[NUM_STANDARD_TARGETS] =
53{
54 "ACCEPT",
55 "DROP",
56 "CONTINUE",
57 "RETURN",
58};
59
Bart De Schuymer6622a012005-01-19 21:09:05 +000060/* The lists of supported tables, matches, watchers and targets */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000061struct ebt_u_table *ebt_tables;
62struct ebt_u_match *ebt_matches;
63struct ebt_u_watcher *ebt_watchers;
64struct ebt_u_target *ebt_targets;
65
Bart De Schuymer6622a012005-01-19 21:09:05 +000066/* Find the right structure belonging to a name */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000067struct ebt_u_target *ebt_find_target(const char *name)
68{
69 struct ebt_u_target *t = ebt_targets;
70
Bart De Schuymer6622a012005-01-19 21:09:05 +000071 while (t && strcmp(t->name, name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000072 t = t->next;
73 return t;
74}
75
76struct ebt_u_match *ebt_find_match(const char *name)
77{
78 struct ebt_u_match *m = ebt_matches;
79
Bart De Schuymer6622a012005-01-19 21:09:05 +000080 while (m && strcmp(m->name, name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000081 m = m->next;
82 return m;
83}
84
85struct ebt_u_watcher *ebt_find_watcher(const char *name)
86{
87 struct ebt_u_watcher *w = ebt_watchers;
88
Bart De Schuymer6622a012005-01-19 21:09:05 +000089 while (w && strcmp(w->name, name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000090 w = w->next;
91 return w;
92}
93
94struct ebt_u_table *ebt_find_table(const char *name)
95{
96 struct ebt_u_table *t = ebt_tables;
97
98 while (t && strcmp(t->name, name))
99 t = t->next;
100 return t;
101}
102
Bart De Schuymer6622a012005-01-19 21:09:05 +0000103/* Prints all registered extensions */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000104void ebt_list_extensions()
105{
106 struct ebt_u_table *tbl = ebt_tables;
107 struct ebt_u_target *t = ebt_targets;
108 struct ebt_u_match *m = ebt_matches;
109 struct ebt_u_watcher *w = ebt_watchers;
110
111 PRINT_VERSION;
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000112 printf("Loaded userspace extensions:\n\nLoaded tables:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000113 while (tbl) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000114 printf("%s\n", tbl->name);
115 tbl = tbl->next;
116 }
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000117 printf("\nLoaded targets:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000118 while (t) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000119 printf("%s\n", t->name);
120 t = t->next;
121 }
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000122 printf("\nLoaded matches:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000123 while (m) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000124 printf("%s\n", m->name);
125 m = m->next;
126 }
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000127 printf("\nLoaded watchers:\n");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000128 while (w) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000129 printf("%s\n", w->name);
130 w = w->next;
131 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000132}
133
Bart De Schuymer8b5594d2011-06-19 18:59:23 +0000134#define LOCKDIR "/var/lib/ebtables"
135#define LOCKFILE LOCKDIR"/lock"
136static int lockfd = -1, locked;
137int use_lockfd;
138/* Returns 0 on success, -1 when the file is locked by another process
139 * or -2 on any other error. */
140static int lock_file()
141{
142 int try = 0;
143 int ret = 0;
144 sigset_t sigset;
145
146tryagain:
147 /* the SIGINT handler will call unlock_file. To make sure the state
148 * of the variable locked is correct, we need to temporarily mask the
149 * SIGINT interrupt. */
150 sigemptyset(&sigset);
151 sigaddset(&sigset, SIGINT);
152 sigprocmask(SIG_BLOCK, &sigset, NULL);
153 lockfd = open(LOCKFILE, O_CREAT | O_EXCL | O_WRONLY, 00600);
154 if (lockfd < 0) {
155 if (errno == EEXIST)
156 ret = -1;
157 else if (try == 1)
158 ret = -2;
159 else {
160 if (mkdir(LOCKDIR, 00700))
161 ret = -2;
162 else {
163 try = 1;
164 goto tryagain;
165 }
166 }
167 } else {
168 close(lockfd);
169 locked = 1;
170 }
171 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
172 return ret;
173}
174
175void unlock_file()
176{
177 if (locked) {
178 remove(LOCKFILE);
179 locked = 0;
180 }
181}
182
183void __attribute__ ((destructor)) onexit()
184{
185 if (use_lockfd)
186 unlock_file();
187}
Bart De Schuymer6622a012005-01-19 21:09:05 +0000188/* Get the table from the kernel or from a binary file
Bart De Schuymer64182a32004-01-21 20:39:54 +0000189 * init: 1 = ask the kernel for the initial contents of a table, i.e. the
190 * way it looks when the table is insmod'ed
Bart De Schuymer6622a012005-01-19 21:09:05 +0000191 * 0 = get the current data in the table */
192int ebt_get_kernel_table(struct ebt_u_replace *replace, int init)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000193{
Bart De Schuymer8b5594d2011-06-19 18:59:23 +0000194 int ret;
195
Bart De Schuymer6622a012005-01-19 21:09:05 +0000196 if (!ebt_find_table(replace->name)) {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000197 ebt_print_error("Bad table name '%s'", replace->name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000198 return -1;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000199 }
Bart De Schuymer8b5594d2011-06-19 18:59:23 +0000200 while (use_lockfd && (ret = lock_file())) {
201 if (ret == -2) {
202 /* if we get an error we can't handle, we exit. This
203 * doesn't break backwards compatibility since using
204 * this file locking is disabled by default. */
205 ebt_print_error2("Unable to create lock file "LOCKFILE);
206 }
207 fprintf(stderr, "Trying to obtain lock %s\n", LOCKFILE);
208 sleep(1);
209 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000210 /* Get the kernel's information */
211 if (ebt_get_table(replace, init)) {
212 if (ebt_errormsg[0] != '\0')
213 return -1;
214 ebtables_insmod("ebtables");
215 if (ebt_get_table(replace, init)) {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000216 ebt_print_error("The kernel doesn't support the ebtables '%s' table", replace->name);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000217 return -1;
218 }
219 }
220 return 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000221}
222
Bart De Schuymer6622a012005-01-19 21:09:05 +0000223/* Put sane values into a new entry */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000224void ebt_initialize_entry(struct ebt_u_entry *e)
225{
226 e->bitmask = EBT_NOPROTO;
227 e->invflags = 0;
228 e->ethproto = 0;
229 strcpy(e->in, "");
230 strcpy(e->out, "");
231 strcpy(e->logical_in, "");
232 strcpy(e->logical_out, "");
233 e->m_list = NULL;
234 e->w_list = NULL;
235 e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000236 ebt_find_target(EBT_STANDARD_TARGET)->used = 1;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000237 e->cnt.pcnt = e->cnt.bcnt = e->cnt_surplus.pcnt = e->cnt_surplus.bcnt = 0;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000238
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000239 if (!e->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000240 ebt_print_bug("Couldn't load standard target");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000241 ((struct ebt_standard_target *)((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000242}
243
Bart De Schuymer6622a012005-01-19 21:09:05 +0000244/* Free up the memory of the table held in userspace, *replace can be reused */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000245void ebt_cleanup_replace(struct ebt_u_replace *replace)
246{
247 int i;
248 struct ebt_u_entries *entries;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000249 struct ebt_cntchanges *cc1, *cc2;
250 struct ebt_u_entry *u_e1, *u_e2;
251
252 replace->name[0] = '\0';
253 replace->valid_hooks = 0;
254 replace->nentries = 0;
255 replace->num_counters = 0;
256 replace->flags = 0;
257 replace->command = 0;
258 replace->selected_chain = -1;
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000259 free(replace->filename);
260 replace->filename = NULL;
261 free(replace->counters);
262 replace->counters = NULL;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000263
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000264 for (i = 0; i < replace->num_chains; i++) {
265 if (!(entries = replace->chains[i]))
266 continue;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000267 u_e1 = entries->entries->next;
268 while (u_e1 != entries->entries) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000269 ebt_free_u_entry(u_e1);
270 u_e2 = u_e1->next;
271 free(u_e1);
272 u_e1 = u_e2;
273 }
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000274 free(entries->entries);
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000275 free(entries);
276 replace->chains[i] = NULL;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000277 }
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000278 cc1 = replace->cc->next;
279 while (cc1 != replace->cc) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000280 cc2 = cc1->next;
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000281 free(cc1);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000282 cc1 = cc2;
283 }
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000284 replace->cc->next = replace->cc->prev = replace->cc;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000285}
286
Bart De Schuymer6622a012005-01-19 21:09:05 +0000287/* Should be called, e.g., between 2 rule adds */
288void ebt_reinit_extensions()
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000289{
290 struct ebt_u_match *m;
291 struct ebt_u_watcher *w;
292 struct ebt_u_target *t;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000293 int size;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000294
295 /* The init functions should determine by themselves whether they are
296 * called for the first time or not (when necessary). */
297 for (m = ebt_matches; m; m = m->next) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000298 if (m->used) {
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000299 size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000300 m->m = (struct ebt_entry_match *)malloc(size);
301 if (!m->m)
302 ebt_print_memory();
303 strcpy(m->m->u.name, m->name);
304 m->m->match_size = EBT_ALIGN(m->size);
305 m->used = 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000306 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000307 m->flags = 0; /* An error can occur before used is set, while flags is changed. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000308 m->init(m->m);
309 }
310 for (w = ebt_watchers; w; w = w->next) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000311 if (w->used) {
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000312 size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000313 w->w = (struct ebt_entry_watcher *)malloc(size);
314 if (!w->w)
315 ebt_print_memory();
316 strcpy(w->w->u.name, w->name);
317 w->w->watcher_size = EBT_ALIGN(w->size);
318 w->used = 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000319 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000320 w->flags = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000321 w->init(w->w);
322 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000323 for (t = ebt_targets; t; t = t->next) {
Bart De Schuymer6622a012005-01-19 21:09:05 +0000324 if (t->used) {
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000325 size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000326 t->t = (struct ebt_entry_target *)malloc(size);
327 if (!t->t)
328 ebt_print_memory();
329 strcpy(t->t->u.name, t->name);
330 t->t->target_size = EBT_ALIGN(t->size);
331 t->used = 0;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000332 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000333 t->flags = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000334 t->init(t->t);
335 }
336}
337
Bart De Schuymer6622a012005-01-19 21:09:05 +0000338/* This doesn't free e, because the calling function might need e->next */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000339void ebt_free_u_entry(struct ebt_u_entry *e)
340{
341 struct ebt_u_match_list *m_l, *m_l2;
342 struct ebt_u_watcher_list *w_l, *w_l2;
343
344 m_l = e->m_list;
345 while (m_l) {
346 m_l2 = m_l->next;
347 free(m_l->m);
348 free(m_l);
349 m_l = m_l2;
350 }
351 w_l = e->w_list;
352 while (w_l) {
353 w_l2 = w_l->next;
354 free(w_l->w);
355 free(w_l);
356 w_l = w_l2;
357 }
358 free(e->t);
359}
360
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000361static char *get_modprobe(void)
362{
363 int procfile;
364 char *ret;
365
366 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
367 if (procfile < 0)
368 return NULL;
369
370 ret = malloc(1024);
371 if (ret) {
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000372 if (read(procfile, ret, 1024) == -1)
373 goto fail;
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000374 /* The kernel adds a '\n' */
375 ret[1023] = '\n';
376 *strchr(ret, '\n') = '\0';
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000377 close(procfile);
378 return ret;
379 }
380 fail:
381 free(ret);
382 close(procfile);
383 return NULL;
384}
385
386char *ebt_modprobe;
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000387/* Try to load the kernel module, analogous to ip_tables.c */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000388int ebtables_insmod(const char *modname)
389{
390 char *buf = NULL;
391 char *argv[3];
392
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000393 /* If they don't explicitly set it, read out of /proc */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000394 if (!ebt_modprobe) {
395 buf = get_modprobe();
396 if (!buf)
397 return -1;
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000398 ebt_modprobe = buf; /* Keep the value for possible later use */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000399 }
400
401 switch (fork()) {
402 case 0:
403 argv[0] = (char *)ebt_modprobe;
404 argv[1] = (char *)modname;
405 argv[2] = NULL;
406 execv(argv[0], argv);
407
Bart De Schuymer6622a012005-01-19 21:09:05 +0000408 /* Not usually reached */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000409 exit(0);
410 case -1:
411 return -1;
412
Bart De Schuymer6622a012005-01-19 21:09:05 +0000413 default: /* Parent */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000414 wait(NULL);
415 }
416
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000417 return 0;
418}
419
Bart De Schuymer6622a012005-01-19 21:09:05 +0000420/* Parse the chain name and return a pointer to the chain base.
421 * Returns NULL on failure. */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000422struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, const char* arg)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000423{
424 int i;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000425 struct ebt_u_entries *chain;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000426
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000427 for (i = 0; i < replace->num_chains; i++) {
428 if (!(chain = replace->chains[i]))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000429 continue;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000430 if (!strcmp(arg, chain->name))
431 return chain;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000432 }
433 return NULL;
434}
435
Bart De Schuymer6622a012005-01-19 21:09:05 +0000436/* Parse the chain name and return the corresponding chain nr
437 * returns -1 on failure */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000438int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg)
439{
440 int i;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000441
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000442 for (i = 0; i < replace->num_chains; i++) {
443 if (!replace->chains[i])
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000444 continue;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000445 if (!strcmp(arg, replace->chains[i]->name))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000446 return i;
447 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000448 return -1;
449}
450
451 /*
452************
453************
454**COMMANDS**
455************
456************
457 */
458
Bart De Schuymer6622a012005-01-19 21:09:05 +0000459/* Change the policy of selected_chain.
460 * Handing a bad policy to this function is a bug. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000461void ebt_change_policy(struct ebt_u_replace *replace, int policy)
462{
463 struct ebt_u_entries *entries = ebt_to_chain(replace);
464
465 if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE)
Bart De Schuymer6622a012005-01-19 21:09:05 +0000466 ebt_print_bug("Wrong policy: %d", policy);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000467 entries->policy = policy;
468}
469
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000470void ebt_delete_cc(struct ebt_cntchanges *cc)
471{
472 if (cc->type == CNT_ADD) {
473 cc->prev->next = cc->next;
474 cc->next->prev = cc->prev;
475 free(cc);
476 }
477 cc->type = CNT_DEL;
478}
479
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000480void ebt_empty_chain(struct ebt_u_entries *entries)
481{
482 struct ebt_u_entry *u_e = entries->entries->next, *tmp;
483 while (u_e != entries->entries) {
484 ebt_delete_cc(u_e->cc);
485 ebt_free_u_entry(u_e);
486 tmp = u_e->next;
487 free(u_e);
488 u_e = tmp;
489 }
490 entries->entries->next = entries->entries->prev = entries->entries;
491 entries->nentries = 0;
492}
493
Bart De Schuymer6622a012005-01-19 21:09:05 +0000494/* Flush one chain or the complete table
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000495 * If selected_chain == -1 then flush the complete table */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000496void ebt_flush_chains(struct ebt_u_replace *replace)
497{
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000498 int i, numdel;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000499 struct ebt_u_entries *entries = ebt_to_chain(replace);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000500
Bart De Schuymer6622a012005-01-19 21:09:05 +0000501 /* Flush whole table */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000502 if (!entries) {
503 if (replace->nentries == 0)
504 return;
505 replace->nentries = 0;
506
Bart De Schuymer6622a012005-01-19 21:09:05 +0000507 /* Free everything and zero (n)entries */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000508 for (i = 0; i < replace->num_chains; i++) {
509 if (!(entries = replace->chains[i]))
510 continue;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000511 entries->counter_offset = 0;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000512 ebt_empty_chain(entries);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000513 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000514 return;
515 }
516
517 if (entries->nentries == 0)
518 return;
519 replace->nentries -= entries->nentries;
520 numdel = entries->nentries;
521
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000522 /* Update counter_offset */
523 for (i = replace->selected_chain+1; i < replace->num_chains; i++) {
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000524 if (!(entries = replace->chains[i]))
525 continue;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000526 entries->counter_offset -= numdel;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000527 }
528
529 entries = ebt_to_chain(replace);
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000530 ebt_empty_chain(entries);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000531}
532
Bart De Schuymerab611e22005-02-14 20:20:03 +0000533#define OPT_COUNT 0x1000 /* This value is also defined in ebtables.c */
Bart De Schuymer6622a012005-01-19 21:09:05 +0000534/* Returns the rule number on success (starting from 0), -1 on failure
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000535 *
536 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer6622a012005-01-19 21:09:05 +0000537 * to contain pointers to ebt_u_{match,watcher,target} */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000538int ebt_check_rule_exists(struct ebt_u_replace *replace,
539 struct ebt_u_entry *new_entry)
540{
541 struct ebt_u_entry *u_e;
542 struct ebt_u_match_list *m_l, *m_l2;
543 struct ebt_u_match *m;
544 struct ebt_u_watcher_list *w_l, *w_l2;
545 struct ebt_u_watcher *w;
546 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
547 struct ebt_u_entries *entries = ebt_to_chain(replace);
548 int i, j, k;
549
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000550 u_e = entries->entries->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000551 /* Check for an existing rule (if there are duplicate rules,
552 * take the first occurance) */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000553 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000554 if (u_e->ethproto != new_entry->ethproto)
555 continue;
556 if (strcmp(u_e->in, new_entry->in))
557 continue;
558 if (strcmp(u_e->out, new_entry->out))
559 continue;
560 if (strcmp(u_e->logical_in, new_entry->logical_in))
561 continue;
562 if (strcmp(u_e->logical_out, new_entry->logical_out))
563 continue;
564 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer6622a012005-01-19 21:09:05 +0000565 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000566 continue;
567 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer6622a012005-01-19 21:09:05 +0000568 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000569 continue;
570 if (new_entry->bitmask != u_e->bitmask ||
Bart De Schuymer6622a012005-01-19 21:09:05 +0000571 new_entry->invflags != u_e->invflags)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000572 continue;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000573 if (replace->flags & OPT_COUNT && (new_entry->cnt.pcnt !=
574 u_e->cnt.pcnt || new_entry->cnt.bcnt != u_e->cnt.bcnt))
575 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000576 /* Compare all matches */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000577 m_l = new_entry->m_list;
578 j = 0;
579 while (m_l) {
580 m = (struct ebt_u_match *)(m_l->m);
581 m_l2 = u_e->m_list;
582 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
583 m_l2 = m_l2->next;
584 if (!m_l2 || !m->compare(m->m, m_l2->m))
585 goto letscontinue;
586 j++;
587 m_l = m_l->next;
588 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000589 /* Now be sure they have the same nr of matches */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000590 k = 0;
591 m_l = u_e->m_list;
592 while (m_l) {
593 k++;
594 m_l = m_l->next;
595 }
596 if (j != k)
597 continue;
598
Bart De Schuymer6622a012005-01-19 21:09:05 +0000599 /* Compare all watchers */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000600 w_l = new_entry->w_list;
601 j = 0;
602 while (w_l) {
603 w = (struct ebt_u_watcher *)(w_l->w);
604 w_l2 = u_e->w_list;
605 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
606 w_l2 = w_l2->next;
607 if (!w_l2 || !w->compare(w->w, w_l2->w))
608 goto letscontinue;
609 j++;
610 w_l = w_l->next;
611 }
612 k = 0;
613 w_l = u_e->w_list;
614 while (w_l) {
615 k++;
616 w_l = w_l->next;
617 }
618 if (j != k)
619 continue;
620 if (strcmp(t->t->u.name, u_e->t->u.name))
621 continue;
622 if (!t->compare(t->t, u_e->t))
623 continue;
624 return i;
Bart De Schuymeraef08942004-09-09 21:41:29 +0000625letscontinue:;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000626 }
627 return -1;
628}
629
630/* Add a rule, rule_nr is the rule to update
631 * rule_nr specifies where the rule should be inserted
632 * rule_nr > 0 : insert the rule right before the rule_nr'th rule
633 * (the first rule is rule 1)
634 * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule,
Bart De Schuymer6622a012005-01-19 21:09:05 +0000635 * where n denotes the number of rules in the chain
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000636 * rule_nr == 0: add a new rule at the end of the chain
637 *
638 * This function expects the ebt_{match,watcher,target} members of new_entry
639 * to contain pointers to ebt_u_{match,watcher,target} and updates these
Bart De Schuymer6622a012005-01-19 21:09:05 +0000640 * pointers so that they point to ebt_{match,watcher,target}, before adding
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000641 * the rule to the chain. Don't free() the ebt_{match,watcher,target} and
642 * don't reuse the new_entry after a successful call to ebt_add_rule() */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000643void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int rule_nr)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000644{
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000645 int i;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000646 struct ebt_u_entry *u_e;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000647 struct ebt_u_match_list *m_l;
648 struct ebt_u_watcher_list *w_l;
649 struct ebt_u_entries *entries = ebt_to_chain(replace);
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000650 struct ebt_cntchanges *cc, *new_cc;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000651
652 if (rule_nr <= 0)
653 rule_nr += entries->nentries;
654 else
655 rule_nr--;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000656 if (rule_nr > entries->nentries || rule_nr < 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000657 ebt_print_error("The specified rule number is incorrect");
Bart De Schuymer6622a012005-01-19 21:09:05 +0000658 return;
659 }
Bart De Schuymer6622a012005-01-19 21:09:05 +0000660 /* Go to the right position in the chain */
Bart De Schuymera0d0a0a2005-08-30 21:51:09 +0000661 if (rule_nr == entries->nentries)
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000662 u_e = entries->entries;
663 else {
664 u_e = entries->entries->next;
665 for (i = 0; i < rule_nr; i++)
666 u_e = u_e->next;
667 }
Bart De Schuymera0d0a0a2005-08-30 21:51:09 +0000668 /* We're adding one rule */
669 replace->nentries++;
670 entries->nentries++;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000671 /* Insert the rule */
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000672 new_entry->next = u_e;
673 new_entry->prev = u_e->prev;
674 u_e->prev->next = new_entry;
675 u_e->prev = new_entry;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000676 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges));
677 if (!new_cc)
678 ebt_print_memory();
679 new_cc->type = CNT_ADD;
680 new_cc->change = 0;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000681 if (new_entry->next == entries->entries) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000682 for (i = replace->selected_chain+1; i < replace->num_chains; i++)
683 if (!replace->chains[i] || replace->chains[i]->nentries == 0)
684 continue;
685 else
686 break;
687 if (i == replace->num_chains)
688 cc = replace->cc;
689 else
Bart De Schuymera0d0a0a2005-08-30 21:51:09 +0000690 cc = replace->chains[i]->entries->next->cc;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000691 } else
692 cc = new_entry->next->cc;
693 new_cc->next = cc;
694 new_cc->prev = cc->prev;
695 cc->prev->next = new_cc;
696 cc->prev = new_cc;
Bart De Schuymer7ac91522005-09-01 20:34:29 +0000697 new_entry->cc = new_cc;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000698
Bart De Schuymer6622a012005-01-19 21:09:05 +0000699 /* Put the ebt_{match, watcher, target} pointers in place */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000700 m_l = new_entry->m_list;
701 while (m_l) {
702 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
703 m_l = m_l->next;
704 }
705 w_l = new_entry->w_list;
706 while (w_l) {
707 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
708 w_l = w_l->next;
709 }
710 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000711 /* Update the counter_offset of chains behind this one */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000712 for (i = replace->selected_chain+1; i < replace->num_chains; i++) {
713 entries = replace->chains[i];
714 if (!(entries = replace->chains[i]))
715 continue;
716 entries->counter_offset++;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000717 }
718}
719
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000720/* If *begin==*end==0 then find the rule corresponding to new_entry,
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000721 * else make the rule numbers positive (starting from 0) and check
722 * for bad rule numbers. */
Bart De Schuymerff587202005-02-08 20:02:28 +0000723static int check_and_change_rule_number(struct ebt_u_replace *replace,
724 struct ebt_u_entry *new_entry, int *begin, int *end)
725{
726 struct ebt_u_entries *entries = ebt_to_chain(replace);
727
728 if (*begin < 0)
729 *begin += entries->nentries + 1;
730 if (*end < 0)
731 *end += entries->nentries + 1;
732
733 if (*begin < 0 || *begin > *end || *end > entries->nentries) {
734 ebt_print_error("Sorry, wrong rule numbers");
735 return -1;
736 }
737
738 if ((*begin * *end == 0) && (*begin + *end != 0))
739 ebt_print_bug("begin and end should be either both zero, "
740 "either both non-zero");
Bart De Schuymerd5dc87d2005-07-16 22:35:32 +0000741 if (*begin != 0) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000742 (*begin)--;
743 (*end)--;
744 } else {
745 *begin = ebt_check_rule_exists(replace, new_entry);
746 *end = *begin;
747 if (*begin == -1) {
748 ebt_print_error("Sorry, rule does not exist");
749 return -1;
750 }
751 }
752 return 0;
753}
754
Bart De Schuymer6622a012005-01-19 21:09:05 +0000755/* Delete a rule or rules
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000756 * begin == end == 0: delete the rule corresponding to new_entry
757 *
Bart De Schuymer6622a012005-01-19 21:09:05 +0000758 * The first rule has rule nr 1, the last rule has rule nr -1, etc.
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000759 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer6622a012005-01-19 21:09:05 +0000760 * to contain pointers to ebt_u_{match,watcher,target}. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000761void ebt_delete_rule(struct ebt_u_replace *replace,
762 struct ebt_u_entry *new_entry, int begin, int end)
763{
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000764 int i, nr_deletes;
Bart De Schuymereb921222005-10-24 18:18:37 +0000765 struct ebt_u_entry *u_e, *u_e2, *u_e3;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000766 struct ebt_u_entries *entries = ebt_to_chain(replace);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000767
Bart De Schuymerff587202005-02-08 20:02:28 +0000768 if (check_and_change_rule_number(replace, new_entry, &begin, &end))
Bart De Schuymer6622a012005-01-19 21:09:05 +0000769 return;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000770 /* We're deleting rules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000771 nr_deletes = end - begin + 1;
772 replace->nentries -= nr_deletes;
773 entries->nentries -= nr_deletes;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000774 /* Go to the right position in the chain */
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000775 u_e = entries->entries->next;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000776 for (i = 0; i < begin; i++)
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000777 u_e = u_e->next;
Bart De Schuymereb921222005-10-24 18:18:37 +0000778 u_e3 = u_e->prev;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000779 /* Remove the rules */
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000780 for (i = 0; i < nr_deletes; i++) {
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000781 u_e2 = u_e;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000782 ebt_delete_cc(u_e2->cc);
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000783 u_e = u_e->next;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000784 /* Free everything */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000785 ebt_free_u_entry(u_e2);
786 free(u_e2);
787 }
Bart De Schuymereb921222005-10-24 18:18:37 +0000788 u_e3->next = u_e;
789 u_e->prev = u_e3;
Bart De Schuymer6622a012005-01-19 21:09:05 +0000790 /* Update the counter_offset of chains behind this one */
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000791 for (i = replace->selected_chain+1; i < replace->num_chains; i++) {
792 if (!(entries = replace->chains[i]))
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000793 continue;
794 entries->counter_offset -= nr_deletes;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000795 }
796}
797
Bart De Schuymerff587202005-02-08 20:02:28 +0000798/* Change the counters of a rule or rules
799 * begin == end == 0: change counters of the rule corresponding to new_entry
800 *
801 * The first rule has rule nr 1, the last rule has rule nr -1, etc.
802 * This function expects the ebt_{match,watcher,target} members of new_entry
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000803 * to contain pointers to ebt_u_{match,watcher,target}.
804 * The mask denotes the following:
805 * pcnt: mask % 3 = 0 : change; = 1: increment; = 2: decrement
806 * bcnt: mask / 3 = 0 : change; = 1: increment = 2: increment
807 * In daemon mode, mask==0 must hold */
Bart De Schuymerff587202005-02-08 20:02:28 +0000808void ebt_change_counters(struct ebt_u_replace *replace,
809 struct ebt_u_entry *new_entry, int begin, int end,
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000810 struct ebt_counter *cnt, int mask)
Bart De Schuymerff587202005-02-08 20:02:28 +0000811{
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000812 int i;
Bart De Schuymerff587202005-02-08 20:02:28 +0000813 struct ebt_u_entry *u_e;
814 struct ebt_u_entries *entries = ebt_to_chain(replace);
Bart De Schuymerff587202005-02-08 20:02:28 +0000815
816 if (check_and_change_rule_number(replace, new_entry, &begin, &end))
817 return;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000818 u_e = entries->entries->next;
Bart De Schuymerff587202005-02-08 20:02:28 +0000819 for (i = 0; i < begin; i++)
820 u_e = u_e->next;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000821 for (i = end-begin+1; i > 0; i--) {
822 if (mask % 3 == 0) {
823 u_e->cnt.pcnt = (*cnt).pcnt;
824 u_e->cnt_surplus.pcnt = 0;
825 } else {
Bart De Schuymer0fbb3f92005-08-12 16:47:02 +0000826#ifdef EBT_DEBUG
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000827 if (u_e->cc->type != CNT_NORM)
828 ebt_print_bug("cc->type != CNT_NORM");
Bart De Schuymer0fbb3f92005-08-12 16:47:02 +0000829#endif
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000830 u_e->cnt_surplus.pcnt = (*cnt).pcnt;
Bart De Schuymerab611e22005-02-14 20:20:03 +0000831 }
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000832
833 if (mask / 3 == 0) {
834 u_e->cnt.bcnt = (*cnt).bcnt;
835 u_e->cnt_surplus.bcnt = 0;
836 } else {
837#ifdef EBT_DEBUG
838 if (u_e->cc->type != CNT_NORM)
839 ebt_print_bug("cc->type != CNT_NORM");
840#endif
841 u_e->cnt_surplus.bcnt = (*cnt).bcnt;
842 }
843 if (u_e->cc->type != CNT_ADD)
844 u_e->cc->type = CNT_CHANGE;
845 u_e->cc->change = mask;
846 u_e = u_e->next;
Bart De Schuymerff587202005-02-08 20:02:28 +0000847 }
848}
849
Bart De Schuymer0436eda2005-03-28 20:29:37 +0000850/* If selected_chain == -1 then zero all counters,
851 * otherwise, zero the counters of selected_chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000852void ebt_zero_counters(struct ebt_u_replace *replace)
853{
854 struct ebt_u_entries *entries = ebt_to_chain(replace);
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000855 struct ebt_u_entry *next;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000856 int i;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000857
858 if (!entries) {
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000859 for (i = 0; i < replace->num_chains; i++) {
860 if (!(entries = replace->chains[i]))
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000861 continue;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000862 next = entries->entries->next;
863 while (next != entries->entries) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000864 if (next->cc->type == CNT_NORM)
865 next->cc->type = CNT_CHANGE;
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000866 next->cnt.bcnt = next->cnt.pcnt = 0;
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000867 next->cc->change = 0;
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000868 next = next->next;
869 }
870 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000871 } else {
872 if (entries->nentries == 0)
873 return;
874
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000875 next = entries->entries->next;
876 while (next != entries->entries) {
Bart De Schuymer482fbaf2005-08-28 13:16:25 +0000877 if (next->cc->type == CNT_NORM)
878 next->cc->type = CNT_CHANGE;
Bart De Schuymer93f36ba2005-01-24 21:11:24 +0000879 next->cnt.bcnt = next->cnt.pcnt = 0;
880 next = next->next;
881 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000882 }
883}
884
Bart De Schuymer6622a012005-01-19 21:09:05 +0000885/* Add a new chain and specify its policy */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000886void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
887{
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000888 struct ebt_u_entries *new;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000889
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000890 if (replace->num_chains == replace->max_chains)
891 ebt_double_chains(replace);
892 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
893 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000894 ebt_print_memory();
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000895 replace->chains[replace->num_chains++] = new;
896 new->nentries = 0;
897 new->policy = policy;
898 new->counter_offset = replace->nentries;
899 new->hook_mask = 0;
900 strcpy(new->name, name);
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000901 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
902 if (!new->entries)
903 ebt_print_memory();
904 new->entries->next = new->entries->prev = new->entries;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000905 new->kernel_start = NULL;
906}
907
Bart De Schuymer0faecd52006-07-31 19:47:45 +0000908/* returns -1 if the chain is referenced, 0 on success */
909static int ebt_delete_a_chain(struct ebt_u_replace *replace, int chain, int print_err)
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000910{
911 int tmp = replace->selected_chain;
912 /* If the chain is referenced, don't delete it,
913 * also decrement jumps to a chain behind the
914 * one we're deleting */
915 replace->selected_chain = chain;
916 if (ebt_check_for_references(replace, print_err))
Bart De Schuymer0faecd52006-07-31 19:47:45 +0000917 return -1;
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000918 decrease_chain_jumps(replace);
919 ebt_flush_chains(replace);
920 replace->selected_chain = tmp;
Bart De Schuymere94eaf72005-08-28 16:06:22 +0000921 free(replace->chains[chain]->entries);
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000922 free(replace->chains[chain]);
923 memmove(replace->chains+chain, replace->chains+chain+1, (replace->num_chains-chain-1)*sizeof(void *));
924 replace->num_chains--;
Bart De Schuymer0faecd52006-07-31 19:47:45 +0000925 return 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000926}
927
Bart De Schuymer6622a012005-01-19 21:09:05 +0000928/* Selected_chain == -1: delete all non-referenced udc
929 * selected_chain < NF_BR_NUMHOOKS is illegal */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000930void ebt_delete_chain(struct ebt_u_replace *replace)
931{
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000932 if (replace->selected_chain != -1 && replace->selected_chain < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000933 ebt_print_bug("You can't remove a standard chain");
Bart De Schuymer0faecd52006-07-31 19:47:45 +0000934 if (replace->selected_chain == -1) {
935 int i = NF_BR_NUMHOOKS;
936
937 while (i < replace->num_chains)
938 if (ebt_delete_a_chain(replace, i, 0))
939 i++;
940 } else
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000941 ebt_delete_a_chain(replace, replace->selected_chain, 1);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000942}
943
Bart De Schuymer6622a012005-01-19 21:09:05 +0000944/* Rename an existing chain. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000945void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
946{
947 struct ebt_u_entries *entries = ebt_to_chain(replace);
948
949 if (!entries)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000950 ebt_print_bug("ebt_rename_chain: entries == NULL");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000951 strcpy(entries->name, name);
952}
953
954
955 /*
956*************************
957*************************
958**SPECIALIZED*FUNCTIONS**
959*************************
960*************************
961 */
962
963
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +0000964void ebt_double_chains(struct ebt_u_replace *replace)
965{
966 struct ebt_u_entries **new;
967
968 replace->max_chains *= 2;
969 new = (struct ebt_u_entries **)malloc(replace->max_chains*sizeof(void *));
970 if (!new)
971 ebt_print_memory();
972 memcpy(new, replace->chains, replace->max_chains/2*sizeof(void *));
973 free(replace->chains);
974 replace->chains = new;
975}
976
Bart De Schuymer6622a012005-01-19 21:09:05 +0000977/* Executes the final_check() function for all extensions used by the rule
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000978 * ebt_check_for_loops should have been executed earlier, to make sure the
Bart De Schuymer6622a012005-01-19 21:09:05 +0000979 * hook_mask is correct. The time argument to final_check() is set to 1,
980 * meaning it's the second time the final_check() function is executed. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000981void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
982 struct ebt_u_entries *entries)
983{
984 struct ebt_u_match_list *m_l;
985 struct ebt_u_watcher_list *w_l;
986 struct ebt_u_target *t;
987 struct ebt_u_match *m;
988 struct ebt_u_watcher *w;
989
990 m_l = e->m_list;
991 w_l = e->w_list;
992 while (m_l) {
993 m = ebt_find_match(m_l->m->u.name);
994 m->final_check(e, m_l->m, replace->name,
995 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000996 if (ebt_errormsg[0] != '\0')
997 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000998 m_l = m_l->next;
999 }
1000 while (w_l) {
1001 w = ebt_find_watcher(w_l->w->u.name);
1002 w->final_check(e, w_l->w, replace->name,
1003 entries->hook_mask, 1);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001004 if (ebt_errormsg[0] != '\0')
1005 return;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001006 w_l = w_l->next;
1007 }
1008 t = ebt_find_target(e->t->u.name);
1009 t->final_check(e, e->t, replace->name,
1010 entries->hook_mask, 1);
1011}
1012
Bart De Schuymer6622a012005-01-19 21:09:05 +00001013/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1014 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1015int ebt_check_for_references(struct ebt_u_replace *replace, int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001016{
Bart De Schuymer6622a012005-01-19 21:09:05 +00001017 if (print_err)
1018 return iterate_entries(replace, 1);
1019 else
1020 return iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001021}
1022
Bart De Schuymer6622a012005-01-19 21:09:05 +00001023/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
1024 * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
1025 * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
1026int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr,
1027 int print_err)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001028{
1029 int tmp = replace->selected_chain, ret;
1030
1031 replace->selected_chain = chain_nr;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001032 if (print_err)
1033 ret = iterate_entries(replace, 1);
1034 else
1035 ret = iterate_entries(replace, 2);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001036 replace->selected_chain = tmp;
1037 return ret;
1038}
1039
1040struct ebt_u_stack
1041{
1042 int chain_nr;
1043 int n;
1044 struct ebt_u_entry *e;
1045 struct ebt_u_entries *entries;
1046};
1047
Bart De Schuymer6622a012005-01-19 21:09:05 +00001048/* Checks for loops
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001049 * As a by-product, the hook_mask member of each chain is filled in
1050 * correctly. The check functions of the extensions need this hook_mask
Bart De Schuymer6622a012005-01-19 21:09:05 +00001051 * to know from which standard chains they can be called. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001052void ebt_check_for_loops(struct ebt_u_replace *replace)
1053{
1054 int chain_nr , i, j , k, sp = 0, verdict;
1055 struct ebt_u_entries *entries, *entries2;
1056 struct ebt_u_stack *stack = NULL;
1057 struct ebt_u_entry *e;
1058
Bart De Schuymer6622a012005-01-19 21:09:05 +00001059 /* Initialize hook_mask to 0 */
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001060 for (i = 0; i < replace->num_chains; i++) {
1061 if (!(entries = replace->chains[i]))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001062 continue;
Bart De Schuymer59763842006-01-23 19:38:49 +00001063 if (i < NF_BR_NUMHOOKS)
1064 /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain
1065 * (usefull in the final_check() funtions) */
1066 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
1067 else
1068 entries->hook_mask = 0;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001069 }
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001070 if (replace->num_chains == NF_BR_NUMHOOKS)
1071 return;
1072 stack = (struct ebt_u_stack *)malloc((replace->num_chains - NF_BR_NUMHOOKS) * sizeof(struct ebt_u_stack));
1073 if (!stack)
1074 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001075
Bart De Schuymer6622a012005-01-19 21:09:05 +00001076 /* Check for loops, starting from every base chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001077 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001078 if (!(entries = replace->chains[i]))
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001079 continue;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001080 chain_nr = i;
1081
Bart De Schuymere94eaf72005-08-28 16:06:22 +00001082 e = entries->entries->next;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001083 for (j = 0; j < entries->nentries; j++) {
1084 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
1085 goto letscontinue;
1086 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
1087 if (verdict < 0)
1088 goto letscontinue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001089 /* Now see if we've been here before */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001090 for (k = 0; k < sp; k++)
Bart De Schuymer6622a012005-01-19 21:09:05 +00001091 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) {
1092 ebt_print_error("Loop from chain '%s' to chain '%s'",
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001093 replace->chains[chain_nr]->name,
1094 replace->chains[stack[k].chain_nr]->name);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001095 goto free_stack;
1096 }
Bart De Schuymer24816d32007-02-11 12:47:58 +00001097 entries2 = replace->chains[verdict + NF_BR_NUMHOOKS];
1098 /* check if we've dealt with this chain already */
1099 if (entries2->hook_mask & (1<<i))
1100 goto letscontinue;
1101 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001102 /* Jump to the chain, make sure we know how to get back */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001103 stack[sp].chain_nr = chain_nr;
1104 stack[sp].n = j;
1105 stack[sp].entries = entries;
1106 stack[sp].e = e;
1107 sp++;
1108 j = -1;
Bart De Schuymer15a1fac2006-07-28 20:15:31 +00001109 e = entries2->entries->next;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001110 chain_nr = verdict + NF_BR_NUMHOOKS;
1111 entries = entries2;
1112 continue;
1113letscontinue:
1114 e = e->next;
1115 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001116 /* We are at the end of a standard chain */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001117 if (sp == 0)
1118 continue;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001119 /* Go back to the chain one level higher */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001120 sp--;
1121 j = stack[sp].n;
1122 chain_nr = stack[sp].chain_nr;
1123 e = stack[sp].e;
1124 entries = stack[sp].entries;
1125 goto letscontinue;
1126 }
Bart De Schuymer6622a012005-01-19 21:09:05 +00001127free_stack:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001128 free(stack);
1129 return;
1130}
1131
Bart De Schuymer6622a012005-01-19 21:09:05 +00001132/* The user will use the match, so put it in new_entry. The ebt_u_match
1133 * pointer is put in the ebt_entry_match pointer. ebt_add_rule will
1134 * fill in the final value for new->m. Unless the rule is added to a chain,
1135 * the pointer will keep pointing to the ebt_u_match (until the new_entry
1136 * is freed). I know, I should use a union for these 2 pointer types... */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001137void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m)
1138{
1139 struct ebt_u_match_list **m_list, *new;
1140
1141 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
1142 new = (struct ebt_u_match_list *)
1143 malloc(sizeof(struct ebt_u_match_list));
1144 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001145 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001146 *m_list = new;
1147 new->next = NULL;
1148 new->m = (struct ebt_entry_match *)m;
1149}
1150
1151void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w)
1152{
1153 struct ebt_u_watcher_list **w_list;
1154 struct ebt_u_watcher_list *new;
1155
1156 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
1157 new = (struct ebt_u_watcher_list *)
1158 malloc(sizeof(struct ebt_u_watcher_list));
1159 if (!new)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001160 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001161 *w_list = new;
1162 new->next = NULL;
1163 new->w = (struct ebt_entry_watcher *)w;
1164}
1165
1166
1167 /*
1168*******************
1169*******************
1170**OTHER*FUNCTIONS**
1171*******************
1172*******************
1173 */
1174
1175
Bart De Schuymer6622a012005-01-19 21:09:05 +00001176/* type = 0 => update chain jumps
1177 * type = 1 => check for reference, print error when referenced
1178 * type = 2 => check for reference, don't print error when referenced
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001179 *
Bart De Schuymer6622a012005-01-19 21:09:05 +00001180 * Returns 1 when type == 1 and the chain is referenced
1181 * returns 0 otherwise */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001182static int iterate_entries(struct ebt_u_replace *replace, int type)
1183{
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001184 int i, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001185 struct ebt_u_entries *entries;
1186 struct ebt_u_entry *e;
1187
1188 if (chain_nr < 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001189 ebt_print_bug("iterate_entries: udc = %d < 0", chain_nr);
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001190 for (i = 0; i < replace->num_chains; i++) {
1191 if (!(entries = replace->chains[i]))
1192 continue;
Bart De Schuymere94eaf72005-08-28 16:06:22 +00001193 e = entries->entries->next;
1194 for (j = 0; j < entries->nentries; j++) {
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001195 int chain_jmp;
1196
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001197 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1198 e = e->next;
1199 continue;
1200 }
Bart De Schuymer64182a32004-01-21 20:39:54 +00001201 chain_jmp = ((struct ebt_standard_target *)e->t)->
1202 verdict;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001203 switch (type) {
1204 case 1:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001205 case 2:
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001206 if (chain_jmp == chain_nr) {
Bart De Schuymer6622a012005-01-19 21:09:05 +00001207 if (type == 2)
1208 return 1;
1209 ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d",
Bart De Schuymer9bfcfd82005-08-27 16:52:19 +00001210 replace->chains[chain_nr + NF_BR_NUMHOOKS]->name, entries->name, j);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001211 return 1;
1212 }
1213 break;
1214 case 0:
Bart De Schuymer6622a012005-01-19 21:09:05 +00001215 /* Adjust the chain jumps when necessary */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001216 if (chain_jmp > chain_nr)
1217 ((struct ebt_standard_target *)e->t)->verdict--;
1218 break;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001219 } /* End switch */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001220 e = e->next;
1221 }
1222 }
1223 return 0;
1224}
1225
1226static void decrease_chain_jumps(struct ebt_u_replace *replace)
1227{
1228 iterate_entries(replace, 0);
1229}
1230
Bart De Schuymer6622a012005-01-19 21:09:05 +00001231/* Used in initialization code of modules */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001232void ebt_register_match(struct ebt_u_match *m)
1233{
1234 int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
1235 struct ebt_u_match **i;
1236
1237 m->m = (struct ebt_entry_match *)malloc(size);
1238 if (!m->m)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001239 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001240 strcpy(m->m->u.name, m->name);
1241 m->m->match_size = EBT_ALIGN(m->size);
1242 m->init(m->m);
1243
1244 for (i = &ebt_matches; *i; i = &((*i)->next));
1245 m->next = NULL;
1246 *i = m;
1247}
1248
1249void ebt_register_watcher(struct ebt_u_watcher *w)
1250{
1251 int size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
1252 struct ebt_u_watcher **i;
1253
1254 w->w = (struct ebt_entry_watcher *)malloc(size);
1255 if (!w->w)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001256 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001257 strcpy(w->w->u.name, w->name);
1258 w->w->watcher_size = EBT_ALIGN(w->size);
1259 w->init(w->w);
1260
1261 for (i = &ebt_watchers; *i; i = &((*i)->next));
1262 w->next = NULL;
1263 *i = w;
1264}
1265
1266void ebt_register_target(struct ebt_u_target *t)
1267{
1268 int size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
1269 struct ebt_u_target **i;
1270
1271 t->t = (struct ebt_entry_target *)malloc(size);
1272 if (!t->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001273 ebt_print_memory();
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001274 strcpy(t->t->u.name, t->name);
1275 t->t->target_size = EBT_ALIGN(t->size);
1276 t->init(t->t);
1277
1278 for (i = &ebt_targets; *i; i = &((*i)->next));
1279 t->next = NULL;
1280 *i = t;
1281}
1282
1283void ebt_register_table(struct ebt_u_table *t)
1284{
1285 t->next = ebt_tables;
1286 ebt_tables = t;
1287}
1288
1289void ebt_iterate_matches(void (*f)(struct ebt_u_match *))
1290{
1291 struct ebt_u_match *i;
1292
1293 for (i = ebt_matches; i; i = i->next)
1294 f(i);
1295}
1296
1297void ebt_iterate_watchers(void (*f)(struct ebt_u_watcher *))
1298{
1299 struct ebt_u_watcher *i;
1300
1301 for (i = ebt_watchers; i; i = i->next)
1302 f(i);
1303}
1304
1305void ebt_iterate_targets(void (*f)(struct ebt_u_target *))
1306{
1307 struct ebt_u_target *i;
1308
1309 for (i = ebt_targets; i; i = i->next)
1310 f(i);
1311}
1312
Bart De Schuymer6622a012005-01-19 21:09:05 +00001313/* Don't use this function, use ebt_print_bug() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001314void __ebt_print_bug(char *file, int line, char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001315{
1316 va_list l;
1317
1318 va_start(l, format);
Bart De Schuymerd9a49df2005-11-09 21:20:39 +00001319 fprintf(stderr, PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
1320 vfprintf(stderr, format, l);
1321 fprintf(stderr, "\n");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001322 va_end(l);
1323 exit (-1);
1324}
1325
Bart De Schuymer6622a012005-01-19 21:09:05 +00001326/* The error messages are put in here when ebt_silent == 1
1327 * ebt_errormsg[0] == '\0' implies there was no error */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001328char ebt_errormsg[ERRORMSG_MAXLEN];
Bart De Schuymer6622a012005-01-19 21:09:05 +00001329/* When error messages should not be printed on the screen, after which
1330 * the program exit()s, set ebt_silent to 1. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001331int ebt_silent;
Bart De Schuymer6622a012005-01-19 21:09:05 +00001332/* Don't use this function, use ebt_print_error() */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001333void __ebt_print_error(char *format, ...)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001334{
1335 va_list l;
1336
1337 va_start(l, format);
Bart De Schuymer6622a012005-01-19 21:09:05 +00001338 if (ebt_silent && ebt_errormsg[0] == '\0') {
1339 vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001340 va_end(l);
1341 } else {
Bart De Schuymer83a1b0f2005-09-28 19:36:17 +00001342 vfprintf(stderr, format, l);
1343 fprintf(stderr, ".\n");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001344 va_end(l);
1345 exit (-1);
1346 }
1347}