blob: e01ef9ff2352c7ab5f5ec3129bf2031ef36cc128 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002 * ebtables.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000026#include <stdio.h>
27#include <stdlib.h>
Bart De Schuymerd4586482002-08-11 16:15:55 +000028#include <stdarg.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000029#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030#include "include/ebtables_u.h"
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000031#include "include/ethernetdb.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000032#include <unistd.h>
33#include <fcntl.h>
34#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000036/*
37 * Don't use this function, use print_bug()
38 */
Bart De Schuymerd4586482002-08-11 16:15:55 +000039void __print_bug(char *file, int line, char *format, ...)
40{
41 va_list l;
42
43 va_start(l, format);
44 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
45 vprintf(format, l);
46 printf("\n");
47 va_end(l);
48 exit (-1);
49}
50
Bart De Schuymerc8531032002-06-14 21:55:29 +000051#ifndef PROC_SYS_MODPROBE
52#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
53#endif
Bart De Schuymer5885b362002-12-03 20:51:36 +000054#define ATOMIC_ENV_VARIABLE "EBTABLES_ATOMIC_FILE"
Bart De Schuymerc8531032002-06-14 21:55:29 +000055
Bart De Schuymer60332e02002-06-23 08:01:47 +000056char *hooknames[NF_BR_NUMHOOKS] =
57{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000058 [NF_BR_PRE_ROUTING]"PREROUTING",
59 [NF_BR_LOCAL_IN]"INPUT",
60 [NF_BR_FORWARD]"FORWARD",
61 [NF_BR_LOCAL_OUT]"OUTPUT",
62 [NF_BR_POST_ROUTING]"POSTROUTING",
63 [NF_BR_BROUTING]"BROUTING"
64};
65
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000066/*
67 * default command line options
68 * do not mess around with the already assigned numbers unless
69 * you know what you are doing
70 */
Bart De Schuymer62423742002-07-14 19:06:20 +000071static struct option ebt_original_options[] =
72{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000073 { "append" , required_argument, 0, 'A' },
74 { "insert" , required_argument, 0, 'I' },
75 { "delete" , required_argument, 0, 'D' },
76 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000077 { "Lc" , no_argument , 0, 4 },
78 { "Ln" , no_argument , 0, 5 },
79 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080 { "zero" , optional_argument, 0, 'Z' },
81 { "flush" , optional_argument, 0, 'F' },
82 { "policy" , required_argument, 0, 'P' },
83 { "in-interface" , required_argument, 0, 'i' },
84 { "in-if" , required_argument, 0, 'i' },
85 { "logical-in" , required_argument, 0, 2 },
86 { "logical-out" , required_argument, 0, 3 },
87 { "out-interface" , required_argument, 0, 'o' },
88 { "out-if" , required_argument, 0, 'o' },
89 { "version" , no_argument , 0, 'V' },
90 { "help" , no_argument , 0, 'h' },
91 { "jump" , required_argument, 0, 'j' },
92 { "proto" , required_argument, 0, 'p' },
93 { "protocol" , required_argument, 0, 'p' },
94 { "db" , required_argument, 0, 'b' },
95 { "source" , required_argument, 0, 's' },
96 { "src" , required_argument, 0, 's' },
97 { "destination" , required_argument, 0, 'd' },
98 { "dst" , required_argument, 0, 'd' },
99 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000100 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000101 { "new-chain" , required_argument, 0, 'N' },
102 { "rename-chain" , required_argument, 0, 'E' },
103 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer5885b362002-12-03 20:51:36 +0000104 { "atomic-init" , no_argument , 0, 7 },
105 { "atomic-commit" , no_argument , 0, 8 },
106 { "atomic-file" , required_argument, 0, 9 },
107 { "atomic-save" , no_argument , 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000108 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109 { 0 }
110};
111
112static struct option *ebt_options = ebt_original_options;
113
Bart De Schuymer62423742002-07-14 19:06:20 +0000114char* standard_targets[NUM_STANDARD_TARGETS] =
115{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000116 "ACCEPT",
117 "DROP",
118 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000119 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000120};
121
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000122unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
123unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000124unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
125unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
126unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
127unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
128
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000129/*
130 * holds all the data
131 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000132static struct ebt_u_replace replace;
133
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000134/*
135 * the chosen table
136 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000138/*
139 * the lists of supported tables, matches, watchers and targets
140 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000141static struct ebt_u_table *tables = NULL;
142static struct ebt_u_match *matches = NULL;
143static struct ebt_u_watcher *watchers = NULL;
144static struct ebt_u_target *targets = NULL;
145
146struct ebt_u_target *find_target(const char *name)
147{
148 struct ebt_u_target *t = targets;
149
150 while(t && strcmp(t->name, name))
151 t = t->next;
152 return t;
153}
154
155struct ebt_u_match *find_match(const char *name)
156{
157 struct ebt_u_match *m = matches;
158
159 while(m && strcmp(m->name, name))
160 m = m->next;
161 return m;
162}
163
164struct ebt_u_watcher *find_watcher(const char *name)
165{
166 struct ebt_u_watcher *w = watchers;
167
168 while(w && strcmp(w->name, name))
169 w = w->next;
170 return w;
171}
172
173struct ebt_u_table *find_table(char *name)
174{
175 struct ebt_u_table *t = tables;
176
177 while (t && strcmp(t->name, name))
178 t = t->next;
179 return t;
180}
181
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000182/*
183 * The pointers in here are special:
184 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
185 * instead of making yet a few other structs, we just do a cast.
186 * We need a struct ebt_u_target pointer because we know the address of the data
187 * they point to won't change. We want to allow that the struct ebt_u_target.t
188 * member can change.
189 * Same holds for the struct ebt_match and struct ebt_watcher pointers
190 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000191struct ebt_u_entry *new_entry;
192
Bart De Schuymer62423742002-07-14 19:06:20 +0000193static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000194{
195 e->bitmask = EBT_NOPROTO;
196 e->invflags = 0;
197 e->ethproto = 0;
198 strcpy(e->in, "");
199 strcpy(e->out, "");
200 strcpy(e->logical_in, "");
201 strcpy(e->logical_out, "");
202 e->m_list = NULL;
203 e->w_list = NULL;
Bart De Schuymerc27432e2003-01-09 22:01:07 +0000204 /*
205 * the init function of the standard target should have put the verdict
206 * on CONTINUE
207 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000208 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
209 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000210 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000211}
212
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000213/*
214 * this doesn't free e, becoz the calling function might need e->next
215 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000216static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000217{
218 struct ebt_u_match_list *m_l, *m_l2;
219 struct ebt_u_watcher_list *w_l, *w_l2;
220
221 m_l = e->m_list;
222 while (m_l) {
223 m_l2 = m_l->next;
224 free(m_l->m);
225 free(m_l);
226 m_l = m_l2;
227 }
228 w_l = e->w_list;
229 while (w_l) {
230 w_l2 = w_l->next;
231 free(w_l->w);
232 free(w_l);
233 w_l = w_l2;
234 }
235 free(e->t);
236}
237
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000238/*
239 * the user will use the match, so put it in new_entry
240 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000241static void add_match(struct ebt_u_match *m)
242{
243 struct ebt_u_match_list **m_list, *new;
244
245 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000246 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000247 new = (struct ebt_u_match_list *)
248 malloc(sizeof(struct ebt_u_match_list));
249 if (!new)
250 print_memory();
251 *m_list = new;
252 new->next = NULL;
253 new->m = (struct ebt_entry_match *)m;
254}
255
256static void add_watcher(struct ebt_u_watcher *w)
257{
258 struct ebt_u_watcher_list **w_list;
259 struct ebt_u_watcher_list *new;
260
261 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000262 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000263 new = (struct ebt_u_watcher_list *)
264 malloc(sizeof(struct ebt_u_watcher_list));
265 if (!new)
266 print_memory();
267 *w_list = new;
268 new->next = NULL;
269 new->w = (struct ebt_entry_watcher *)w;
270}
271
272static int global_option_offset = 0;
273#define OPTION_OFFSET 256
274static struct option *
275merge_options(struct option *oldopts, const struct option *newopts,
276 unsigned int *options_offset)
277{
278 unsigned int num_old, num_new, i;
279 struct option *merge;
280
281 if (!newopts || !oldopts || !options_offset)
282 print_bug("merge wrong");
283 for (num_old = 0; oldopts[num_old].name; num_old++);
284 for (num_new = 0; newopts[num_new].name; num_new++);
285
286 global_option_offset += OPTION_OFFSET;
287 *options_offset = global_option_offset;
288
289 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
290 if (!merge)
291 print_memory();
292 memcpy(merge, oldopts, num_old * sizeof(struct option));
293 for (i = 0; i < num_new; i++) {
294 merge[num_old + i] = newopts[i];
295 merge[num_old + i].val += *options_offset;
296 }
297 memset(merge + num_old + num_new, 0, sizeof(struct option));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000298 /* only free dynamically allocated stuff */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000299 if (oldopts != ebt_original_options)
300 free(oldopts);
301
302 return merge;
303}
304
305void register_match(struct ebt_u_match *m)
306{
307 int size = m->size + sizeof(struct ebt_entry_match);
308 struct ebt_u_match **i;
309
310 m->m = (struct ebt_entry_match *)malloc(size);
311 if (!m->m)
312 print_memory();
313 strcpy(m->m->u.name, m->name);
314 m->m->match_size = m->size;
315 ebt_options = merge_options
316 (ebt_options, m->extra_ops, &(m->option_offset));
317 m->init(m->m);
318
319 for (i = &matches; *i; i = &((*i)->next));
320 m->next = NULL;
321 *i = m;
322}
323
324void register_watcher(struct ebt_u_watcher *w)
325{
326 int size = w->size + sizeof(struct ebt_entry_watcher);
327 struct ebt_u_watcher **i;
328
329 w->w = (struct ebt_entry_watcher *)malloc(size);
330 if (!w->w)
331 print_memory();
332 strcpy(w->w->u.name, w->name);
333 w->w->watcher_size = w->size;
334 ebt_options = merge_options
335 (ebt_options, w->extra_ops, &(w->option_offset));
336 w->init(w->w);
337
338 for (i = &watchers; *i; i = &((*i)->next));
339 w->next = NULL;
340 *i = w;
341}
342
343void register_target(struct ebt_u_target *t)
344{
345 int size = t->size + sizeof(struct ebt_entry_target);
346 struct ebt_u_target **i;
347
348 t->t = (struct ebt_entry_target *)malloc(size);
349 if (!t->t)
350 print_memory();
351 strcpy(t->t->u.name, t->name);
352 t->t->target_size = t->size;
353 ebt_options = merge_options
354 (ebt_options, t->extra_ops, &(t->option_offset));
355 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000356
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000357 for (i = &targets; *i; i = &((*i)->next));
358 t->next = NULL;
359 *i = t;
360}
361
362void register_table(struct ebt_u_table *t)
363{
364 t->next = tables;
365 tables = t;
366}
367
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000368/*
369 * blatently stolen (again) from iptables.c userspace program
370 * find out where the modprobe utility is located
371 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000372static char *get_modprobe(void)
373{
374 int procfile;
375 char *ret;
376
377 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
378 if (procfile < 0)
379 return NULL;
380
381 ret = malloc(1024);
382 if (ret) {
383 switch (read(procfile, ret, 1024)) {
384 case -1: goto fail;
385 case 1024: goto fail; /* Partial read. Wierd */
386 }
387 if (ret[strlen(ret)-1]=='\n')
388 ret[strlen(ret)-1]=0;
389 close(procfile);
390 return ret;
391 }
392 fail:
393 free(ret);
394 close(procfile);
395 return NULL;
396}
397
Bart De Schuymerc8531032002-06-14 21:55:29 +0000398int ebtables_insmod(const char *modname, const char *modprobe)
399{
400 char *buf = NULL;
401 char *argv[3];
402
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000403 /* If they don't explicitly set it, read out of kernel */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000404 if (!modprobe) {
405 buf = get_modprobe();
406 if (!buf)
407 return -1;
408 modprobe = buf;
409 }
410
411 switch (fork()) {
412 case 0:
413 argv[0] = (char *)modprobe;
414 argv[1] = (char *)modname;
415 argv[2] = NULL;
416 execv(argv[0], argv);
417
418 /* not usually reached */
419 exit(0);
420 case -1:
421 return -1;
422
423 default: /* parent */
424 wait(NULL);
425 }
426
427 free(buf);
428 return 0;
429}
430
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000431static void list_extensions()
432{
433 struct ebt_u_table *tbl = tables;
434 struct ebt_u_target *t = targets;
435 struct ebt_u_match *m = matches;
436 struct ebt_u_watcher *w = watchers;
437
438 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
439 printf("Supported userspace extensions:\n\nSupported tables:\n");
440 while(tbl) {
441 printf("%s\n", tbl->name);
442 tbl = tbl->next;
443 }
444 printf("\nSupported targets:\n");
445 while(t) {
446 printf("%s\n", t->name);
447 t = t->next;
448 }
449 printf("\nSupported matches:\n");
450 while(m) {
451 printf("%s\n", m->name);
452 m = m->next;
453 }
454 printf("\nSupported watchers:\n");
455 while(w) {
456 printf("%s\n", w->name);
457 w = w->next;
458 }
459 exit(0);
460}
461
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000462/*
463 * we use replace.flags, so we can't use the following values:
464 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
465 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000466#define LIST_N 0x04
467#define LIST_C 0x08
468#define LIST_X 0x10
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000469/*
470 * helper function for list_rules()
471 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000472static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000473{
474 int i, j, space = 0, digits;
475 struct ebt_u_entry *hlp;
476 struct ebt_u_match_list *m_l;
477 struct ebt_u_watcher_list *w_l;
478 struct ebt_u_match *m;
479 struct ebt_u_watcher *w;
480 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000481
Bart De Schuymer60332e02002-06-23 08:01:47 +0000482 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000483 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
484 printf("ebtables -t %s -P %s %s\n", replace.name,
485 entries->name, standard_targets[-entries->policy - 1]);
486 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000487 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
488 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000489 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000490 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491
Bart De Schuymer60332e02002-06-23 08:01:47 +0000492 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000493 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000494 space++;
495 i /= 10;
496 }
497
Bart De Schuymer60332e02002-06-23 08:01:47 +0000498 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000499 if (replace.flags & LIST_N) {
500 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000501 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000502 j = i + 1;
503 while (j > 9) {
504 digits++;
505 j /= 10;
506 }
507 for (j = 0; j < space - digits; j++)
508 printf(" ");
509 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000511 if (replace.flags & LIST_X)
512 printf("ebtables -t %s -A %s ",
513 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000514
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000515 /*
516 * Don't print anything about the protocol if no protocol was
517 * specified, obviously this means any protocol will do.
518 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000520 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000521 if (hlp->invflags & EBT_IPROTO)
522 printf("! ");
523 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000524 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000525 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000526 struct ethertypeent *ent;
527
528 ent = getethertypebynumber(ntohs(hlp->ethproto));
529 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000530 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000531 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000532 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000533 }
534 }
535 if (hlp->bitmask & EBT_SOURCEMAC) {
536 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
537
Bart De Schuymer60332e02002-06-23 08:01:47 +0000538 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000539 if (hlp->invflags & EBT_ISOURCE)
540 printf("! ");
541 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
542 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
543 printf("Unicast");
544 goto endsrc;
545 }
546 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
547 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
548 printf("Multicast");
549 goto endsrc;
550 }
551 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
552 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
553 printf("Broadcast");
554 goto endsrc;
555 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000556 printf("%s", ether_ntoa((struct ether_addr *)
557 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
559 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000560 printf("%s", ether_ntoa((struct ether_addr *)
561 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000562 }
563endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 }
566 if (hlp->bitmask & EBT_DESTMAC) {
567 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
568
Bart De Schuymer60332e02002-06-23 08:01:47 +0000569 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000570 if (hlp->invflags & EBT_IDEST)
571 printf("! ");
572 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
573 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
574 printf("Unicast");
575 goto enddst;
576 }
577 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
578 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
579 printf("Multicast");
580 goto enddst;
581 }
582 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
583 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
584 printf("Broadcast");
585 goto enddst;
586 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000587 printf("%s", ether_ntoa((struct ether_addr *)
588 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
590 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000591 printf("%s", ether_ntoa((struct ether_addr *)
592 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000593 }
594enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000595 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000596 }
597 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000598 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000599 if (hlp->invflags & EBT_IIN)
600 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000601 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000602 }
603 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000604 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000605 if (hlp->invflags & EBT_ILOGICALIN)
606 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000607 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 }
609 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000610 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 if (hlp->invflags & EBT_ILOGICALOUT)
612 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000613 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 }
615 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000616 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000617 if (hlp->invflags & EBT_IOUT)
618 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000619 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000620 }
621
622 m_l = hlp->m_list;
623 while (m_l) {
624 m = find_match(m_l->m->u.name);
625 if (!m)
626 print_bug("Match not found");
627 m->print(hlp, m_l->m);
628 m_l = m_l->next;
629 }
630 w_l = hlp->w_list;
631 while (w_l) {
632 w = find_watcher(w_l->w->u.name);
633 if (!w)
634 print_bug("Watcher not found");
635 w->print(hlp, w_l->w);
636 w_l = w_l->next;
637 }
638
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000639 printf("-j ");
640 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
641 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000642 t = find_target(hlp->t->u.name);
643 if (!t)
644 print_bug("Target not found");
645 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000646 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000647 printf(", pcnt = %llu -- bcnt = %llu",
648 replace.counters[entries->counter_offset + i].pcnt,
649 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000650 printf("\n");
651 hlp = hlp->next;
652 }
653}
654
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000655struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000656{
657 if (nr == -1)
658 return NULL;
659 if (nr < NF_BR_NUMHOOKS)
660 return replace.hook_entry[nr];
661 else {
662 int i;
663 struct ebt_u_chain_list *cl = replace.udc;
664
665 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000666 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000667 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000668 i--;
669 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000670 if (cl)
671 return cl->udc;
672 else
673 return NULL;
674 }
675}
676
Bart De Schuymercc440052002-11-06 21:10:33 +0000677static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000678{
679 return nr_to_chain(replace.selected_hook);
680}
681
682struct ebt_u_stack
683{
684 int chain_nr;
685 int n;
686 struct ebt_u_entry *e;
687 struct ebt_u_entries *entries;
688};
689
Bart De Schuymer62423742002-07-14 19:06:20 +0000690static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000691{
692 int chain_nr , i, j , k, sp = 0, verdict;
693 struct ebt_u_entries *entries, *entries2;
694 struct ebt_u_stack *stack = NULL;
695 struct ebt_u_entry *e;
696
697 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000698 /*
699 * initialize hook_mask to 0
700 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000701 while (1) {
702 i++;
703 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
704 continue;
705 entries = nr_to_chain(i);
706 if (!entries)
707 break;
708 entries->hook_mask = 0;
709 }
710 if (i > NF_BR_NUMHOOKS) {
711 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
712 sizeof(struct ebt_u_stack));
713 if (!stack)
714 print_memory();
715 }
716
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000717 /*
718 * check for loops, starting from every base chain
719 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000720 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
721 if (!(replace.valid_hooks & (1 << i)))
722 continue;
723 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000724 /*
725 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
726 * (usefull in the final_check() funtions)
727 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000728 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000729 chain_nr = i;
730
731 e = entries->entries;
732 for (j = 0; j < entries->nentries; j++) {
733 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
734 goto letscontinue;
735 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
736 if (verdict < 0)
737 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000738 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000739 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000740 /*
741 * now see if we've been here before
742 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000743 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000744 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000745 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000746 nr_to_chain(chain_nr)->name,
747 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000748 /*
749 * jump to the chain, make sure we know how to get back
750 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000751 stack[sp].chain_nr = chain_nr;
752 stack[sp].n = j;
753 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000754 stack[sp].e = e;
755 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000756 j = -1;
757 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000758 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000759 entries = entries2;
760 continue;
761letscontinue:
762 e = e->next;
763 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000764 /*
765 * we are at the end of a standard chain
766 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000767 if (sp == 0)
768 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000769 /*
770 * go back to the chain one level higher
771 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000772 sp--;
773 j = stack[sp].n;
774 chain_nr = stack[sp].chain_nr;
775 e = stack[sp].e;
776 entries = stack[sp].entries;
777 goto letscontinue;
778 }
779 free(stack);
780 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000781}
782
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000783/*
784 * parse the chain name and return the corresponding nr
785 * returns -1 on failure
786 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000787int get_hooknr(char* arg)
788{
789 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000790 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000791
Bart De Schuymer60332e02002-06-23 08:01:47 +0000792 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
793 if (!(replace.valid_hooks & (1 << i)))
794 continue;
795 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000796 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000797 }
798 while(cl) {
799 if (!strcmp(arg, cl->udc->name))
800 return i;
801 i++;
802 cl = cl->next;
803 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000804 return -1;
805}
806
Bart De Schuymer62423742002-07-14 19:06:20 +0000807static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000808{
809 struct ebt_u_match_list *m_l;
810 struct ebt_u_watcher_list *w_l;
811
Bart De Schuymerd4586482002-08-11 16:15:55 +0000812 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000813"Usage:\n"
814"ebtables -[ADI] chain rule-specification [options]\n"
815"ebtables -P chain target\n"
816"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000817"ebtables -[NX] [chain]\n"
818"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000819"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000820"--append -A chain : append to chain\n"
821"--delete -D chain : delete matching rule from chain\n"
822"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000823"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000824"--list -L [chain] : list the rules in a chain or in all chains\n"
825"--flush -F [chain] : delete all rules in chain or in all chains\n"
826"--init-table : replace the kernel table with the initial table\n"
827"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
828"--policy -P chain target : change policy on chain to target\n"
829"--new-chain -N chain : create a user defined chain\n"
830"--rename-chain -E old new : rename a chain\n"
831"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000832"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
833"--atomic-init : put the initial kernel table into <FILE>\n"
834"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000835"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000836"Options:\n"
837"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
838"--src -s [!] address[/mask]: source mac address\n"
839"--dst -d [!] address[/mask]: destination mac address\n"
840"--in-if -i [!] name : network input interface name\n"
841"--out-if -o [!] name : network output interface name\n"
842"--logical-in [!] name : logical bridge input interface name\n"
843"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000844"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000845"--version -V : print package version\n\n"
846"Environment variable:\n"
847ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
848"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000849
850 m_l = new_entry->m_list;
851 while (m_l) {
852 ((struct ebt_u_match *)m_l->m)->help();
853 printf("\n");
854 m_l = m_l->next;
855 }
856 w_l = new_entry->w_list;
857 while (w_l) {
858 ((struct ebt_u_watcher *)w_l->w)->help();
859 printf("\n");
860 w_l = w_l->next;
861 }
862 ((struct ebt_u_target *)new_entry->t)->help();
863 printf("\n");
864 if (table->help)
865 table->help(hooknames);
866 exit(0);
867}
868
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000869/*
870 * execute command L
871 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000872static void list_rules()
873{
874 int i;
875
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000876 if (!(replace.flags & LIST_X))
877 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000878 if (replace.selected_hook != -1) {
879 list_em(to_chain());
880 } else {
881 struct ebt_u_chain_list *cl = replace.udc;
882
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000883 /*
884 * create new chains and rename standard chains when necessary
885 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000886 if (replace.flags & LIST_X) {
887 while (cl) {
888 printf("ebtables -t %s -N %s\n", replace.name,
889 cl->udc->name);
890 cl = cl->next;
891 }
892 cl = replace.udc;
893 for (i = 0; i < NF_BR_NUMHOOKS; i++)
894 if (replace.valid_hooks & (1 << i) &&
895 strcmp(replace.hook_entry[i]->name, hooknames[i]))
896 printf("ebtables -t %s -E %s %s\n",
897 replace.name, hooknames[i],
898 replace.hook_entry[i]->name);
899 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000900 i = 0;
901 while (1) {
902 if (i < NF_BR_NUMHOOKS) {
903 if (replace.valid_hooks & (1 << i))
904 list_em(replace.hook_entry[i]);
905 i++;
906 continue;
907 } else {
908 if (!cl)
909 break;
910 list_em(cl->udc);
911 cl = cl->next;
912 }
913 }
914 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000915}
916
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000917/*
918 * execute command P
919 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000920static void change_policy(int policy)
921{
922 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000923 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000924
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000925 /*
926 * don't do anything if the policy is the same
927 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000928 if (entries->policy != policy) {
929 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000930 replace.num_counters = replace.nentries;
931 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000932 /*
933 * '+ 1' for the CNT_END
934 */
Bart De Schuymered053432002-07-21 19:35:39 +0000935 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000936 (replace.nentries + 1) * sizeof(unsigned short))))
937 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000938 /*
939 * done nothing special to the rules
940 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000941 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000942 replace.counterchanges[i] = CNT_NORM;
943 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000944 }
945 else
Bart De Schuymered053432002-07-21 19:35:39 +0000946 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000947 }
948 else
949 exit(0);
950}
951
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000952/*
953 * flush one chain or the complete table
954 * -1 == nothing to do
955 * 0 == give back to kernel
956 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000957static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000958{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000959 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960 unsigned short *cnt;
961 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000962 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000963
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000964 /*
965 * flush whole table
966 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000967 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000969 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000970 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000971 /*
972 * no need for the kernel to give us counters back
973 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000974 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000976 /*
977 * free everything and zero (n)entries
978 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000979 i = -1;
980 while (1) {
981 i++;
982 entries = nr_to_chain(i);
983 if (!entries) {
984 if (i < NF_BR_NUMHOOKS)
985 continue;
986 else
987 break;
988 }
989 entries->nentries = 0;
990 entries->counter_offset = 0;
991 u_e = entries->entries;
992 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000993 while (u_e) {
994 free_u_entry(u_e);
995 tmp = u_e->next;
996 free(u_e);
997 u_e = tmp;
998 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000999 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001000 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001001 }
1002
Bart De Schuymer60332e02002-06-23 08:01:47 +00001003 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001004 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001005 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001006 replace.nentries -= entries->nentries;
1007 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001008
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001009 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001010 /*
1011 * +1 for CNT_END
1012 */
Bart De Schuymered053432002-07-21 19:35:39 +00001013 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001014 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1015 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001016 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001017 /*
1018 * delete the counters belonging to the specified chain,
1019 * update counter_offset
1020 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001021 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001022 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001023 while (1) {
1024 i++;
1025 entries = nr_to_chain(i);
1026 if (!entries) {
1027 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001028 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 else
1030 break;
1031 }
1032 if (i > replace.selected_hook)
1033 entries->counter_offset -= numdel;
1034 if (replace.nentries) {
1035 for (j = 0; j < entries->nentries; j++) {
1036 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001037 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001038 else
1039 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 cnt++;
1041 }
1042 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001043 }
1044
1045 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001046 *cnt = CNT_END;
1047 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001048 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001049 replace.num_counters = 0;
1050
Bart De Schuymer60332e02002-06-23 08:01:47 +00001051 entries = to_chain();
1052 entries->nentries = 0;
1053 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001054 while (u_e) {
1055 free_u_entry(u_e);
1056 tmp = u_e->next;
1057 free(u_e);
1058 u_e = tmp;
1059 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001060 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001061 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001062}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001063
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001064/*
1065 * -1 == no match
1066 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001067static int check_rule_exists(int rule_nr)
1068{
1069 struct ebt_u_entry *u_e;
1070 struct ebt_u_match_list *m_l, *m_l2;
1071 struct ebt_u_match *m;
1072 struct ebt_u_watcher_list *w_l, *w_l2;
1073 struct ebt_u_watcher *w;
1074 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001075 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001076 int i, j, k;
1077
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001078 /*
1079 * handle '-D chain rulenr' command
1080 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001081 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001082 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001083 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001084 /*
1085 * user starts counting from 1
1086 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001087 return rule_nr - 1;
1088 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001089 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001090 /*
1091 * check for an existing rule (if there are duplicate rules,
1092 * take the first occurance)
1093 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001094 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001095 if (!u_e)
1096 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001097 if (u_e->ethproto != new_entry->ethproto)
1098 continue;
1099 if (strcmp(u_e->in, new_entry->in))
1100 continue;
1101 if (strcmp(u_e->out, new_entry->out))
1102 continue;
1103 if (strcmp(u_e->logical_in, new_entry->logical_in))
1104 continue;
1105 if (strcmp(u_e->logical_out, new_entry->logical_out))
1106 continue;
1107 if (new_entry->bitmask & EBT_SOURCEMAC &&
1108 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1109 continue;
1110 if (new_entry->bitmask & EBT_DESTMAC &&
1111 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1112 continue;
1113 if (new_entry->bitmask != u_e->bitmask ||
1114 new_entry->invflags != u_e->invflags)
1115 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001116 /*
1117 * compare all matches
1118 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001119 m_l = new_entry->m_list;
1120 j = 0;
1121 while (m_l) {
1122 m = (struct ebt_u_match *)(m_l->m);
1123 m_l2 = u_e->m_list;
1124 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1125 m_l2 = m_l2->next;
1126 if (!m_l2 || !m->compare(m->m, m_l2->m))
1127 goto letscontinue;
1128 j++;
1129 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001130 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001131 /*
1132 * now be sure they have the same nr of matches
1133 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001134 k = 0;
1135 m_l = u_e->m_list;
1136 while (m_l) {
1137 k++;
1138 m_l = m_l->next;
1139 }
1140 if (j != k)
1141 continue;
1142
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001143 /*
1144 * compare all watchers
1145 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001146 w_l = new_entry->w_list;
1147 j = 0;
1148 while (w_l) {
1149 w = (struct ebt_u_watcher *)(w_l->w);
1150 w_l2 = u_e->w_list;
1151 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1152 w_l2 = w_l2->next;
1153 if (!w_l2 || !w->compare(w->w, w_l2->w))
1154 goto letscontinue;
1155 j++;
1156 w_l = w_l->next;
1157 }
1158 k = 0;
1159 w_l = u_e->w_list;
1160 while (w_l) {
1161 k++;
1162 w_l = w_l->next;
1163 }
1164 if (j != k)
1165 continue;
1166 if (strcmp(t->t->u.name, u_e->t->u.name))
1167 continue;
1168 if (!t->compare(t->t, u_e->t))
1169 continue;
1170 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001171letscontinue:
1172 }
1173 return -1;
1174}
1175
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001176/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001177static void add_rule(int rule_nr)
1178{
1179 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001180 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001181 unsigned short *cnt;
1182 struct ebt_u_match_list *m_l;
1183 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001184 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001185
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001186 if (rule_nr != -1) { /* command -I */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001187 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001188 print_error("rule nr too high: %d > %d", rule_nr + 1,
1189 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001190 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001191 rule_nr = entries->nentries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001192 /*
1193 * we're adding one rule
1194 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001195 replace.num_counters = replace.nentries;
1196 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001197 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001198
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001199 /*
1200 * handle counter stuff
1201 * +1 for CNT_END
1202 */
Bart De Schuymered053432002-07-21 19:35:39 +00001203 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001204 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1205 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001206 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001207 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001208 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001209 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001210 entries2 = nr_to_chain(i);
1211 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001212 *cnt = CNT_NORM;
1213 cnt++;
1214 }
1215 }
1216 for (i = 0; i < rule_nr; i++) {
1217 *cnt = CNT_NORM;
1218 cnt++;
1219 }
1220 *cnt = CNT_ADD;
1221 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001222 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001223 *cnt = CNT_NORM;
1224 cnt++;
1225 }
1226 *cnt = CNT_END;
1227
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001228 /*
1229 * go to the right position in the chain
1230 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001231 u_e = &entries->entries;
1232 for (i = 0; i < rule_nr; i++)
1233 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001234 /*
1235 * insert the rule
1236 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001237 new_entry->next = *u_e;
1238 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001239
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001240 /*
1241 * put the ebt_[match, watcher, target] pointers in place
1242 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001243 m_l = new_entry->m_list;
1244 while (m_l) {
1245 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1246 m_l = m_l->next;
1247 }
1248 w_l = new_entry->w_list;
1249 while (w_l) {
1250 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1251 w_l = w_l->next;
1252 }
1253 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001254
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001255 /*
1256 * update the counter_offset of chains behind this one
1257 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001258 i = replace.selected_hook;
1259 while (1) {
1260 i++;
1261 entries = nr_to_chain(i);
1262 if (!entries) {
1263 if (i < NF_BR_NUMHOOKS)
1264 continue;
1265 else
1266 break;
1267 } else
1268 entries->counter_offset++;
1269 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001270}
1271
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001272/*
1273 * execute command D
1274 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001275static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001276{
Bart De Schuymercc440052002-11-06 21:10:33 +00001277 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001278 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001279 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001280 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001281
Bart De Schuymercc440052002-11-06 21:10:33 +00001282 if ((begin = check_rule_exists(begin)) == -1 ||
1283 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001284 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001285
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001286 /*
1287 * we're deleting rules
1288 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001289 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001290 nr_deletes = end - begin + 1;
1291 replace.nentries -= nr_deletes;
1292 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001293
1294 if (replace.nentries) {
1295 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001296 if (j < NF_BR_NUMHOOKS &&
1297 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001298 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001299 entries2 = nr_to_chain(j);
1300 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001301 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001302 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001303 /*
1304 * +1 for CNT_END
1305 */
Bart De Schuymered053432002-07-21 19:35:39 +00001306 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001307 (replace.num_counters + 1) * sizeof(unsigned short))) )
1308 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001309 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001310 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001311 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001312 for (j = 0; j < nr_deletes; j++, cnt++)
1313 *cnt = CNT_DEL;
1314
1315 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1316 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001317 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001318
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001319 *cnt = CNT_END;
1320 }
1321 else
1322 replace.num_counters = 0;
1323
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001324 /*
1325 * go to the right position in the chain
1326 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001327 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001328 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001329 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001330 /*
1331 * remove the rules
1332 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001333 j = nr_deletes;
1334 while(j--) {
1335 u_e2 = *u_e;
1336 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001337 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001338 free_u_entry(u_e2);
1339 free(u_e2);
1340 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001341
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001342 /*
1343 * update the counter_offset of chains behind this one
1344 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001345 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001346 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001347 j++;
1348 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001349 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001350 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001351 continue;
1352 else
1353 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001354 } else
1355 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001356 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001357}
1358
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001359/*
1360 * execute command Z
1361 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001362static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001363{
1364
1365 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001366 /*
1367 * tell main() we don't update the counters
1368 * this results in tricking the kernel to zero its counters,
1369 * naively expecting userspace to update its counters. Muahahaha
1370 */
Bart De Schuymered053432002-07-21 19:35:39 +00001371 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001372 replace.num_counters = 0;
1373 } else {
1374 int i, j;
1375 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001376 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001377
Bart De Schuymer60332e02002-06-23 08:01:47 +00001378 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001379 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001380 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001381 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001382 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001383 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001384 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001385 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001386 if (i < NF_BR_NUMHOOKS &&
1387 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001388 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001389 e2 = nr_to_chain(i);
1390 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001391 *cnt = CNT_NORM;
1392 cnt++;
1393 }
1394 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001395 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001396 *cnt = CNT_ZERO;
1397 cnt++;
1398 }
Bart De Schuymered053432002-07-21 19:35:39 +00001399 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001400 *cnt = CNT_NORM;
1401 cnt++;
1402 }
1403 *cnt = CNT_END;
1404 }
1405}
1406
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001407/*
1408 * Checks the type for validity and calls getethertypebynumber()
1409 */
1410struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001412 if (type < 1536)
1413 print_error("Ethernet protocols have values >= 0x0600");
1414 if (type > 0xffff)
1415 print_error("Ethernet protocols have values <= 0xffff");
1416 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001417}
1418
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001419/*
1420 * put the mac address into 6 (ETH_ALEN) bytes
1421 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001422int getmac_and_mask(char *from, char *to, char *mask)
1423{
1424 char *p;
1425 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001426 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001427
1428 if (strcasecmp(from, "Unicast") == 0) {
1429 memcpy(to, mac_type_unicast, ETH_ALEN);
1430 memcpy(mask, msk_type_unicast, ETH_ALEN);
1431 return 0;
1432 }
1433 if (strcasecmp(from, "Multicast") == 0) {
1434 memcpy(to, mac_type_multicast, ETH_ALEN);
1435 memcpy(mask, msk_type_multicast, ETH_ALEN);
1436 return 0;
1437 }
1438 if (strcasecmp(from, "Broadcast") == 0) {
1439 memcpy(to, mac_type_broadcast, ETH_ALEN);
1440 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1441 return 0;
1442 }
1443 if ( (p = strrchr(from, '/')) != NULL) {
1444 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001445 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001446 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001447 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001448 } else
1449 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001450 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001451 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001452 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001453 for (i = 0; i < ETH_ALEN; i++)
1454 to[i] &= mask[i];
1455 return 0;
1456}
1457
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001458/*
1459 * executes the final_check() function for all extensions used by the rule
1460 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001461static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001462{
1463 struct ebt_u_match_list *m_l;
1464 struct ebt_u_watcher_list *w_l;
1465 struct ebt_u_target *t;
1466 struct ebt_u_match *m;
1467 struct ebt_u_watcher *w;
1468
1469 m_l = e->m_list;
1470 w_l = e->w_list;
1471 while (m_l) {
1472 m = find_match(m_l->m->u.name);
1473 m->final_check(e, m_l->m, replace.name,
1474 entries->hook_mask, 1);
1475 m_l = m_l->next;
1476 }
1477 while (w_l) {
1478 w = find_watcher(w_l->w->u.name);
1479 w->final_check(e, w_l->w, replace.name,
1480 entries->hook_mask, 1);
1481 w_l = w_l->next;
1482 }
1483 t = find_target(e->t->u.name);
1484 t->final_check(e, e->t, replace.name,
1485 entries->hook_mask, 1);
1486}
1487
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001488/*
1489 * used for the -X command
1490 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001491static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001492{
1493 int i = -1, j;
1494 struct ebt_u_entries *entries;
1495 struct ebt_u_entry *e;
1496
1497 while (1) {
1498 i++;
1499 entries = nr_to_chain(i);
1500 if (!entries) {
1501 if (i < NF_BR_NUMHOOKS)
1502 continue;
1503 else
1504 break;
1505 }
1506 e = entries->entries;
1507 j = 0;
1508 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001509 int chain_jmp;
1510
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001511 j++;
1512 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1513 e = e->next;
1514 continue;
1515 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001516 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1517 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001518 print_error("Can't delete the chain, it's referenced "
1519 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001520 /* adjust the chain jumps when necessary */
1521 if (chain_jmp > chain_nr)
1522 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001523 e = e->next;
1524 }
1525 }
1526}
1527
Bart De Schuymercc440052002-11-06 21:10:33 +00001528static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1529{
1530 char *colon = strchr(argv, ':'), *buffer;
1531
1532 if (colon) {
1533 *colon = '\0';
1534 if (*(colon + 1) == '\0')
1535 *rule_nr_end = -1;
1536 else {
1537 *rule_nr_end = strtol(colon + 1, &buffer, 10);
1538 if (*buffer != '\0' || *rule_nr_end < 0)
1539 return -1;
1540 }
1541 }
1542 if (colon == argv)
1543 *rule_nr = 1;
1544 else {
1545 *rule_nr = strtol(argv, &buffer, 10);
1546 if (*buffer != '\0' || *rule_nr < 0)
1547 return -1;
1548 }
1549 if (!colon)
1550 *rule_nr_end = *rule_nr;
1551 if (*rule_nr_end != -1 && *rule_nr > *rule_nr_end)
1552 return -1;
1553 return 0;
1554}
1555
Bart De Schuymera615b962002-11-03 14:54:09 +00001556static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001557int check_inverse(const char option[])
1558{
1559 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001560 if (invert == 1)
1561 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001562 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001563 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001564 return 1;
1565 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001566 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001567}
1568
1569void check_option(unsigned int *flags, unsigned int mask)
1570{
1571 if (*flags & mask)
1572 print_error("Multiple use of same option not allowed");
1573 *flags |= mask;
1574}
1575
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001576static void get_kernel_table(const char *modprobe)
1577{
1578 if ( !(table = find_table(replace.name)) )
1579 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001580 /*
1581 * get the kernel's information
1582 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001583 if (get_table(&replace)) {
1584 ebtables_insmod("ebtables", modprobe);
1585 if (get_table(&replace))
1586 print_error("The kernel doesn't support the ebtables "
1587 "%s table", replace.name);
1588 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001589 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001590 * when listing a table contained in a file, we don't demand that
1591 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001592 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001593 if ( !(table = find_table(replace.name)) )
1594 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001595}
1596
Bart De Schuymerc5075142002-08-18 14:21:19 +00001597#define print_if_l_error print_error("Interface name length must be less " \
1598 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001599#define OPT_COMMAND 0x01
1600#define OPT_TABLE 0x02
1601#define OPT_IN 0x04
1602#define OPT_OUT 0x08
1603#define OPT_JUMP 0x10
1604#define OPT_PROTOCOL 0x20
1605#define OPT_SOURCE 0x40
1606#define OPT_DEST 0x80
1607#define OPT_ZERO 0x100
1608#define OPT_LOGICALIN 0x200
1609#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001610/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001611int main(int argc, char *argv[])
1612{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001613 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001614 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001615 /*
1616 * this special one for the -Z option (we can have -Z <this> -L <that>)
1617 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001618 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001619 int policy = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001620 int rule_nr = -1; /* used for -[D,I] */
1621 int rule_nr_end = -1; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001622 struct ebt_u_target *t;
1623 struct ebt_u_match *m;
1624 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001625 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001626 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001627 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001628 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001629
Bart De Schuymera615b962002-11-03 14:54:09 +00001630 opterr = 0;
1631
Bart De Schuymer5885b362002-12-03 20:51:36 +00001632 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001633 /*
1634 * initialize the table name, OPT_ flags, selected hook and command
1635 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001636 strcpy(replace.name, "filter");
1637 replace.flags = 0;
1638 replace.selected_hook = -1;
1639 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001640 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001641
1642 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1643 if (!new_entry)
1644 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001645 /*
1646 * put some sane values in our new entry
1647 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001648 initialize_entry(new_entry);
1649
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001650 /*
1651 * The scenario induced by this loop makes that:
1652 * '-t' ,'-M' and --atomic (if specified) have to come
1653 * before '-A' and the like
1654 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001655
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001656 /*
1657 * getopt saves the day
1658 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001659 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001660 "-A:D:I:N:E:X:L::Z::F::P:Vhi:o:j:p:s:d:t:M:", ebt_options, NULL)) != -1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001661 switch (c) {
1662
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001663 case 'A': /* add a rule */
1664 case 'D': /* delete a rule */
1665 case 'P': /* define policy */
1666 case 'I': /* insert a rule */
1667 case 'N': /* make a user defined chain */
1668 case 'E': /* rename chain */
1669 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001670 replace.command = c;
1671 if (replace.flags & OPT_COMMAND)
1672 print_error("Multiple commands not allowed");
1673 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001674 get_kernel_table(modprobe);
1675 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001676 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001677 if (c == 'N') {
1678 struct ebt_u_chain_list *cl, **cl2;
1679
1680 if (get_hooknr(optarg) != -1)
1681 print_error("Chain %s already exists",
1682 optarg);
1683 if (find_target(optarg))
1684 print_error("Target with name %s exists"
1685 , optarg);
1686 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001687 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001688 EBT_CHAIN_MAXNAMELEN - 1);
1689 cl = (struct ebt_u_chain_list *)
1690 malloc(sizeof(struct ebt_u_chain_list));
1691 if (!cl)
1692 print_memory();
1693 cl->next = NULL;
1694 cl->udc = (struct ebt_u_entries *)
1695 malloc(sizeof(struct ebt_u_entries));
1696 if (!cl->udc)
1697 print_memory();
1698 cl->udc->nentries = 0;
1699 cl->udc->policy = EBT_ACCEPT;
1700 cl->udc->counter_offset = replace.nentries;
1701 cl->udc->hook_mask = 0;
1702 strcpy(cl->udc->name, optarg);
1703 cl->udc->entries = NULL;
1704 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001705 /*
1706 * put the new chain at the end
1707 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001708 cl2 = &replace.udc;
1709 while (*cl2)
1710 cl2 = &((*cl2)->next);
1711 *cl2 = cl;
1712 break;
1713 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001714 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1715 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001716 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001717 if (optind >= argc || argv[optind][0] == '-' ||
1718 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001719 print_error("No new chain name specified");
1720 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1721 print_error("Chain name len can't exceed %d",
1722 EBT_CHAIN_MAXNAMELEN - 1);
1723 if (get_hooknr(argv[optind]) != -1)
1724 print_error("Chain %s already exists",
1725 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001726 if (find_target(argv[optind]))
1727 print_error("Target with name %s exists"
1728 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001729 entries = to_chain();
1730 strcpy(entries->name, argv[optind]);
1731 optind++;
1732 break;
1733 }
1734 if (c == 'X') {
1735 struct ebt_u_chain_list *cl, **cl2;
1736
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001737 if (replace.selected_hook < NF_BR_NUMHOOKS)
1738 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001739 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001740 * if the chain is referenced, don't delete it,
1741 * also decrement jumps to a chain behind the
1742 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001743 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001744 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001745 flush_chains();
1746 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001747 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001748 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001749 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001750 cl = (*cl2);
1751 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001752 free(cl->udc);
1753 free(cl);
1754 break;
1755 }
1756
Bart De Schuymercc440052002-11-06 21:10:33 +00001757 if (c == 'D' && optind < argc &&
1758 argv[optind][0] != '-') {
1759 if (parse_delete_rule(argv[optind],
1760 &rule_nr, &rule_nr_end))
1761 print_error("Problem with the "
1762 "specified rule number(s)");
1763 optind++;
1764 }
1765 if (c == 'I') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001766 if (optind >= argc || argv[optind][0] == '-')
1767 print_error("No rulenr for -I"
1768 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001769 rule_nr = strtol(argv[optind], &buffer, 10);
1770 if (*buffer != '\0' || rule_nr < 0)
1771 print_error("Problem with the "
1772 "specified rule number");
1773 optind++;
1774 }
1775 if (c == 'P') {
1776 if (optind >= argc)
1777 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001778 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001779 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001780 if (!strcmp(argv[optind],
1781 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001782 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001783 if (policy == EBT_CONTINUE)
1784 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001785 break;
1786 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001787 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001788 print_error("Wrong policy");
1789 optind++;
1790 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001791 break;
1792
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001793 case 'L': /* list */
1794 case 'F': /* flush */
1795 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001796 if (c == 'Z') {
1797 if (replace.flags & OPT_ZERO)
1798 print_error("Multiple commands"
1799 " not allowed");
1800 if ( (replace.flags & OPT_COMMAND &&
1801 replace.command != 'L'))
1802 print_error("command -Z only allowed "
1803 "together with command -L");
1804 replace.flags |= OPT_ZERO;
1805 } else {
1806 replace.command = c;
1807 if (replace.flags & OPT_COMMAND)
1808 print_error("Multiple commands"
1809 " not allowed");
1810 replace.flags |= OPT_COMMAND;
1811 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001812 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001813 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001814 if (optarg) {
1815 if ( (i = get_hooknr(optarg)) == -1 )
1816 print_error("Bad chain");
1817 } else
1818 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001819 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001820 print_error("Bad chain");
1821 optind++;
1822 }
1823 if (i != -1) {
1824 if (c == 'Z')
1825 zerochain = i;
1826 else
1827 replace.selected_hook = i;
1828 }
1829 break;
1830
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001831 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001832 replace.command = 'V';
1833 if (replace.flags & OPT_COMMAND)
1834 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001835 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001836 exit(0);
1837
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001838 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001839 if (replace.command != 'h')
1840 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001841 modprobe = optarg;
1842 break;
1843
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001844 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001845 if (replace.flags & OPT_COMMAND)
1846 print_error("Multiple commands not allowed");
1847 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001848 /*
1849 * All other arguments should be extension names
1850 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001851 while (optind < argc) {
1852 struct ebt_u_match *m;
1853 struct ebt_u_watcher *w;
1854
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00001855 if (!strcasecmp("list_extensions",
1856 argv[optind]))
1857 list_extensions();
1858
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001859 if ((m = find_match(argv[optind])))
1860 add_match(m);
1861 else if ((w = find_watcher(argv[optind])))
1862 add_watcher(w);
1863 else {
1864 if (!(t = find_target(argv[optind])))
1865 print_error("Extension %s "
1866 "not found", argv[optind]);
1867 if (replace.flags & OPT_JUMP)
1868 print_error("Sorry, you can "
1869 "only see help for one "
1870 "target extension each time");
1871 replace.flags |= OPT_JUMP;
1872 new_entry->t =
1873 (struct ebt_entry_target *)t;
1874 }
1875 optind++;
1876 }
1877 break;
1878
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001879 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001880 if (replace.command != 'h')
1881 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001882 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001883 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001884 print_error("Table name too long");
1885 strcpy(replace.name, optarg);
1886 break;
1887
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001888 case 'i': /* input interface */
1889 case 2 : /* logical input interface */
1890 case 'o': /* output interface */
1891 case 3 : /* logical output interface */
1892 case 'j': /* target */
1893 case 'p': /* net family protocol */
1894 case 's': /* source mac */
1895 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001896 if ((replace.flags & OPT_COMMAND) == 0)
1897 print_error("No command specified");
1898 if ( replace.command != 'A' &&
1899 replace.command != 'D' && replace.command != 'I')
1900 print_error("Command and option do not match");
1901 if (c == 'i') {
1902 check_option(&replace.flags, OPT_IN);
1903 if (replace.selected_hook > 2 &&
1904 replace.selected_hook < NF_BR_BROUTING)
1905 print_error("Use in-interface only in "
1906 "INPUT, FORWARD, PREROUTING and"
1907 "BROUTING chains");
1908 if (check_inverse(optarg))
1909 new_entry->invflags |= EBT_IIN;
1910
1911 if (optind > argc)
1912 print_error("No in-interface "
1913 "specified");
1914 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001915 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001916 strcpy(new_entry->in, argv[optind - 1]);
1917 break;
1918 }
1919 if (c == 2) {
1920 check_option(&replace.flags, OPT_LOGICALIN);
1921 if (replace.selected_hook > 2 &&
1922 replace.selected_hook < NF_BR_BROUTING)
1923 print_error("Use logical in-interface "
1924 "only in INPUT, FORWARD, "
1925 "PREROUTING and BROUTING chains");
1926 if (check_inverse(optarg))
1927 new_entry->invflags |= EBT_ILOGICALIN;
1928
1929 if (optind > argc)
1930 print_error("No logical in-interface "
1931 "specified");
1932 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001933 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001934 strcpy(new_entry->logical_in, argv[optind - 1]);
1935 break;
1936 }
1937 if (c == 'o') {
1938 check_option(&replace.flags, OPT_OUT);
1939 if (replace.selected_hook < 2)
1940 print_error("Use out-interface only"
1941 " in OUTPUT, FORWARD and "
1942 "POSTROUTING chains");
1943 if (check_inverse(optarg))
1944 new_entry->invflags |= EBT_IOUT;
1945
1946 if (optind > argc)
1947 print_error("No out-interface "
1948 "specified");
1949
1950 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001951 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001952 strcpy(new_entry->out, argv[optind - 1]);
1953 break;
1954 }
1955 if (c == 3) {
1956 check_option(&replace.flags, OPT_LOGICALOUT);
1957 if (replace.selected_hook < 2)
1958 print_error("Use logical out-interface "
1959 "only in OUTPUT, FORWARD and "
1960 "POSTROUTING chains");
1961 if (check_inverse(optarg))
1962 new_entry->invflags |= EBT_ILOGICALOUT;
1963
1964 if (optind > argc)
1965 print_error("No logical out-interface "
1966 "specified");
1967
1968 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001969 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001970 strcpy(new_entry->logical_out,
1971 argv[optind - 1]);
1972 break;
1973 }
1974 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001975 check_option(&replace.flags, OPT_JUMP);
1976 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1977 if (!strcmp(optarg,
1978 standard_targets[i])) {
1979 t = find_target(
1980 EBT_STANDARD_TARGET);
1981 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001982 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001983 break;
1984 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001985 if (-i - 1 == EBT_RETURN) {
1986 if (replace.selected_hook < NF_BR_NUMHOOKS)
1987 print_error("Return target"
1988 " only for user defined chains");
1989 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001990 if (i != NUM_STANDARD_TARGETS)
1991 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001992 if ((i = get_hooknr(optarg)) != -1) {
1993 if (i < NF_BR_NUMHOOKS)
1994 print_error("don't jump"
1995 " to a standard chain");
1996 t = find_target(
1997 EBT_STANDARD_TARGET);
1998 ((struct ebt_standard_target *)
1999 t->t)->verdict = i - NF_BR_NUMHOOKS;
2000 break;
2001 }
2002 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002003 /*
2004 * must be an extension then
2005 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002006 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002007
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002008 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002009 /*
2010 * -j standard not allowed either
2011 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002012 if (!t || t ==
2013 (struct ebt_u_target *)new_entry->t)
2014 print_error("Illegal target "
2015 "name");
2016 new_entry->t =
2017 (struct ebt_entry_target *)t;
2018 }
2019 break;
2020 }
2021 if (c == 's') {
2022 check_option(&replace.flags, OPT_SOURCE);
2023 if (check_inverse(optarg))
2024 new_entry->invflags |= EBT_ISOURCE;
2025
2026 if (optind > argc)
2027 print_error("No source mac "
2028 "specified");
2029 if (getmac_and_mask(argv[optind - 1],
2030 new_entry->sourcemac, new_entry->sourcemsk))
2031 print_error("Problem with specified "
2032 "source mac");
2033 new_entry->bitmask |= EBT_SOURCEMAC;
2034 break;
2035 }
2036 if (c == 'd') {
2037 check_option(&replace.flags, OPT_DEST);
2038 if (check_inverse(optarg))
2039 new_entry->invflags |= EBT_IDEST;
2040
2041 if (optind > argc)
2042 print_error("No destination mac "
2043 "specified");
2044 if (getmac_and_mask(argv[optind - 1],
2045 new_entry->destmac, new_entry->destmsk))
2046 print_error("Problem with specified "
2047 "destination mac");
2048 new_entry->bitmask |= EBT_DESTMAC;
2049 break;
2050 }
2051 check_option(&replace.flags, OPT_PROTOCOL);
2052 if (check_inverse(optarg))
2053 new_entry->invflags |= EBT_IPROTO;
2054
2055 if (optind > argc)
2056 print_error("No protocol specified");
2057 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2058 i = strtol(argv[optind - 1], &buffer, 16);
2059 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2060 print_error("Problem with the specified "
2061 "protocol");
2062 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002063 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002064 struct ethertypeent *ent;
2065
2066 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2067 new_entry->bitmask |= EBT_802_3;
2068 break;
2069 }
2070 ent = getethertypebyname(argv[optind - 1]);
2071 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002072 print_error("Problem with the specified"
2073 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002074 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002075 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002076 if (new_entry->ethproto < 1536 &&
2077 !(new_entry->bitmask & EBT_802_3))
2078 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002079 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002080 break;
2081
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002082 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002083 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002084 if (replace.command != 'L')
2085 print_error("Use --Lc with -L");
2086 if (replace.flags & LIST_X)
2087 print_error("--Lx not compatible with --Lc");
2088 replace.flags |= LIST_C;
2089 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002090 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002091 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002092 if (replace.command != 'L')
2093 print_error("Use --Ln with -L");
2094 if (replace.flags & LIST_X)
2095 print_error("--Lx not compatible with --Ln");
2096 replace.flags |= LIST_N;
2097 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002098 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002099 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002100 if (replace.command != 'L')
2101 print_error("Use --Lx with -L");
2102 if (replace.flags & LIST_C)
2103 print_error("--Lx not compatible with --Lc");
2104 if (replace.flags & LIST_N)
2105 print_error("--Lx not compatible with --Ln");
2106 replace.flags |= LIST_X;
2107 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002108 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002109 replace.command = c;
2110 if (replace.flags & OPT_COMMAND)
2111 print_error("Multiple commands not allowed");
2112 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002113 if (!replace.filename)
2114 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002115 /*
2116 * get the information from the file
2117 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002118 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002119 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002120 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002121 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2122 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002123 replace.counterchanges[i] = CNT_NORM;
2124 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002125 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002126 /*
2127 * we don't want the kernel giving us its counters, they would
2128 * overwrite the counters extracted from the file
2129 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002130 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002131 /*
2132 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002133 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002134 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002135 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002136 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002137 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002138 case 7 : /* atomic-init */
2139 case 10: /* atomic-save */
2140 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002141 replace.command = c;
2142 if (replace.flags & OPT_COMMAND)
2143 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002144 if (c != 11 && !replace.filename)
2145 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002146 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002147 {
2148 char *tmp = replace.filename;
2149
2150 tmp = replace.filename;
2151 /* get the kernel table */
2152 replace.filename = NULL;
2153 get_kernel_table(modprobe);
2154 replace.filename = tmp;
2155 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002156 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002157 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002158 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2159 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002160 replace.counterchanges[i] = CNT_NORM;
2161 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002162 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002163 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002164 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002165 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002166 print_error("--atomic has to come before"
2167 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002168 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002169 replace.filename = (char *)malloc(strlen(optarg) + 1);
2170 strcpy(replace.filename, optarg);
2171 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002172 case 1 :
2173 if (!strcmp(optarg, "!"))
2174 check_inverse(optarg);
2175 else
2176 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002177 /*
2178 * check_inverse() did optind++
2179 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002180 optind--;
2181 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002182 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002183 /*
2184 * is it a target option?
2185 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002186 t = (struct ebt_u_target *)new_entry->t;
2187 if ((t->parse(c - t->option_offset, argv, argc,
2188 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002189 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002190
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002191 /*
2192 * is it a match_option?
2193 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002194 for (m = matches; m; m = m->next)
2195 if (m->parse(c - m->option_offset, argv,
2196 argc, new_entry, &m->flags, &m->m))
2197 break;
2198
2199 if (m != NULL) {
2200 if (m->used == 0)
2201 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002202 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002203 }
2204
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002205 /*
2206 * is it a watcher option?
2207 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002208 for (w = watchers; w; w = w->next)
2209 if (w->parse(c-w->option_offset, argv,
2210 argc, new_entry, &w->flags, &w->w))
2211 break;
2212
2213 if (w == NULL)
2214 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002215 if (w->used == 0)
2216 add_watcher(w);
2217check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002218 if (replace.command != 'A' && replace.command != 'I' &&
2219 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002220 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002221 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002222 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002223 }
2224
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002225 if ( !table && !(table = find_table(replace.name)) )
2226 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002227
2228 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2229 replace.flags & OPT_ZERO )
2230 print_error("Command -Z only allowed together with command -L");
2231
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002232 /*
2233 * do this after parsing everything, so we can print specific info
2234 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002235 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2236 print_help();
2237
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002238 /*
2239 * do the final checks
2240 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002241 if (replace.command == 'A' || replace.command == 'I' ||
2242 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002243 /*
2244 * this will put the hook_mask right for the chains
2245 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002246 check_for_loops();
2247 entries = to_chain();
2248 m_l = new_entry->m_list;
2249 w_l = new_entry->w_list;
2250 t = (struct ebt_u_target *)new_entry->t;
2251 while (m_l) {
2252 m = (struct ebt_u_match *)(m_l->m);
2253 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002254 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002255 m_l = m_l->next;
2256 }
2257 while (w_l) {
2258 w = (struct ebt_u_watcher *)(w_l->w);
2259 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002260 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002261 w_l = w_l->next;
2262 }
2263 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002264 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002265 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002266 /*
2267 * so, the extensions can work with the host endian
2268 * the kernel does not have to do this ofcourse
2269 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002270 new_entry->ethproto = htons(new_entry->ethproto);
2271
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002272 if (replace.command == 'P') {
2273 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2274 policy == EBT_RETURN)
2275 print_error("Policy RETURN only allowed for user "
2276 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002277 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002278 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002279 list_rules();
2280 if (replace.flags & OPT_ZERO)
2281 zero_counters(zerochain);
2282 else
2283 exit(0);
2284 }
2285 if (replace.flags & OPT_ZERO)
2286 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002287 else if (replace.command == 'F') {
2288 if (flush_chains() == -1)
2289 exit(0);
2290 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002291 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002292 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002293 /*
2294 * do the final_check(), for all entries
2295 * needed when adding a rule that has a chain target
2296 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002297 i = -1;
2298 while (1) {
2299 struct ebt_u_entry *e;
2300
2301 i++;
2302 entries = nr_to_chain(i);
2303 if (!entries) {
2304 if (i < NF_BR_NUMHOOKS)
2305 continue;
2306 else
2307 break;
2308 }
2309 e = entries->entries;
2310 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002311 /*
2312 * userspace extensions use host endian
2313 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002314 e->ethproto = ntohs(e->ethproto);
2315 do_final_checks(e, entries);
2316 e->ethproto = htons(e->ethproto);
2317 e = e->next;
2318 }
2319 }
Bart De Schuymercc440052002-11-06 21:10:33 +00002320 } else if (replace.command == 'D') {
2321 if (rule_nr != -1 && rule_nr_end == -1)
2322 rule_nr_end = entries->nentries;
2323 delete_rule(rule_nr, rule_nr_end);
2324 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002325 /*
2326 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2327 * --init-table fall through
2328 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002329
2330 if (table->check)
2331 table->check(&replace);
2332
2333 deliver_table(&replace);
2334
Bart De Schuymered053432002-07-21 19:35:39 +00002335 if (replace.counterchanges)
2336 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002337 return 0;
2338}