iptables.c revision 228e98dd6303af11925235af4cf3c3ec450f3f41
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Code to take an iptables-style command line and do it. */
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*
4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	This program is free software; you can redistribute it and/or modify
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	it under the terms of the GNU General Public License as published by
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	the Free Software Foundation; either version 2 of the License, or
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	(at your option) any later version.
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *
11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	This program is distributed in the hope that it will be useful,
12e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	but WITHOUT ANY WARRANTY; without even the implied warranty of
13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	GNU General Public License for more details.
15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *
16e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	You should have received a copy of the GNU General Public License
17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	along with this program; if not, write to the Free Software
18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */
20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h>
22e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h>
23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <netdb.h>
24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <errno.h>
25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h>
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <dlfcn.h>
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <ctype.h>
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdarg.h>
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <limits.h>
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <iptables.h>
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef TRUE
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define TRUE 1
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef FALSE
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FALSE 0
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables"
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_NUMERIC	0x0001
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_NOCOUNTS	0x0002
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_KILOMEGAGIGA 0x0004
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_OPTIONS	0x0008
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_NOTABLE	0x0010
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_NOTARGET	0x0020
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_VIA		0x0040
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_NONEWLINE	0x0080
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_LINENUMBERS 0x0100
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			| FMT_NUMERIC | FMT_NOTABLE)
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_NONE		0x0000U
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_INSERT		0x0001U
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_DELETE		0x0002U
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_DELETE_NUM		0x0004U
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_REPLACE		0x0008U
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_APPEND		0x0010U
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_LIST		0x0020U
66e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_FLUSH		0x0040U
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_ZERO		0x0080U
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_NEW_CHAIN		0x0100U
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_DELETE_CHAIN	0x0200U
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_SET_POLICY		0x0400U
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_CHECK		0x0800U
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define CMD_RENAME_CHAIN	0x1000U
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define NUMBER_OF_CMD	13
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				 'N', 'X', 'P', 'C', 'E' };
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPTION_OFFSET 256
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_NONE	0x00000U
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_NUMERIC	0x00001U
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_SOURCE	0x00002U
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_DESTINATION	0x00004U
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_PROTOCOL	0x00008U
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_JUMP	0x00010U
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_VERBOSE	0x00020U
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_EXPANDED	0x00040U
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_VIANAMEIN	0x00080U
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_VIANAMEOUT	0x00100U
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_FRAGMENT    0x00200U
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define OPT_LINENUMBERS 0x00400U
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define NUMBER_OF_OPT	11
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char optflags[NUMBER_OF_OPT]
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '3'};
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct option original_opts[] = {
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "append", 1, 0, 'A' },
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "delete", 1, 0,  'D' },
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "insert", 1, 0,  'I' },
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "replace", 1, 0,  'R' },
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "list", 2, 0,  'L' },
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "flush", 2, 0,  'F' },
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "zero", 2, 0,  'Z' },
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "check", 1, 0,  'C' },
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "new-chain", 1, 0,  'N' },
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "delete-chain", 2, 0,  'X' },
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "rename-chain", 2, 0,  'E' },
107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "policy", 1, 0,  'P' },
108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "source", 1, 0, 's' },
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "destination", 1, 0,  'd' },
110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "src", 1, 0,  's' }, /* synonym */
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "dst", 1, 0,  'd' }, /* synonym */
1122e0a3216c501753709781769f83e29821e62c805Rusty Russell	{ "protocol", 1, 0,  'p' },
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "in-interface", 1, 0, 'i' },
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "jump", 1, 0, 'j' },
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "table", 1, 0, 't' },
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "match", 1, 0, 'm' },
117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "numeric", 0, 0, 'n' },
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "out-interface", 1, 0, 'o' },
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "verbose", 0, 0, 'v' },
120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "exact", 0, 0, 'x' },
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "fragments", 0, 0, 'f' },
122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "version", 0, 0, 'V' },
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "help", 2, 0, 'h' },
124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "line-numbers", 0, 0, '0' },
125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ 0 }
126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1289e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell#if 0
1299e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russellstatic struct ipt_entry_target *
1309e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russellipt_get_target(struct ipt_entry *e)
1319e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell{
1329e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	return (void *)e + e->target_offset;
1339e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell}
1349e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell#endif
1359e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell
136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct option *opts = original_opts;
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int global_option_offset = 0;
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Table of legal combinations of commands and options.  If any of the
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * given commands make an option legal, that option is legal (applies to
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * CMD_LIST and CMD_ZERO only).
142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Key:
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *  +  compulsory
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *  x  illegal
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *     optional
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Well, it's better than "Re: Linux vs FreeBSD" */
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/*     -n  -s  -d  -p  -j  -v  -x  -i  -o  -f  --line */
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'},
153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'},
154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'},
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*REPLACE*/   {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'},
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*APPEND*/    {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x'},
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*LIST*/      {' ','x','x','x','x',' ',' ','x','x','x',' '},
158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*FLUSH*/     {'x','x','x','x','x',' ','x','x','x','x','x'},
159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*ZERO*/      {'x','x','x','x','x',' ','x','x','x','x','x'},
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x'},
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*CHECK*/     {'x','+','+','+','x',' ','x','+','+',' ','x'},
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x'}
165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int inverse_for_options[NUMBER_OF_OPT] =
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -n */ 0,
170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -s */ IPT_INV_SRCIP,
171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -d */ IPT_INV_DSTIP,
172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -p */ IPT_INV_PROTO,
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -j */ 0,
174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -v */ 0,
175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -x */ 0,
176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -i */ IPT_INV_VIA_IN,
177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -o */ IPT_INV_VIA_OUT,
178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* -f */ IPT_INV_FRAG,
179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*--line*/ 0
180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *program_version;
183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char *program_name;
184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1852e0a3216c501753709781769f83e29821e62c805Rusty Russell/* Keeping track of external matches and targets: linked lists.  */
186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptables_match *iptables_matches = NULL;
187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptables_target *iptables_targets = NULL;
188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Extra debugging from libiptc */
190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherextern void dump_entries(const iptc_handle_t handle);
191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* A few hardcoded protocols for 'all' and in case the user has no
193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   /etc/protocols */
194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct pprot {
195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *name;
196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	u_int8_t num;
197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const struct pprot chain_protos[] = {
200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "tcp", IPPROTO_TCP },
201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "udp", IPPROTO_UDP },
202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "icmp", IPPROTO_ICMP },
203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "all", 0 },
204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char *
207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherproto_to_name(u_int8_t proto)
208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (proto) {
212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct protoent *pent = getprotobynumber(proto);
213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (pent)
214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return pent->p_name;
215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (chain_protos[i].num == proto)
219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return chain_protos[i].name;
220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct in_addr *
225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdotted_to_addr(const char *dotted)
226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	static struct in_addr addr;
228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned char *addrp;
229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *p, *q;
230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int onebyte, i;
231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char buf[20];
232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* copy dotted string, because we need to modify it */
234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strncpy(buf, dotted, sizeof(buf) - 1);
235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	addrp = (unsigned char *) &(addr.s_addr);
236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	p = buf;
238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < 3; i++) {
239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((q = strchr(p, '.')) == NULL)
240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return (struct in_addr *) NULL;
241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*q = '\0';
243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((onebyte = string_to_number(p, 0, 255)) == -1)
244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return (struct in_addr *) NULL;
245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addrp[i] = (unsigned char) onebyte;
247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		p = q + 1;
248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* we've checked 3 bytes, now we check the last one */
251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((onebyte = string_to_number(p, 0, 255)) == -1)
252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (struct in_addr *) NULL;
253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	addrp[3] = (unsigned char) onebyte;
255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return &addr;
257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct in_addr *
260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchernetwork_to_addr(const char *name)
261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct netent *net;
263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	static struct in_addr addr;
264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((net = getnetbyname(name)) != NULL) {
266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (net->n_addrtype != AF_INET)
267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return (struct in_addr *) NULL;
268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addr.s_addr = htonl((unsigned long) net->n_net);
269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return &addr;
270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (struct in_addr *) NULL;
273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinaddrcpy(struct in_addr *dst, struct in_addr *src)
277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* memcpy(dst, src, sizeof(struct in_addr)); */
279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dst->s_addr = src->s_addr;
280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherexit_error(enum exittype status, char *msg, ...)
284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	va_list args;
286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	va_start(args, msg);
288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "%s v%s: ", program_name, program_version);
289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	vfprintf(stderr, msg, args);
290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	va_end(args);
291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "\n");
292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (status == PARAMETER_PROBLEM)
293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_tryhelp(status);
294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (status == VERSION_PROBLEM)
295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr,
296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			"Perhaps iptables or your kernel needs to be upgraded.\n");
297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	exit(status);
298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherexit_tryhelp(int status)
302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			program_name, program_name );
305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	exit(status);
306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherexit_printhelp(void)
310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
3112e0a3216c501753709781769f83e29821e62c805Rusty Russell	struct iptables_match *m = NULL;
3122e0a3216c501753709781769f83e29821e62c805Rusty Russell	struct iptables_target *t = NULL;
3132e0a3216c501753709781769f83e29821e62c805Rusty Russell
314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("%s v%s\n\n"
315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"Usage: %s -[ADC] chain rule-specification [options]\n"
316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -[RI] chain rulenum rule-specification [options]\n"
317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -D chain rulenum [options]\n"
318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -[LFZ] [chain] [options]\n"
319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -[NX] chain\n"
320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -E old-chain-name new-chain-name\n"
321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -P chain target [options]\n"
322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"       %s -h (print this help information)\n\n",
323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       program_name, program_version, program_name, program_name,
324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       program_name, program_name, program_name, program_name,
325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       program_name, program_name);
326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf(
328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"Commands:\n"
329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"Either long or short options are allowed.\n"
330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --append  -A chain		Append to chain\n"
331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --delete  -D chain		Delete matching rule from chain\n"
332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --delete  -D chain rulenum\n"
333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				Delete rule rulenum (1 = first) from chain\n"
334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --insert  -I chain [rulenum]\n"
335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				Insert in chain as rulenum (default 1=first)\n"
336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --replace -R chain rulenum\n"
337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				Replace rule rulenum (1 = first) in chain\n"
338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --list    -L [chain]		List the rules in a chain or all chains\n"
339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --flush   -F [chain]		Delete all rules in  chain or all chains\n"
340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --zero    -Z [chain]		Zero counters in chain or all chains\n"
341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --check   -C chain		Test this packet on chain\n"
342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --new     -N chain		Create a new user-defined chain\n"
343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --delete-chain\n"
344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"            -X [chain]		Delete a user-defined chain\n"
345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --policy  -P chain target\n"
346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				Change policy on chain to target\n"
347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --rename-chain\n"
348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"            -E old-chain new-chain\n"
349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				Change chain name, (moving any references)\n"
350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"Options:\n"
352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --proto	-p [!] proto	protocol: by number or name, eg. `tcp'\n"
353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --source	-s [!] address[/mask]\n"
354e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				source specification\n"
355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --destination -d [!] address[/mask]\n"
356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				destination specification\n"
357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --in-interface -i [!] input name[+]\n"
358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				network interface name ([+] for wildcard)\n"
359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --jump	-j target\n"
360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				target for rule\n"
361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --numeric	-n		numeric output of addresses and ports\n"
362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --out-interface -o [!] output name[+]\n"
363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				network interface name ([+] for wildcard)\n"
364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --table	-t table	table to manipulate (default: `filter')\n"
365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --verbose	-v		verbose mode\n"
366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"  --exact	-x		expand numbers (display exact values)\n"
367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"[!] --fragment	-f		match second or further fragments only\n"
368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"[!] --version	-V		print package version.\n");
369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
3702e0a3216c501753709781769f83e29821e62c805Rusty Russell	/* Print out any special helps. A user might like to be able to add a --help
3712e0a3216c501753709781769f83e29821e62c805Rusty Russell	   to the commandline, and see expected results. So we call help for all
3722e0a3216c501753709781769f83e29821e62c805Rusty Russell	   matches & targets */
3732e0a3216c501753709781769f83e29821e62c805Rusty Russell	for (t=iptables_targets;t;t=t->next) {
374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("\n");
3752e0a3216c501753709781769f83e29821e62c805Rusty Russell		t->help();
376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
3772e0a3216c501753709781769f83e29821e62c805Rusty Russell	for (m=iptables_matches;m;m=m->next) {
378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("\n");
3792e0a3216c501753709781769f83e29821e62c805Rusty Russell		m->help();
380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	exit(0);
382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchergeneric_opt_check(int command, int options)
386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int i, j, legal = 0;
388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Check that commands are valid with options.  Complicated by the
390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	 * fact that if an option is legal with *any* command given, it is
391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	 * legal overall (ie. -z and -l).
392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	 */
393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < NUMBER_OF_OPT; i++) {
394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (j = 0; j < NUMBER_OF_CMD; j++) {
397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!(command & (1<<j)))
398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				continue;
399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!(options & (1<<i))) {
401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				if (commands_v_options[j][i] == '+')
402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					exit_error(PARAMETER_PROBLEM,
403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   "You need to supply the `-%c' "
404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   "option for this command\n",
405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   optflags[i]);
406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			} else {
407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				if (commands_v_options[j][i] != 'x')
408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					legal = 1;
409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				else if (legal == 0)
410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					legal = -1;
411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
413e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (legal == -1)
414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Illegal option `-%c' with this command\n",
416e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   optflags[i]);
417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
418e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
420e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char
421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheropt2char(int option)
422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *ptr;
424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (ptr = optflags; option > 1; option >>= 1, ptr++);
425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return *ptr;
427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
428e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
429e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char
430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercmd2char(int option)
431e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *ptr;
433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return *ptr;
436e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheradd_command(int *cmd, const int newcmd, const int othercmds, int invert)
440e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (invert)
442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "unexpected ! flag");
443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*cmd & (~othercmds))
444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
446e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*cmd |= newcmd;
447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_inverse(const char option[], int *invert)
451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (option && strcmp(option, "!") == 0) {
453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (*invert)
454e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Multiple `!' flags not allowed");
456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*invert = TRUE;
458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return TRUE;
459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return FALSE;
461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *
464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfw_calloc(size_t count, size_t size)
465e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	void *p;
467e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((p = calloc(count, size)) == NULL) {
469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		perror("iptables: calloc failed");
470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return p;
473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
475e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *
476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfw_malloc(size_t size)
477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	void *p;
479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((p = malloc(size)) == NULL) {
481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		perror("iptables: malloc failed");
482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
483e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return p;
485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct in_addr *
488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherhost_to_addr(const char *name, unsigned int *naddr)
489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct hostent *host;
491e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct in_addr *addr;
492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*naddr = 0;
495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((host = gethostbyname(name)) != NULL) {
496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (host->h_addrtype != AF_INET ||
497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    host->h_length != sizeof(struct in_addr))
498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return (struct in_addr *) NULL;
499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		while (host->h_addr_list[*naddr] != (char *) NULL)
501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			(*naddr)++;
502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addr = fw_calloc(*naddr, sizeof(struct in_addr));
503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (i = 0; i < *naddr; i++)
504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			inaddrcpy(&(addr[i]),
505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				  (struct in_addr *) host->h_addr_list[i]);
506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return addr;
507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (struct in_addr *) NULL;
510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
511e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char *
513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheraddr_to_host(const struct in_addr *addr)
514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct hostent *host;
516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((host = gethostbyaddr((char *) addr,
518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				  sizeof(struct in_addr), AF_INET)) != NULL)
519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (char *) host->h_name;
520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (char *) NULL;
522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/*
525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	All functions starting with "parse" should succeed, otherwise
526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	the program fails.
527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	Most routines return pointers to static data that may change
528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	between calls to the same or other routines with a few exceptions:
529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	"host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *	return global static data.
531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/
532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct in_addr *
534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_hostnetwork(const char *name, unsigned int *naddrs)
535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct in_addr *addrp, *addrptmp;
537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((addrptmp = dotted_to_addr(name)) != NULL ||
539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    (addrptmp = network_to_addr(name)) != NULL) {
540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addrp = fw_malloc(sizeof(struct in_addr));
541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		inaddrcpy(addrp, addrptmp);
542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*naddrs = 1;
543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return addrp;
544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((addrp = host_to_addr(name, naddrs)) != NULL)
546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return addrp;
547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct in_addr *
552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_mask(char *mask)
553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	static struct in_addr maskaddr;
555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct in_addr *addrp;
556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int bits;
557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (mask == NULL) {
559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* no mask at all defaults to 32 bits */
560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		maskaddr.s_addr = 0xFFFFFFFF;
561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return &maskaddr;
562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((addrp = dotted_to_addr(mask)) != NULL)
564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* dotted_to_addr already returns a network byte order addr */
565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return addrp;
566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((bits = string_to_number(mask, 0, 32)) == -1)
567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "invalid mask `%s' specified", mask);
569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (bits != 0) {
570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return &maskaddr;
572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	maskaddr.s_addr = 0L;
575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return &maskaddr;
576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_hostnetworkmask(const char *name, struct in_addr **addrpp,
580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		      struct in_addr *maskp, unsigned int *naddrs)
581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct in_addr *addrp;
583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char buf[256];
584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *p;
585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int i, j, k, n;
586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strncpy(buf, name, sizeof(buf) - 1);
588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((p = strrchr(buf, '/')) != NULL) {
589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*p = '\0';
590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addrp = parse_mask(p + 1);
591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addrp = parse_mask(NULL);
593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	inaddrcpy(maskp, addrp);
594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* if a null mask is given, the name is ignored, like in "any/0" */
596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (maskp->s_addr == 0L)
597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		strcpy(buf, "0.0.0.0");
598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	addrp = *addrpp = parse_hostnetwork(buf, naddrs);
600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	n = *naddrs;
601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0, j = 0; i < n; i++) {
602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		addrp[j++].s_addr &= maskp->s_addr;
603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (k = 0; k < j - 1; k++) {
604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (addrp[k].s_addr == addrp[j - 1].s_addr) {
605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				(*naddrs)--;
606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				j--;
607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				break;
608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
610e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptables_match *
614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfind_match(const char *name, int tryload)
615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct iptables_match *ptr;
617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (ptr = iptables_matches; ptr; ptr = ptr->next) {
619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (strcmp(name, ptr->name) == 0)
620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!ptr && tryload) {
624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 + strlen(name)];
626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
6279e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		if (dlopen(path, RTLD_NOW)) {
6289e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			/* Found library.  If it didn't register itself,
6299e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			   maybe they specified target as match. */
6309e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			ptr = find_match(name, 0);
6319e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			if (!ptr)
6329e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				exit_error(PARAMETER_PROBLEM,
6339e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell					   "Couldn't load match `%s'\n",
6349e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell					   name);
6359e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		}
636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ptr;
639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic u_int16_t
642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_protocol(const char *s)
643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int proto = string_to_number(s, 0, 65535);
645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (proto == -1) {
647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		struct protoent *pent;
648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if ((pent = getprotobyname(s)))
650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			proto = pent->p_proto;
651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else {
652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			unsigned int i;
653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			for (i = 0;
654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			     i < sizeof(chain_protos)/sizeof(struct pprot);
655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			     i++) {
656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				if (strcmp(s, chain_protos[i].name) == 0) {
657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					proto = chain_protos[i].num;
658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					break;
659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				}
660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (i == sizeof(chain_protos)/sizeof(struct pprot))
662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "unknown protocol `%s' specified",
664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   s);
665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (u_int16_t)proto;
669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_interface(const char *arg, char *vianame, unsigned char *mask)
673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int vialen = strlen(arg);
675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i;
676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(mask, 0, IFNAMSIZ);
678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(vianame, 0, IFNAMSIZ);
679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (vialen + 1 > IFNAMSIZ)
681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "interface name `%s' must be shorter than IFNAMSIZ"
683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   " (%i)", arg, IFNAMSIZ-1);
6847e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	strcpy(vianame, arg);
686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (vialen == 0)
687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memset(mask, 0, IFNAMSIZ);
688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else if (vianame[vialen - 1] == '+') {
689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memset(mask, 0xFF, vialen - 1);
690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Remove `+' */
692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		vianame[vialen - 1] = '\0';
693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* Include nul-terminator in match */
695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memset(mask, 0xFF, vialen + 1);
696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; vianame[i]; i++) {
699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!isalnum(vianame[i])) {
700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("Warning: wierd character in interface"
701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       " `%s' (No aliases, :, ! or *).\n",
702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       vianame);
703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Can't be zero. */
709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_rulenumber(const char *rule)
711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int rulenum = string_to_number(rule, 1, INT_MAX);
713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (rulenum == -1)
715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "Invalid rule number `%s'", rule);
717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return rulenum;
719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *
722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_target(const char *targetname)
723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *ptr;
725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(targetname) < 1)
727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "Invalid target name (too short)");
729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strlen(targetname)+1 > sizeof(ipt_chainlabel))
731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "Invalid target name `%s' (%i chars max)",
733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   targetname, sizeof(ipt_chainlabel)-1);
734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (ptr = targetname; *ptr; ptr++)
736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (isspace(*ptr))
737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Invalid target name `%s'", targetname);
739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return targetname;
740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char *
743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheraddr_to_network(const struct in_addr *addr)
744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct netent *net;
746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return (char *) net->n_name;
749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return (char *) NULL;
751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherchar *
754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheraddr_to_dotted(const struct in_addr *addrp)
755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	static char buf[20];
757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const unsigned char *bytep;
758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	bytep = (const unsigned char *) &(addrp->s_addr);
760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return buf;
762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char *
764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheraddr_to_anyname(const struct in_addr *addr)
765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *name;
767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((name = addr_to_host(addr)) != NULL ||
769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    (name = addr_to_network(addr)) != NULL)
770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return name;
771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return addr_to_dotted(addr);
773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic char *
776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermask_to_dotted(const struct in_addr *mask)
777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int i;
779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	static char buf[20];
780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	u_int32_t maskaddr, bits;
781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	maskaddr = ntohl(mask->s_addr);
783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (maskaddr == 0xFFFFFFFFL)
785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* we don't want to see "/32" */
786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return "";
787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	i = 32;
789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	bits = 0xFFFFFFFEL;
790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	while (--i >= 0 && maskaddr != bits)
791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		bits <<= 1;
792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (i >= 0)
793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sprintf(buf, "/%d", i);
794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* mask was not a decent combination of 1's and 0's */
796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sprintf(buf, "/%s", addr_to_dotted(mask));
797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return buf;
799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint
802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstring_to_number(const char *s, int min, int max)
803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int number;
805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *end;
806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Handle hex, octal, etc. */
808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	number = (int)strtol(s, &end, 0);
809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*end == '\0' && end != s) {
810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* we parsed a number, let's see if we want this */
811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (min <= number && number <= max)
812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			return number;
813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return -1;
815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherset_option(unsigned int *options, unsigned int option, u_int8_t *invflg,
819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   int invert)
820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (*options & option)
822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   opt2char(option));
824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*options |= option;
825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (invert) {
827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int i;
828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (i = 0; 1 << i != option; i++);
829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!inverse_for_options[i])
831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "cannot have ! before -%c",
833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   opt2char(option));
834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		*invflg |= inverse_for_options[i];
835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptables_target *
839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfind_target(const char *name, int tryload)
840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct iptables_target *ptr;
842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Standard target? */
844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(name, "") == 0
845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(name, IPTC_LABEL_ACCEPT) == 0
846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(name, IPTC_LABEL_DROP) == 0
847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(name, IPTC_LABEL_QUEUE) == 0
848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || strcmp(name, IPTC_LABEL_RETURN) == 0)
849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		name = "standard";
850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (ptr = iptables_targets; ptr; ptr = ptr->next) {
852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (strcmp(name, ptr->name) == 0)
853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!ptr && tryload) {
857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 + strlen(name)];
859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
8609e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		if (dlopen(path, RTLD_NOW)) {
8619e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			/* Found library.  If it didn't register itself,
8629e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			   maybe they specified match as a target. */
8639e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			ptr = find_target(name, 0);
8649e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			if (!ptr)
8659e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				exit_error(PARAMETER_PROBLEM,
8669e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell					   "Couldn't load target `%s'\n",
8679e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell					   name);
8689e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		}
869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ptr;
872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct option *
875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermerge_options(struct option *oldopts, struct option *newopts,
876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      unsigned int *option_offset)
877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int num_old, num_new, i;
879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct option *merge;
880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (num_old = 0; oldopts[num_old].name; num_old++);
882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (num_new = 0; newopts[num_new].name; num_new++);
883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	global_option_offset += OPTION_OFFSET;
885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*option_offset = global_option_offset;
886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memcpy(merge, oldopts, num_old * sizeof(struct option));
889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < num_new; i++) {
890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		merge[num_old + i] = newopts[i];
891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		merge[num_old + i].val += *option_offset;
892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(merge + num_old + num_new, 0, sizeof(struct option));
894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return merge;
896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherregister_match(struct iptables_match *me)
900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(me->version, program_version) != 0) {
902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n",
903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			program_name, me->name, me->version, program_version);
904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (find_match(me->name, 0)) {
908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "%s: match `%s' already registered.\n",
909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			program_name, me->name);
910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Prepend to list. */
914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	me->next = iptables_matches;
915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptables_matches = me;
916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	me->m = NULL;
917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	me->mflags = 0;
918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	opts = merge_options(opts, me->extra_opts, &me->option_offset);
920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherregister_target(struct iptables_target *me)
924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (strcmp(me->version, program_version) != 0) {
926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n",
927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			program_name, me->name, me->version, program_version);
928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (find_target(me->name, 0)) {
932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stderr, "%s: target `%s' already registered.\n",
933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			program_name, me->name);
934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit(1);
935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Prepend to list. */
938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	me->next = iptables_targets;
939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	iptables_targets = me;
940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	me->t = NULL;
941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	me->tflags = 0;
942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	opts = merge_options(opts, me->extra_opts, &me->option_offset);
944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
947e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_header(unsigned int format, const char *chain, iptc_handle_t *handle)
948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_counters counters;
950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *pol = iptc_get_policy(chain, &counters, handle);
951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("Chain %s", chain);
952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (pol) {
953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(" (policy %s", pol);
954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!(format & FMT_NOCOUNTS))
955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(" %llu packets, %llu bytes",
956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       counters.pcnt, counters.bcnt);
957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(")\n");
958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		unsigned int refs;
9609e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		if (!iptc_get_references(&refs, chain, handle))
9619e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			printf(" (ERROR obtaining refs)\n");
9629e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		else
9639e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			printf(" (%u references)\n", refs);
964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_LINENUMBERS)
967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-4s ", "%s "), "num");
968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(format & FMT_NOCOUNTS)) {
969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (format & FMT_KILOMEGAGIGA) {
970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%5s ","%s "), "pkts");
971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%5s ","%s "), "bytes");
972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else {
973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%8s ","%s "), "pkts");
974e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%10s ","%s "), "bytes");
975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(format & FMT_NOTARGET))
978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-9s ","%s "), "target");
979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fputs(" prot ", stdout);
980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_OPTIONS)
981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fputs("opt", stdout);
982e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_VIA) {
983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT(" %-6s ","%s "), "in");
984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-6s ","%s "), "out");
985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
986e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf(FMT(" %-19s ","%s "), "source");
987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf(FMT(" %-19s "," %s "), "destination");
988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf("\n");
989e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
991e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_num(u_int64_t number, unsigned int format)
993e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_KILOMEGAGIGA) {
995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (number > 99999) {
996e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			number = (number + 500) / 1000;
997e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (number > 9999) {
998e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				number = (number + 500) / 1000;
999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				if (number > 9999) {
1000e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					number = (number + 500) / 1000;
1001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					printf(FMT("%4lluG ","%lluG "),number);
1002e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				}
1003e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				else printf(FMT("%4lluM ","%lluM "), number);
1004e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			} else
1005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf(FMT("%4lluK ","%lluK "), number);
1006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else
1007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%5llu ","%llu "), number);
1008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else
1009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%8llu ","%llu "), number);
1010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1012e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1013e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_match(const struct ipt_entry_match *m,
1014e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    const struct ipt_ip *ip,
1015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    int numeric)
1016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1017228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	struct iptables_match *match = find_match(m->u.user.name, 1);
1018e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1019e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (match) {
1020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (match->print)
1021e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			match->print(ip, m, numeric);
1022e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
1023228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		if (m->u.user.name[0])
1024228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			printf("UNKNOWN match `%s' ", m->u.user.name);
1025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Don't stop iterating. */
1027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return 0;
1028e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1030e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* e is called `fw' here for hysterical raisins */
1031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
1032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_firewall(const struct ipt_entry *fw,
1033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       const char *targname,
1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       unsigned int num,
1035e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       unsigned int format,
1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       const iptc_handle_t handle)
1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct iptables_target *target = NULL;
1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const struct ipt_entry_target *t;
1040e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	u_int8_t flags;
1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char buf[BUFSIZ];
1042e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* User creates a chain called "REJECT": this overrides the
1044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   `REJECT' target module.  Keep feeding them rope until the
1045e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   revolution... Bwahahahahah */
1046e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!iptc_is_chain(targname, handle))
1047e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		target = find_target(targname, 1);
1048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
1049e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		target = find_target(IPT_STANDARD_TARGET, 1);
1050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1051e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = ipt_get_target((struct ipt_entry *)fw);
1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	flags = fw->ip.flags;
1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_LINENUMBERS)
1055e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-4u ", "%u "), num+1);
1056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1057e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(format & FMT_NOCOUNTS)) {
1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		print_num(fw->counters.pcnt, format);
1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		print_num(fw->counters.bcnt, format);
1060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1061e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1062e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(format & FMT_NOTARGET))
1063e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-9s ", "%s "), targname);
1064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout);
1066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{
1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		char *pname = proto_to_name(fw->ip.proto);
1068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (pname)
1069e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%-5s", "%s "), pname);
1070e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
1071e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(FMT("%-5hu", "%hu "), fw->ip.proto);
1072e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1073e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1074e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_OPTIONS) {
1075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (format & FMT_NOTABLE)
1076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fputs("opt ", stdout);
1077e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
1078e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
1079e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fputc(' ', stdout);
1080e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1081e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1082e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_VIA) {
1083e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		char iface[IFNAMSIZ+2];
1084e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1085e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (fw->ip.invflags & IPT_INV_VIA_IN) {
1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			iface[0] = '!';
1087e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			iface[1] = '\0';
1088e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1089e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else iface[0] = '\0';
1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (fw->ip.iniface[0] != '\0') {
1092e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			strcat(iface, fw->ip.iniface);
1093e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* If it doesn't compare the nul-term, it's a
1094e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   wildcard. */
1095e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (fw->ip.iniface_mask[strlen(fw->ip.iniface)] == 0)
1096e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				strcat(iface, "+");
1097e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1098e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (format & FMT_NUMERIC) strcat(iface, "*");
1099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else strcat(iface, "any");
1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT(" %-6s ","in %s "), iface);
1101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (fw->ip.invflags & IPT_INV_VIA_OUT) {
1103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			iface[0] = '!';
1104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			iface[1] = '\0';
1105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else iface[0] = '\0';
1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (fw->ip.outiface[0] != '\0') {
1109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			strcat(iface, fw->ip.outiface);
1110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* If it doesn't compare the nul-term, it's a
1111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   wildcard. */
1112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (fw->ip.outiface_mask[strlen(fw->ip.outiface)] == 0)
1113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				strcat(iface, "+");
1114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else if (format & FMT_NUMERIC) strcat(iface, "*");
1116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else strcat(iface, "any");
1117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-6s ","out %s "), iface);
1118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
1121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
1122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-19s ","%s "), "anywhere");
1123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (format & FMT_NUMERIC)
1125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src)));
1126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
1127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src)));
1128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		strcat(buf, mask_to_dotted(&(fw->ip.smsk)));
1129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-19s ","%s "), buf);
1130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
1133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
1134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-19s","-> %s"), "anywhere");
1135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else {
1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (format & FMT_NUMERIC)
1137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst)));
1138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
1139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst)));
1140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		strcat(buf, mask_to_dotted(&(fw->ip.dmsk)));
1141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(FMT("%-19s","-> %s"), buf);
1142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (format & FMT_NOTABLE)
1145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fputs("  ", stdout);
1146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
1148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (target) {
1150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (target->print)
1151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Print the target information. */
1152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			target->print(&fw->ip, t, format & FMT_NUMERIC);
1153228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	} else if (t->u.target_size != sizeof(*t))
1154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("[%u bytes of unknown target data] ",
1155228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		       t->u.target_size - sizeof(*t));
1156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!(format & FMT_NONEWLINE))
1158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fputc('\n', stdout);
1159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
1162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_firewall_line(const struct ipt_entry *fw,
1163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    const iptc_handle_t h)
1164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry_target *t;
1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	t = ipt_get_target((struct ipt_entry *)fw);
1168228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
1169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherappend_entry(const ipt_chainlabel chain,
1173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     struct ipt_entry *fw,
1174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int nsaddrs,
1175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr saddrs[],
1176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int ndaddrs,
1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr daddrs[],
1178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int verbose,
1179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
1180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, j;
1182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret = 1;
1183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < nsaddrs; i++) {
1185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fw->ip.src.s_addr = saddrs[i].s_addr;
1186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (j = 0; j < ndaddrs; j++) {
1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw->ip.dst.s_addr = daddrs[j].s_addr;
1188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (verbose)
1189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				print_firewall_line(fw, *handle);
1190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			ret &= iptc_append_entry(chain, fw, handle);
1191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherreplace_entry(const ipt_chainlabel chain,
1199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      struct ipt_entry *fw,
1200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      unsigned int rulenum,
1201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      const struct in_addr *saddr,
1202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      const struct in_addr *daddr,
1203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      int verbose,
1204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      iptc_handle_t *handle)
1205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fw->ip.src.s_addr = saddr->s_addr;
1207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	fw->ip.dst.s_addr = daddr->s_addr;
1208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (verbose)
1210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		print_firewall_line(fw, *handle);
1211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return iptc_replace_entry(chain, fw, rulenum, handle);
1212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinsert_entry(const ipt_chainlabel chain,
1216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     struct ipt_entry *fw,
1217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int rulenum,
1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int nsaddrs,
1219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr saddrs[],
1220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int ndaddrs,
1221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr daddrs[],
1222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int verbose,
1223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
1224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, j;
1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret = 1;
1227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1228e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < nsaddrs; i++) {
1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fw->ip.src.s_addr = saddrs[i].s_addr;
1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (j = 0; j < ndaddrs; j++) {
1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw->ip.dst.s_addr = daddrs[j].s_addr;
1232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (verbose)
1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				print_firewall_line(fw, *handle);
1234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			ret &= iptc_insert_entry(chain, fw, rulenum, handle);
1235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12412e0a3216c501753709781769f83e29821e62c805Rusty Russellstatic unsigned char *
12422e0a3216c501753709781769f83e29821e62c805Rusty Russellmake_delete_mask(struct ipt_entry *fw)
12432e0a3216c501753709781769f83e29821e62c805Rusty Russell{
12442e0a3216c501753709781769f83e29821e62c805Rusty Russell	/* Establish mask for comparison */
12452e0a3216c501753709781769f83e29821e62c805Rusty Russell	unsigned int size;
12462e0a3216c501753709781769f83e29821e62c805Rusty Russell	struct iptables_match *m;
12472e0a3216c501753709781769f83e29821e62c805Rusty Russell	unsigned char *mask, *mptr;
12482e0a3216c501753709781769f83e29821e62c805Rusty Russell
12492e0a3216c501753709781769f83e29821e62c805Rusty Russell	size = sizeof(struct ipt_entry);
12502e0a3216c501753709781769f83e29821e62c805Rusty Russell	for (m = iptables_matches; m; m = m->next)
12512e0a3216c501753709781769f83e29821e62c805Rusty Russell		size += sizeof(struct ipt_entry_match) + m->size;
12522e0a3216c501753709781769f83e29821e62c805Rusty Russell
12539e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	mask = fw_calloc(1, size
12549e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			 + sizeof(struct ipt_entry_target)
12559e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			 + iptables_targets->size);
12562e0a3216c501753709781769f83e29821e62c805Rusty Russell
12579e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	memset(mask, 0xFF, sizeof(struct ipt_entry));
12589e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	mptr = mask + sizeof(struct ipt_entry);
12592e0a3216c501753709781769f83e29821e62c805Rusty Russell
12602e0a3216c501753709781769f83e29821e62c805Rusty Russell	for (m = iptables_matches; m; m = m->next) {
12612e0a3216c501753709781769f83e29821e62c805Rusty Russell		memset(mptr, 0xFF,
12622e0a3216c501753709781769f83e29821e62c805Rusty Russell		       sizeof(struct ipt_entry_match) + m->userspacesize);
12632e0a3216c501753709781769f83e29821e62c805Rusty Russell		mptr += sizeof(struct ipt_entry_match) + m->size;
12642e0a3216c501753709781769f83e29821e62c805Rusty Russell	}
12652e0a3216c501753709781769f83e29821e62c805Rusty Russell
12662e0a3216c501753709781769f83e29821e62c805Rusty Russell	memset(mptr, 0xFF, sizeof(struct ipt_entry_target));
12672e0a3216c501753709781769f83e29821e62c805Rusty Russell	mptr += sizeof(struct ipt_entry_target);
12689e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	memset(mptr, 0xFF, iptables_targets->userspacesize);
12692e0a3216c501753709781769f83e29821e62c805Rusty Russell
12702e0a3216c501753709781769f83e29821e62c805Rusty Russell	return mask;
12712e0a3216c501753709781769f83e29821e62c805Rusty Russell}
12722e0a3216c501753709781769f83e29821e62c805Rusty Russell
1273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdelete_entry(const ipt_chainlabel chain,
1275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     struct ipt_entry *fw,
1276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int nsaddrs,
1277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr saddrs[],
1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int ndaddrs,
1279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr daddrs[],
1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int verbose,
1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, j;
1284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret = 1;
12852e0a3216c501753709781769f83e29821e62c805Rusty Russell	unsigned char *mask;
1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
12872e0a3216c501753709781769f83e29821e62c805Rusty Russell	mask = make_delete_mask(fw);
1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < nsaddrs; i++) {
1289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fw->ip.src.s_addr = saddrs[i].s_addr;
1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (j = 0; j < ndaddrs; j++) {
1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw->ip.dst.s_addr = daddrs[j].s_addr;
1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (verbose)
1293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				print_firewall_line(fw, *handle);
12942e0a3216c501753709781769f83e29821e62c805Rusty Russell			ret &= iptc_delete_entry(chain, fw, mask, handle);
1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_packet(const ipt_chainlabel chain,
1302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     struct ipt_entry *fw,
1303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int nsaddrs,
1304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr saddrs[],
1305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     unsigned int ndaddrs,
1306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     const struct in_addr daddrs[],
1307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int verbose,
1308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret = 1;
1311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int i, j;
1312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *msg;
1313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (i = 0; i < nsaddrs; i++) {
1315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fw->ip.src.s_addr = saddrs[i].s_addr;
1316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		for (j = 0; j < ndaddrs; j++) {
1317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw->ip.dst.s_addr = daddrs[j].s_addr;
1318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (verbose)
1319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				print_firewall_line(fw, *handle);
1320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			msg = iptc_check_packet(chain, fw, handle);
1321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!msg) ret = 0;
1322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else printf("%s\n", msg);
1323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherfor_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
13319e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	       int verbose, int builtinstoo, iptc_handle_t *handle)
1332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher        int ret = 1;
13349e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	const char *chain;
13359e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	char *chains;
13369e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	unsigned int i, chaincount = 0;
13379e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell
13389e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	chain = iptc_first_chain(handle);
13399e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	while (chain) {
13409e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		chaincount++;
13419e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		chain = iptc_next_chain(handle);
13429e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell        }
1343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13449e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount);
13459e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	i = 0;
13469e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	chain = iptc_first_chain(handle);
13479e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	while (chain) {
13489e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		strcpy(chains + i*sizeof(ipt_chainlabel), chain);
13499e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		i++;
13509e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		chain = iptc_next_chain(handle);
1351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher        }
1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
13539e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	for (i = 0; i < chaincount; i++) {
13549e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		if (!builtinstoo
13559e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		    && iptc_builtin(chains + i*sizeof(ipt_chainlabel),
13569e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				    *handle))
13579e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			continue;
13589e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	        ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle);
13599e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	}
13609e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell
13619e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	free(chains);
1362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher        return ret;
1363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherflush_entries(const ipt_chainlabel chain, int verbose,
1367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	      iptc_handle_t *handle)
1368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!chain)
13709e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		return for_each_chain(flush_entries, verbose, 1, handle);
13717e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
13727e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell	if (verbose)
13737e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell		fprintf(stdout, "Flushing chain `%s'\n", chain);
13747e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell	return iptc_flush_entries(chain, handle);
13757e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell}
1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherzero_entries(const ipt_chainlabel chain, int verbose,
1379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
1380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!chain)
13829e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		return for_each_chain(zero_entries, verbose, 1, handle);
13837e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (verbose)
1385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		fprintf(stdout, "Zeroing chain `%s'\n", chain);
1386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return iptc_zero_entries(chain, handle);
1387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdelete_chain(const ipt_chainlabel chain, int verbose,
1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     iptc_handle_t *handle)
1392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
13939e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	if (!chain)
13949e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		return for_each_chain(delete_chain, verbose, 0, handle);
1395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (verbose)
1397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	        fprintf(stdout, "Deleting chain `%s'\n", chain);
1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return iptc_delete_chain(chain, handle);
1399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherlist_entries(const ipt_chainlabel chain, int verbose, int numeric,
1403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	     int expanded, int linenumbers, iptc_handle_t *handle)
1404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int found = 0;
14069e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	unsigned int format;
14079e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	const char *this;
1408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	format = FMT_OPTIONS;
1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!verbose)
1411e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		format |= FMT_NOCOUNTS;
1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
1413e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		format |= FMT_VIA;
1414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (numeric)
1416e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		format |= FMT_NUMERIC;
1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1418e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!expanded)
1419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		format |= FMT_KILOMEGAGIGA;
1420e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (linenumbers)
1422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		format |= FMT_LINENUMBERS;
1423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
14249e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	for (this = iptc_first_chain(handle);
14259e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	     this;
14269e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell	     this = iptc_next_chain(handle)) {
14279e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		const struct ipt_entry *i;
14289e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		unsigned int num;
1429e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (chain && strcmp(chain, this) != 0)
1431e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			continue;
1432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (found) printf("\n");
1434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		print_header(format, this, handle);
14369e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		i = iptc_first_rule(this, handle);
14379e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell
14389e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		num = 0;
14399e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		while (i) {
14409e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			print_firewall(i,
14419e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				       iptc_get_target(i, handle),
14429e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				       num++,
1443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       format,
1444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       *handle);
14459e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			i = iptc_next_rule(i, handle);
14469e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell		}
1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		found = 1;
1448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1449e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	errno = ENOENT;
1451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return found;
1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1454e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct ipt_entry *
1455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchergenerate_entry(const struct ipt_entry *fw,
1456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       struct iptables_match *matches,
1457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	       struct ipt_entry_target *target)
1458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int size;
1460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct iptables_match *m;
1461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry *e;
1462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size = sizeof(struct ipt_entry);
1464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (m = matches; m; m = m->next)
1465228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		size += m->m->u.match_size;
1466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1467228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	e = fw_malloc(size + target->u.target_size);
1468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*e = *fw;
1469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	e->target_offset = size;
1470228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	e->next_offset = size + target->u.target_size;
1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	size = 0;
1473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (m = matches; m; m = m->next) {
1474228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		memcpy(e->elems + size, m->m, m->m->u.match_size);
1475228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell		size += m->m->u.match_size;
1476e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1477228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell	memcpy(e->elems + size, target, target->u.target_size);
1478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return e;
1480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
1481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
1483e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ipt_entry fw, *e = NULL;
1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int invert = 0;
1486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int nsaddrs = 0, ndaddrs = 0;
1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct in_addr *saddrs = NULL, *daddrs = NULL;
1488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int c, verbose = 0;
1490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *chain = NULL;
1491e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
1492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *policy = NULL, *newname = NULL;
1493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	unsigned int rulenum = 0, options = 0, command = 0;
1494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int ret = 1;
1495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct iptables_match *m;
1496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct iptables_target *target = NULL;
1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *jumpto = "";
1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	char *protocol = NULL;
1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	memset(&fw, 0, sizeof(fw));
1501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Suppress error messages: we may add new options if we
1503e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher           demand-load a protocol. */
1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	opterr = 0;
1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	while ((c = getopt_long(argc, argv,
1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	   "-A:C:D:R:I:L::F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:x",
1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   opts, NULL)) != -1) {
1509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		switch (c) {
1510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/*
1511e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Command selection
1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'A':
1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_APPEND, CMD_NONE,
1515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'D':
1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_DELETE, CMD_NONE,
1521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optind < argc && argv[optind][0] != '-'
1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && argv[optind][0] != '!') {
1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				rulenum = parse_rulenumber(argv[optind++]);
1526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				command = CMD_DELETE_NUM;
1527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'C':
1531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_CHECK, CMD_NONE,
1532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'R':
1537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_REPLACE, CMD_NONE,
1538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optind < argc && argv[optind][0] != '-'
1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && argv[optind][0] != '!')
1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				rulenum = parse_rulenumber(argv[optind++]);
1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else
1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "-%c requires a rule number",
1546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   cmd2char(CMD_REPLACE));
1547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'I':
1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_INSERT, CMD_NONE,
1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optind < argc && argv[optind][0] != '-'
1554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && argv[optind][0] != '!')
1555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				rulenum = parse_rulenumber(argv[optind++]);
1556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else rulenum = 1;
1557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'L':
1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_LIST, CMD_ZERO,
1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optarg) chain = optarg;
1563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else if (optind < argc && argv[optind][0] != '-'
1564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				 && argv[optind][0] != '!')
1565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				chain = argv[optind++];
1566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'F':
1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_FLUSH, CMD_NONE,
1570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optarg) chain = optarg;
1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else if (optind < argc && argv[optind][0] != '-'
1573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				 && argv[optind][0] != '!')
1574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				chain = argv[optind++];
1575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'Z':
1578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_ZERO, CMD_LIST,
1579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optarg) chain = optarg;
1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else if (optind < argc && argv[optind][0] != '-'
1582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				&& argv[optind][0] != '!')
1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				chain = argv[optind++];
1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'N':
1587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
1588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'X':
1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
1594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optarg) chain = optarg;
1596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else if (optind < argc && argv[optind][0] != '-'
1597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				 && argv[optind][0] != '!')
1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				chain = argv[optind++];
1599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'E':
1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
1603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optind < argc && argv[optind][0] != '-'
1606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && argv[optind][0] != '!')
1607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				newname = argv[optind++];
1608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1610e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'P':
1611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			add_command(&command, CMD_SET_POLICY, CMD_NONE,
1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    invert);
1613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			chain = optarg;
1614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optind < argc && argv[optind][0] != '-'
1615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && argv[optind][0] != '!')
1616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				policy = argv[optind++];
1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else
1618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "-%c requires a chain and a policy",
1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   cmd2char(CMD_SET_POLICY));
1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'h':
1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!optarg)
1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optarg = argv[optind];
1626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16272e0a3216c501753709781769f83e29821e62c805Rusty Russell			/* iptables -p icmp -h */
16282e0a3216c501753709781769f83e29821e62c805Rusty Russell			if (!iptables_matches && protocol)
16292e0a3216c501753709781769f83e29821e62c805Rusty Russell			    find_match(protocol, 1);
16302e0a3216c501753709781769f83e29821e62c805Rusty Russell
1631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_printhelp();
1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/*
1634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 * Option selection
1635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			 */
1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'p':
1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (check_inverse(optarg, &invert))
1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optind++;
1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_PROTOCOL, &fw.ip.invflags,
1640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Canonicalize into lower case */
1643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			for (protocol = argv[optind-1]; *protocol; protocol++)
1644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				*protocol = tolower(*protocol);
1645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			protocol = argv[optind-1];
1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.ip.proto = parse_protocol(protocol);
1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (fw.ip.proto == 0
1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    && (fw.ip.invflags & IPT_INV_PROTO))
1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "rule would never match protocol");
1653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.nfcache |= NFC_IP_PROTO;
1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 's':
1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (check_inverse(optarg, &invert))
1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optind++;
1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_SOURCE, &fw.ip.invflags,
1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			shostnetworkmask = argv[optind-1];
1662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.nfcache |= NFC_IP_SRC;
1663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'd':
1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (check_inverse(optarg, &invert))
1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optind++;
1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_DESTINATION, &fw.ip.invflags,
1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			dhostnetworkmask = argv[optind-1];
1671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.nfcache |= NFC_IP_DST;
1672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'j':
1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_JUMP, &fw.ip.invflags,
1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			jumpto = parse_target(optarg);
1678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			target = find_target(jumpto, 1);
1679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (target) {
1681228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				size_t size;
1682228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell
1683228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				size = IPT_ALIGN(sizeof(struct ipt_entry_target)
1684228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell						 + target->size);
1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
16862e0a3216c501753709781769f83e29821e62c805Rusty Russell				target->t = fw_calloc(1, size);
1687228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				target->t->u.target_size = size;
1688228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				strcpy(target->t->u.user.name, jumpto);
1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				target->init(target->t, &fw.nfcache);
1690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
1691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'i':
1695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (check_inverse(optarg, &invert))
1696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optind++;
1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags,
1698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			parse_interface(argv[optind-1],
1700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					fw.ip.iniface,
1701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					fw.ip.iniface_mask);
1702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.nfcache |= NFC_IP_IF_IN;
1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'o':
1706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (check_inverse(optarg, &invert))
1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optind++;
1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags,
1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			parse_interface(argv[optind-1],
1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					fw.ip.outiface,
1712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					fw.ip.outiface_mask);
1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.nfcache |= NFC_IP_IF_OUT;
1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'f':
1717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_FRAGMENT, &fw.ip.invflags,
1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.ip.flags |= IPT_F_FRAG;
1720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			fw.nfcache |= NFC_IP_FRAG;
1721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'v':
1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!verbose)
1725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				set_option(&options, OPT_VERBOSE,
1726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   &fw.ip.invflags, invert);
1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			verbose++;
1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'm':
1731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (invert)
1732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "unexpected ! flag before --match");
1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			m = find_match(optarg, 1);
1736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!m)
1737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "Couldn't load match `%s'", optarg);
1739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else {
1740228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				size_t size;
1741228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell
1742228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				size = IPT_ALIGN(sizeof(struct ipt_entry_match)
1743228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell						 + m->size);
17442e0a3216c501753709781769f83e29821e62c805Rusty Russell				m->m = fw_calloc(1, size);
1745228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				m->m->u.match_size = size;
1746228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				strcpy(m->m->u.user.name, optarg);
1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				m->init(m->m, &fw.nfcache);
1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'n':
1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_NUMERIC, &fw.ip.invflags,
1753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 't':
1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (invert)
1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "unexpected ! flag before --table");
1760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			*table = argv[optind-1];
1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'x':
1764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_EXPANDED, &fw.ip.invflags,
1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 'V':
1769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (invert)
1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("Not %s ;-)\n", program_version);
1771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			else
1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				printf("%s v%s\n",
1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				       program_name, program_version);
1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit(0);
1775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case '0':
1777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags,
1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   invert);
1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			break;
1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		case 1: /* non option */
1782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (optarg[0] == '!' && optarg[1] == '\0') {
1783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				if (invert)
1784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					exit_error(PARAMETER_PROBLEM,
1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   "multiple consecutive ! not"
1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   " allowed");
1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				invert = TRUE;
1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				optarg[0] = '\0';
1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				continue;
1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
17919e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell			printf("Bad argument `%s'\n", optarg);
1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_tryhelp(2);
1793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		default:
1795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* FIXME: This scheme doesn't allow two of the same
1796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   matches --RR */
1797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!target
1798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    || !(target->parse(c - target->option_offset,
1799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					       argv, invert,
1800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					       &target->tflags,
1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					       &fw, &target->t))) {
1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				for (m = iptables_matches; m; m = m->next) {
1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					if (m->parse(c - m->option_offset,
1804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						     argv, invert,
1805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						     &m->mflags,
1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						     &fw,
1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						     &fw.nfcache,
1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						     &m->m))
1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						break;
1810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				}
1811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				/* If you listen carefully, you can
1813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   acually hear this code suck. */
18149e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				if (m == NULL
1815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    && protocol
18169e1d214b30b916df55b4c1c5db224200f02e15a5Rusty Russell				    && !find_match(protocol, 0)
1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    && (m = find_match(protocol, 1))) {
1818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					/* Try loading protocol */
1819228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell					size_t size;
1820228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell
1821228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell					size = IPT_ALIGN(sizeof(struct ipt_entry_match)
1822228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell							 + m->size);
1823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
18242e0a3216c501753709781769f83e29821e62c805Rusty Russell					m->m = fw_calloc(1, size);
1825228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell					m->m->u.match_size = size;
1826228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell					strcpy(m->m->u.user.name, protocol);
1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					m->init(m->m, &fw.nfcache);
1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					optind--;
1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					continue;
1831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				}
1832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				if (!m)
1833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					exit_error(PARAMETER_PROBLEM,
1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   "Unknown arg `%s'",
1835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher						   argv[optind-1]);
1836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			}
1837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		invert = FALSE;
1839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	for (m = iptables_matches; m; m = m->next)
1842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		m->final_check(m->mflags);
1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (target)
1844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		target->final_check(target->tflags);
1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Fix me: must put inverse options checking here --MN */
1847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (optind < argc)
1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "unknown arguments found on commandline");
1851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!command)
1852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "no command specified");
1853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (invert)
1854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "nothing appropriate following !");
1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1857744bd02e37167ca6b5646cefd8f0f24e71b512c4Marc Boucher	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND |
1858744bd02e37167ca6b5646cefd8f0f24e71b512c4Marc Boucher	    CMD_CHECK)) {
1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!(options & OPT_DESTINATION))
1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			dhostnetworkmask = "0.0.0.0/0";
1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!(options & OPT_SOURCE))
1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			shostnetworkmask = "0.0.0.0/0";
1863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (shostnetworkmask)
1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		parse_hostnetworkmask(shostnetworkmask, &saddrs,
1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      &(fw.ip.smsk), &nsaddrs);
1868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (dhostnetworkmask)
1870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		parse_hostnetworkmask(dhostnetworkmask, &daddrs,
1871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				      &(fw.ip.dmsk), &ndaddrs);
1872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((nsaddrs > 1 || ndaddrs > 1) &&
1874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "! not allowed with multiple"
1876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   " source or destination IP addresses");
1877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (command == CMD_CHECK && fw.ip.invflags != 0)
1879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "! not allowed with -%c",
1880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   cmd2char(CMD_CHECK));
1881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "Replacement rule does not "
1884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "specify a unique address");
1885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	generic_opt_check(command, options);
1887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN)
1889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM,
1890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "chain name `%s' too long (must be under %i chars)",
1891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   chain, IPT_FUNCTION_MAXNAMELEN);
1892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*handle = iptc_init(*table);
1894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!*handle)
1895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(VERSION_PROBLEM,
1896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   "can't initialize iptables table `%s': %s",
1897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			   *table, iptc_strerror(errno));
1898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1899744bd02e37167ca6b5646cefd8f0f24e71b512c4Marc Boucher	if (command == CMD_CHECK
1900744bd02e37167ca6b5646cefd8f0f24e71b512c4Marc Boucher	    || command == CMD_APPEND
1901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || command == CMD_DELETE
1902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || command == CMD_INSERT
1903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || command == CMD_REPLACE) {
1904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* -o not valid with incoming packets. */
1905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (options & OPT_VIANAMEOUT)
1906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (strcmp(chain, "PREROUTING") == 0
1907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    	    || strcmp(chain, "INPUT") == 0) {
1908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "Can't use -%c with %s\n",
1910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   opt2char(OPT_VIANAMEOUT),
1911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   chain);
1912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* -i not valid with outgoing packets */
1915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (options & OPT_VIANAMEIN)
1916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (strcmp(chain, "POSTROUTING") == 0
1917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			    || strcmp(chain, "OUTPUT") == 0) {
1918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(PARAMETER_PROBLEM,
1919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "Can't use -%c with %s\n",
1920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   opt2char(OPT_VIANAMEIN),
1921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   chain);
1922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (target && iptc_is_chain(jumpto, *handle)) {
1925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("Warning: using chain %s, not extension\n",
1926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			       jumpto);
1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			target = NULL;
1929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* If they didn't specify a target, or it's a chain
1932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		   name, use standard. */
1933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!target
1934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    && (strlen(jumpto) == 0
1935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			|| iptc_is_chain(jumpto, *handle))) {
1936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			size_t size;
1937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			target = find_target(IPT_STANDARD_TARGET, 1);
1938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			if (!target)
1940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				exit_error(OTHER_PROBLEM,
1941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   "Can't find standard target\n");
1942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			size = sizeof(struct ipt_entry_target)
1944228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell				+ target->size;
19452e0a3216c501753709781769f83e29821e62c805Rusty Russell			target->t = fw_calloc(1, size);
1946228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			target->t->u.target_size = size;
1947228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			strcpy(target->t->u.user.name, jumpto);
1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			target->init(target->t, &fw.nfcache);
1949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
19517e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell		if (!target) {
1952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			struct ipt_entry_target unknown_target;
19537e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell
1954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* Don't know it.  Must be extension with no
1955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher                           options? */
1956228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			unknown_target.u.target_size = sizeof(unknown_target);
1957228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell			strcpy(unknown_target.u.user.name, jumpto);
1958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			e = generate_entry(&fw, iptables_matches,
1960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   &unknown_target);
1961e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else {
1962e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			e = generate_entry(&fw, iptables_matches, target->t);
1963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
1964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
1965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
1966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	switch (command) {
1967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_APPEND:
1968e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = append_entry(chain, e,
1969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   nsaddrs, saddrs, ndaddrs, daddrs,
1970e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_VERBOSE,
1971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   handle);
1972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
1973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_CHECK:
1974e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = check_packet(chain, e,
1975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   nsaddrs, saddrs, ndaddrs, daddrs,
1976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_VERBOSE, handle);
1977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
1978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_DELETE:
1979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = delete_entry(chain, e,
1980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   nsaddrs, saddrs, ndaddrs, daddrs,
1981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_VERBOSE,
1982e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   handle);
1983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
1984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_DELETE_NUM:
1985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = iptc_delete_num_entry(chain, rulenum - 1, handle);
1986e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
1987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_REPLACE:
1988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = replace_entry(chain, e, rulenum - 1,
1989e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    saddrs, daddrs, options&OPT_VERBOSE,
1990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				    handle);
1991e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
1992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_INSERT:
1993e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = insert_entry(chain, e, rulenum - 1,
1994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   nsaddrs, saddrs, ndaddrs, daddrs,
1995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_VERBOSE,
1996e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   handle);
1997e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
1998e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_LIST:
1999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = list_entries(chain,
2000e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_VERBOSE,
2001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_NUMERIC,
2002e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_EXPANDED,
2003e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_LINENUMBERS,
2004e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   handle);
2005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_FLUSH:
2007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = flush_entries(chain, options&OPT_VERBOSE, handle);
2008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_ZERO:
2010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = zero_entries(chain, options&OPT_VERBOSE, handle);
2011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2012e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_LIST|CMD_ZERO:
2013e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = list_entries(chain,
2014e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_VERBOSE,
2015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_NUMERIC,
2016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_EXPANDED,
2017e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   options&OPT_LINENUMBERS,
2018e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   handle);
2019e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (ret)
2020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			ret = zero_entries(chain,
2021e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher					   options&OPT_VERBOSE, handle);
2022e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2023e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_NEW_CHAIN:
2024e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = iptc_create_chain(chain, handle);
2025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_DELETE_CHAIN:
2027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = delete_chain(chain, options&OPT_VERBOSE, handle);
2028e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_RENAME_CHAIN:
2030e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = iptc_rename_chain(chain, newname,	handle);
2031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case CMD_SET_POLICY:
2033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		ret = iptc_set_policy(chain, policy, handle);
2034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
2035e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	default:
2036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		/* We should never reach this... */
2037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_tryhelp(2);
2038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
2039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2040e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (verbose > 1)
2041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		dump_entries(*handle);
2042e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
2043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return ret;
2044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
2045