blob: dfe4b81c573ea9d4ce21c5df947e048035716a4c [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/*
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000037 * default command line options
38 * do not mess around with the already assigned numbers unless
39 * you know what you are doing
40 */
Bart De Schuymer62423742002-07-14 19:06:20 +000041static struct option ebt_original_options[] =
42{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000043 { "append" , required_argument, 0, 'A' },
44 { "insert" , required_argument, 0, 'I' },
45 { "delete" , required_argument, 0, 'D' },
46 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000047 { "Lc" , no_argument , 0, 4 },
48 { "Ln" , no_argument , 0, 5 },
49 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer22d03a22003-05-03 20:28:22 +000050 { "Lmac2" , no_argument , 0, 12 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000051 { "zero" , optional_argument, 0, 'Z' },
52 { "flush" , optional_argument, 0, 'F' },
53 { "policy" , required_argument, 0, 'P' },
54 { "in-interface" , required_argument, 0, 'i' },
55 { "in-if" , required_argument, 0, 'i' },
56 { "logical-in" , required_argument, 0, 2 },
57 { "logical-out" , required_argument, 0, 3 },
58 { "out-interface" , required_argument, 0, 'o' },
59 { "out-if" , required_argument, 0, 'o' },
60 { "version" , no_argument , 0, 'V' },
61 { "help" , no_argument , 0, 'h' },
62 { "jump" , required_argument, 0, 'j' },
63 { "proto" , required_argument, 0, 'p' },
64 { "protocol" , required_argument, 0, 'p' },
65 { "db" , required_argument, 0, 'b' },
66 { "source" , required_argument, 0, 's' },
67 { "src" , required_argument, 0, 's' },
68 { "destination" , required_argument, 0, 'd' },
69 { "dst" , required_argument, 0, 'd' },
70 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000071 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000072 { "new-chain" , required_argument, 0, 'N' },
73 { "rename-chain" , required_argument, 0, 'E' },
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +000074 { "delete-chain" , optional_argument, 0, 'X' },
Bart De Schuymer5885b362002-12-03 20:51:36 +000075 { "atomic-init" , no_argument , 0, 7 },
76 { "atomic-commit" , no_argument , 0, 8 },
77 { "atomic-file" , required_argument, 0, 9 },
78 { "atomic-save" , no_argument , 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000079 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080 { 0 }
81};
82
83static struct option *ebt_options = ebt_original_options;
84
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000085/*
86 * holds all the data
87 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000088static struct ebt_u_replace replace;
89
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000090/*
91 * the chosen table
92 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000093static struct ebt_u_table *table = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000094
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000095/*
96 * The pointers in here are special:
97 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
98 * instead of making yet a few other structs, we just do a cast.
99 * We need a struct ebt_u_target pointer because we know the address of the data
100 * they point to won't change. We want to allow that the struct ebt_u_target.t
101 * member can change.
102 * Same holds for the struct ebt_match and struct ebt_watcher pointers
103 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000104struct ebt_u_entry *new_entry;
105
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000106
107static int global_option_offset = 0;
108#define OPTION_OFFSET 256
109static struct option *
110merge_options(struct option *oldopts, const struct option *newopts,
111 unsigned int *options_offset)
112{
113 unsigned int num_old, num_new, i;
114 struct option *merge;
115
116 if (!newopts || !oldopts || !options_offset)
117 print_bug("merge wrong");
118 for (num_old = 0; oldopts[num_old].name; num_old++);
119 for (num_new = 0; newopts[num_new].name; num_new++);
120
121 global_option_offset += OPTION_OFFSET;
122 *options_offset = global_option_offset;
123
124 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
125 if (!merge)
126 print_memory();
127 memcpy(merge, oldopts, num_old * sizeof(struct option));
128 for (i = 0; i < num_new; i++) {
129 merge[num_old + i] = newopts[i];
130 merge[num_old + i].val += *options_offset;
131 }
132 memset(merge + num_old + num_new, 0, sizeof(struct option));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000133 /* only free dynamically allocated stuff */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000134 if (oldopts != ebt_original_options)
135 free(oldopts);
136
137 return merge;
138}
139
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000140static void merge_match(struct ebt_u_match *m)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000141{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000142 ebt_options = merge_options
143 (ebt_options, m->extra_ops, &(m->option_offset));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000144}
145
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000146static void merge_watcher(struct ebt_u_watcher *w)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000147{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000148 ebt_options = merge_options
149 (ebt_options, w->extra_ops, &(w->option_offset));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000150}
151
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000152static void merge_target(struct ebt_u_target *t)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000153{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000154 ebt_options = merge_options
155 (ebt_options, t->extra_ops, &(t->option_offset));
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000156}
157
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000158/*
159 * we use replace.flags, so we can't use the following values:
160 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
161 */
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000162#define LIST_N 0x04
163#define LIST_C 0x08
164#define LIST_X 0x10
165#define LIST_MAC2 0x20
166
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000167/*
168 * helper function for list_rules()
169 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000170static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000171{
172 int i, j, space = 0, digits;
173 struct ebt_u_entry *hlp;
174 struct ebt_u_match_list *m_l;
175 struct ebt_u_watcher_list *w_l;
176 struct ebt_u_match *m;
177 struct ebt_u_watcher *w;
178 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000179
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000180 if (replace.flags & LIST_MAC2)
181 ebt_printstyle_mac = 2;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000182 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000183 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
184 printf("ebtables -t %s -P %s %s\n", replace.name,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000185 entries->name, ebt_standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000186 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000187 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
188 entries->name, entries->nentries,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000189 ebt_standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000190 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000191
Bart De Schuymer60332e02002-06-23 08:01:47 +0000192 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000193 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000194 space++;
195 i /= 10;
196 }
197
Bart De Schuymer60332e02002-06-23 08:01:47 +0000198 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000199 if (replace.flags & LIST_N) {
200 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000201 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000202 j = i + 1;
203 while (j > 9) {
204 digits++;
205 j /= 10;
206 }
207 for (j = 0; j < space - digits; j++)
208 printf(" ");
209 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000210 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000211 if (replace.flags & LIST_X)
212 printf("ebtables -t %s -A %s ",
213 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000215 /*
216 * Don't print anything about the protocol if no protocol was
217 * specified, obviously this means any protocol will do.
218 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000219 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000220 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000221 if (hlp->invflags & EBT_IPROTO)
222 printf("! ");
223 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000224 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000225 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000226 struct ethertypeent *ent;
227
228 ent = getethertypebynumber(ntohs(hlp->ethproto));
229 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000230 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000231 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000232 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000233 }
234 }
235 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000236 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000237 if (hlp->invflags & EBT_ISOURCE)
238 printf("! ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000239 ebt_print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000240 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000241 }
242 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000243 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000244 if (hlp->invflags & EBT_IDEST)
245 printf("! ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000246 ebt_print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000247 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000248 }
249 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000250 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000251 if (hlp->invflags & EBT_IIN)
252 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000253 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000254 }
255 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000256 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000257 if (hlp->invflags & EBT_ILOGICALIN)
258 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000259 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000260 }
261 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000262 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000263 if (hlp->invflags & EBT_ILOGICALOUT)
264 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000265 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 }
267 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000268 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000269 if (hlp->invflags & EBT_IOUT)
270 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000271 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000272 }
273
274 m_l = hlp->m_list;
275 while (m_l) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000276 m = ebt_find_match(m_l->m->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000277 if (!m)
278 print_bug("Match not found");
279 m->print(hlp, m_l->m);
280 m_l = m_l->next;
281 }
282 w_l = hlp->w_list;
283 while (w_l) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000284 w = ebt_find_watcher(w_l->w->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000285 if (!w)
286 print_bug("Watcher not found");
287 w->print(hlp, w_l->w);
288 w_l = w_l->next;
289 }
290
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000291 printf("-j ");
292 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
293 printf("%s ", hlp->t->u.name);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000294 t = ebt_find_target(hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000295 if (!t)
296 print_bug("Target not found");
297 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000298 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000299 printf(", pcnt = %llu -- bcnt = %llu",
300 replace.counters[entries->counter_offset + i].pcnt,
301 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000302 printf("\n");
303 hlp = hlp->next;
304 }
305}
306
Bart De Schuymer62423742002-07-14 19:06:20 +0000307static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000308{
309 struct ebt_u_match_list *m_l;
310 struct ebt_u_watcher_list *w_l;
311
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000312 PRINT_VERSION;
313 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000314"Usage:\n"
315"ebtables -[ADI] chain rule-specification [options]\n"
316"ebtables -P chain target\n"
317"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000318"ebtables -[NX] [chain]\n"
319"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000320"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000321"--append -A chain : append to chain\n"
322"--delete -D chain : delete matching rule from chain\n"
323"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000324"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000325"--list -L [chain] : list the rules in a chain or in all chains\n"
326"--flush -F [chain] : delete all rules in chain or in all chains\n"
327"--init-table : replace the kernel table with the initial table\n"
328"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
329"--policy -P chain target : change policy on chain to target\n"
330"--new-chain -N chain : create a user defined chain\n"
331"--rename-chain -E old new : rename a chain\n"
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000332"--delete-chain -X [chain] : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000333"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
334"--atomic-init : put the initial kernel table into <FILE>\n"
335"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000336"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000337"Options:\n"
338"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
339"--src -s [!] address[/mask]: source mac address\n"
340"--dst -d [!] address[/mask]: destination mac address\n"
341"--in-if -i [!] name : network input interface name\n"
342"--out-if -o [!] name : network output interface name\n"
343"--logical-in [!] name : logical bridge input interface name\n"
344"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000345"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000346"--version -V : print package version\n\n"
347"Environment variable:\n"
348ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
349"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000350
351 m_l = new_entry->m_list;
352 while (m_l) {
353 ((struct ebt_u_match *)m_l->m)->help();
354 printf("\n");
355 m_l = m_l->next;
356 }
357 w_l = new_entry->w_list;
358 while (w_l) {
359 ((struct ebt_u_watcher *)w_l->w)->help();
360 printf("\n");
361 w_l = w_l->next;
362 }
363 ((struct ebt_u_target *)new_entry->t)->help();
364 printf("\n");
365 if (table->help)
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000366 table->help(ebt_hooknames);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000367 exit(0);
368}
369
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000370/*
371 * execute command L
372 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000373static void list_rules()
374{
375 int i;
376
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000377 if (!(replace.flags & LIST_X))
378 printf("Bridge table: %s\n", table->name);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000379 if (replace.selected_chain != -1) {
380 list_em(ebt_to_chain(&replace));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000381 } else {
382 struct ebt_u_chain_list *cl = replace.udc;
383
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000384 /*
385 * create new chains and rename standard chains when necessary
386 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000387 if (replace.flags & LIST_X) {
388 while (cl) {
389 printf("ebtables -t %s -N %s\n", replace.name,
390 cl->udc->name);
391 cl = cl->next;
392 }
393 cl = replace.udc;
394 for (i = 0; i < NF_BR_NUMHOOKS; i++)
395 if (replace.valid_hooks & (1 << i) &&
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000396 strcmp(replace.hook_entry[i]->name,
397 ebt_hooknames[i]))
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000398 printf("ebtables -t %s -E %s %s\n",
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000399 replace.name, ebt_hooknames[i],
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000400 replace.hook_entry[i]->name);
401 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000402 i = 0;
403 while (1) {
404 if (i < NF_BR_NUMHOOKS) {
405 if (replace.valid_hooks & (1 << i))
406 list_em(replace.hook_entry[i]);
407 i++;
408 continue;
409 } else {
410 if (!cl)
411 break;
412 list_em(cl->udc);
413 cl = cl->next;
414 }
415 }
416 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000417}
418
Bart De Schuymercc440052002-11-06 21:10:33 +0000419static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
420{
421 char *colon = strchr(argv, ':'), *buffer;
422
423 if (colon) {
424 *colon = '\0';
425 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000426 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +0000427 else {
428 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000429 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +0000430 return -1;
431 }
432 }
433 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000434 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +0000435 else {
436 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000437 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +0000438 return -1;
439 }
440 if (!colon)
441 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +0000442 return 0;
443}
444
Bart De Schuymerc5075142002-08-18 14:21:19 +0000445#define print_if_l_error print_error("Interface name length must be less " \
446 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000447#define OPT_COMMAND 0x01
448#define OPT_TABLE 0x02
449#define OPT_IN 0x04
450#define OPT_OUT 0x08
451#define OPT_JUMP 0x10
452#define OPT_PROTOCOL 0x20
453#define OPT_SOURCE 0x40
454#define OPT_DEST 0x80
455#define OPT_ZERO 0x100
456#define OPT_LOGICALIN 0x200
457#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +0000458/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000459int main(int argc, char *argv[])
460{
Bart De Schuymer923a5732002-08-11 12:01:33 +0000461 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000462 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000463 /*
464 * this special one for the -Z option (we can have -Z <this> -L <that>)
465 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000466 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000467 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000468 int rule_nr = 0; /* used for -[D,I] */
469 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000470 struct ebt_u_target *t;
471 struct ebt_u_match *m;
472 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000473 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000474 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000475 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000476
Bart De Schuymera615b962002-11-03 14:54:09 +0000477 opterr = 0;
478
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000479 ebt_iterate_matches(merge_match);
480 ebt_iterate_watchers(merge_watcher);
481 ebt_iterate_targets(merge_target);
482
Bart De Schuymer5885b362002-12-03 20:51:36 +0000483 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000484 /*
485 * initialize the table name, OPT_ flags, selected hook and command
486 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000487 strcpy(replace.name, "filter");
488 replace.flags = 0;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000489 replace.selected_chain = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000490 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +0000491 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000492
493 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
494 if (!new_entry)
495 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000496 /*
497 * put some sane values in our new entry
498 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000499 ebt_initialize_entry(new_entry);
500 new_entry->replace = &replace;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000501
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000502 /*
503 * The scenario induced by this loop makes that:
504 * '-t' ,'-M' and --atomic (if specified) have to come
505 * before '-A' and the like
506 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000507
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000508 /*
509 * getopt saves the day
510 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000511 while ((c = getopt_long(argc, argv,
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000512 "-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 +0000513 switch (c) {
514
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000515 case 'A': /* add a rule */
516 case 'D': /* delete a rule */
517 case 'P': /* define policy */
518 case 'I': /* insert a rule */
519 case 'N': /* make a user defined chain */
520 case 'E': /* rename chain */
521 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 replace.command = c;
523 if (replace.flags & OPT_COMMAND)
524 print_error("Multiple commands not allowed");
525 replace.flags |= OPT_COMMAND;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000526 ebt_get_kernel_table(&replace, table);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000527 if (optarg && (optarg[0] == '-' ||
528 !strcmp(optarg, "!")))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000529 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000530 if (c == 'N') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000531 ebt_new_chain(&replace, optarg, EBT_ACCEPT);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000532 break;
533 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000534 if (c == 'X') {
535 char *opt;
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000536
537 if (!optarg && (optind >= argc ||
Bart De Schuymerf3196482003-07-25 12:53:17 +0000538 (argv[optind][0] == '-'
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000539 && strcmp(argv[optind], "!")))) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000540 replace.selected_chain = -1;
541 ebt_delete_chain(&replace);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000542 break;
543 }
544 if (optarg)
545 opt = optarg;
546 else {
547 opt = argv[optind];
548 optind++;
549 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000550 if ((replace.selected_chain =
551 ebt_get_chainnr(&replace, opt)) == -1)
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000552 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000553 ebt_delete_chain(&replace);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000554 break;
555 }
556
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000557 if ((replace.selected_chain =
558 ebt_get_chainnr(&replace, optarg)) == -1)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000559 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000560 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000561 if (optind >= argc || argv[optind][0] == '-' ||
562 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000563 print_error("No new chain name specified");
564 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
565 print_error("Chain name len can't exceed %d",
566 EBT_CHAIN_MAXNAMELEN - 1);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000567 if (ebt_get_chainnr(&replace, argv[optind]) != -1)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000568 print_error("Chain %s already exists",
569 argv[optind]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000570 if (ebt_find_target(argv[optind]))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000571 print_error("Target with name %s exists"
572 , argv[optind]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000573 ebt_rename_chain(&replace, argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000574 optind++;
575 break;
576 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000577
Bart De Schuymercc440052002-11-06 21:10:33 +0000578 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000579 (argv[optind][0] != '-' ||
580 (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +0000581 if (parse_delete_rule(argv[optind],
582 &rule_nr, &rule_nr_end))
583 print_error("Problem with the "
584 "specified rule number(s)");
585 optind++;
586 }
587 if (c == 'I') {
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000588 if (optind >= argc || (argv[optind][0] == '-' &&
589 (argv[optind][1] < '0' || argv[optind][1] > '9')))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000590 print_error("No rulenr for -I"
591 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000592 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000593 if (*buffer != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000594 print_error("Problem with the "
595 "specified rule number");
596 optind++;
597 }
598 if (c == 'P') {
599 if (optind >= argc)
600 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000601 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000602 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000603 if (!strcmp(argv[optind],
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000604 ebt_standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000605 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000606 if (policy == EBT_CONTINUE)
607 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 break;
609 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000610 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 print_error("Wrong policy");
612 optind++;
613 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 break;
615
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000616 case 'L': /* list */
617 case 'F': /* flush */
618 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 if (c == 'Z') {
620 if (replace.flags & OPT_ZERO)
621 print_error("Multiple commands"
622 " not allowed");
623 if ( (replace.flags & OPT_COMMAND &&
624 replace.command != 'L'))
625 print_error("command -Z only allowed "
626 "together with command -L");
627 replace.flags |= OPT_ZERO;
628 } else {
629 replace.command = c;
630 if (replace.flags & OPT_COMMAND)
631 print_error("Multiple commands"
632 " not allowed");
633 replace.flags |= OPT_COMMAND;
634 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000635 ebt_get_kernel_table(&replace, table);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000636 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000637 if (optarg) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000638 if ( (i = ebt_get_chainnr(&replace, optarg)) == -1 )
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000639 print_error("Bad chain");
640 } else
641 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000642 if ((i = ebt_get_chainnr(&replace,
643 argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000644 print_error("Bad chain");
645 optind++;
646 }
647 if (i != -1) {
648 if (c == 'Z')
649 zerochain = i;
650 else
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000651 replace.selected_chain = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000652 }
653 break;
654
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000655 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000656 replace.command = 'V';
657 if (replace.flags & OPT_COMMAND)
658 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000659 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660 exit(0);
661
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000662 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000663 if (replace.command != 'h')
664 print_error("Please put the -M option earlier");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000665 ebt_modprobe = optarg;
Bart De Schuymerc8531032002-06-14 21:55:29 +0000666 break;
667
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000668 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000669 if (replace.flags & OPT_COMMAND)
670 print_error("Multiple commands not allowed");
671 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000672 /*
673 * All other arguments should be extension names
674 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000675 while (optind < argc) {
676 struct ebt_u_match *m;
677 struct ebt_u_watcher *w;
678
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000679 if (!strcasecmp("list_extensions",
680 argv[optind]))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000681 ebt_list_extensions();
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000682
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000683 if ((m = ebt_find_match(argv[optind])))
684 ebt_add_match(new_entry, m);
685 else if ((w = ebt_find_watcher(argv[optind])))
686 ebt_add_watcher(new_entry, w);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000687 else {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000688 if (!(t = ebt_find_target(argv[optind])))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000689 print_error("Extension %s "
690 "not found", argv[optind]);
691 if (replace.flags & OPT_JUMP)
692 print_error("Sorry, you can "
693 "only see help for one "
694 "target extension each time");
695 replace.flags |= OPT_JUMP;
696 new_entry->t =
697 (struct ebt_entry_target *)t;
698 }
699 optind++;
700 }
701 break;
702
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000703 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000704 if (replace.command != 'h')
705 print_error("Please put the -t option first");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000706 ebt_check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000707 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000708 print_error("Table name too long");
709 strcpy(replace.name, optarg);
710 break;
711
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000712 case 'i': /* input interface */
713 case 2 : /* logical input interface */
714 case 'o': /* output interface */
715 case 3 : /* logical output interface */
716 case 'j': /* target */
717 case 'p': /* net family protocol */
718 case 's': /* source mac */
719 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000720 if ((replace.flags & OPT_COMMAND) == 0)
721 print_error("No command specified");
722 if ( replace.command != 'A' &&
723 replace.command != 'D' && replace.command != 'I')
724 print_error("Command and option do not match");
725 if (c == 'i') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000726 ebt_check_option(&replace.flags, OPT_IN);
727 if (replace.selected_chain > 2 &&
728 replace.selected_chain < NF_BR_BROUTING)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000729 print_error("Use in-interface only in "
730 "INPUT, FORWARD, PREROUTING and"
731 "BROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000732 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000733 new_entry->invflags |= EBT_IIN;
734
735 if (optind > argc)
736 print_error("No in-interface "
737 "specified");
738 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000739 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000740 strcpy(new_entry->in, argv[optind - 1]);
741 break;
742 }
743 if (c == 2) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000744 ebt_check_option(&replace.flags, OPT_LOGICALIN);
745 if (replace.selected_chain > 2 &&
746 replace.selected_chain < NF_BR_BROUTING)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000747 print_error("Use logical in-interface "
748 "only in INPUT, FORWARD, "
749 "PREROUTING and BROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000750 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000751 new_entry->invflags |= EBT_ILOGICALIN;
752
753 if (optind > argc)
754 print_error("No logical in-interface "
755 "specified");
756 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000757 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000758 strcpy(new_entry->logical_in, argv[optind - 1]);
759 break;
760 }
761 if (c == 'o') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000762 ebt_check_option(&replace.flags, OPT_OUT);
763 if (replace.selected_chain < 2)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000764 print_error("Use out-interface only"
765 " in OUTPUT, FORWARD and "
766 "POSTROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000767 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000768 new_entry->invflags |= EBT_IOUT;
769
770 if (optind > argc)
771 print_error("No out-interface "
772 "specified");
773
774 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000775 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000776 strcpy(new_entry->out, argv[optind - 1]);
777 break;
778 }
779 if (c == 3) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000780 ebt_check_option(&replace.flags, OPT_LOGICALOUT);
781 if (replace.selected_chain < 2)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000782 print_error("Use logical out-interface "
783 "only in OUTPUT, FORWARD and "
784 "POSTROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000785 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000786 new_entry->invflags |= EBT_ILOGICALOUT;
787
788 if (optind > argc)
789 print_error("No logical out-interface "
790 "specified");
791
792 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000793 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000794 strcpy(new_entry->logical_out,
795 argv[optind - 1]);
796 break;
797 }
798 if (c == 'j') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000799 ebt_check_option(&replace.flags, OPT_JUMP);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000800 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
801 if (!strcmp(optarg,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000802 ebt_standard_targets[i])) {
803 t = ebt_find_target(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000804 EBT_STANDARD_TARGET);
805 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000806 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000807 break;
808 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000809 if (-i - 1 == EBT_RETURN) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000810 if (replace.selected_chain < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000811 print_error("Return target"
812 " only for user defined chains");
813 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000814 if (i != NUM_STANDARD_TARGETS)
815 break;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000816 if ((i = ebt_get_chainnr(&replace, optarg)) != -1) {
817 if (i < NF_BR_NUMHOOKS)
818 print_error("don't jump"
819 " to a standard chain");
820 t = ebt_find_target(EBT_STANDARD_TARGET);
821 ((struct ebt_standard_target *)
822 t->t)->verdict = i - NF_BR_NUMHOOKS;
823 break;
824 } else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000825 /*
826 * must be an extension then
827 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000828 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000829
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000830 t = ebt_find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000831 /*
832 * -j standard not allowed either
833 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000834 if (!t || t ==
835 (struct ebt_u_target *)new_entry->t)
836 print_error("Illegal target "
837 "name");
838 new_entry->t =
839 (struct ebt_entry_target *)t;
840 }
841 break;
842 }
843 if (c == 's') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000844 ebt_check_option(&replace.flags, OPT_SOURCE);
845 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000846 new_entry->invflags |= EBT_ISOURCE;
847
848 if (optind > argc)
849 print_error("No source mac "
850 "specified");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000851 if (ebt_get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000852 new_entry->sourcemac, new_entry->sourcemsk))
853 print_error("Problem with specified "
854 "source mac");
855 new_entry->bitmask |= EBT_SOURCEMAC;
856 break;
857 }
858 if (c == 'd') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000859 ebt_check_option(&replace.flags, OPT_DEST);
860 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000861 new_entry->invflags |= EBT_IDEST;
862
863 if (optind > argc)
864 print_error("No destination mac "
865 "specified");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000866 if (ebt_get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000867 new_entry->destmac, new_entry->destmsk))
868 print_error("Problem with specified "
869 "destination mac");
870 new_entry->bitmask |= EBT_DESTMAC;
871 break;
872 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000873 ebt_check_option(&replace.flags, OPT_PROTOCOL);
874 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000875 new_entry->invflags |= EBT_IPROTO;
876
877 if (optind > argc)
878 print_error("No protocol specified");
879 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
880 i = strtol(argv[optind - 1], &buffer, 16);
881 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
882 print_error("Problem with the specified "
883 "protocol");
884 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +0000885 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000886 struct ethertypeent *ent;
887
888 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
889 new_entry->bitmask |= EBT_802_3;
890 break;
891 }
892 ent = getethertypebyname(argv[optind - 1]);
893 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000894 print_error("Problem with the specified"
895 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000896 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +0000897 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000898 if (new_entry->ethproto < 1536 &&
899 !(new_entry->bitmask & EBT_802_3))
900 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000901 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000902 break;
903
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000904 case 4 : /* Lc */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000905 ebt_check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000906 if (replace.command != 'L')
907 print_error("Use --Lc with -L");
908 if (replace.flags & LIST_X)
909 print_error("--Lx not compatible with --Lc");
910 replace.flags |= LIST_C;
911 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000912 case 5 : /* Ln */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000913 ebt_check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000914 if (replace.command != 'L')
915 print_error("Use --Ln with -L");
916 if (replace.flags & LIST_X)
917 print_error("--Lx not compatible with --Ln");
918 replace.flags |= LIST_N;
919 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000920 case 6 : /* Lx */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000921 ebt_check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000922 if (replace.command != 'L')
923 print_error("Use --Lx with -L");
924 if (replace.flags & LIST_C)
925 print_error("--Lx not compatible with --Lc");
926 if (replace.flags & LIST_N)
927 print_error("--Lx not compatible with --Ln");
928 replace.flags |= LIST_X;
929 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000930 case 12 : /* Lmac2 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000931 ebt_check_option(&replace.flags, LIST_MAC2);
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000932 if (replace.command != 'L')
933 print_error("Use --Lmac2 with -L");
934 replace.flags |= LIST_MAC2;
935 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000936 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +0000937 replace.command = c;
938 if (replace.flags & OPT_COMMAND)
939 print_error("Multiple commands not allowed");
940 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +0000941 if (!replace.filename)
942 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000943 /*
944 * get the information from the file
945 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000946 ebt_get_table(&replace);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000947 /*
948 * we don't want the kernel giving us its counters, they would
949 * overwrite the counters extracted from the file
950 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000951 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000952 /*
953 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +0000954 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000955 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000956 replace.filename = NULL;
957 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000958 case 7 : /* atomic-init */
959 case 10: /* atomic-save */
960 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +0000961 replace.command = c;
962 if (replace.flags & OPT_COMMAND)
963 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +0000964 if (c != 11 && !replace.filename)
965 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +0000966 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +0000967 {
968 char *tmp = replace.filename;
969
970 tmp = replace.filename;
971 /* get the kernel table */
972 replace.filename = NULL;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000973 ebt_get_kernel_table(&replace, table);
Bart De Schuymer5885b362002-12-03 20:51:36 +0000974 replace.filename = tmp;
975 }
Bart De Schuymer5885b362002-12-03 20:51:36 +0000976 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000977 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +0000978 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000979 print_error("--atomic has to come before"
980 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +0000981 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +0000982 replace.filename = (char *)malloc(strlen(optarg) + 1);
983 strcpy(replace.filename, optarg);
984 break;
Bart De Schuymera615b962002-11-03 14:54:09 +0000985 case 1 :
986 if (!strcmp(optarg, "!"))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000987 ebt_check_inverse(optarg);
Bart De Schuymera615b962002-11-03 14:54:09 +0000988 else
989 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000990 /*
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000991 * ebt_check_inverse() did optind++
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000992 */
Bart De Schuymera615b962002-11-03 14:54:09 +0000993 optind--;
994 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000995 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000996 /*
997 * is it a target option?
998 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000999 t = (struct ebt_u_target *)new_entry->t;
1000 if ((t->parse(c - t->option_offset, argv, argc,
1001 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001002 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001003
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001004 /*
1005 * is it a match_option?
1006 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001007 for (m = ebt_matches; m; m = m->next)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001008 if (m->parse(c - m->option_offset, argv,
1009 argc, new_entry, &m->flags, &m->m))
1010 break;
1011
1012 if (m != NULL) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001013 if (m->used == 0) {
1014 ebt_add_match(new_entry, m);
1015 m->used = 1;
1016 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001017 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018 }
1019
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001020 /*
1021 * is it a watcher option?
1022 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001023 for (w = ebt_watchers; w; w = w->next)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001024 if (w->parse(c-w->option_offset, argv,
1025 argc, new_entry, &w->flags, &w->w))
1026 break;
1027
1028 if (w == NULL)
1029 print_error("Unknown argument");
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001030 if (w->used == 0) {
1031 ebt_add_watcher(new_entry, w);
1032 w->used = 1;
1033 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001034check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00001035 if (replace.command != 'A' && replace.command != 'I' &&
1036 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001037 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001038 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001039 ebt_invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 }
1041
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001042 if ( !table && !(table = ebt_find_table(replace.name)) )
Bart De Schuymer25c741d2002-06-23 18:54:34 +00001043 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001044
1045 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
1046 replace.flags & OPT_ZERO )
1047 print_error("Command -Z only allowed together with command -L");
1048
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001049 /*
1050 * do this after parsing everything, so we can print specific info
1051 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001052 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
1053 print_help();
1054
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001055 /*
1056 * do the final checks
1057 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001058 if (replace.command == 'A' || replace.command == 'I' ||
1059 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001060 /*
1061 * this will put the hook_mask right for the chains
1062 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001063 ebt_check_for_loops(&replace);
1064 entries = ebt_to_chain(&replace);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001065 m_l = new_entry->m_list;
1066 w_l = new_entry->w_list;
1067 t = (struct ebt_u_target *)new_entry->t;
1068 while (m_l) {
1069 m = (struct ebt_u_match *)(m_l->m);
1070 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001071 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001072 m_l = m_l->next;
1073 }
1074 while (w_l) {
1075 w = (struct ebt_u_watcher *)(w_l->w);
1076 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001077 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001078 w_l = w_l->next;
1079 }
1080 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001081 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001082 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001083 /*
1084 * so, the extensions can work with the host endian
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001085 * the kernel does not have to do this of course
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001086 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001087 new_entry->ethproto = htons(new_entry->ethproto);
1088
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001089 if (replace.command == 'P') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001090 if (replace.selected_chain < NF_BR_NUMHOOKS &&
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001091 policy == EBT_RETURN)
1092 print_error("Policy RETURN only allowed for user "
1093 "defined chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001094 ebt_change_policy(&replace, policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001095 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001096 list_rules();
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001097 if (replace.flags & OPT_ZERO) {
1098 replace.selected_chain = zerochain;
1099 ebt_zero_counters(&replace);
1100 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001101 exit(0);
1102 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001103 if (replace.flags & OPT_ZERO) {
1104 replace.selected_chain = zerochain;
1105 ebt_zero_counters(&replace);
1106 } else if (replace.command == 'F')
1107 ebt_flush_chains(&replace);
1108 else if (replace.command == 'A' || replace.command == 'I') {
1109 ebt_add_rule(&replace, new_entry, rule_nr);
1110 ebt_check_for_loops(&replace);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001111 /*
1112 * do the final_check(), for all entries
1113 * needed when adding a rule that has a chain target
1114 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001115 i = -1;
1116 while (1) {
1117 struct ebt_u_entry *e;
1118
1119 i++;
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001120 entries = ebt_nr_to_chain(&replace, i);
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001121 if (!entries) {
1122 if (i < NF_BR_NUMHOOKS)
1123 continue;
1124 else
1125 break;
1126 }
1127 e = entries->entries;
1128 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001129 /*
1130 * userspace extensions use host endian
1131 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001132 e->ethproto = ntohs(e->ethproto);
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001133 ebt_do_final_checks(&replace, e, entries);
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001134 e->ethproto = htons(e->ethproto);
1135 e = e->next;
1136 }
1137 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001138 } else if (replace.command == 'D')
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001139 ebt_delete_rule(&replace, new_entry, rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001140 /*
1141 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
1142 * --init-table fall through
1143 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001144
1145 if (table->check)
1146 table->check(&replace);
1147
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001148 ebt_deliver_table(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001149
Bart De Schuymered053432002-07-21 19:35:39 +00001150 if (replace.counterchanges)
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001151 ebt_deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001152 return 0;
1153}