blob: 58dad06a022e55ba290e56eea8160667d76d21e1 [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 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
Bart De Schuymer64182a32004-01-21 20:39:54 +0000228 ent = getethertypebynumber
229 (ntohs(hlp->ethproto));
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000230 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000231 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000232 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000233 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000234 }
235 }
236 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000237 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000238 if (hlp->invflags & EBT_ISOURCE)
239 printf("! ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000240 ebt_print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000241 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000242 }
243 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000244 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000245 if (hlp->invflags & EBT_IDEST)
246 printf("! ");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000247 ebt_print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000248 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000249 }
250 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000251 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000252 if (hlp->invflags & EBT_IIN)
253 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000254 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000255 }
256 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000257 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000258 if (hlp->invflags & EBT_ILOGICALIN)
259 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000260 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000261 }
262 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000263 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000264 if (hlp->invflags & EBT_ILOGICALOUT)
265 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000266 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000267 }
268 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000269 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000270 if (hlp->invflags & EBT_IOUT)
271 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000272 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000273 }
274
275 m_l = hlp->m_list;
276 while (m_l) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000277 m = ebt_find_match(m_l->m->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000278 if (!m)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000279 ebt_print_bug("Match not found");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000280 m->print(hlp, m_l->m);
281 m_l = m_l->next;
282 }
283 w_l = hlp->w_list;
284 while (w_l) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000285 w = ebt_find_watcher(w_l->w->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000286 if (!w)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000287 ebt_print_bug("Watcher not found");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000288 w->print(hlp, w_l->w);
289 w_l = w_l->next;
290 }
291
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000292 printf("-j ");
293 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
294 printf("%s ", hlp->t->u.name);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000295 t = ebt_find_target(hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000296 if (!t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000297 ebt_print_bug("Target not found");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000298 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000299 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000300 printf(", pcnt = %llu -- bcnt = %llu",
301 replace.counters[entries->counter_offset + i].pcnt,
302 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000303 printf("\n");
304 hlp = hlp->next;
305 }
306}
307
Bart De Schuymer62423742002-07-14 19:06:20 +0000308static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000309{
310 struct ebt_u_match_list *m_l;
311 struct ebt_u_watcher_list *w_l;
312
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000313 PRINT_VERSION;
314 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000315"Usage:\n"
316"ebtables -[ADI] chain rule-specification [options]\n"
317"ebtables -P chain target\n"
318"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000319"ebtables -[NX] [chain]\n"
320"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000321"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000322"--append -A chain : append to chain\n"
323"--delete -D chain : delete matching rule from chain\n"
324"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000325"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000326"--list -L [chain] : list the rules in a chain or in all chains\n"
327"--flush -F [chain] : delete all rules in chain or in all chains\n"
328"--init-table : replace the kernel table with the initial table\n"
329"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
330"--policy -P chain target : change policy on chain to target\n"
331"--new-chain -N chain : create a user defined chain\n"
332"--rename-chain -E old new : rename a chain\n"
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000333"--delete-chain -X [chain] : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000334"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
335"--atomic-init : put the initial kernel table into <FILE>\n"
336"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000337"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000338"Options:\n"
339"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
340"--src -s [!] address[/mask]: source mac address\n"
341"--dst -d [!] address[/mask]: destination mac address\n"
342"--in-if -i [!] name : network input interface name\n"
343"--out-if -o [!] name : network output interface name\n"
344"--logical-in [!] name : logical bridge input interface name\n"
345"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000346"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000347"--version -V : print package version\n\n"
348"Environment variable:\n"
349ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
350"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000351 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 Schuymer64182a32004-01-21 20:39:54 +0000445#define print_if_l_error ebt_print_error("Interface name length must be less " \
Bart De Schuymerc5075142002-08-18 14:21:19 +0000446 "than %d", IFNAMSIZ)
Bart De Schuymer64182a32004-01-21 20:39:54 +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
458#define OPT_KERNELDATA 0x800 /* if set, we already have loaded the table
459 * in userspace */
Bart De Schuymer5885b362002-12-03 20:51:36 +0000460/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000461int main(int argc, char *argv[])
462{
Bart De Schuymer923a5732002-08-11 12:01:33 +0000463 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000464 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000465 /*
466 * this special one for the -Z option (we can have -Z <this> -L <that>)
467 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000468 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000469 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000470 int rule_nr = 0; /* used for -[D,I] */
471 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000472 struct ebt_u_target *t;
473 struct ebt_u_match *m;
474 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000475 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000476 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000477 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000478
Bart De Schuymera615b962002-11-03 14:54:09 +0000479 opterr = 0;
480
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000481 ebt_iterate_matches(merge_match);
482 ebt_iterate_watchers(merge_watcher);
483 ebt_iterate_targets(merge_target);
484
Bart De Schuymer64182a32004-01-21 20:39:54 +0000485 buffer = getenv(ATOMIC_ENV_VARIABLE);
486 if (buffer) {
487 replace.filename = malloc(strlen(buffer)+1);
488 if (!replace.filename)
489 ebt_print_memory();
490 memcpy(replace.filename, buffer, strlen(buffer)+1);
491 buffer = NULL;
492 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000493 /*
494 * initialize the table name, OPT_ flags, selected hook and command
495 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000496 strcpy(replace.name, "filter");
497 replace.flags = 0;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000498 replace.selected_chain = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000499 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +0000500 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000501
502 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
503 if (!new_entry)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000504 ebt_print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000505 /*
506 * put some sane values in our new entry
507 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000508 ebt_initialize_entry(new_entry);
509 new_entry->replace = &replace;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000511 /*
512 * The scenario induced by this loop makes that:
513 * '-t' ,'-M' and --atomic (if specified) have to come
514 * before '-A' and the like
515 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000516
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000517 /*
518 * getopt saves the day
519 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000520 while ((c = getopt_long(argc, argv,
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000521 "-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 +0000522 switch (c) {
523
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000524 case 'A': /* add a rule */
525 case 'D': /* delete a rule */
526 case 'P': /* define policy */
527 case 'I': /* insert a rule */
528 case 'N': /* make a user defined chain */
529 case 'E': /* rename chain */
530 case 'X': /* delete chain */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000531 /* We allow -N chainname -P policy */
532 if (replace.command == 'N' && c == 'P') {
533 replace.command = c;
534 optind--;
535 goto handle_P;
536 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000537 replace.command = c;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000538 replace.flags |= OPT_COMMAND;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000539 if (!(replace.flags & OPT_KERNELDATA)) {
540 ebt_get_kernel_table(&replace, table, 0);
541 replace.flags |= OPT_KERNELDATA;
542 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000543 if (optarg && (optarg[0] == '-' ||
544 !strcmp(optarg, "!")))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000545 ebt_print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000546 if (c == 'N') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000547 ebt_new_chain(&replace, optarg, EBT_ACCEPT);
Bart De Schuymer64182a32004-01-21 20:39:54 +0000548 /* This is needed to get -N x -P y working */
549 replace.selected_chain =
550 ebt_get_chainnr(&replace, optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000551 break;
552 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000553 if (c == 'X') {
554 char *opt;
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000555
556 if (!optarg && (optind >= argc ||
Bart De Schuymerf3196482003-07-25 12:53:17 +0000557 (argv[optind][0] == '-'
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000558 && strcmp(argv[optind], "!")))) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000559 replace.selected_chain = -1;
560 ebt_delete_chain(&replace);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000561 break;
562 }
563 if (optarg)
564 opt = optarg;
565 else {
566 opt = argv[optind];
567 optind++;
568 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000569 if ((replace.selected_chain =
570 ebt_get_chainnr(&replace, opt)) == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000571 ebt_print_error("Chain %s doesn't "
572 "exist", optarg);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000573 ebt_delete_chain(&replace);
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000574 break;
575 }
576
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000577 if ((replace.selected_chain =
578 ebt_get_chainnr(&replace, optarg)) == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000579 ebt_print_error("Chain %s doesn't exist",
580 optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000581 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000582 if (optind >= argc || argv[optind][0] == '-' ||
583 !strcmp(argv[optind], "!"))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000584 ebt_print_error("No new chain name "
585 "specified");
586 if (strlen(argv[optind])>=EBT_CHAIN_MAXNAMELEN)
587 ebt_print_error("Chain name len can't "
588 "exceed %d",
589 EBT_CHAIN_MAXNAMELEN - 1);
590 if (ebt_get_chainnr(&replace, argv[optind]) !=
591 -1)
592 ebt_print_error("Chain %s already "
593 "exists", argv[optind]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000594 if (ebt_find_target(argv[optind]))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000595 ebt_print_error("Target with name %s "
596 "exists", argv[optind]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000597 ebt_rename_chain(&replace, argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000598 optind++;
599 break;
600 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000601
Bart De Schuymercc440052002-11-06 21:10:33 +0000602 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000603 (argv[optind][0] != '-' ||
Bart De Schuymer64182a32004-01-21 20:39:54 +0000604 (argv[optind][1] >= '0' &&
605 argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +0000606 if (parse_delete_rule(argv[optind],
607 &rule_nr, &rule_nr_end))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000608 ebt_print_error("Problem with the "
Bart De Schuymercc440052002-11-06 21:10:33 +0000609 "specified rule number(s)");
610 optind++;
611 }
612 if (c == 'I') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000613 if (optind >= argc ||
614 (argv[optind][0] == '-' &&
615 (argv[optind][1] < '0' ||
616 argv[optind][1] > '9')))
617 ebt_print_error("No rulenr for -I"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000618 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +0000620 if (*buffer != '\0')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000621 ebt_print_error("Problem with the "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 "specified rule number");
623 optind++;
624 }
625 if (c == 'P') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000626handle_P:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000627 if (optind >= argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000628 ebt_print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000629 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000630 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000631 if (!strcmp(argv[optind],
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000632 ebt_standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000633 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000634 if (policy == EBT_CONTINUE)
635 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000636 break;
637 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000638 if (policy == 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000639 ebt_print_error("Wrong policy");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000640 optind++;
641 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000642 break;
643
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000644 case 'L': /* list */
645 case 'F': /* flush */
646 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000647 if (c == 'Z') {
648 if (replace.flags & OPT_ZERO)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000649 ebt_print_error("Multiple commands"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000650 " not allowed");
651 if ( (replace.flags & OPT_COMMAND &&
652 replace.command != 'L'))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000653 ebt_print_error("command -Z only "
654 "allowed together with command -L");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000655 replace.flags |= OPT_ZERO;
656 } else {
657 replace.command = c;
658 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000659 ebt_print_error("Multiple commands"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660 " not allowed");
661 replace.flags |= OPT_COMMAND;
662 }
Bart De Schuymer64182a32004-01-21 20:39:54 +0000663 ebt_get_kernel_table(&replace, table, 0);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000664 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000665 if (optarg) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000666 if ( (i = ebt_get_chainnr(&replace, optarg)) ==
667 -1 )
668 ebt_print_error("Bad chain");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000669 } else
670 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000671 if ((i = ebt_get_chainnr(&replace,
672 argv[optind])) == -1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000673 ebt_print_error("Bad chain");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000674 optind++;
675 }
676 if (i != -1) {
677 if (c == 'Z')
678 zerochain = i;
679 else
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000680 replace.selected_chain = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000681 }
682 break;
683
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000684 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000685 replace.command = 'V';
686 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000687 ebt_print_error("Multiple commands not "
688 "allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000689 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000690 exit(0);
691
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000692 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000693 if (replace.command != 'h')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000694 ebt_print_error("Please put the -M option "
695 "earlier");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000696 ebt_modprobe = optarg;
Bart De Schuymerc8531032002-06-14 21:55:29 +0000697 break;
698
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000699 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000700 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000701 ebt_print_error("Multiple commands not "
702 "allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000703 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000704 /*
705 * All other arguments should be extension names
706 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000707 while (optind < argc) {
708 struct ebt_u_match *m;
709 struct ebt_u_watcher *w;
710
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000711 if (!strcasecmp("list_extensions",
712 argv[optind]))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000713 ebt_list_extensions();
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000714
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000715 if ((m = ebt_find_match(argv[optind])))
716 ebt_add_match(new_entry, m);
717 else if ((w = ebt_find_watcher(argv[optind])))
718 ebt_add_watcher(new_entry, w);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000719 else {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000720 if (!(t = ebt_find_target(argv[optind])))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000721 ebt_print_error("Extension %s "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000722 "not found", argv[optind]);
723 if (replace.flags & OPT_JUMP)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000724 ebt_print_error("Sorry, you "
725 "can only see help for one "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000726 "target extension each time");
727 replace.flags |= OPT_JUMP;
728 new_entry->t =
729 (struct ebt_entry_target *)t;
730 }
731 optind++;
732 }
733 break;
734
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000735 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000736 if (replace.command != 'h')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000737 ebt_print_error("Please put the -t option "
738 "first");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000739 ebt_check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000740 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000741 ebt_print_error("Table name too long");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000742 strcpy(replace.name, optarg);
743 break;
744
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000745 case 'i': /* input interface */
746 case 2 : /* logical input interface */
747 case 'o': /* output interface */
748 case 3 : /* logical output interface */
749 case 'j': /* target */
750 case 'p': /* net family protocol */
751 case 's': /* source mac */
752 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000753 if ((replace.flags & OPT_COMMAND) == 0)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000754 ebt_print_error("No command specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000755 if ( replace.command != 'A' &&
756 replace.command != 'D' && replace.command != 'I')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000757 ebt_print_error("Command and option do not "
758 "match");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000759 if (c == 'i') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000760 ebt_check_option(&replace.flags, OPT_IN);
761 if (replace.selected_chain > 2 &&
762 replace.selected_chain < NF_BR_BROUTING)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000763 ebt_print_error("Use in-interface "
764 "only in "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000765 "INPUT, FORWARD, PREROUTING and"
766 "BROUTING 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_IIN;
769
770 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000771 ebt_print_error("No in-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000772 "specified");
773 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000774 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000775 strcpy(new_entry->in, argv[optind - 1]);
776 break;
777 }
778 if (c == 2) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000779 ebt_check_option(&replace.flags, OPT_LOGICALIN);
780 if (replace.selected_chain > 2 &&
781 replace.selected_chain < NF_BR_BROUTING)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000782 ebt_print_error("Use logical "
783 "in-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000784 "only in INPUT, FORWARD, "
785 "PREROUTING and BROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000786 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000787 new_entry->invflags |= EBT_ILOGICALIN;
788
789 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000790 ebt_print_error("No logical "
791 "in-interface specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000792 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_in, argv[optind - 1]);
795 break;
796 }
797 if (c == 'o') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000798 ebt_check_option(&replace.flags, OPT_OUT);
799 if (replace.selected_chain < 2)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000800 ebt_print_error("Use out-interface "
801 "only in OUTPUT, FORWARD and "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000802 "POSTROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000803 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000804 new_entry->invflags |= EBT_IOUT;
805
806 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000807 ebt_print_error("No out-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000808 "specified");
809
810 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000811 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000812 strcpy(new_entry->out, argv[optind - 1]);
813 break;
814 }
815 if (c == 3) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000816 ebt_check_option(&replace.flags,
817 OPT_LOGICALOUT);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000818 if (replace.selected_chain < 2)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000819 ebt_print_error("Use logical "
820 "out-interface "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000821 "only in OUTPUT, FORWARD and "
822 "POSTROUTING chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000823 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000824 new_entry->invflags |= EBT_ILOGICALOUT;
825
826 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000827 ebt_print_error("No logical "
828 "out-interface specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000829
830 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +0000831 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000832 strcpy(new_entry->logical_out,
833 argv[optind - 1]);
834 break;
835 }
836 if (c == 'j') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000837 ebt_check_option(&replace.flags, OPT_JUMP);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000838 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
839 if (!strcmp(optarg,
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000840 ebt_standard_targets[i])) {
841 t = ebt_find_target(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000842 EBT_STANDARD_TARGET);
843 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000844 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000845 break;
846 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000847 if (-i - 1 == EBT_RETURN) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000848 if (replace.selected_chain <
849 NF_BR_NUMHOOKS)
850 ebt_print_error("Return target"
851 " only for user defined "
852 "chains");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000853 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000854 if (i != NUM_STANDARD_TARGETS)
855 break;
Bart De Schuymer64182a32004-01-21 20:39:54 +0000856 if ((i = ebt_get_chainnr(&replace, optarg)) !=
857 -1) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000858 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000859 ebt_print_error("don't jump"
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000860 " to a standard chain");
861 t = ebt_find_target(EBT_STANDARD_TARGET);
862 ((struct ebt_standard_target *)
863 t->t)->verdict = i - NF_BR_NUMHOOKS;
864 break;
865 } else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000866 /*
867 * must be an extension then
868 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000869 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000870
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000871 t = ebt_find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000872 /*
873 * -j standard not allowed either
874 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000875 if (!t || t ==
876 (struct ebt_u_target *)new_entry->t)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000877 ebt_print_error("Illegal "
878 "target name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000879 new_entry->t =
880 (struct ebt_entry_target *)t;
881 }
882 break;
883 }
884 if (c == 's') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000885 ebt_check_option(&replace.flags, OPT_SOURCE);
886 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000887 new_entry->invflags |= EBT_ISOURCE;
888
889 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000890 ebt_print_error("No source mac "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000891 "specified");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000892 if (ebt_get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000893 new_entry->sourcemac, new_entry->sourcemsk))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000894 ebt_print_error("Problem with "
895 "specified source mac");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000896 new_entry->bitmask |= EBT_SOURCEMAC;
897 break;
898 }
899 if (c == 'd') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000900 ebt_check_option(&replace.flags, OPT_DEST);
901 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000902 new_entry->invflags |= EBT_IDEST;
903
904 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000905 ebt_print_error("No destination mac "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000906 "specified");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000907 if (ebt_get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000908 new_entry->destmac, new_entry->destmsk))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000909 ebt_print_error("Problem with "
910 "specified destination mac");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000911 new_entry->bitmask |= EBT_DESTMAC;
912 break;
913 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000914 ebt_check_option(&replace.flags, OPT_PROTOCOL);
915 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000916 new_entry->invflags |= EBT_IPROTO;
917
918 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000919 ebt_print_error("No protocol specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000920 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
921 i = strtol(argv[optind - 1], &buffer, 16);
922 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000923 ebt_print_error("Problem with the specified "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000924 "protocol");
925 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +0000926 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000927 struct ethertypeent *ent;
928
929 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
930 new_entry->bitmask |= EBT_802_3;
931 break;
932 }
933 ent = getethertypebyname(argv[optind - 1]);
934 if (!ent)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000935 ebt_print_error("Problem with the "
936 "specified protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000937 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +0000938 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000939 if (new_entry->ethproto < 1536 &&
940 !(new_entry->bitmask & EBT_802_3))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000941 ebt_print_error("Sorry, protocols have values "
942 "above or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000943 break;
944
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000945 case 4 : /* Lc */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000946 ebt_check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000947 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000948 ebt_print_error("Use --Lc with -L");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000949 if (replace.flags & LIST_X)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000950 ebt_print_error("--Lx not compatible with "
951 "--Lc");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000952 replace.flags |= LIST_C;
953 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000954 case 5 : /* Ln */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000955 ebt_check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000956 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000957 ebt_print_error("Use --Ln with -L");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000958 if (replace.flags & LIST_X)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000959 ebt_print_error("--Lx not compatible with "
960 "--Ln");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000961 replace.flags |= LIST_N;
962 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000963 case 6 : /* Lx */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000964 ebt_check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000965 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000966 ebt_print_error("Use --Lx with -L");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000967 if (replace.flags & LIST_C)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000968 ebt_print_error("--Lx not compatible with "
969 "--Lc");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000970 if (replace.flags & LIST_N)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000971 ebt_print_error("--Lx not compatible with "
972 "--Ln");
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000973 replace.flags |= LIST_X;
974 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000975 case 12 : /* Lmac2 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000976 ebt_check_option(&replace.flags, LIST_MAC2);
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000977 if (replace.command != 'L')
Bart De Schuymer64182a32004-01-21 20:39:54 +0000978 ebt_print_error("Use --Lmac2 with -L");
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000979 replace.flags |= LIST_MAC2;
980 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000981 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +0000982 replace.command = c;
983 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000984 ebt_print_error("Multiple commands not "
985 "allowed");
Bart De Schuymer62423742002-07-14 19:06:20 +0000986 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +0000987 if (!replace.filename)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000988 ebt_print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000989 /*
990 * get the information from the file
991 */
Bart De Schuymer64182a32004-01-21 20:39:54 +0000992 ebt_get_table(&replace, 0);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000993 /*
Bart De Schuymer64182a32004-01-21 20:39:54 +0000994 * we don't want the kernel giving us its counters,
995 * they would overwrite the counters extracted from
996 * the file
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000997 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000998 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000999 /*
1000 * make sure the table will be written to the kernel
1001 */
Bart De Schuymer64182a32004-01-21 20:39:54 +00001002 free(replace.filename);
Bart De Schuymer62423742002-07-14 19:06:20 +00001003 replace.filename = NULL;
1004 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001005 case 7 : /* atomic-init */
1006 case 10: /* atomic-save */
1007 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00001008 replace.command = c;
1009 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001010 ebt_print_error("Multiple commands not "
1011 "allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00001012 if (c != 11 && !replace.filename)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001013 ebt_print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00001014 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001015 {
1016 char *tmp = replace.filename;
Bart De Schuymer64182a32004-01-21 20:39:54 +00001017 int init = 1;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001018
Bart De Schuymer64182a32004-01-21 20:39:54 +00001019 if (c == 10)
1020 init = 0;
Bart De Schuymer5885b362002-12-03 20:51:36 +00001021 tmp = replace.filename;
1022 /* get the kernel table */
1023 replace.filename = NULL;
Bart De Schuymer64182a32004-01-21 20:39:54 +00001024 ebt_get_kernel_table(&replace, table, init);
Bart De Schuymer5885b362002-12-03 20:51:36 +00001025 replace.filename = tmp;
1026 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00001027 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001028 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00001029 if (replace.flags & OPT_COMMAND)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001030 ebt_print_error("--atomic has to come before"
1031 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00001032 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00001033 replace.filename = (char *)malloc(strlen(optarg) + 1);
1034 strcpy(replace.filename, optarg);
1035 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00001036 case 1 :
1037 if (!strcmp(optarg, "!"))
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001038 ebt_check_inverse(optarg);
Bart De Schuymera615b962002-11-03 14:54:09 +00001039 else
Bart De Schuymer64182a32004-01-21 20:39:54 +00001040 ebt_print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001041 /*
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001042 * ebt_check_inverse() did optind++
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001043 */
Bart De Schuymera615b962002-11-03 14:54:09 +00001044 optind--;
1045 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001046 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001047 /*
1048 * is it a target option?
1049 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 t = (struct ebt_u_target *)new_entry->t;
1051 if ((t->parse(c - t->option_offset, argv, argc,
1052 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001053 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001054
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001055 /*
1056 * is it a match_option?
1057 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001058 for (m = ebt_matches; m; m = m->next)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001059 if (m->parse(c - m->option_offset, argv,
1060 argc, new_entry, &m->flags, &m->m))
1061 break;
1062
1063 if (m != NULL) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001064 if (m->used == 0) {
1065 ebt_add_match(new_entry, m);
1066 m->used = 1;
1067 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001068 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001069 }
1070
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001071 /*
1072 * is it a watcher option?
1073 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001074 for (w = ebt_watchers; w; w = w->next)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001075 if (w->parse(c-w->option_offset, argv,
1076 argc, new_entry, &w->flags, &w->w))
1077 break;
1078
1079 if (w == NULL)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001080 ebt_print_error("Unknown argument");
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001081 if (w->used == 0) {
1082 ebt_add_watcher(new_entry, w);
1083 w->used = 1;
1084 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001085check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00001086 if (replace.command != 'A' && replace.command != 'I' &&
1087 replace.command != 'D')
Bart De Schuymer64182a32004-01-21 20:39:54 +00001088 ebt_print_error("Extensions only for -A, "
1089 "-I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001090 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001091 ebt_invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001092 }
1093
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001094 if ( !table && !(table = ebt_find_table(replace.name)) )
Bart De Schuymer64182a32004-01-21 20:39:54 +00001095 ebt_print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001096
1097 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
1098 replace.flags & OPT_ZERO )
Bart De Schuymer64182a32004-01-21 20:39:54 +00001099 ebt_print_error("Command -Z only allowed together with "
1100 "command -L");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001101
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001102 /*
1103 * do this after parsing everything, so we can print specific info
1104 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001105 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
1106 print_help();
1107
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001108 /*
1109 * do the final checks
1110 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001111 if (replace.command == 'A' || replace.command == 'I' ||
1112 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001113 /*
1114 * this will put the hook_mask right for the chains
1115 */
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001116 ebt_check_for_loops(&replace);
1117 entries = ebt_to_chain(&replace);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001118 m_l = new_entry->m_list;
1119 w_l = new_entry->w_list;
1120 t = (struct ebt_u_target *)new_entry->t;
1121 while (m_l) {
1122 m = (struct ebt_u_match *)(m_l->m);
1123 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001124 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001125 m_l = m_l->next;
1126 }
1127 while (w_l) {
1128 w = (struct ebt_u_watcher *)(w_l->w);
1129 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001130 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001131 w_l = w_l->next;
1132 }
1133 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001134 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001135 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001136 /*
1137 * so, the extensions can work with the host endian
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001138 * the kernel does not have to do this of course
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001139 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001140 new_entry->ethproto = htons(new_entry->ethproto);
1141
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001142 if (replace.command == 'P') {
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001143 if (replace.selected_chain < NF_BR_NUMHOOKS &&
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001144 policy == EBT_RETURN)
Bart De Schuymer64182a32004-01-21 20:39:54 +00001145 ebt_print_error("Policy RETURN only allowed for user "
1146 "defined chains");
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001147 ebt_change_policy(&replace, policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00001148 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001149 list_rules();
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001150 if (replace.flags & OPT_ZERO) {
1151 replace.selected_chain = zerochain;
1152 ebt_zero_counters(&replace);
1153 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001154 exit(0);
1155 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001156 if (replace.flags & OPT_ZERO) {
1157 replace.selected_chain = zerochain;
1158 ebt_zero_counters(&replace);
1159 } else if (replace.command == 'F')
1160 ebt_flush_chains(&replace);
1161 else if (replace.command == 'A' || replace.command == 'I') {
1162 ebt_add_rule(&replace, new_entry, rule_nr);
1163 ebt_check_for_loops(&replace);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001164 /*
1165 * do the final_check(), for all entries
1166 * needed when adding a rule that has a chain target
1167 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001168 i = -1;
1169 while (1) {
1170 struct ebt_u_entry *e;
1171
1172 i++;
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001173 entries = ebt_nr_to_chain(&replace, i);
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001174 if (!entries) {
1175 if (i < NF_BR_NUMHOOKS)
1176 continue;
1177 else
1178 break;
1179 }
1180 e = entries->entries;
1181 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001182 /*
1183 * userspace extensions use host endian
1184 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001185 e->ethproto = ntohs(e->ethproto);
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001186 ebt_do_final_checks(&replace, e, entries);
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001187 e->ethproto = htons(e->ethproto);
1188 e = e->next;
1189 }
1190 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001191 } else if (replace.command == 'D')
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001192 ebt_delete_rule(&replace, new_entry, rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001193 /*
1194 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
1195 * --init-table fall through
1196 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197
1198 if (table->check)
1199 table->check(&replace);
1200
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001201 ebt_deliver_table(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001202
Bart De Schuymered053432002-07-21 19:35:39 +00001203 if (replace.counterchanges)
Bart De Schuymer8339ff12004-01-14 20:05:27 +00001204 ebt_deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001205 return 0;
1206}