blob: f4225de1b8cc14606854471c2d0e29f32b8e4a5b [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)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000117 ebt_print_bug("merge wrong");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000118 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)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000126 ebt_print_memory();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000127 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 Schuymer37d520d2004-10-24 07:36:15 +0000158/* be backwards compatible, so don't use '+' in kernel */
159#define IF_WILDCARD 1
160static void print_iface(const char *iface)
161{
162 char *c;
163
164 if ((c = strchr(iface, IF_WILDCARD)))
165 *c = '+';
166 printf("%s ", iface);
167 if (c)
168 *c = IF_WILDCARD;
169}
170
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000171/*
172 * we use replace.flags, so we can't use the following values:
173 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
174 */
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000175#define LIST_N 0x04
176#define LIST_C 0x08
177#define LIST_X 0x10
178#define LIST_MAC2 0x20
179
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000180/*
181 * helper function for list_rules()
182 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000183static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000184{
185 int i, j, space = 0, digits;
186 struct ebt_u_entry *hlp;
187 struct ebt_u_match_list *m_l;
188 struct ebt_u_watcher_list *w_l;
189 struct ebt_u_match *m;
190 struct ebt_u_watcher *w;
191 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000192
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000193 if (replace.flags & LIST_MAC2)
194 ebt_printstyle_mac = 2;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000195 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000196 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
197 printf("ebtables -t %s -P %s %s\n", replace.name,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000198 entries->name, ebt_standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000199 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000200 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
201 entries->name, entries->nentries,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000202 ebt_standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000203 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000204
Bart De Schuymer60332e02002-06-23 08:01:47 +0000205 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000206 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000207 space++;
208 i /= 10;
209 }
210
Bart De Schuymer60332e02002-06-23 08:01:47 +0000211 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000212 if (replace.flags & LIST_N) {
213 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000214 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000215 j = i + 1;
216 while (j > 9) {
217 digits++;
218 j /= 10;
219 }
220 for (j = 0; j < space - digits; j++)
221 printf(" ");
222 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000223 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000224 if (replace.flags & LIST_X)
225 printf("ebtables -t %s -A %s ",
226 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000227
Bart De Schuymercaa9a462004-12-05 15:59:17 +0000228 /* The standard target's print() uses this to find out
229 * the name of a udc */
230 hlp->replace = &replace;
231
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000232 /*
233 * Don't print anything about the protocol if no protocol was
234 * specified, obviously this means any protocol will do.
235 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000236 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000237 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000238 if (hlp->invflags & EBT_IPROTO)
239 printf("! ");
240 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000241 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000242 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000243 struct ethertypeent *ent;
244
Bart De Schuymer64182a32004-01-21 20:39:54 +0000245 ent = getethertypebynumber
246 (ntohs(hlp->ethproto));
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000247 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000248 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000249 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000250 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000251 }
252 }
253 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000254 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000255 if (hlp->invflags & EBT_ISOURCE)
256 printf("! ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000257 ebt_print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000258 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000259 }
260 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000261 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000262 if (hlp->invflags & EBT_IDEST)
263 printf("! ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000264 ebt_print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000265 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 }
267 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000268 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000269 if (hlp->invflags & EBT_IIN)
270 printf("! ");
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000271 print_iface(hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000272 }
273 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000274 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000275 if (hlp->invflags & EBT_ILOGICALIN)
276 printf("! ");
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000277 print_iface(hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000278 }
279 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000280 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000281 if (hlp->invflags & EBT_ILOGICALOUT)
282 printf("! ");
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000283 print_iface(hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000284 }
285 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000286 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000287 if (hlp->invflags & EBT_IOUT)
288 printf("! ");
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000289 print_iface(hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000290 }
291
292 m_l = hlp->m_list;
293 while (m_l) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000294 m = ebt_find_match(m_l->m->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000295 if (!m)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000296 ebt_print_bug("Match not found");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000297 m->print(hlp, m_l->m);
298 m_l = m_l->next;
299 }
300 w_l = hlp->w_list;
301 while (w_l) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000302 w = ebt_find_watcher(w_l->w->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000303 if (!w)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000304 ebt_print_bug("Watcher not found");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000305 w->print(hlp, w_l->w);
306 w_l = w_l->next;
307 }
308
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000309 printf("-j ");
310 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
311 printf("%s ", hlp->t->u.name);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000312 t = ebt_find_target(hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000313 if (!t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000314 ebt_print_bug("Target not found");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000315 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000316 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000317 printf(", pcnt = %llu -- bcnt = %llu",
318 replace.counters[entries->counter_offset + i].pcnt,
319 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000320 printf("\n");
321 hlp = hlp->next;
322 }
323}
324
Bart De Schuymer62423742002-07-14 19:06:20 +0000325static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000326{
327 struct ebt_u_match_list *m_l;
328 struct ebt_u_watcher_list *w_l;
329
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000330 PRINT_VERSION;
331 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000332"Usage:\n"
333"ebtables -[ADI] chain rule-specification [options]\n"
334"ebtables -P chain target\n"
335"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000336"ebtables -[NX] [chain]\n"
337"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000338"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000339"--append -A chain : append to chain\n"
340"--delete -D chain : delete matching rule from chain\n"
341"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000342"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000343"--list -L [chain] : list the rules in a chain or in all chains\n"
344"--flush -F [chain] : delete all rules in chain or in all chains\n"
345"--init-table : replace the kernel table with the initial table\n"
346"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
347"--policy -P chain target : change policy on chain to target\n"
348"--new-chain -N chain : create a user defined chain\n"
349"--rename-chain -E old new : rename a chain\n"
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000350"--delete-chain -X [chain] : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000351"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
352"--atomic-init : put the initial kernel table into <FILE>\n"
353"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000354"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000355"Options:\n"
356"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
357"--src -s [!] address[/mask]: source mac address\n"
358"--dst -d [!] address[/mask]: destination mac address\n"
359"--in-if -i [!] name : network input interface name\n"
360"--out-if -o [!] name : network output interface name\n"
361"--logical-in [!] name : logical bridge input interface name\n"
362"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000363"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000364"--version -V : print package version\n\n"
365"Environment variable:\n"
366ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
367"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000368 m_l = new_entry->m_list;
369 while (m_l) {
370 ((struct ebt_u_match *)m_l->m)->help();
371 printf("\n");
372 m_l = m_l->next;
373 }
374 w_l = new_entry->w_list;
375 while (w_l) {
376 ((struct ebt_u_watcher *)w_l->w)->help();
377 printf("\n");
378 w_l = w_l->next;
379 }
380 ((struct ebt_u_target *)new_entry->t)->help();
381 printf("\n");
382 if (table->help)
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000383 table->help(ebt_hooknames);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000384 exit(0);
385}
386
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000387/*
388 * execute command L
389 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000390static void list_rules()
391{
392 int i;
393
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000394 if (!(replace.flags & LIST_X))
395 printf("Bridge table: %s\n", table->name);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000396 if (replace.selected_chain != -1) {
397 list_em(ebt_to_chain(&replace));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000398 } else {
399 struct ebt_u_chain_list *cl = replace.udc;
400
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000401 /*
402 * create new chains and rename standard chains when necessary
403 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000404 if (replace.flags & LIST_X) {
405 while (cl) {
406 printf("ebtables -t %s -N %s\n", replace.name,
407 cl->udc->name);
408 cl = cl->next;
409 }
410 cl = replace.udc;
411 for (i = 0; i < NF_BR_NUMHOOKS; i++)
412 if (replace.valid_hooks & (1 << i) &&
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000413 strcmp(replace.hook_entry[i]->name,
414 ebt_hooknames[i]))
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000415 printf("ebtables -t %s -E %s %s\n",
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000416 replace.name, ebt_hooknames[i],
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000417 replace.hook_entry[i]->name);
418 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000419 i = 0;
420 while (1) {
421 if (i < NF_BR_NUMHOOKS) {
422 if (replace.valid_hooks & (1 << i))
423 list_em(replace.hook_entry[i]);
424 i++;
425 continue;
426 } else {
427 if (!cl)
428 break;
429 list_em(cl->udc);
430 cl = cl->next;
431 }
432 }
433 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000434}
435
Bart De Schuymercc440052002-11-06 21:10:33 +0000436static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
437{
438 char *colon = strchr(argv, ':'), *buffer;
439
440 if (colon) {
441 *colon = '\0';
442 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000443 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +0000444 else {
445 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000446 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +0000447 return -1;
448 }
449 }
450 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000451 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +0000452 else {
453 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000454 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +0000455 return -1;
456 }
457 if (!colon)
458 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +0000459 return 0;
460}
461
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000462static void parse_iface(char *iface, char *option)
463{
464 char *c;
465
466 if ((c = strchr(iface, '+'))) {
467 if (*(c + 1) != '\0') {
468 ebt_print_error("Spurious characters after '+' "
469 "wildcard for %s", option);
470 } else
471 *c = IF_WILDCARD;
472 }
473}
474
Bart De Schuymer64182a32004-01-21 20:39:54 +0000475#define print_if_l_error ebt_print_error("Interface name length must be less " \
Bart De Schuymerc5075142002-08-18 14:21:19 +0000476 "than %d", IFNAMSIZ)
Bart De Schuymer9557dce2004-11-11 17:56:02 +0000477#define print_epoto_error(__proto) ebt_print_error("Problem with the specified"\
478 " Ethernet protocol (%s), perhaps "_PATH_ETHERTYPES " is missing", __proto);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000479#define OPT_COMMAND 0x01
480#define OPT_TABLE 0x02
481#define OPT_IN 0x04
482#define OPT_OUT 0x08
483#define OPT_JUMP 0x10
484#define OPT_PROTOCOL 0x20
485#define OPT_SOURCE 0x40
486#define OPT_DEST 0x80
487#define OPT_ZERO 0x100
488#define OPT_LOGICALIN 0x200
489#define OPT_LOGICALOUT 0x400
490#define OPT_KERNELDATA 0x800 /* if set, we already have loaded the table
491 * in userspace */
Bart De Schuymer5885b362002-12-03 20:51:36 +0000492/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000493int main(int argc, char *argv[])
494{
Bart De Schuymer923a5732002-08-11 12:01:33 +0000495 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000496 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000497 /*
498 * this special one for the -Z option (we can have -Z <this> -L <that>)
499 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000500 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000501 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000502 int rule_nr = 0; /* used for -[D,I] */
503 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000504 struct ebt_u_target *t;
505 struct ebt_u_match *m;
506 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000507 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000508 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000509 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510
Bart De Schuymera615b962002-11-03 14:54:09 +0000511 opterr = 0;
512
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000513 ebt_iterate_matches(merge_match);
514 ebt_iterate_watchers(merge_watcher);
515 ebt_iterate_targets(merge_target);
516
Bart De Schuymer64182a32004-01-21 20:39:54 +0000517 buffer = getenv(ATOMIC_ENV_VARIABLE);
518 if (buffer) {
519 replace.filename = malloc(strlen(buffer)+1);
520 if (!replace.filename)
521 ebt_print_memory();
522 memcpy(replace.filename, buffer, strlen(buffer)+1);
523 buffer = NULL;
524 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000525 /*
526 * initialize the table name, OPT_ flags, selected hook and command
527 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000528 strcpy(replace.name, "filter");
529 replace.flags = 0;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000530 replace.selected_chain = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000531 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +0000532 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000533
534 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
535 if (!new_entry)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000536 ebt_print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000537 /*
538 * put some sane values in our new entry
539 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000540 ebt_initialize_entry(new_entry);
541 new_entry->replace = &replace;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000542
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000543 /*
544 * The scenario induced by this loop makes that:
545 * '-t' ,'-M' and --atomic (if specified) have to come
546 * before '-A' and the like
547 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000549 /*
550 * getopt saves the day
551 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552 while ((c = getopt_long(argc, argv,
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000553 "-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 +0000554 switch (c) {
555
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000556 case 'A': /* add a rule */
557 case 'D': /* delete a rule */
558 case 'P': /* define policy */
559 case 'I': /* insert a rule */
560 case 'N': /* make a user defined chain */
561 case 'E': /* rename chain */
562 case 'X': /* delete chain */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000563 /* We allow -N chainname -P policy */
564 if (replace.command == 'N' && c == 'P') {
565 replace.command = c;
566 optind--;
567 goto handle_P;
568 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000569 replace.command = c;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000570 replace.flags |= OPT_COMMAND;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000571 if (!(replace.flags & OPT_KERNELDATA)) {
572 ebt_get_kernel_table(&replace, table, 0);
573 replace.flags |= OPT_KERNELDATA;
574 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000575 if (optarg && (optarg[0] == '-' ||
576 !strcmp(optarg, "!")))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000577 ebt_print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000578 if (c == 'N') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000579 ebt_new_chain(&replace, optarg, EBT_ACCEPT);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000580 /* This is needed to get -N x -P y working */
581 replace.selected_chain =
582 ebt_get_chainnr(&replace, optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000583 break;
584 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000585 if (c == 'X') {
586 char *opt;
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000587
588 if (!optarg && (optind >= argc ||
Bart De Schuymerf3196482003-07-25 12:53:17 +0000589 (argv[optind][0] == '-'
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000590 && strcmp(argv[optind], "!")))) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000591 replace.selected_chain = -1;
592 ebt_delete_chain(&replace);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000593 break;
594 }
595 if (optarg)
596 opt = optarg;
597 else {
598 opt = argv[optind];
599 optind++;
600 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000601 if ((replace.selected_chain =
602 ebt_get_chainnr(&replace, opt)) == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000603 ebt_print_error("Chain %s doesn't "
604 "exist", optarg);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000605 ebt_delete_chain(&replace);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000606 break;
607 }
608
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000609 if ((replace.selected_chain =
610 ebt_get_chainnr(&replace, optarg)) == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000611 ebt_print_error("Chain %s doesn't exist",
612 optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000613 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000614 if (optind >= argc || argv[optind][0] == '-' ||
615 !strcmp(argv[optind], "!"))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000616 ebt_print_error("No new chain name "
617 "specified");
618 if (strlen(argv[optind])>=EBT_CHAIN_MAXNAMELEN)
619 ebt_print_error("Chain name len can't "
620 "exceed %d",
621 EBT_CHAIN_MAXNAMELEN - 1);
622 if (ebt_get_chainnr(&replace, argv[optind]) !=
623 -1)
624 ebt_print_error("Chain %s already "
625 "exists", argv[optind]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000626 if (ebt_find_target(argv[optind]))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000627 ebt_print_error("Target with name %s "
628 "exists", argv[optind]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000629 ebt_rename_chain(&replace, argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000630 optind++;
631 break;
632 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000633
Bart De Schuymercc440052002-11-06 21:10:33 +0000634 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000635 (argv[optind][0] != '-' ||
Bart De Schuymer64182a32004-01-21 20:39:54 +0000636 (argv[optind][1] >= '0' &&
637 argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +0000638 if (parse_delete_rule(argv[optind],
639 &rule_nr, &rule_nr_end))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000640 ebt_print_error("Problem with the "
Bart De Schuymercc440052002-11-06 21:10:33 +0000641 "specified rule number(s)");
642 optind++;
643 }
644 if (c == 'I') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000645 if (optind >= argc ||
646 (argv[optind][0] == '-' &&
647 (argv[optind][1] < '0' ||
648 argv[optind][1] > '9')))
649 ebt_print_error("No rulenr for -I"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000650 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000651 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000652 if (*buffer != '\0')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000653 ebt_print_error("Problem with the "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654 "specified rule number");
655 optind++;
656 }
657 if (c == 'P') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000658handle_P:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000659 if (optind >= argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000660 ebt_print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000661 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000662 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000663 if (!strcmp(argv[optind],
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000664 ebt_standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000665 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000666 if (policy == EBT_CONTINUE)
667 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000668 break;
669 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000670 if (policy == 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000671 ebt_print_error("Wrong policy");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000672 optind++;
673 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000674 break;
675
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000676 case 'L': /* list */
677 case 'F': /* flush */
678 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000679 if (c == 'Z') {
680 if (replace.flags & OPT_ZERO)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000681 ebt_print_error("Multiple commands"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000682 " not allowed");
683 if ( (replace.flags & OPT_COMMAND &&
684 replace.command != 'L'))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000685 ebt_print_error("command -Z only "
686 "allowed together with command -L");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000687 replace.flags |= OPT_ZERO;
688 } else {
689 replace.command = c;
690 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000691 ebt_print_error("Multiple commands"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000692 " not allowed");
693 replace.flags |= OPT_COMMAND;
694 }
Bart De Schuymer64182a32004-01-21 20:39:54 +0000695 ebt_get_kernel_table(&replace, table, 0);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000696 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000697 if (optarg) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000698 if ( (i = ebt_get_chainnr(&replace, optarg)) ==
699 -1 )
700 ebt_print_error("Bad chain");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000701 } else
702 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000703 if ((i = ebt_get_chainnr(&replace,
704 argv[optind])) == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000705 ebt_print_error("Bad chain");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000706 optind++;
707 }
708 if (i != -1) {
709 if (c == 'Z')
710 zerochain = i;
711 else
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000712 replace.selected_chain = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000713 }
714 break;
715
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000716 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000717 replace.command = 'V';
718 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000719 ebt_print_error("Multiple commands not "
720 "allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000721 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000722 exit(0);
723
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000724 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000725 if (replace.command != 'h')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000726 ebt_print_error("Please put the -M option "
727 "earlier");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000728 ebt_modprobe = optarg;
Bart De Schuymerc8531032002-06-14 21:55:29 +0000729 break;
730
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000731 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000732 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000733 ebt_print_error("Multiple commands not "
734 "allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000735 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000736 /*
737 * All other arguments should be extension names
738 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000739 while (optind < argc) {
740 struct ebt_u_match *m;
741 struct ebt_u_watcher *w;
742
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000743 if (!strcasecmp("list_extensions",
744 argv[optind]))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000745 ebt_list_extensions();
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000746
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000747 if ((m = ebt_find_match(argv[optind])))
748 ebt_add_match(new_entry, m);
749 else if ((w = ebt_find_watcher(argv[optind])))
750 ebt_add_watcher(new_entry, w);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000751 else {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000752 if (!(t = ebt_find_target(argv[optind])))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000753 ebt_print_error("Extension %s "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000754 "not found", argv[optind]);
755 if (replace.flags & OPT_JUMP)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000756 ebt_print_error("Sorry, you "
757 "can only see help for one "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000758 "target extension each time");
759 replace.flags |= OPT_JUMP;
760 new_entry->t =
761 (struct ebt_entry_target *)t;
762 }
763 optind++;
764 }
765 break;
766
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000767 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000768 if (replace.command != 'h')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000769 ebt_print_error("Please put the -t option "
770 "first");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000771 ebt_check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000772 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000773 ebt_print_error("Table name too long");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000774 strcpy(replace.name, optarg);
775 break;
776
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000777 case 'i': /* input interface */
778 case 2 : /* logical input interface */
779 case 'o': /* output interface */
780 case 3 : /* logical output interface */
781 case 'j': /* target */
782 case 'p': /* net family protocol */
783 case 's': /* source mac */
784 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000785 if ((replace.flags & OPT_COMMAND) == 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000786 ebt_print_error("No command specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000787 if ( replace.command != 'A' &&
788 replace.command != 'D' && replace.command != 'I')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000789 ebt_print_error("Command and option do not "
790 "match");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000791 if (c == 'i') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000792 ebt_check_option(&replace.flags, OPT_IN);
793 if (replace.selected_chain > 2 &&
794 replace.selected_chain < NF_BR_BROUTING)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000795 ebt_print_error("Use in-interface "
796 "only in "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000797 "INPUT, FORWARD, PREROUTING and"
798 "BROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000799 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000800 new_entry->invflags |= EBT_IIN;
801
802 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000803 ebt_print_error("No in-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000804 "specified");
805 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000806 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000807 strcpy(new_entry->in, argv[optind - 1]);
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000808 parse_iface(new_entry->in, "-i");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000809 break;
810 }
811 if (c == 2) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000812 ebt_check_option(&replace.flags, OPT_LOGICALIN);
813 if (replace.selected_chain > 2 &&
814 replace.selected_chain < NF_BR_BROUTING)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000815 ebt_print_error("Use logical "
816 "in-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000817 "only in INPUT, FORWARD, "
818 "PREROUTING and BROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000819 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000820 new_entry->invflags |= EBT_ILOGICALIN;
821
822 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000823 ebt_print_error("No logical "
824 "in-interface specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000825 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000826 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000827 strcpy(new_entry->logical_in, argv[optind - 1]);
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000828 parse_iface(new_entry->logical_in,
829 "--logical-in");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000830 break;
831 }
832 if (c == 'o') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000833 ebt_check_option(&replace.flags, OPT_OUT);
834 if (replace.selected_chain < 2)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000835 ebt_print_error("Use out-interface "
836 "only in OUTPUT, FORWARD and "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000837 "POSTROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000838 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000839 new_entry->invflags |= EBT_IOUT;
840
841 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000842 ebt_print_error("No out-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000843 "specified");
844
845 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000846 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000847 strcpy(new_entry->out, argv[optind - 1]);
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000848 parse_iface(new_entry->out, "-o");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000849 break;
850 }
851 if (c == 3) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000852 ebt_check_option(&replace.flags,
853 OPT_LOGICALOUT);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000854 if (replace.selected_chain < 2)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000855 ebt_print_error("Use logical "
856 "out-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000857 "only in OUTPUT, FORWARD and "
858 "POSTROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000859 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000860 new_entry->invflags |= EBT_ILOGICALOUT;
861
862 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000863 ebt_print_error("No logical "
864 "out-interface specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000865
866 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000867 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000868 strcpy(new_entry->logical_out,
869 argv[optind - 1]);
Bart De Schuymer37d520d2004-10-24 07:36:15 +0000870 parse_iface(new_entry->logical_out,
871 "--logical-out");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000872 break;
873 }
874 if (c == 'j') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000875 ebt_check_option(&replace.flags, OPT_JUMP);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000876 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
877 if (!strcmp(optarg,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000878 ebt_standard_targets[i])) {
879 t = ebt_find_target(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000880 EBT_STANDARD_TARGET);
881 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000882 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000883 break;
884 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000885 if (-i - 1 == EBT_RETURN) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000886 if (replace.selected_chain <
887 NF_BR_NUMHOOKS)
888 ebt_print_error("Return target"
889 " only for user defined "
890 "chains");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000891 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000892 if (i != NUM_STANDARD_TARGETS)
893 break;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000894 if ((i = ebt_get_chainnr(&replace, optarg)) !=
895 -1) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000896 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000897 ebt_print_error("don't jump"
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000898 " to a standard chain");
899 t = ebt_find_target(EBT_STANDARD_TARGET);
900 ((struct ebt_standard_target *)
901 t->t)->verdict = i - NF_BR_NUMHOOKS;
902 break;
903 } else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000904 /*
905 * must be an extension then
906 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000907 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000908
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000909 t = ebt_find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000910 /*
911 * -j standard not allowed either
912 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000913 if (!t || t ==
914 (struct ebt_u_target *)new_entry->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000915 ebt_print_error("Illegal "
916 "target name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000917 new_entry->t =
918 (struct ebt_entry_target *)t;
919 }
920 break;
921 }
922 if (c == 's') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000923 ebt_check_option(&replace.flags, OPT_SOURCE);
924 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925 new_entry->invflags |= EBT_ISOURCE;
926
927 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000928 ebt_print_error("No source mac "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000929 "specified");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000930 if (ebt_get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000931 new_entry->sourcemac, new_entry->sourcemsk))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000932 ebt_print_error("Problem with "
933 "specified source mac");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000934 new_entry->bitmask |= EBT_SOURCEMAC;
935 break;
936 }
937 if (c == 'd') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000938 ebt_check_option(&replace.flags, OPT_DEST);
939 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000940 new_entry->invflags |= EBT_IDEST;
941
942 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000943 ebt_print_error("No destination mac "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000944 "specified");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000945 if (ebt_get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000946 new_entry->destmac, new_entry->destmsk))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000947 ebt_print_error("Problem with "
948 "specified destination mac");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949 new_entry->bitmask |= EBT_DESTMAC;
950 break;
951 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000952 ebt_check_option(&replace.flags, OPT_PROTOCOL);
953 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000954 new_entry->invflags |= EBT_IPROTO;
955
956 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000957 ebt_print_error("No protocol specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000958 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
959 i = strtol(argv[optind - 1], &buffer, 16);
960 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000961 ebt_print_error("Problem with the specified "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 "protocol");
963 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +0000964 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000965 struct ethertypeent *ent;
966
967 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
968 new_entry->bitmask |= EBT_802_3;
969 break;
970 }
971 ent = getethertypebyname(argv[optind - 1]);
972 if (!ent)
Bart De Schuymer9557dce2004-11-11 17:56:02 +0000973 print_epoto_error(argv[optind - 1]);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000974 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +0000975 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000976 if (new_entry->ethproto < 1536 &&
977 !(new_entry->bitmask & EBT_802_3))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000978 ebt_print_error("Sorry, protocols have values "
979 "above or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000980 break;
981
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000982 case 4 : /* Lc */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000983 ebt_check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000984 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000985 ebt_print_error("Use --Lc with -L");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000986 if (replace.flags & LIST_X)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000987 ebt_print_error("--Lx not compatible with "
988 "--Lc");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000989 replace.flags |= LIST_C;
990 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000991 case 5 : /* Ln */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000992 ebt_check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000993 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000994 ebt_print_error("Use --Ln with -L");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000995 if (replace.flags & LIST_X)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000996 ebt_print_error("--Lx not compatible with "
997 "--Ln");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000998 replace.flags |= LIST_N;
999 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001000 case 6 : /* Lx */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001001 ebt_check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001002 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +00001003 ebt_print_error("Use --Lx with -L");
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001004 if (replace.flags & LIST_C)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001005 ebt_print_error("--Lx not compatible with "
1006 "--Lc");
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001007 if (replace.flags & LIST_N)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001008 ebt_print_error("--Lx not compatible with "
1009 "--Ln");
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001010 replace.flags |= LIST_X;
1011 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +00001012 case 12 : /* Lmac2 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001013 ebt_check_option(&replace.flags, LIST_MAC2);
Bart De Schuymer22d03a22003-05-03 20:28:22 +00001014 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +00001015 ebt_print_error("Use --Lmac2 with -L");
Bart De Schuymer22d03a22003-05-03 20:28:22 +00001016 replace.flags |= LIST_MAC2;
1017 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001018 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00001019 replace.command = c;
1020 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001021 ebt_print_error("Multiple commands not "
1022 "allowed");
Bart De Schuymer62423742002-07-14 19:06:20 +00001023 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001024 if (!replace.filename)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001025 ebt_print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001026 /*
1027 * get the information from the file
1028 */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001029 ebt_get_table(&replace, 0);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001030 /*
Bart De Schuymer64182a32004-01-21 20:39:54 +00001031 * we don't want the kernel giving us its counters,
1032 * they would overwrite the counters extracted from
1033 * the file
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001034 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001035 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001036 /*
1037 * make sure the table will be written to the kernel
1038 */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001039 free(replace.filename);
Bart De Schuymer62423742002-07-14 19:06:20 +00001040 replace.filename = NULL;
1041 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001042 case 7 : /* atomic-init */
1043 case 10: /* atomic-save */
1044 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00001045 replace.command = c;
1046 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001047 ebt_print_error("Multiple commands not "
1048 "allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00001049 if (c != 11 && !replace.filename)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001050 ebt_print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00001051 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001052 {
1053 char *tmp = replace.filename;
Bart De Schuymer64182a32004-01-21 20:39:54 +00001054 int init = 1;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001055
Bart De Schuymer64182a32004-01-21 20:39:54 +00001056 if (c == 10)
1057 init = 0;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001058 tmp = replace.filename;
1059 /* get the kernel table */
1060 replace.filename = NULL;
Bart De Schuymer64182a32004-01-21 20:39:54 +00001061 ebt_get_kernel_table(&replace, table, init);
Bart De Schuymer5885b362002-12-03 20:51:36 +00001062 replace.filename = tmp;
1063 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00001064 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001065 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00001066 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001067 ebt_print_error("--atomic has to come before"
1068 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00001069 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00001070 replace.filename = (char *)malloc(strlen(optarg) + 1);
1071 strcpy(replace.filename, optarg);
1072 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00001073 case 1 :
1074 if (!strcmp(optarg, "!"))
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001075 ebt_check_inverse(optarg);
Bart De Schuymera615b962002-11-03 14:54:09 +00001076 else
Bart De Schuymer64182a32004-01-21 20:39:54 +00001077 ebt_print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001078 /*
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001079 * ebt_check_inverse() did optind++
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001080 */
Bart De Schuymera615b962002-11-03 14:54:09 +00001081 optind--;
1082 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001083 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001084 /*
1085 * is it a target option?
1086 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001087 t = (struct ebt_u_target *)new_entry->t;
1088 if ((t->parse(c - t->option_offset, argv, argc,
1089 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001090 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001091
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001092 /*
1093 * is it a match_option?
1094 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001095 for (m = ebt_matches; m; m = m->next)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001096 if (m->parse(c - m->option_offset, argv,
1097 argc, new_entry, &m->flags, &m->m))
1098 break;
1099
1100 if (m != NULL) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001101 if (m->used == 0) {
1102 ebt_add_match(new_entry, m);
1103 m->used = 1;
1104 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001105 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001106 }
1107
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001108 /*
1109 * is it a watcher option?
1110 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001111 for (w = ebt_watchers; w; w = w->next)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001112 if (w->parse(c-w->option_offset, argv,
1113 argc, new_entry, &w->flags, &w->w))
1114 break;
1115
1116 if (w == NULL)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001117 ebt_print_error("Unknown argument");
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001118 if (w->used == 0) {
1119 ebt_add_watcher(new_entry, w);
1120 w->used = 1;
1121 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001122check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00001123 if (replace.command != 'A' && replace.command != 'I' &&
1124 replace.command != 'D')
Bart De Schuymer64182a32004-01-21 20:39:54 +00001125 ebt_print_error("Extensions only for -A, "
1126 "-I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001127 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001128 ebt_invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001129 }
1130
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001131 if ( !table && !(table = ebt_find_table(replace.name)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +00001132 ebt_print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001133
1134 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
1135 replace.flags & OPT_ZERO )
Bart De Schuymer64182a32004-01-21 20:39:54 +00001136 ebt_print_error("Command -Z only allowed together with "
1137 "command -L");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001138
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001139 /*
1140 * do this after parsing everything, so we can print specific info
1141 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001142 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
1143 print_help();
1144
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001145 /*
1146 * do the final checks
1147 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001148 if (replace.command == 'A' || replace.command == 'I' ||
1149 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001150 /*
1151 * this will put the hook_mask right for the chains
1152 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001153 ebt_check_for_loops(&replace);
1154 entries = ebt_to_chain(&replace);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001155 m_l = new_entry->m_list;
1156 w_l = new_entry->w_list;
1157 t = (struct ebt_u_target *)new_entry->t;
1158 while (m_l) {
1159 m = (struct ebt_u_match *)(m_l->m);
1160 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001161 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001162 m_l = m_l->next;
1163 }
1164 while (w_l) {
1165 w = (struct ebt_u_watcher *)(w_l->w);
1166 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001167 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001168 w_l = w_l->next;
1169 }
1170 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001171 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001172 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001173 /*
1174 * so, the extensions can work with the host endian
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001175 * the kernel does not have to do this of course
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001176 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001177 new_entry->ethproto = htons(new_entry->ethproto);
1178
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001179 if (replace.command == 'P') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001180 if (replace.selected_chain < NF_BR_NUMHOOKS &&
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001181 policy == EBT_RETURN)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001182 ebt_print_error("Policy RETURN only allowed for user "
1183 "defined chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001184 ebt_change_policy(&replace, policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001185 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001186 list_rules();
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001187 if (replace.flags & OPT_ZERO) {
1188 replace.selected_chain = zerochain;
1189 ebt_zero_counters(&replace);
1190 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001191 exit(0);
1192 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001193 if (replace.flags & OPT_ZERO) {
1194 replace.selected_chain = zerochain;
1195 ebt_zero_counters(&replace);
1196 } else if (replace.command == 'F')
1197 ebt_flush_chains(&replace);
1198 else if (replace.command == 'A' || replace.command == 'I') {
1199 ebt_add_rule(&replace, new_entry, rule_nr);
1200 ebt_check_for_loops(&replace);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001201 /*
1202 * do the final_check(), for all entries
1203 * needed when adding a rule that has a chain target
1204 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001205 i = -1;
1206 while (1) {
1207 struct ebt_u_entry *e;
1208
1209 i++;
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001210 entries = ebt_nr_to_chain(&replace, i);
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001211 if (!entries) {
1212 if (i < NF_BR_NUMHOOKS)
1213 continue;
1214 else
1215 break;
1216 }
1217 e = entries->entries;
1218 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001219 /*
1220 * userspace extensions use host endian
1221 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001222 e->ethproto = ntohs(e->ethproto);
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001223 ebt_do_final_checks(&replace, e, entries);
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001224 e->ethproto = htons(e->ethproto);
1225 e = e->next;
1226 }
1227 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001228 } else if (replace.command == 'D')
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001229 ebt_delete_rule(&replace, new_entry, rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001230 /*
1231 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
1232 * --init-table fall through
1233 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001234
1235 if (table->check)
1236 table->check(&replace);
1237
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001238 ebt_deliver_table(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001239
Bart De Schuymered053432002-07-21 19:35:39 +00001240 if (replace.counterchanges)
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001241 ebt_deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001242 return 0;
1243}