blob: 7d8771d0b44343ae50e7d331ef63418df3e6ad6f [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Code to take an iptables-style command line and do it. */
2
3/*
4 * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
5 *
Harald Welted4ab5ad2002-08-07 09:07:24 +00006 * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>:
7 * Paul 'Rusty' Russell <rusty@rustcorp.com.au>
8 * Marc Boucher <marc+nf@mbsi.ca>
9 * James Morris <jmorris@intercode.com.au>
10 * Harald Welte <laforge@gnumonks.org>
11 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
12 *
Marc Bouchere6869a82000-03-20 06:03:29 +000013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <getopt.h>
29#include <string.h>
30#include <netdb.h>
31#include <errno.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <dlfcn.h>
35#include <ctype.h>
36#include <stdarg.h>
37#include <limits.h>
Harald Welte82dd2ec2000-12-19 05:18:15 +000038#include <unistd.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000039#include <iptables.h>
Harald Welte82dd2ec2000-12-19 05:18:15 +000040#include <fcntl.h>
41#include <sys/wait.h>
Phil Oester8cf65912005-09-19 15:00:33 +000042#include <sys/utsname.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000043
44#ifndef TRUE
45#define TRUE 1
46#endif
47#ifndef FALSE
48#define FALSE 0
49#endif
50
Harald Welte82dd2ec2000-12-19 05:18:15 +000051#ifndef PROC_SYS_MODPROBE
52#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
53#endif
54
Marc Bouchere6869a82000-03-20 06:03:29 +000055#define FMT_NUMERIC 0x0001
56#define FMT_NOCOUNTS 0x0002
57#define FMT_KILOMEGAGIGA 0x0004
58#define FMT_OPTIONS 0x0008
59#define FMT_NOTABLE 0x0010
60#define FMT_NOTARGET 0x0020
61#define FMT_VIA 0x0040
62#define FMT_NONEWLINE 0x0080
63#define FMT_LINENUMBERS 0x0100
64
65#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \
66 | FMT_NUMERIC | FMT_NOTABLE)
67#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
68
69
70#define CMD_NONE 0x0000U
71#define CMD_INSERT 0x0001U
72#define CMD_DELETE 0x0002U
73#define CMD_DELETE_NUM 0x0004U
74#define CMD_REPLACE 0x0008U
75#define CMD_APPEND 0x0010U
76#define CMD_LIST 0x0020U
77#define CMD_FLUSH 0x0040U
78#define CMD_ZERO 0x0080U
79#define CMD_NEW_CHAIN 0x0100U
80#define CMD_DELETE_CHAIN 0x0200U
81#define CMD_SET_POLICY 0x0400U
Harald Welte0eca33f2006-04-21 11:56:30 +000082#define CMD_RENAME_CHAIN 0x0800U
Marc Bouchere6869a82000-03-20 06:03:29 +000083#define NUMBER_OF_CMD 13
84static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
Harald Welte6336bfd2002-05-07 14:41:43 +000085 'N', 'X', 'P', 'E' };
Marc Bouchere6869a82000-03-20 06:03:29 +000086
87#define OPTION_OFFSET 256
88
89#define OPT_NONE 0x00000U
90#define OPT_NUMERIC 0x00001U
91#define OPT_SOURCE 0x00002U
92#define OPT_DESTINATION 0x00004U
93#define OPT_PROTOCOL 0x00008U
94#define OPT_JUMP 0x00010U
95#define OPT_VERBOSE 0x00020U
96#define OPT_EXPANDED 0x00040U
97#define OPT_VIANAMEIN 0x00080U
98#define OPT_VIANAMEOUT 0x00100U
99#define OPT_FRAGMENT 0x00200U
100#define OPT_LINENUMBERS 0x00400U
Harald Welteccd49e52001-01-23 22:54:34 +0000101#define OPT_COUNTERS 0x00800U
102#define NUMBER_OF_OPT 12
Marc Bouchere6869a82000-03-20 06:03:29 +0000103static const char optflags[NUMBER_OF_OPT]
Jonas Berlin4a06cf02005-04-01 06:38:25 +0000104= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '0', 'c'};
Marc Bouchere6869a82000-03-20 06:03:29 +0000105
106static struct option original_opts[] = {
107 { "append", 1, 0, 'A' },
108 { "delete", 1, 0, 'D' },
109 { "insert", 1, 0, 'I' },
110 { "replace", 1, 0, 'R' },
111 { "list", 2, 0, 'L' },
112 { "flush", 2, 0, 'F' },
113 { "zero", 2, 0, 'Z' },
Marc Bouchere6869a82000-03-20 06:03:29 +0000114 { "new-chain", 1, 0, 'N' },
115 { "delete-chain", 2, 0, 'X' },
Harald Welte68ec9c72002-11-02 14:48:17 +0000116 { "rename-chain", 1, 0, 'E' },
Marc Bouchere6869a82000-03-20 06:03:29 +0000117 { "policy", 1, 0, 'P' },
118 { "source", 1, 0, 's' },
119 { "destination", 1, 0, 'd' },
120 { "src", 1, 0, 's' }, /* synonym */
121 { "dst", 1, 0, 'd' }, /* synonym */
Rusty Russell2e0a3212000-04-19 11:23:18 +0000122 { "protocol", 1, 0, 'p' },
Marc Bouchere6869a82000-03-20 06:03:29 +0000123 { "in-interface", 1, 0, 'i' },
124 { "jump", 1, 0, 'j' },
125 { "table", 1, 0, 't' },
126 { "match", 1, 0, 'm' },
127 { "numeric", 0, 0, 'n' },
128 { "out-interface", 1, 0, 'o' },
129 { "verbose", 0, 0, 'v' },
130 { "exact", 0, 0, 'x' },
131 { "fragments", 0, 0, 'f' },
132 { "version", 0, 0, 'V' },
133 { "help", 2, 0, 'h' },
134 { "line-numbers", 0, 0, '0' },
Harald Welte82dd2ec2000-12-19 05:18:15 +0000135 { "modprobe", 1, 0, 'M' },
Harald Welteccd49e52001-01-23 22:54:34 +0000136 { "set-counters", 1, 0, 'c' },
Henrik Nordstrom17fc1632005-11-05 09:26:40 +0000137 { "goto", 1, 0, 'g' },
Marc Bouchere6869a82000-03-20 06:03:29 +0000138 { 0 }
139};
140
Illes Marci63e90632003-03-03 08:08:37 +0000141/* we need this for iptables-restore. iptables-restore.c sets line to the
142 * current line of the input file, in order to give a more precise error
143 * message. iptables itself doesn't need this, so it is initialized to the
144 * magic number of -1 */
145int line = -1;
146
Marc Bouchere6869a82000-03-20 06:03:29 +0000147static struct option *opts = original_opts;
148static unsigned int global_option_offset = 0;
149
150/* Table of legal combinations of commands and options. If any of the
151 * given commands make an option legal, that option is legal (applies to
152 * CMD_LIST and CMD_ZERO only).
153 * Key:
154 * + compulsory
155 * x illegal
156 * optional
157 */
158
159static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
160/* Well, it's better than "Re: Linux vs FreeBSD" */
161{
Patrick McHardyHarald Welte2cfbd9f2006-04-22 02:08:12 +0000162 /* -n -s -d -p -j -v -x -i -o -f --line -c */
163/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
164/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x','x'},
165/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
166/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
167/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '},
168/*LIST*/ {' ','x','x','x','x',' ',' ','x','x','x',' ','x'},
169/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
170/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
171/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
172/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
173/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
Patrick McHardyHarald Welte2cfbd9f2006-04-22 02:08:12 +0000174/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}
Marc Bouchere6869a82000-03-20 06:03:29 +0000175};
176
177static int inverse_for_options[NUMBER_OF_OPT] =
178{
179/* -n */ 0,
180/* -s */ IPT_INV_SRCIP,
181/* -d */ IPT_INV_DSTIP,
182/* -p */ IPT_INV_PROTO,
183/* -j */ 0,
184/* -v */ 0,
185/* -x */ 0,
186/* -i */ IPT_INV_VIA_IN,
187/* -o */ IPT_INV_VIA_OUT,
188/* -f */ IPT_INV_FRAG,
Patrick McHardyHarald Welte2cfbd9f2006-04-22 02:08:12 +0000189/*--line*/ 0,
190/* -c */ 0,
Marc Bouchere6869a82000-03-20 06:03:29 +0000191};
192
193const char *program_version;
194const char *program_name;
Martin Josefsson357d59d2004-12-27 19:49:28 +0000195char *lib_dir;
Marc Bouchere6869a82000-03-20 06:03:29 +0000196
Phil Oester8cf65912005-09-19 15:00:33 +0000197int kernel_version;
198
Yasuyuki KOZAKAI740d7272006-11-13 05:09:16 +0000199/* the path to command to load kernel module */
200const char *modprobe = NULL;
201
Rusty Russell2e0a3212000-04-19 11:23:18 +0000202/* Keeping track of external matches and targets: linked lists. */
Marc Bouchere6869a82000-03-20 06:03:29 +0000203struct iptables_match *iptables_matches = NULL;
204struct iptables_target *iptables_targets = NULL;
205
206/* Extra debugging from libiptc */
207extern void dump_entries(const iptc_handle_t handle);
208
209/* A few hardcoded protocols for 'all' and in case the user has no
210 /etc/protocols */
211struct pprot {
212 char *name;
213 u_int8_t num;
214};
215
Rusty Russella3e6aaa2000-12-19 04:45:23 +0000216/* Primitive headers... */
András Kis-Szabó764316a2001-02-26 17:31:20 +0000217/* defined in netinet/in.h */
218#if 0
Rusty Russella3e6aaa2000-12-19 04:45:23 +0000219#ifndef IPPROTO_ESP
220#define IPPROTO_ESP 50
221#endif
222#ifndef IPPROTO_AH
223#define IPPROTO_AH 51
224#endif
András Kis-Szabó764316a2001-02-26 17:31:20 +0000225#endif
Rusty Russella3e6aaa2000-12-19 04:45:23 +0000226
Marc Bouchere6869a82000-03-20 06:03:29 +0000227static const struct pprot chain_protos[] = {
228 { "tcp", IPPROTO_TCP },
229 { "udp", IPPROTO_UDP },
230 { "icmp", IPPROTO_ICMP },
Jan Echternachaf8fe9e2000-08-27 07:41:39 +0000231 { "esp", IPPROTO_ESP },
232 { "ah", IPPROTO_AH },
Harald Welte12915232004-02-21 09:20:34 +0000233 { "sctp", IPPROTO_SCTP },
Marc Bouchere6869a82000-03-20 06:03:29 +0000234};
235
Patrick McHardyJesper Brouerc1eae412006-07-25 01:50:48 +0000236static char *
Rusty Russell28381a42000-05-10 00:19:50 +0000237proto_to_name(u_int8_t proto, int nolookup)
Marc Bouchere6869a82000-03-20 06:03:29 +0000238{
239 unsigned int i;
240
Rusty Russell28381a42000-05-10 00:19:50 +0000241 if (proto && !nolookup) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000242 struct protoent *pent = getprotobynumber(proto);
243 if (pent)
244 return pent->p_name;
245 }
246
247 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
248 if (chain_protos[i].num == proto)
249 return chain_protos[i].name;
250
251 return NULL;
252}
253
Phil Oester58179b12006-07-20 17:00:19 +0000254int
255service_to_port(const char *name, const char *proto)
256{
257 struct servent *service;
258
259 if ((service = getservbyname(name, proto)) != NULL)
260 return ntohs((unsigned short) service->s_port);
261
262 return -1;
263}
264
Phil Oesterdbac8ad2006-07-20 17:01:54 +0000265u_int16_t
266parse_port(const char *port, const char *proto)
267{
268 unsigned int portnum;
269
270 if ((string_to_number(port, 0, 65535, &portnum)) != -1 ||
271 (portnum = service_to_port(port, proto)) != -1)
272 return (u_int16_t)portnum;
273
274 exit_error(PARAMETER_PROBLEM,
275 "invalid port/service `%s' specified", port);
276}
277
Pablo Neira Ayuso267a5702006-11-29 13:32:32 +0000278enum {
279 IPT_DOTTED_ADDR = 0,
280 IPT_DOTTED_MASK
281};
282
283static struct in_addr *
284__dotted_to_addr(const char *dotted, int type)
Marc Bouchere6869a82000-03-20 06:03:29 +0000285{
286 static struct in_addr addr;
287 unsigned char *addrp;
288 char *p, *q;
Harald Welteed498492001-07-23 01:24:22 +0000289 unsigned int onebyte;
290 int i;
Marc Bouchere6869a82000-03-20 06:03:29 +0000291 char buf[20];
292
293 /* copy dotted string, because we need to modify it */
294 strncpy(buf, dotted, sizeof(buf) - 1);
Karsten Desler9cc354f2004-01-31 13:22:18 +0000295 buf[sizeof(buf) - 1] = '\0';
Marc Bouchere6869a82000-03-20 06:03:29 +0000296 addrp = (unsigned char *) &(addr.s_addr);
297
298 p = buf;
299 for (i = 0; i < 3; i++) {
Pablo Neira Ayuso267a5702006-11-29 13:32:32 +0000300 if ((q = strchr(p, '.')) == NULL) {
301 if (type == IPT_DOTTED_ADDR) {
302 /* autocomplete, this is a network address */
303 if (string_to_number(p, 0, 255, &onebyte) == -1)
304 return (struct in_addr *) NULL;
305
306 addrp[i] = (unsigned char) onebyte;
307 while (i < 3)
308 addrp[++i] = 0;
309
310 return &addr;
311 } else
312 return (struct in_addr *) NULL;
313 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000314
315 *q = '\0';
Harald Welteed498492001-07-23 01:24:22 +0000316 if (string_to_number(p, 0, 255, &onebyte) == -1)
Marc Bouchere6869a82000-03-20 06:03:29 +0000317 return (struct in_addr *) NULL;
318
319 addrp[i] = (unsigned char) onebyte;
320 p = q + 1;
321 }
322
323 /* we've checked 3 bytes, now we check the last one */
Harald Welteed498492001-07-23 01:24:22 +0000324 if (string_to_number(p, 0, 255, &onebyte) == -1)
Marc Bouchere6869a82000-03-20 06:03:29 +0000325 return (struct in_addr *) NULL;
326
327 addrp[3] = (unsigned char) onebyte;
328
329 return &addr;
330}
331
Pablo Neira Ayuso267a5702006-11-29 13:32:32 +0000332struct in_addr *
333dotted_to_addr(const char *dotted)
334{
335 return __dotted_to_addr(dotted, IPT_DOTTED_ADDR);
336}
337
338struct in_addr *
339dotted_to_mask(const char *dotted)
340{
341 return __dotted_to_addr(dotted, IPT_DOTTED_MASK);
342}
343
Marc Bouchere6869a82000-03-20 06:03:29 +0000344static struct in_addr *
345network_to_addr(const char *name)
346{
347 struct netent *net;
348 static struct in_addr addr;
349
350 if ((net = getnetbyname(name)) != NULL) {
351 if (net->n_addrtype != AF_INET)
352 return (struct in_addr *) NULL;
353 addr.s_addr = htonl((unsigned long) net->n_net);
354 return &addr;
355 }
356
357 return (struct in_addr *) NULL;
358}
359
360static void
361inaddrcpy(struct in_addr *dst, struct in_addr *src)
362{
363 /* memcpy(dst, src, sizeof(struct in_addr)); */
364 dst->s_addr = src->s_addr;
365}
366
Pablo Neiradfdcd642005-05-29 19:05:23 +0000367static void free_opts(int reset_offset)
368{
369 if (opts != original_opts) {
370 free(opts);
371 opts = original_opts;
372 if (reset_offset)
373 global_option_offset = 0;
374 }
375}
376
Marc Bouchere6869a82000-03-20 06:03:29 +0000377void
378exit_error(enum exittype status, char *msg, ...)
379{
380 va_list args;
381
382 va_start(args, msg);
383 fprintf(stderr, "%s v%s: ", program_name, program_version);
384 vfprintf(stderr, msg, args);
385 va_end(args);
386 fprintf(stderr, "\n");
387 if (status == PARAMETER_PROBLEM)
388 exit_tryhelp(status);
389 if (status == VERSION_PROBLEM)
390 fprintf(stderr,
391 "Perhaps iptables or your kernel needs to be upgraded.\n");
Pablo Neiradfdcd642005-05-29 19:05:23 +0000392 /* On error paths, make sure that we don't leak memory */
393 free_opts(1);
Marc Bouchere6869a82000-03-20 06:03:29 +0000394 exit(status);
395}
396
397void
398exit_tryhelp(int status)
399{
Maciej Soltysiakedad9bb2003-03-31 12:11:55 +0000400 if (line != -1)
Harald Weltea5bb0a62003-05-03 18:56:19 +0000401 fprintf(stderr, "Error occurred at line: %d\n", line);
Marc Bouchere6869a82000-03-20 06:03:29 +0000402 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
403 program_name, program_name );
Pablo Neiradfdcd642005-05-29 19:05:23 +0000404 free_opts(1);
Marc Bouchere6869a82000-03-20 06:03:29 +0000405 exit(status);
406}
407
408void
Martin Josefsson66aea6f2004-05-26 15:41:54 +0000409exit_printhelp(struct iptables_rule_match *matches)
Marc Bouchere6869a82000-03-20 06:03:29 +0000410{
Martin Josefsson66aea6f2004-05-26 15:41:54 +0000411 struct iptables_rule_match *matchp = NULL;
Rusty Russell2e0a3212000-04-19 11:23:18 +0000412 struct iptables_target *t = NULL;
413
Marc Bouchere6869a82000-03-20 06:03:29 +0000414 printf("%s v%s\n\n"
András Kis-Szabó0c4188f2002-08-14 11:40:41 +0000415"Usage: %s -[AD] chain rule-specification [options]\n"
Marc Bouchere6869a82000-03-20 06:03:29 +0000416" %s -[RI] chain rulenum rule-specification [options]\n"
417" %s -D chain rulenum [options]\n"
418" %s -[LFZ] [chain] [options]\n"
419" %s -[NX] chain\n"
420" %s -E old-chain-name new-chain-name\n"
421" %s -P chain target [options]\n"
422" %s -h (print this help information)\n\n",
423 program_name, program_version, program_name, program_name,
424 program_name, program_name, program_name, program_name,
425 program_name, program_name);
426
427 printf(
428"Commands:\n"
429"Either long or short options are allowed.\n"
430" --append -A chain Append to chain\n"
431" --delete -D chain Delete matching rule from chain\n"
432" --delete -D chain rulenum\n"
433" Delete rule rulenum (1 = first) from chain\n"
434" --insert -I chain [rulenum]\n"
435" Insert in chain as rulenum (default 1=first)\n"
436" --replace -R chain rulenum\n"
437" Replace rule rulenum (1 = first) in chain\n"
438" --list -L [chain] List the rules in a chain or all chains\n"
439" --flush -F [chain] Delete all rules in chain or all chains\n"
440" --zero -Z [chain] Zero counters in chain or all chains\n"
Marc Bouchere6869a82000-03-20 06:03:29 +0000441" --new -N chain Create a new user-defined chain\n"
442" --delete-chain\n"
443" -X [chain] Delete a user-defined chain\n"
444" --policy -P chain target\n"
445" Change policy on chain to target\n"
446" --rename-chain\n"
447" -E old-chain new-chain\n"
448" Change chain name, (moving any references)\n"
449
450"Options:\n"
451" --proto -p [!] proto protocol: by number or name, eg. `tcp'\n"
452" --source -s [!] address[/mask]\n"
453" source specification\n"
454" --destination -d [!] address[/mask]\n"
455" destination specification\n"
456" --in-interface -i [!] input name[+]\n"
457" network interface name ([+] for wildcard)\n"
458" --jump -j target\n"
Rusty Russell363112d2000-08-11 13:49:26 +0000459" target for rule (may load target extension)\n"
Henrik Nordstrom17fc1632005-11-05 09:26:40 +0000460#ifdef IPT_F_GOTO
461" --goto -g chain\n"
462" jump to chain with no return\n"
463#endif
Rusty Russell363112d2000-08-11 13:49:26 +0000464" --match -m match\n"
465" extended match (may load extension)\n"
Marc Bouchere6869a82000-03-20 06:03:29 +0000466" --numeric -n numeric output of addresses and ports\n"
467" --out-interface -o [!] output name[+]\n"
468" network interface name ([+] for wildcard)\n"
469" --table -t table table to manipulate (default: `filter')\n"
470" --verbose -v verbose mode\n"
Harald Welte82dd2ec2000-12-19 05:18:15 +0000471" --line-numbers print line numbers when listing\n"
Marc Bouchere6869a82000-03-20 06:03:29 +0000472" --exact -x expand numbers (display exact values)\n"
473"[!] --fragment -f match second or further fragments only\n"
Rusty Russella4d3e1f2001-01-07 06:56:02 +0000474" --modprobe=<command> try to insert modules using this command\n"
Harald Welteccd49e52001-01-23 22:54:34 +0000475" --set-counters PKTS BYTES set the counter during insert/append\n"
Marc Bouchere6869a82000-03-20 06:03:29 +0000476"[!] --version -V print package version.\n");
477
Rusty Russell363112d2000-08-11 13:49:26 +0000478 /* Print out any special helps. A user might like to be able
479 to add a --help to the commandline, and see expected
Martin Josefsson66aea6f2004-05-26 15:41:54 +0000480 results. So we call help for all specified matches & targets */
481 for (t = iptables_targets; t ;t = t->next) {
482 if (t->used) {
483 printf("\n");
484 t->help();
485 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000486 }
Martin Josefsson66aea6f2004-05-26 15:41:54 +0000487 for (matchp = matches; matchp; matchp = matchp->next) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000488 printf("\n");
Martin Josefsson66aea6f2004-05-26 15:41:54 +0000489 matchp->match->help();
Marc Bouchere6869a82000-03-20 06:03:29 +0000490 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000491 exit(0);
492}
493
494static void
495generic_opt_check(int command, int options)
496{
497 int i, j, legal = 0;
498
499 /* Check that commands are valid with options. Complicated by the
500 * fact that if an option is legal with *any* command given, it is
501 * legal overall (ie. -z and -l).
502 */
503 for (i = 0; i < NUMBER_OF_OPT; i++) {
504 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
505
506 for (j = 0; j < NUMBER_OF_CMD; j++) {
507 if (!(command & (1<<j)))
508 continue;
509
510 if (!(options & (1<<i))) {
511 if (commands_v_options[j][i] == '+')
512 exit_error(PARAMETER_PROBLEM,
513 "You need to supply the `-%c' "
514 "option for this command\n",
515 optflags[i]);
516 } else {
517 if (commands_v_options[j][i] != 'x')
518 legal = 1;
519 else if (legal == 0)
520 legal = -1;
521 }
522 }
523 if (legal == -1)
524 exit_error(PARAMETER_PROBLEM,
525 "Illegal option `-%c' with this command\n",
526 optflags[i]);
527 }
528}
529
530static char
531opt2char(int option)
532{
533 const char *ptr;
534 for (ptr = optflags; option > 1; option >>= 1, ptr++);
535
536 return *ptr;
537}
538
539static char
540cmd2char(int option)
541{
542 const char *ptr;
543 for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
544
545 return *ptr;
546}
547
548static void
Harald Welteefa8fc22005-07-19 22:03:49 +0000549add_command(unsigned int *cmd, const int newcmd, const int othercmds,
550 int invert)
Marc Bouchere6869a82000-03-20 06:03:29 +0000551{
552 if (invert)
553 exit_error(PARAMETER_PROBLEM, "unexpected ! flag");
554 if (*cmd & (~othercmds))
555 exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
556 cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
557 *cmd |= newcmd;
558}
559
560int
Harald Welteb77f1da2002-03-14 11:35:58 +0000561check_inverse(const char option[], int *invert, int *optind, int argc)
Marc Bouchere6869a82000-03-20 06:03:29 +0000562{
563 if (option && strcmp(option, "!") == 0) {
564 if (*invert)
565 exit_error(PARAMETER_PROBLEM,
566 "Multiple `!' flags not allowed");
Marc Bouchere6869a82000-03-20 06:03:29 +0000567 *invert = TRUE;
Harald Welteb77f1da2002-03-14 11:35:58 +0000568 if (optind) {
569 *optind = *optind+1;
570 if (argc && *optind > argc)
571 exit_error(PARAMETER_PROBLEM,
572 "no argument following `!'");
573 }
574
Marc Bouchere6869a82000-03-20 06:03:29 +0000575 return TRUE;
576 }
577 return FALSE;
578}
579
580static void *
581fw_calloc(size_t count, size_t size)
582{
583 void *p;
584
585 if ((p = calloc(count, size)) == NULL) {
586 perror("iptables: calloc failed");
587 exit(1);
588 }
589 return p;
590}
591
592static void *
593fw_malloc(size_t size)
594{
595 void *p;
596
597 if ((p = malloc(size)) == NULL) {
598 perror("iptables: malloc failed");
599 exit(1);
600 }
601 return p;
602}
603
604static struct in_addr *
605host_to_addr(const char *name, unsigned int *naddr)
606{
607 struct hostent *host;
608 struct in_addr *addr;
609 unsigned int i;
610
611 *naddr = 0;
612 if ((host = gethostbyname(name)) != NULL) {
613 if (host->h_addrtype != AF_INET ||
614 host->h_length != sizeof(struct in_addr))
615 return (struct in_addr *) NULL;
616
617 while (host->h_addr_list[*naddr] != (char *) NULL)
618 (*naddr)++;
Patrick McHardy80938442004-08-03 22:38:39 +0000619 addr = fw_calloc(*naddr, sizeof(struct in_addr) * *naddr);
Marc Bouchere6869a82000-03-20 06:03:29 +0000620 for (i = 0; i < *naddr; i++)
621 inaddrcpy(&(addr[i]),
622 (struct in_addr *) host->h_addr_list[i]);
623 return addr;
624 }
625
626 return (struct in_addr *) NULL;
627}
628
629static char *
630addr_to_host(const struct in_addr *addr)
631{
632 struct hostent *host;
633
634 if ((host = gethostbyaddr((char *) addr,
635 sizeof(struct in_addr), AF_INET)) != NULL)
636 return (char *) host->h_name;
637
638 return (char *) NULL;
639}
640
641/*
642 * All functions starting with "parse" should succeed, otherwise
643 * the program fails.
644 * Most routines return pointers to static data that may change
645 * between calls to the same or other routines with a few exceptions:
646 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
647 * return global static data.
648*/
649
650static struct in_addr *
651parse_hostnetwork(const char *name, unsigned int *naddrs)
652{
653 struct in_addr *addrp, *addrptmp;
654
655 if ((addrptmp = dotted_to_addr(name)) != NULL ||
656 (addrptmp = network_to_addr(name)) != NULL) {
657 addrp = fw_malloc(sizeof(struct in_addr));
658 inaddrcpy(addrp, addrptmp);
659 *naddrs = 1;
660 return addrp;
661 }
662 if ((addrp = host_to_addr(name, naddrs)) != NULL)
663 return addrp;
664
665 exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
666}
667
668static struct in_addr *
669parse_mask(char *mask)
670{
671 static struct in_addr maskaddr;
672 struct in_addr *addrp;
Harald Welteed498492001-07-23 01:24:22 +0000673 unsigned int bits;
Marc Bouchere6869a82000-03-20 06:03:29 +0000674
675 if (mask == NULL) {
676 /* no mask at all defaults to 32 bits */
677 maskaddr.s_addr = 0xFFFFFFFF;
678 return &maskaddr;
679 }
Pablo Neira Ayuso267a5702006-11-29 13:32:32 +0000680 if ((addrp = dotted_to_mask(mask)) != NULL)
Marc Bouchere6869a82000-03-20 06:03:29 +0000681 /* dotted_to_addr already returns a network byte order addr */
682 return addrp;
Harald Welteed498492001-07-23 01:24:22 +0000683 if (string_to_number(mask, 0, 32, &bits) == -1)
Marc Bouchere6869a82000-03-20 06:03:29 +0000684 exit_error(PARAMETER_PROBLEM,
685 "invalid mask `%s' specified", mask);
686 if (bits != 0) {
687 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
688 return &maskaddr;
689 }
690
691 maskaddr.s_addr = 0L;
692 return &maskaddr;
693}
694
Marc Boucherb93c7982001-12-06 14:50:19 +0000695void
Marc Bouchere6869a82000-03-20 06:03:29 +0000696parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
697 struct in_addr *maskp, unsigned int *naddrs)
698{
699 struct in_addr *addrp;
700 char buf[256];
701 char *p;
702 int i, j, k, n;
703
704 strncpy(buf, name, sizeof(buf) - 1);
Karsten Desler617b7dd2004-01-31 15:14:38 +0000705 buf[sizeof(buf) - 1] = '\0';
Marc Bouchere6869a82000-03-20 06:03:29 +0000706 if ((p = strrchr(buf, '/')) != NULL) {
707 *p = '\0';
708 addrp = parse_mask(p + 1);
709 } else
710 addrp = parse_mask(NULL);
711 inaddrcpy(maskp, addrp);
712
713 /* if a null mask is given, the name is ignored, like in "any/0" */
714 if (maskp->s_addr == 0L)
715 strcpy(buf, "0.0.0.0");
716
717 addrp = *addrpp = parse_hostnetwork(buf, naddrs);
718 n = *naddrs;
719 for (i = 0, j = 0; i < n; i++) {
720 addrp[j++].s_addr &= maskp->s_addr;
721 for (k = 0; k < j - 1; k++) {
722 if (addrp[k].s_addr == addrp[j - 1].s_addr) {
723 (*naddrs)--;
724 j--;
725 break;
726 }
727 }
728 }
729}
730
731struct iptables_match *
Martin Josefsson78cafda2004-02-02 20:01:18 +0000732find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_match **matches)
Marc Bouchere6869a82000-03-20 06:03:29 +0000733{
734 struct iptables_match *ptr;
735
736 for (ptr = iptables_matches; ptr; ptr = ptr->next) {
Joszef Kadlecsika258ad72006-03-03 09:36:50 +0000737 if (strcmp(name, ptr->name) == 0) {
738 struct iptables_match *clone;
739
740 /* First match of this type: */
741 if (ptr->m == NULL)
742 break;
743
744 /* Second and subsequent clones */
745 clone = fw_malloc(sizeof(struct iptables_match));
746 memcpy(clone, ptr, sizeof(struct iptables_match));
747 clone->mflags = 0;
748 /* This is a clone: */
749 clone->next = clone;
750
751 ptr = clone;
Marc Bouchere6869a82000-03-20 06:03:29 +0000752 break;
Joszef Kadlecsika258ad72006-03-03 09:36:50 +0000753 }
754 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000755
Harald Welte3efb6ea2001-08-06 18:50:21 +0000756#ifndef NO_SHARED_LIBS
Jones Desougif5b86e62005-12-22 03:33:50 +0000757 if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
Rusty Russell208d42e2004-12-20 05:29:52 +0000758 char path[strlen(lib_dir) + sizeof("/libipt_.so")
Marc Bouchere6869a82000-03-20 06:03:29 +0000759 + strlen(name)];
Rusty Russell208d42e2004-12-20 05:29:52 +0000760 sprintf(path, "%s/libipt_%s.so", lib_dir, name);
Rusty Russell9e1d2142000-04-23 09:11:12 +0000761 if (dlopen(path, RTLD_NOW)) {
762 /* Found library. If it didn't register itself,
763 maybe they specified target as match. */
Martin Josefsson78cafda2004-02-02 20:01:18 +0000764 ptr = find_match(name, DONT_LOAD, NULL);
Rusty Russell52a51492000-05-02 16:44:29 +0000765
Rusty Russell9e1d2142000-04-23 09:11:12 +0000766 if (!ptr)
767 exit_error(PARAMETER_PROBLEM,
768 "Couldn't load match `%s'\n",
769 name);
Rusty Russell52a51492000-05-02 16:44:29 +0000770 } else if (tryload == LOAD_MUST_SUCCEED)
771 exit_error(PARAMETER_PROBLEM,
Rusty Russella4d3e1f2001-01-07 06:56:02 +0000772 "Couldn't load match `%s':%s\n",
Harald Welteaa204722000-08-11 14:02:27 +0000773 name, dlerror());
Marc Bouchere6869a82000-03-20 06:03:29 +0000774 }
Harald Welte3efb6ea2001-08-06 18:50:21 +0000775#else
776 if (ptr && !ptr->loaded) {
777 if (tryload != DONT_LOAD)
778 ptr->loaded = 1;
779 else
780 ptr = NULL;
781 }
Marc Boucher067477b2002-03-24 15:09:31 +0000782 if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
783 exit_error(PARAMETER_PROBLEM,
784 "Couldn't find match `%s'\n", name);
785 }
Harald Welte3efb6ea2001-08-06 18:50:21 +0000786#endif
Marc Bouchere6869a82000-03-20 06:03:29 +0000787
Martin Josefsson78cafda2004-02-02 20:01:18 +0000788 if (ptr && matches) {
789 struct iptables_rule_match **i;
790 struct iptables_rule_match *newentry;
791
792 newentry = fw_malloc(sizeof(struct iptables_rule_match));
793
Joszef Kadlecsika258ad72006-03-03 09:36:50 +0000794 for (i = matches; *i; i = &(*i)->next) {
795 if (strcmp(name, (*i)->match->name) == 0)
796 (*i)->completed = 1;
797 }
Martin Josefsson78cafda2004-02-02 20:01:18 +0000798 newentry->match = ptr;
Joszef Kadlecsika258ad72006-03-03 09:36:50 +0000799 newentry->completed = 0;
Martin Josefsson78cafda2004-02-02 20:01:18 +0000800 newentry->next = NULL;
801 *i = newentry;
802 }
Harald Welteae1ff9f2000-12-01 14:26:20 +0000803
Marc Bouchere6869a82000-03-20 06:03:29 +0000804 return ptr;
805}
806
Rusty Russell28381a42000-05-10 00:19:50 +0000807/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
808static struct iptables_match *
Martin Josefsson78cafda2004-02-02 20:01:18 +0000809find_proto(const char *pname, enum ipt_tryload tryload, int nolookup, struct iptables_rule_match **matches)
Rusty Russell28381a42000-05-10 00:19:50 +0000810{
Harald Welteed498492001-07-23 01:24:22 +0000811 unsigned int proto;
Rusty Russell28381a42000-05-10 00:19:50 +0000812
Harald Welte0b0013a2002-02-18 16:15:31 +0000813 if (string_to_number(pname, 0, 255, &proto) != -1) {
814 char *protoname = proto_to_name(proto, nolookup);
Rusty Russell28381a42000-05-10 00:19:50 +0000815
Harald Welte0b0013a2002-02-18 16:15:31 +0000816 if (protoname)
Martin Josefsson78cafda2004-02-02 20:01:18 +0000817 return find_match(protoname, tryload, matches);
Harald Welte0b0013a2002-02-18 16:15:31 +0000818 } else
Martin Josefsson78cafda2004-02-02 20:01:18 +0000819 return find_match(pname, tryload, matches);
Harald Welte0b0013a2002-02-18 16:15:31 +0000820
821 return NULL;
Rusty Russell28381a42000-05-10 00:19:50 +0000822}
823
Marc Boucherb93c7982001-12-06 14:50:19 +0000824u_int16_t
Marc Bouchere6869a82000-03-20 06:03:29 +0000825parse_protocol(const char *s)
826{
Harald Welteed498492001-07-23 01:24:22 +0000827 unsigned int proto;
Marc Bouchere6869a82000-03-20 06:03:29 +0000828
Harald Welteed498492001-07-23 01:24:22 +0000829 if (string_to_number(s, 0, 255, &proto) == -1) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000830 struct protoent *pent;
831
Harald Weltecbe1ec72006-02-11 09:50:11 +0000832 /* first deal with the special case of 'all' to prevent
833 * people from being able to redefine 'all' in nsswitch
834 * and/or provoke expensive [not working] ldap/nis/...
835 * lookups */
836 if (!strcmp(s, "all"))
837 return 0;
838
Marc Bouchere6869a82000-03-20 06:03:29 +0000839 if ((pent = getprotobyname(s)))
840 proto = pent->p_proto;
841 else {
842 unsigned int i;
843 for (i = 0;
844 i < sizeof(chain_protos)/sizeof(struct pprot);
845 i++) {
846 if (strcmp(s, chain_protos[i].name) == 0) {
847 proto = chain_protos[i].num;
848 break;
849 }
850 }
851 if (i == sizeof(chain_protos)/sizeof(struct pprot))
852 exit_error(PARAMETER_PROBLEM,
853 "unknown protocol `%s' specified",
854 s);
855 }
856 }
857
858 return (u_int16_t)proto;
859}
860
Yasuyuki KOZAKAI9867e812005-06-22 12:24:21 +0000861void parse_interface(const char *arg, char *vianame, unsigned char *mask)
Marc Bouchere6869a82000-03-20 06:03:29 +0000862{
863 int vialen = strlen(arg);
864 unsigned int i;
865
866 memset(mask, 0, IFNAMSIZ);
867 memset(vianame, 0, IFNAMSIZ);
868
869 if (vialen + 1 > IFNAMSIZ)
870 exit_error(PARAMETER_PROBLEM,
871 "interface name `%s' must be shorter than IFNAMSIZ"
872 " (%i)", arg, IFNAMSIZ-1);
Rusty Russell7e53bf92000-03-20 07:03:28 +0000873
Marc Bouchere6869a82000-03-20 06:03:29 +0000874 strcpy(vianame, arg);
Ozgur AKAN3610deb2004-04-07 09:36:29 +0000875 if ((vialen == 0) || (vialen == 1 && vianame[0] == '+'))
Marc Bouchere6869a82000-03-20 06:03:29 +0000876 memset(mask, 0, IFNAMSIZ);
877 else if (vianame[vialen - 1] == '+') {
878 memset(mask, 0xFF, vialen - 1);
879 memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
Harald Weltede1578f2001-05-23 23:07:33 +0000880 /* Don't remove `+' here! -HW */
Marc Bouchere6869a82000-03-20 06:03:29 +0000881 } else {
882 /* Include nul-terminator in match */
883 memset(mask, 0xFF, vialen + 1);
884 memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
Harald Weltede1578f2001-05-23 23:07:33 +0000885 for (i = 0; vianame[i]; i++) {
Patrick McHardy2d1a2972006-09-20 08:32:25 +0000886 if (vianame[i] == ':' ||
887 vianame[i] == '!' ||
888 vianame[i] == '*') {
Patrick McHardy42bd67b2006-10-11 07:37:26 +0000889 printf("Warning: weird character in interface"
Harald Weltede1578f2001-05-23 23:07:33 +0000890 " `%s' (No aliases, :, ! or *).\n",
891 vianame);
892 break;
893 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000894 }
895 }
896}
897
898/* Can't be zero. */
899static int
900parse_rulenumber(const char *rule)
901{
Harald Welteed498492001-07-23 01:24:22 +0000902 unsigned int rulenum;
Marc Bouchere6869a82000-03-20 06:03:29 +0000903
Harald Welteed498492001-07-23 01:24:22 +0000904 if (string_to_number(rule, 1, INT_MAX, &rulenum) == -1)
Marc Bouchere6869a82000-03-20 06:03:29 +0000905 exit_error(PARAMETER_PROBLEM,
906 "Invalid rule number `%s'", rule);
907
908 return rulenum;
909}
910
911static const char *
912parse_target(const char *targetname)
913{
914 const char *ptr;
915
916 if (strlen(targetname) < 1)
917 exit_error(PARAMETER_PROBLEM,
918 "Invalid target name (too short)");
919
920 if (strlen(targetname)+1 > sizeof(ipt_chainlabel))
921 exit_error(PARAMETER_PROBLEM,
Martin Josefssona28d4952004-05-26 16:04:48 +0000922 "Invalid target name `%s' (%u chars max)",
923 targetname, (unsigned int)sizeof(ipt_chainlabel)-1);
Marc Bouchere6869a82000-03-20 06:03:29 +0000924
925 for (ptr = targetname; *ptr; ptr++)
926 if (isspace(*ptr))
927 exit_error(PARAMETER_PROBLEM,
928 "Invalid target name `%s'", targetname);
929 return targetname;
930}
931
932static char *
933addr_to_network(const struct in_addr *addr)
934{
935 struct netent *net;
936
937 if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
938 return (char *) net->n_name;
939
940 return (char *) NULL;
941}
942
943char *
944addr_to_dotted(const struct in_addr *addrp)
945{
946 static char buf[20];
947 const unsigned char *bytep;
948
949 bytep = (const unsigned char *) &(addrp->s_addr);
950 sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
951 return buf;
952}
Marc Boucherb93c7982001-12-06 14:50:19 +0000953
954char *
Marc Bouchere6869a82000-03-20 06:03:29 +0000955addr_to_anyname(const struct in_addr *addr)
956{
957 char *name;
958
959 if ((name = addr_to_host(addr)) != NULL ||
960 (name = addr_to_network(addr)) != NULL)
961 return name;
962
963 return addr_to_dotted(addr);
964}
965
Marc Boucherb93c7982001-12-06 14:50:19 +0000966char *
Marc Bouchere6869a82000-03-20 06:03:29 +0000967mask_to_dotted(const struct in_addr *mask)
968{
969 int i;
970 static char buf[20];
971 u_int32_t maskaddr, bits;
972
973 maskaddr = ntohl(mask->s_addr);
974
975 if (maskaddr == 0xFFFFFFFFL)
976 /* we don't want to see "/32" */
977 return "";
978
979 i = 32;
980 bits = 0xFFFFFFFEL;
981 while (--i >= 0 && maskaddr != bits)
982 bits <<= 1;
983 if (i >= 0)
984 sprintf(buf, "/%d", i);
985 else
986 /* mask was not a decent combination of 1's and 0's */
987 sprintf(buf, "/%s", addr_to_dotted(mask));
988
989 return buf;
990}
991
992int
Martin Josefssonb105bc92004-05-26 15:54:49 +0000993string_to_number_ll(const char *s, unsigned long long min, unsigned long long max,
994 unsigned long long *ret)
Marc Bouchere6869a82000-03-20 06:03:29 +0000995{
Martin Josefssonb105bc92004-05-26 15:54:49 +0000996 unsigned long long number;
Marc Bouchere6869a82000-03-20 06:03:29 +0000997 char *end;
998
999 /* Handle hex, octal, etc. */
Jan Echternach5a1041d2000-08-26 04:44:39 +00001000 errno = 0;
Martin Josefssonb105bc92004-05-26 15:54:49 +00001001 number = strtoull(s, &end, 0);
Marc Bouchere6869a82000-03-20 06:03:29 +00001002 if (*end == '\0' && end != s) {
1003 /* we parsed a number, let's see if we want this */
Martin Josefssonb105bc92004-05-26 15:54:49 +00001004 if (errno != ERANGE && min <= number && (!max || number <= max)) {
Harald Welteed498492001-07-23 01:24:22 +00001005 *ret = number;
1006 return 0;
1007 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001008 }
1009 return -1;
1010}
1011
Martin Josefssonb105bc92004-05-26 15:54:49 +00001012int
1013string_to_number_l(const char *s, unsigned long min, unsigned long max,
1014 unsigned long *ret)
1015{
1016 int result;
1017 unsigned long long number;
1018
1019 result = string_to_number_ll(s, min, max, &number);
1020 *ret = (unsigned long)number;
1021
1022 return result;
1023}
1024
1025int string_to_number(const char *s, unsigned int min, unsigned int max,
1026 unsigned int *ret)
1027{
1028 int result;
1029 unsigned long number;
1030
1031 result = string_to_number_l(s, min, max, &number);
1032 *ret = (unsigned int)number;
1033
1034 return result;
1035}
1036
Marc Bouchere6869a82000-03-20 06:03:29 +00001037static void
1038set_option(unsigned int *options, unsigned int option, u_int8_t *invflg,
1039 int invert)
1040{
1041 if (*options & option)
1042 exit_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
1043 opt2char(option));
1044 *options |= option;
1045
1046 if (invert) {
1047 unsigned int i;
1048 for (i = 0; 1 << i != option; i++);
1049
1050 if (!inverse_for_options[i])
1051 exit_error(PARAMETER_PROBLEM,
1052 "cannot have ! before -%c",
1053 opt2char(option));
1054 *invflg |= inverse_for_options[i];
1055 }
1056}
1057
1058struct iptables_target *
Rusty Russell52a51492000-05-02 16:44:29 +00001059find_target(const char *name, enum ipt_tryload tryload)
Marc Bouchere6869a82000-03-20 06:03:29 +00001060{
1061 struct iptables_target *ptr;
1062
1063 /* Standard target? */
1064 if (strcmp(name, "") == 0
1065 || strcmp(name, IPTC_LABEL_ACCEPT) == 0
1066 || strcmp(name, IPTC_LABEL_DROP) == 0
1067 || strcmp(name, IPTC_LABEL_QUEUE) == 0
1068 || strcmp(name, IPTC_LABEL_RETURN) == 0)
1069 name = "standard";
1070
1071 for (ptr = iptables_targets; ptr; ptr = ptr->next) {
1072 if (strcmp(name, ptr->name) == 0)
1073 break;
1074 }
1075
Harald Welte3efb6ea2001-08-06 18:50:21 +00001076#ifndef NO_SHARED_LIBS
Jones Desougif5b86e62005-12-22 03:33:50 +00001077 if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
Rusty Russell208d42e2004-12-20 05:29:52 +00001078 char path[strlen(lib_dir) + sizeof("/libipt_.so")
Marc Bouchere6869a82000-03-20 06:03:29 +00001079 + strlen(name)];
Rusty Russell208d42e2004-12-20 05:29:52 +00001080 sprintf(path, "%s/libipt_%s.so", lib_dir, name);
Rusty Russell9e1d2142000-04-23 09:11:12 +00001081 if (dlopen(path, RTLD_NOW)) {
1082 /* Found library. If it didn't register itself,
1083 maybe they specified match as a target. */
Rusty Russell52a51492000-05-02 16:44:29 +00001084 ptr = find_target(name, DONT_LOAD);
Rusty Russell9e1d2142000-04-23 09:11:12 +00001085 if (!ptr)
1086 exit_error(PARAMETER_PROBLEM,
1087 "Couldn't load target `%s'\n",
1088 name);
Rusty Russell52a51492000-05-02 16:44:29 +00001089 } else if (tryload == LOAD_MUST_SUCCEED)
1090 exit_error(PARAMETER_PROBLEM,
Rusty Russella4d3e1f2001-01-07 06:56:02 +00001091 "Couldn't load target `%s':%s\n",
Harald Welteaa204722000-08-11 14:02:27 +00001092 name, dlerror());
Marc Bouchere6869a82000-03-20 06:03:29 +00001093 }
Harald Welte3efb6ea2001-08-06 18:50:21 +00001094#else
1095 if (ptr && !ptr->loaded) {
1096 if (tryload != DONT_LOAD)
1097 ptr->loaded = 1;
1098 else
1099 ptr = NULL;
1100 }
Marc Boucher067477b2002-03-24 15:09:31 +00001101 if(!ptr && (tryload == LOAD_MUST_SUCCEED)) {
1102 exit_error(PARAMETER_PROBLEM,
1103 "Couldn't find target `%s'\n", name);
1104 }
Harald Welte3efb6ea2001-08-06 18:50:21 +00001105#endif
Marc Bouchere6869a82000-03-20 06:03:29 +00001106
Harald Welteae1ff9f2000-12-01 14:26:20 +00001107 if (ptr)
1108 ptr->used = 1;
1109
Marc Bouchere6869a82000-03-20 06:03:29 +00001110 return ptr;
1111}
1112
1113static struct option *
Jan Echternach5a1041d2000-08-26 04:44:39 +00001114merge_options(struct option *oldopts, const struct option *newopts,
Marc Bouchere6869a82000-03-20 06:03:29 +00001115 unsigned int *option_offset)
1116{
1117 unsigned int num_old, num_new, i;
1118 struct option *merge;
1119
1120 for (num_old = 0; oldopts[num_old].name; num_old++);
1121 for (num_new = 0; newopts[num_new].name; num_new++);
1122
1123 global_option_offset += OPTION_OFFSET;
1124 *option_offset = global_option_offset;
1125
1126 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
1127 memcpy(merge, oldopts, num_old * sizeof(struct option));
Marcus Sundbergd91ed752005-07-29 13:26:35 +00001128 free_opts(0); /* Release previous options merged if any */
Marc Bouchere6869a82000-03-20 06:03:29 +00001129 for (i = 0; i < num_new; i++) {
1130 merge[num_old + i] = newopts[i];
1131 merge[num_old + i].val += *option_offset;
1132 }
1133 memset(merge + num_old + num_new, 0, sizeof(struct option));
1134
1135 return merge;
1136}
1137
Rusty Russell3aef54d2005-01-03 03:48:40 +00001138static int compatible_revision(const char *name, u_int8_t revision, int opt)
1139{
1140 struct ipt_get_revision rev;
1141 socklen_t s = sizeof(rev);
1142 int max_rev, sockfd;
1143
1144 sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1145 if (sockfd < 0) {
1146 fprintf(stderr, "Could not open socket to kernel: %s\n",
1147 strerror(errno));
1148 exit(1);
1149 }
1150
Yasuyuki KOZAKAI740d7272006-11-13 05:09:16 +00001151 load_iptables_ko(modprobe);
1152
Rusty Russell3aef54d2005-01-03 03:48:40 +00001153 strcpy(rev.name, name);
1154 rev.revision = revision;
1155
1156 max_rev = getsockopt(sockfd, IPPROTO_IP, opt, &rev, &s);
1157 if (max_rev < 0) {
1158 /* Definitely don't support this? */
1159 if (errno == EPROTONOSUPPORT) {
1160 close(sockfd);
1161 return 0;
1162 } else if (errno == ENOPROTOOPT) {
1163 close(sockfd);
1164 /* Assume only revision 0 support (old kernel) */
1165 return (revision == 0);
1166 } else {
1167 fprintf(stderr, "getsockopt failed strangely: %s\n",
1168 strerror(errno));
1169 exit(1);
1170 }
1171 }
1172 close(sockfd);
1173 return 1;
1174}
1175
1176static int compatible_match_revision(const char *name, u_int8_t revision)
1177{
1178 return compatible_revision(name, revision, IPT_SO_GET_REVISION_MATCH);
1179}
1180
1181static int compatible_target_revision(const char *name, u_int8_t revision)
1182{
1183 return compatible_revision(name, revision, IPT_SO_GET_REVISION_TARGET);
1184}
1185
Marc Bouchere6869a82000-03-20 06:03:29 +00001186void
1187register_match(struct iptables_match *me)
1188{
Rusty Russell3aef54d2005-01-03 03:48:40 +00001189 struct iptables_match **i, *old;
Rusty Russell9f60bbf2000-07-07 02:17:46 +00001190
Marc Bouchere6869a82000-03-20 06:03:29 +00001191 if (strcmp(me->version, program_version) != 0) {
1192 fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n",
1193 program_name, me->name, me->version, program_version);
1194 exit(1);
1195 }
1196
Martin Josefsson93911bf2005-01-03 07:46:07 +00001197 /* Revision field stole a char from name. */
1198 if (strlen(me->name) >= IPT_FUNCTION_MAXNAMELEN-1) {
Rusty Russell3aef54d2005-01-03 03:48:40 +00001199 fprintf(stderr, "%s: target `%s' has invalid name\n",
Marc Bouchere6869a82000-03-20 06:03:29 +00001200 program_name, me->name);
1201 exit(1);
1202 }
1203
Jones Desougif5b86e62005-12-22 03:33:50 +00001204 old = find_match(me->name, DURING_LOAD, NULL);
Rusty Russell3aef54d2005-01-03 03:48:40 +00001205 if (old) {
1206 if (old->revision == me->revision) {
1207 fprintf(stderr,
1208 "%s: match `%s' already registered.\n",
1209 program_name, me->name);
1210 exit(1);
1211 }
1212
1213 /* Now we have two (or more) options, check compatibility. */
1214 if (compatible_match_revision(old->name, old->revision)
1215 && old->revision > me->revision)
1216 return;
1217
1218 /* Replace if compatible. */
1219 if (!compatible_match_revision(me->name, me->revision))
1220 return;
1221
1222 /* Delete old one. */
1223 for (i = &iptables_matches; *i!=old; i = &(*i)->next);
1224 *i = old->next;
1225 }
1226
Rusty Russell73f72f52000-07-03 10:17:57 +00001227 if (me->size != IPT_ALIGN(me->size)) {
1228 fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
Martin Josefssona28d4952004-05-26 16:04:48 +00001229 program_name, me->name, (unsigned int)me->size);
Rusty Russell73f72f52000-07-03 10:17:57 +00001230 exit(1);
1231 }
1232
Rusty Russell9f60bbf2000-07-07 02:17:46 +00001233 /* Append to list. */
1234 for (i = &iptables_matches; *i; i = &(*i)->next);
1235 me->next = NULL;
1236 *i = me;
1237
Marc Bouchere6869a82000-03-20 06:03:29 +00001238 me->m = NULL;
1239 me->mflags = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001240}
1241
1242void
1243register_target(struct iptables_target *me)
1244{
Rusty Russell3aef54d2005-01-03 03:48:40 +00001245 struct iptables_target *old;
1246
Marc Bouchere6869a82000-03-20 06:03:29 +00001247 if (strcmp(me->version, program_version) != 0) {
1248 fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n",
1249 program_name, me->name, me->version, program_version);
1250 exit(1);
1251 }
1252
Martin Josefsson93911bf2005-01-03 07:46:07 +00001253 /* Revision field stole a char from name. */
1254 if (strlen(me->name) >= IPT_FUNCTION_MAXNAMELEN-1) {
Rusty Russell3aef54d2005-01-03 03:48:40 +00001255 fprintf(stderr, "%s: target `%s' has invalid name\n",
Marc Bouchere6869a82000-03-20 06:03:29 +00001256 program_name, me->name);
1257 exit(1);
1258 }
1259
Jones Desougif5b86e62005-12-22 03:33:50 +00001260 old = find_target(me->name, DURING_LOAD);
Rusty Russell3aef54d2005-01-03 03:48:40 +00001261 if (old) {
1262 struct iptables_target **i;
1263
1264 if (old->revision == me->revision) {
1265 fprintf(stderr,
1266 "%s: target `%s' already registered.\n",
1267 program_name, me->name);
1268 exit(1);
1269 }
1270
Rusty Russell3aef54d2005-01-03 03:48:40 +00001271 /* Now we have two (or more) options, check compatibility. */
1272 if (compatible_target_revision(old->name, old->revision)
1273 && old->revision > me->revision)
1274 return;
1275
1276 /* Replace if compatible. */
1277 if (!compatible_target_revision(me->name, me->revision))
1278 return;
1279
1280 /* Delete old one. */
1281 for (i = &iptables_targets; *i!=old; i = &(*i)->next);
1282 *i = old->next;
1283 }
1284
Rusty Russell73f72f52000-07-03 10:17:57 +00001285 if (me->size != IPT_ALIGN(me->size)) {
1286 fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
Martin Josefssona28d4952004-05-26 16:04:48 +00001287 program_name, me->name, (unsigned int)me->size);
Rusty Russell73f72f52000-07-03 10:17:57 +00001288 exit(1);
1289 }
1290
Marc Bouchere6869a82000-03-20 06:03:29 +00001291 /* Prepend to list. */
1292 me->next = iptables_targets;
1293 iptables_targets = me;
1294 me->t = NULL;
1295 me->tflags = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001296}
1297
1298static void
Harald Weltea0b4f792001-03-25 19:55:04 +00001299print_num(u_int64_t number, unsigned int format)
1300{
1301 if (format & FMT_KILOMEGAGIGA) {
1302 if (number > 99999) {
1303 number = (number + 500) / 1000;
1304 if (number > 9999) {
1305 number = (number + 500) / 1000;
1306 if (number > 9999) {
1307 number = (number + 500) / 1000;
Rusty Russell5a66fe42001-08-15 11:21:59 +00001308 if (number > 9999) {
1309 number = (number + 500) / 1000;
Martin Josefssona28d4952004-05-26 16:04:48 +00001310 printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
Rusty Russell5a66fe42001-08-15 11:21:59 +00001311 }
Martin Josefssona28d4952004-05-26 16:04:48 +00001312 else printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
Harald Weltea0b4f792001-03-25 19:55:04 +00001313 }
Martin Josefssona28d4952004-05-26 16:04:48 +00001314 else printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
Harald Weltea0b4f792001-03-25 19:55:04 +00001315 } else
Martin Josefssona28d4952004-05-26 16:04:48 +00001316 printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
Harald Weltea0b4f792001-03-25 19:55:04 +00001317 } else
Martin Josefssona28d4952004-05-26 16:04:48 +00001318 printf(FMT("%5llu ","%llu "), (unsigned long long)number);
Harald Weltea0b4f792001-03-25 19:55:04 +00001319 } else
Martin Josefssona28d4952004-05-26 16:04:48 +00001320 printf(FMT("%8llu ","%llu "), (unsigned long long)number);
Harald Weltea0b4f792001-03-25 19:55:04 +00001321}
1322
1323
1324static void
Marc Bouchere6869a82000-03-20 06:03:29 +00001325print_header(unsigned int format, const char *chain, iptc_handle_t *handle)
1326{
1327 struct ipt_counters counters;
1328 const char *pol = iptc_get_policy(chain, &counters, handle);
1329 printf("Chain %s", chain);
1330 if (pol) {
1331 printf(" (policy %s", pol);
Harald Weltea0b4f792001-03-25 19:55:04 +00001332 if (!(format & FMT_NOCOUNTS)) {
1333 fputc(' ', stdout);
1334 print_num(counters.pcnt, (format|FMT_NOTABLE));
1335 fputs("packets, ", stdout);
1336 print_num(counters.bcnt, (format|FMT_NOTABLE));
1337 fputs("bytes", stdout);
1338 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001339 printf(")\n");
1340 } else {
1341 unsigned int refs;
Rusty Russell9e1d2142000-04-23 09:11:12 +00001342 if (!iptc_get_references(&refs, chain, handle))
1343 printf(" (ERROR obtaining refs)\n");
1344 else
1345 printf(" (%u references)\n", refs);
Marc Bouchere6869a82000-03-20 06:03:29 +00001346 }
1347
1348 if (format & FMT_LINENUMBERS)
1349 printf(FMT("%-4s ", "%s "), "num");
1350 if (!(format & FMT_NOCOUNTS)) {
1351 if (format & FMT_KILOMEGAGIGA) {
1352 printf(FMT("%5s ","%s "), "pkts");
1353 printf(FMT("%5s ","%s "), "bytes");
1354 } else {
1355 printf(FMT("%8s ","%s "), "pkts");
1356 printf(FMT("%10s ","%s "), "bytes");
1357 }
1358 }
1359 if (!(format & FMT_NOTARGET))
1360 printf(FMT("%-9s ","%s "), "target");
1361 fputs(" prot ", stdout);
1362 if (format & FMT_OPTIONS)
1363 fputs("opt", stdout);
1364 if (format & FMT_VIA) {
1365 printf(FMT(" %-6s ","%s "), "in");
1366 printf(FMT("%-6s ","%s "), "out");
1367 }
1368 printf(FMT(" %-19s ","%s "), "source");
1369 printf(FMT(" %-19s "," %s "), "destination");
1370 printf("\n");
1371}
1372
Marc Bouchere6869a82000-03-20 06:03:29 +00001373
1374static int
1375print_match(const struct ipt_entry_match *m,
1376 const struct ipt_ip *ip,
1377 int numeric)
1378{
Martin Josefsson78cafda2004-02-02 20:01:18 +00001379 struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD, NULL);
Marc Bouchere6869a82000-03-20 06:03:29 +00001380
1381 if (match) {
1382 if (match->print)
1383 match->print(ip, m, numeric);
Rusty Russell629149f2000-09-01 06:01:00 +00001384 else
Rusty Russellb039b022000-09-01 06:04:05 +00001385 printf("%s ", match->name);
Marc Bouchere6869a82000-03-20 06:03:29 +00001386 } else {
Rusty Russell228e98d2000-04-27 10:28:06 +00001387 if (m->u.user.name[0])
1388 printf("UNKNOWN match `%s' ", m->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +00001389 }
1390 /* Don't stop iterating. */
1391 return 0;
1392}
1393
1394/* e is called `fw' here for hysterical raisins */
1395static void
1396print_firewall(const struct ipt_entry *fw,
1397 const char *targname,
1398 unsigned int num,
1399 unsigned int format,
1400 const iptc_handle_t handle)
1401{
1402 struct iptables_target *target = NULL;
1403 const struct ipt_entry_target *t;
1404 u_int8_t flags;
1405 char buf[BUFSIZ];
1406
Marc Bouchere6869a82000-03-20 06:03:29 +00001407 if (!iptc_is_chain(targname, handle))
Rusty Russell52a51492000-05-02 16:44:29 +00001408 target = find_target(targname, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +00001409 else
Rusty Russell52a51492000-05-02 16:44:29 +00001410 target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED);
Marc Bouchere6869a82000-03-20 06:03:29 +00001411
1412 t = ipt_get_target((struct ipt_entry *)fw);
1413 flags = fw->ip.flags;
1414
1415 if (format & FMT_LINENUMBERS)
1416 printf(FMT("%-4u ", "%u "), num+1);
1417
1418 if (!(format & FMT_NOCOUNTS)) {
1419 print_num(fw->counters.pcnt, format);
1420 print_num(fw->counters.bcnt, format);
1421 }
1422
1423 if (!(format & FMT_NOTARGET))
1424 printf(FMT("%-9s ", "%s "), targname);
1425
1426 fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout);
1427 {
Rusty Russell28381a42000-05-10 00:19:50 +00001428 char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
Marc Bouchere6869a82000-03-20 06:03:29 +00001429 if (pname)
1430 printf(FMT("%-5s", "%s "), pname);
1431 else
1432 printf(FMT("%-5hu", "%hu "), fw->ip.proto);
1433 }
1434
1435 if (format & FMT_OPTIONS) {
1436 if (format & FMT_NOTABLE)
1437 fputs("opt ", stdout);
1438 fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
1439 fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
1440 fputc(' ', stdout);
1441 }
1442
1443 if (format & FMT_VIA) {
1444 char iface[IFNAMSIZ+2];
1445
1446 if (fw->ip.invflags & IPT_INV_VIA_IN) {
1447 iface[0] = '!';
1448 iface[1] = '\0';
1449 }
1450 else iface[0] = '\0';
1451
1452 if (fw->ip.iniface[0] != '\0') {
1453 strcat(iface, fw->ip.iniface);
Marc Bouchere6869a82000-03-20 06:03:29 +00001454 }
1455 else if (format & FMT_NUMERIC) strcat(iface, "*");
1456 else strcat(iface, "any");
1457 printf(FMT(" %-6s ","in %s "), iface);
1458
1459 if (fw->ip.invflags & IPT_INV_VIA_OUT) {
1460 iface[0] = '!';
1461 iface[1] = '\0';
1462 }
1463 else iface[0] = '\0';
1464
1465 if (fw->ip.outiface[0] != '\0') {
1466 strcat(iface, fw->ip.outiface);
Marc Bouchere6869a82000-03-20 06:03:29 +00001467 }
1468 else if (format & FMT_NUMERIC) strcat(iface, "*");
1469 else strcat(iface, "any");
1470 printf(FMT("%-6s ","out %s "), iface);
1471 }
1472
1473 fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
1474 if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
1475 printf(FMT("%-19s ","%s "), "anywhere");
1476 else {
1477 if (format & FMT_NUMERIC)
1478 sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src)));
1479 else
1480 sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src)));
1481 strcat(buf, mask_to_dotted(&(fw->ip.smsk)));
1482 printf(FMT("%-19s ","%s "), buf);
1483 }
1484
1485 fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
1486 if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
Harald Welte25fc1d72003-05-31 21:30:33 +00001487 printf(FMT("%-19s ","-> %s"), "anywhere");
Marc Bouchere6869a82000-03-20 06:03:29 +00001488 else {
1489 if (format & FMT_NUMERIC)
1490 sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst)));
1491 else
1492 sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst)));
1493 strcat(buf, mask_to_dotted(&(fw->ip.dmsk)));
Harald Welte25fc1d72003-05-31 21:30:33 +00001494 printf(FMT("%-19s ","-> %s"), buf);
Marc Bouchere6869a82000-03-20 06:03:29 +00001495 }
1496
1497 if (format & FMT_NOTABLE)
1498 fputs(" ", stdout);
1499
Harald Welte72bd87e2005-11-24 17:04:05 +00001500#ifdef IPT_F_GOTO
Henrik Nordstrom17fc1632005-11-05 09:26:40 +00001501 if(fw->ip.flags & IPT_F_GOTO)
1502 printf("[goto] ");
Harald Welte72bd87e2005-11-24 17:04:05 +00001503#endif
Henrik Nordstrom17fc1632005-11-05 09:26:40 +00001504
Marc Bouchere6869a82000-03-20 06:03:29 +00001505 IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
1506
1507 if (target) {
1508 if (target->print)
1509 /* Print the target information. */
1510 target->print(&fw->ip, t, format & FMT_NUMERIC);
Rusty Russell228e98d2000-04-27 10:28:06 +00001511 } else if (t->u.target_size != sizeof(*t))
Marc Bouchere6869a82000-03-20 06:03:29 +00001512 printf("[%u bytes of unknown target data] ",
Martin Josefssona28d4952004-05-26 16:04:48 +00001513 (unsigned int)(t->u.target_size - sizeof(*t)));
Marc Bouchere6869a82000-03-20 06:03:29 +00001514
1515 if (!(format & FMT_NONEWLINE))
1516 fputc('\n', stdout);
1517}
1518
1519static void
1520print_firewall_line(const struct ipt_entry *fw,
1521 const iptc_handle_t h)
1522{
1523 struct ipt_entry_target *t;
1524
1525 t = ipt_get_target((struct ipt_entry *)fw);
Rusty Russell228e98d2000-04-27 10:28:06 +00001526 print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
Marc Bouchere6869a82000-03-20 06:03:29 +00001527}
1528
1529static int
1530append_entry(const ipt_chainlabel chain,
1531 struct ipt_entry *fw,
1532 unsigned int nsaddrs,
1533 const struct in_addr saddrs[],
1534 unsigned int ndaddrs,
1535 const struct in_addr daddrs[],
1536 int verbose,
1537 iptc_handle_t *handle)
1538{
1539 unsigned int i, j;
1540 int ret = 1;
1541
1542 for (i = 0; i < nsaddrs; i++) {
1543 fw->ip.src.s_addr = saddrs[i].s_addr;
1544 for (j = 0; j < ndaddrs; j++) {
1545 fw->ip.dst.s_addr = daddrs[j].s_addr;
1546 if (verbose)
1547 print_firewall_line(fw, *handle);
1548 ret &= iptc_append_entry(chain, fw, handle);
1549 }
1550 }
1551
1552 return ret;
1553}
1554
1555static int
1556replace_entry(const ipt_chainlabel chain,
1557 struct ipt_entry *fw,
1558 unsigned int rulenum,
1559 const struct in_addr *saddr,
1560 const struct in_addr *daddr,
1561 int verbose,
1562 iptc_handle_t *handle)
1563{
1564 fw->ip.src.s_addr = saddr->s_addr;
1565 fw->ip.dst.s_addr = daddr->s_addr;
1566
1567 if (verbose)
1568 print_firewall_line(fw, *handle);
1569 return iptc_replace_entry(chain, fw, rulenum, handle);
1570}
1571
1572static int
1573insert_entry(const ipt_chainlabel chain,
1574 struct ipt_entry *fw,
1575 unsigned int rulenum,
1576 unsigned int nsaddrs,
1577 const struct in_addr saddrs[],
1578 unsigned int ndaddrs,
1579 const struct in_addr daddrs[],
1580 int verbose,
1581 iptc_handle_t *handle)
1582{
1583 unsigned int i, j;
1584 int ret = 1;
1585
1586 for (i = 0; i < nsaddrs; i++) {
1587 fw->ip.src.s_addr = saddrs[i].s_addr;
1588 for (j = 0; j < ndaddrs; j++) {
1589 fw->ip.dst.s_addr = daddrs[j].s_addr;
1590 if (verbose)
1591 print_firewall_line(fw, *handle);
1592 ret &= iptc_insert_entry(chain, fw, rulenum, handle);
1593 }
1594 }
1595
1596 return ret;
1597}
1598
Rusty Russell2e0a3212000-04-19 11:23:18 +00001599static unsigned char *
Martin Josefsson78cafda2004-02-02 20:01:18 +00001600make_delete_mask(struct ipt_entry *fw, struct iptables_rule_match *matches)
Rusty Russell2e0a3212000-04-19 11:23:18 +00001601{
1602 /* Establish mask for comparison */
1603 unsigned int size;
Martin Josefsson78cafda2004-02-02 20:01:18 +00001604 struct iptables_rule_match *matchp;
Rusty Russell2e0a3212000-04-19 11:23:18 +00001605 unsigned char *mask, *mptr;
1606
1607 size = sizeof(struct ipt_entry);
Martin Josefsson78cafda2004-02-02 20:01:18 +00001608 for (matchp = matches; matchp; matchp = matchp->next)
1609 size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
Rusty Russell2e0a3212000-04-19 11:23:18 +00001610
Rusty Russell9e1d2142000-04-23 09:11:12 +00001611 mask = fw_calloc(1, size
Rusty Russell73f72f52000-07-03 10:17:57 +00001612 + IPT_ALIGN(sizeof(struct ipt_entry_target))
Rusty Russell9e1d2142000-04-23 09:11:12 +00001613 + iptables_targets->size);
Rusty Russell2e0a3212000-04-19 11:23:18 +00001614
Rusty Russell9e1d2142000-04-23 09:11:12 +00001615 memset(mask, 0xFF, sizeof(struct ipt_entry));
1616 mptr = mask + sizeof(struct ipt_entry);
Rusty Russell2e0a3212000-04-19 11:23:18 +00001617
Martin Josefsson78cafda2004-02-02 20:01:18 +00001618 for (matchp = matches; matchp; matchp = matchp->next) {
Rusty Russell2e0a3212000-04-19 11:23:18 +00001619 memset(mptr, 0xFF,
Rusty Russell73f72f52000-07-03 10:17:57 +00001620 IPT_ALIGN(sizeof(struct ipt_entry_match))
Martin Josefsson78cafda2004-02-02 20:01:18 +00001621 + matchp->match->userspacesize);
1622 mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
Rusty Russell2e0a3212000-04-19 11:23:18 +00001623 }
1624
Rusty Russella4d3e1f2001-01-07 06:56:02 +00001625 memset(mptr, 0xFF,
Rusty Russell73f72f52000-07-03 10:17:57 +00001626 IPT_ALIGN(sizeof(struct ipt_entry_target))
1627 + iptables_targets->userspacesize);
Rusty Russell2e0a3212000-04-19 11:23:18 +00001628
1629 return mask;
1630}
1631
Marc Bouchere6869a82000-03-20 06:03:29 +00001632static int
1633delete_entry(const ipt_chainlabel chain,
1634 struct ipt_entry *fw,
1635 unsigned int nsaddrs,
1636 const struct in_addr saddrs[],
1637 unsigned int ndaddrs,
1638 const struct in_addr daddrs[],
1639 int verbose,
Martin Josefsson78cafda2004-02-02 20:01:18 +00001640 iptc_handle_t *handle,
1641 struct iptables_rule_match *matches)
Marc Bouchere6869a82000-03-20 06:03:29 +00001642{
1643 unsigned int i, j;
1644 int ret = 1;
Rusty Russell2e0a3212000-04-19 11:23:18 +00001645 unsigned char *mask;
Marc Bouchere6869a82000-03-20 06:03:29 +00001646
Martin Josefsson78cafda2004-02-02 20:01:18 +00001647 mask = make_delete_mask(fw, matches);
Marc Bouchere6869a82000-03-20 06:03:29 +00001648 for (i = 0; i < nsaddrs; i++) {
1649 fw->ip.src.s_addr = saddrs[i].s_addr;
1650 for (j = 0; j < ndaddrs; j++) {
1651 fw->ip.dst.s_addr = daddrs[j].s_addr;
1652 if (verbose)
1653 print_firewall_line(fw, *handle);
Rusty Russell2e0a3212000-04-19 11:23:18 +00001654 ret &= iptc_delete_entry(chain, fw, mask, handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001655 }
1656 }
Martin Josefsson4dd5fed2004-05-18 18:09:43 +00001657 free(mask);
1658
Marc Bouchere6869a82000-03-20 06:03:29 +00001659 return ret;
1660}
1661
Harald Welteae1ff9f2000-12-01 14:26:20 +00001662int
Marc Bouchere6869a82000-03-20 06:03:29 +00001663for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
Rusty Russell9e1d2142000-04-23 09:11:12 +00001664 int verbose, int builtinstoo, iptc_handle_t *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001665{
1666 int ret = 1;
Rusty Russell9e1d2142000-04-23 09:11:12 +00001667 const char *chain;
1668 char *chains;
1669 unsigned int i, chaincount = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001670
Rusty Russell9e1d2142000-04-23 09:11:12 +00001671 chain = iptc_first_chain(handle);
1672 while (chain) {
1673 chaincount++;
1674 chain = iptc_next_chain(handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001675 }
1676
Rusty Russell9e1d2142000-04-23 09:11:12 +00001677 chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount);
1678 i = 0;
1679 chain = iptc_first_chain(handle);
1680 while (chain) {
1681 strcpy(chains + i*sizeof(ipt_chainlabel), chain);
1682 i++;
1683 chain = iptc_next_chain(handle);
1684 }
1685
1686 for (i = 0; i < chaincount; i++) {
1687 if (!builtinstoo
1688 && iptc_builtin(chains + i*sizeof(ipt_chainlabel),
Harald Welte3a506ac2004-08-30 16:00:09 +00001689 *handle) == 1)
Rusty Russell9e1d2142000-04-23 09:11:12 +00001690 continue;
1691 ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle);
1692 }
1693
1694 free(chains);
Marc Bouchere6869a82000-03-20 06:03:29 +00001695 return ret;
1696}
1697
Harald Welteae1ff9f2000-12-01 14:26:20 +00001698int
Marc Bouchere6869a82000-03-20 06:03:29 +00001699flush_entries(const ipt_chainlabel chain, int verbose,
1700 iptc_handle_t *handle)
1701{
1702 if (!chain)
Rusty Russell9e1d2142000-04-23 09:11:12 +00001703 return for_each_chain(flush_entries, verbose, 1, handle);
Rusty Russell7e53bf92000-03-20 07:03:28 +00001704
1705 if (verbose)
1706 fprintf(stdout, "Flushing chain `%s'\n", chain);
1707 return iptc_flush_entries(chain, handle);
1708}
Marc Bouchere6869a82000-03-20 06:03:29 +00001709
1710static int
1711zero_entries(const ipt_chainlabel chain, int verbose,
1712 iptc_handle_t *handle)
1713{
1714 if (!chain)
Rusty Russell9e1d2142000-04-23 09:11:12 +00001715 return for_each_chain(zero_entries, verbose, 1, handle);
Rusty Russell7e53bf92000-03-20 07:03:28 +00001716
Marc Bouchere6869a82000-03-20 06:03:29 +00001717 if (verbose)
1718 fprintf(stdout, "Zeroing chain `%s'\n", chain);
1719 return iptc_zero_entries(chain, handle);
1720}
1721
Harald Welteae1ff9f2000-12-01 14:26:20 +00001722int
Marc Bouchere6869a82000-03-20 06:03:29 +00001723delete_chain(const ipt_chainlabel chain, int verbose,
1724 iptc_handle_t *handle)
1725{
Rusty Russell9e1d2142000-04-23 09:11:12 +00001726 if (!chain)
1727 return for_each_chain(delete_chain, verbose, 0, handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001728
1729 if (verbose)
1730 fprintf(stdout, "Deleting chain `%s'\n", chain);
1731 return iptc_delete_chain(chain, handle);
1732}
1733
1734static int
1735list_entries(const ipt_chainlabel chain, int verbose, int numeric,
1736 int expanded, int linenumbers, iptc_handle_t *handle)
1737{
1738 int found = 0;
Rusty Russell9e1d2142000-04-23 09:11:12 +00001739 unsigned int format;
1740 const char *this;
Marc Bouchere6869a82000-03-20 06:03:29 +00001741
1742 format = FMT_OPTIONS;
1743 if (!verbose)
1744 format |= FMT_NOCOUNTS;
1745 else
1746 format |= FMT_VIA;
1747
1748 if (numeric)
1749 format |= FMT_NUMERIC;
1750
1751 if (!expanded)
1752 format |= FMT_KILOMEGAGIGA;
1753
1754 if (linenumbers)
1755 format |= FMT_LINENUMBERS;
1756
Rusty Russell9e1d2142000-04-23 09:11:12 +00001757 for (this = iptc_first_chain(handle);
1758 this;
1759 this = iptc_next_chain(handle)) {
1760 const struct ipt_entry *i;
1761 unsigned int num;
Marc Bouchere6869a82000-03-20 06:03:29 +00001762
Marc Bouchere6869a82000-03-20 06:03:29 +00001763 if (chain && strcmp(chain, this) != 0)
1764 continue;
1765
1766 if (found) printf("\n");
1767
1768 print_header(format, this, handle);
Rusty Russell9e1d2142000-04-23 09:11:12 +00001769 i = iptc_first_rule(this, handle);
1770
1771 num = 0;
1772 while (i) {
1773 print_firewall(i,
1774 iptc_get_target(i, handle),
1775 num++,
Marc Bouchere6869a82000-03-20 06:03:29 +00001776 format,
1777 *handle);
Rusty Russell9e1d2142000-04-23 09:11:12 +00001778 i = iptc_next_rule(i, handle);
1779 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001780 found = 1;
1781 }
1782
1783 errno = ENOENT;
1784 return found;
1785}
1786
Harald Welte82dd2ec2000-12-19 05:18:15 +00001787static char *get_modprobe(void)
1788{
1789 int procfile;
1790 char *ret;
1791
Harald Welte10f7f142004-10-22 08:14:07 +00001792#define PROCFILE_BUFSIZ 1024
Harald Welte82dd2ec2000-12-19 05:18:15 +00001793 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
1794 if (procfile < 0)
1795 return NULL;
1796
Harald Welte10f7f142004-10-22 08:14:07 +00001797 ret = (char *) malloc(PROCFILE_BUFSIZ);
Harald Welte82dd2ec2000-12-19 05:18:15 +00001798 if (ret) {
Harald Welte10f7f142004-10-22 08:14:07 +00001799 memset(ret, 0, PROCFILE_BUFSIZ);
1800 switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
Harald Welte82dd2ec2000-12-19 05:18:15 +00001801 case -1: goto fail;
Harald Welte10f7f142004-10-22 08:14:07 +00001802 case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
Harald Welte82dd2ec2000-12-19 05:18:15 +00001803 }
Rusty Russell8cc887b2001-02-09 02:16:02 +00001804 if (ret[strlen(ret)-1]=='\n')
1805 ret[strlen(ret)-1]=0;
1806 close(procfile);
Harald Welte82dd2ec2000-12-19 05:18:15 +00001807 return ret;
1808 }
1809 fail:
1810 free(ret);
1811 close(procfile);
1812 return NULL;
1813}
1814
Harald Welte58918652001-06-16 18:25:25 +00001815int iptables_insmod(const char *modname, const char *modprobe)
Harald Welte82dd2ec2000-12-19 05:18:15 +00001816{
1817 char *buf = NULL;
1818 char *argv[3];
Rusty Russell8beb0492004-12-22 00:37:10 +00001819 int status;
Harald Welte82dd2ec2000-12-19 05:18:15 +00001820
1821 /* If they don't explicitly set it, read out of kernel */
1822 if (!modprobe) {
1823 buf = get_modprobe();
1824 if (!buf)
1825 return -1;
1826 modprobe = buf;
1827 }
1828
1829 switch (fork()) {
1830 case 0:
1831 argv[0] = (char *)modprobe;
1832 argv[1] = (char *)modname;
1833 argv[2] = NULL;
1834 execv(argv[0], argv);
1835
1836 /* not usually reached */
Rusty Russell8beb0492004-12-22 00:37:10 +00001837 exit(1);
Harald Welte82dd2ec2000-12-19 05:18:15 +00001838 case -1:
1839 return -1;
1840
1841 default: /* parent */
Rusty Russell8beb0492004-12-22 00:37:10 +00001842 wait(&status);
Harald Welte82dd2ec2000-12-19 05:18:15 +00001843 }
1844
1845 free(buf);
Rusty Russell8beb0492004-12-22 00:37:10 +00001846 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
1847 return 0;
1848 return -1;
Harald Welte82dd2ec2000-12-19 05:18:15 +00001849}
1850
Yasuyuki KOZAKAI740d7272006-11-13 05:09:16 +00001851int load_iptables_ko(const char *modprobe)
1852{
1853 static int loaded = 0;
1854 static int ret = -1;
1855
1856 if (!loaded) {
1857 ret = iptables_insmod("ip_tables", NULL);
1858 loaded = 1;
1859 }
1860
1861 return ret;
1862}
1863
Marc Bouchere6869a82000-03-20 06:03:29 +00001864static struct ipt_entry *
1865generate_entry(const struct ipt_entry *fw,
Martin Josefsson78cafda2004-02-02 20:01:18 +00001866 struct iptables_rule_match *matches,
Marc Bouchere6869a82000-03-20 06:03:29 +00001867 struct ipt_entry_target *target)
1868{
1869 unsigned int size;
Martin Josefsson78cafda2004-02-02 20:01:18 +00001870 struct iptables_rule_match *matchp;
Marc Bouchere6869a82000-03-20 06:03:29 +00001871 struct ipt_entry *e;
1872
1873 size = sizeof(struct ipt_entry);
Martin Josefsson78cafda2004-02-02 20:01:18 +00001874 for (matchp = matches; matchp; matchp = matchp->next)
1875 size += matchp->match->m->u.match_size;
Marc Bouchere6869a82000-03-20 06:03:29 +00001876
Rusty Russell228e98d2000-04-27 10:28:06 +00001877 e = fw_malloc(size + target->u.target_size);
Marc Bouchere6869a82000-03-20 06:03:29 +00001878 *e = *fw;
1879 e->target_offset = size;
Rusty Russell228e98d2000-04-27 10:28:06 +00001880 e->next_offset = size + target->u.target_size;
Marc Bouchere6869a82000-03-20 06:03:29 +00001881
1882 size = 0;
Martin Josefsson78cafda2004-02-02 20:01:18 +00001883 for (matchp = matches; matchp; matchp = matchp->next) {
1884 memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
1885 size += matchp->match->m->u.match_size;
Marc Bouchere6869a82000-03-20 06:03:29 +00001886 }
Rusty Russell228e98d2000-04-27 10:28:06 +00001887 memcpy(e->elems + size, target, target->u.target_size);
Marc Bouchere6869a82000-03-20 06:03:29 +00001888
1889 return e;
1890}
1891
Martin Josefsson78cafda2004-02-02 20:01:18 +00001892void clear_rule_matches(struct iptables_rule_match **matches)
1893{
1894 struct iptables_rule_match *matchp, *tmp;
1895
1896 for (matchp = *matches; matchp;) {
1897 tmp = matchp->next;
Harald Welted6bc6082006-02-11 09:34:16 +00001898 if (matchp->match->m) {
Martin Josefsson4dd5fed2004-05-18 18:09:43 +00001899 free(matchp->match->m);
Harald Welted6bc6082006-02-11 09:34:16 +00001900 matchp->match->m = NULL;
1901 }
Joszef Kadlecsika258ad72006-03-03 09:36:50 +00001902 if (matchp->match == matchp->match->next) {
1903 free(matchp->match);
1904 matchp->match = NULL;
1905 }
Martin Josefsson78cafda2004-02-02 20:01:18 +00001906 free(matchp);
1907 matchp = tmp;
1908 }
1909
1910 *matches = NULL;
1911}
1912
Rusty Russell3aef54d2005-01-03 03:48:40 +00001913static void set_revision(char *name, u_int8_t revision)
1914{
1915 /* Old kernel sources don't have ".revision" field,
1916 but we stole a byte from name. */
1917 name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
1918 name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
1919}
1920
Phil Oester8cf65912005-09-19 15:00:33 +00001921void
1922get_kernel_version(void) {
1923 static struct utsname uts;
1924 int x = 0, y = 0, z = 0;
1925
1926 if (uname(&uts) == -1) {
1927 fprintf(stderr, "Unable to retrieve kernel version.\n");
1928 free_opts(1);
1929 exit(1);
1930 }
1931
1932 sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
1933 kernel_version = LINUX_VERSION(x, y, z);
1934}
1935
Marc Bouchere6869a82000-03-20 06:03:29 +00001936int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
1937{
1938 struct ipt_entry fw, *e = NULL;
1939 int invert = 0;
1940 unsigned int nsaddrs = 0, ndaddrs = 0;
1941 struct in_addr *saddrs = NULL, *daddrs = NULL;
1942
1943 int c, verbose = 0;
1944 const char *chain = NULL;
1945 const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
1946 const char *policy = NULL, *newname = NULL;
1947 unsigned int rulenum = 0, options = 0, command = 0;
Harald Welteccd49e52001-01-23 22:54:34 +00001948 const char *pcnt = NULL, *bcnt = NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +00001949 int ret = 1;
1950 struct iptables_match *m;
Martin Josefsson78cafda2004-02-02 20:01:18 +00001951 struct iptables_rule_match *matches = NULL;
1952 struct iptables_rule_match *matchp;
Marc Bouchere6869a82000-03-20 06:03:29 +00001953 struct iptables_target *target = NULL;
Harald Welteae1ff9f2000-12-01 14:26:20 +00001954 struct iptables_target *t;
Marc Bouchere6869a82000-03-20 06:03:29 +00001955 const char *jumpto = "";
1956 char *protocol = NULL;
Harald Welte2d86b772002-08-26 12:21:44 +00001957 int proto_used = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001958
1959 memset(&fw, 0, sizeof(fw));
1960
Harald Welteae1ff9f2000-12-01 14:26:20 +00001961 /* re-set optind to 0 in case do_command gets called
1962 * a second time */
1963 optind = 0;
1964
1965 /* clear mflags in case do_command gets called a second time
1966 * (we clear the global list of all matches for security)*/
Martin Josefsson78cafda2004-02-02 20:01:18 +00001967 for (m = iptables_matches; m; m = m->next)
Harald Welteae1ff9f2000-12-01 14:26:20 +00001968 m->mflags = 0;
Harald Welteae1ff9f2000-12-01 14:26:20 +00001969
1970 for (t = iptables_targets; t; t = t->next) {
1971 t->tflags = 0;
1972 t->used = 0;
1973 }
1974
Marc Bouchere6869a82000-03-20 06:03:29 +00001975 /* Suppress error messages: we may add new options if we
1976 demand-load a protocol. */
1977 opterr = 0;
1978
1979 while ((c = getopt_long(argc, argv,
Henrik Nordstrom17fc1632005-11-05 09:26:40 +00001980 "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
Marc Bouchere6869a82000-03-20 06:03:29 +00001981 opts, NULL)) != -1) {
1982 switch (c) {
1983 /*
1984 * Command selection
1985 */
1986 case 'A':
1987 add_command(&command, CMD_APPEND, CMD_NONE,
1988 invert);
1989 chain = optarg;
1990 break;
1991
1992 case 'D':
1993 add_command(&command, CMD_DELETE, CMD_NONE,
1994 invert);
1995 chain = optarg;
1996 if (optind < argc && argv[optind][0] != '-'
1997 && argv[optind][0] != '!') {
1998 rulenum = parse_rulenumber(argv[optind++]);
1999 command = CMD_DELETE_NUM;
2000 }
2001 break;
2002
Marc Bouchere6869a82000-03-20 06:03:29 +00002003 case 'R':
2004 add_command(&command, CMD_REPLACE, CMD_NONE,
2005 invert);
2006 chain = optarg;
2007 if (optind < argc && argv[optind][0] != '-'
2008 && argv[optind][0] != '!')
2009 rulenum = parse_rulenumber(argv[optind++]);
2010 else
2011 exit_error(PARAMETER_PROBLEM,
2012 "-%c requires a rule number",
2013 cmd2char(CMD_REPLACE));
2014 break;
2015
2016 case 'I':
2017 add_command(&command, CMD_INSERT, CMD_NONE,
2018 invert);
2019 chain = optarg;
2020 if (optind < argc && argv[optind][0] != '-'
2021 && argv[optind][0] != '!')
2022 rulenum = parse_rulenumber(argv[optind++]);
2023 else rulenum = 1;
2024 break;
2025
2026 case 'L':
2027 add_command(&command, CMD_LIST, CMD_ZERO,
2028 invert);
2029 if (optarg) chain = optarg;
2030 else if (optind < argc && argv[optind][0] != '-'
2031 && argv[optind][0] != '!')
2032 chain = argv[optind++];
2033 break;
2034
2035 case 'F':
2036 add_command(&command, CMD_FLUSH, CMD_NONE,
2037 invert);
2038 if (optarg) chain = optarg;
2039 else if (optind < argc && argv[optind][0] != '-'
2040 && argv[optind][0] != '!')
2041 chain = argv[optind++];
2042 break;
2043
2044 case 'Z':
2045 add_command(&command, CMD_ZERO, CMD_LIST,
2046 invert);
2047 if (optarg) chain = optarg;
2048 else if (optind < argc && argv[optind][0] != '-'
2049 && argv[optind][0] != '!')
2050 chain = argv[optind++];
2051 break;
2052
2053 case 'N':
Yasuyuki KOZAKAI8d8c8ea2005-06-13 01:06:10 +00002054 if (optarg && (*optarg == '-' || *optarg == '!'))
Harald Welte6336bfd2002-05-07 14:41:43 +00002055 exit_error(PARAMETER_PROBLEM,
2056 "chain name not allowed to start "
Yasuyuki KOZAKAI8d8c8ea2005-06-13 01:06:10 +00002057 "with `%c'\n", *optarg);
Joszef Kadlecsik08f15272002-06-24 12:37:29 +00002058 if (find_target(optarg, TRY_LOAD))
2059 exit_error(PARAMETER_PROBLEM,
2060 "chain name may not clash "
2061 "with target name\n");
Marc Bouchere6869a82000-03-20 06:03:29 +00002062 add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
2063 invert);
2064 chain = optarg;
2065 break;
2066
2067 case 'X':
2068 add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
2069 invert);
2070 if (optarg) chain = optarg;
2071 else if (optind < argc && argv[optind][0] != '-'
2072 && argv[optind][0] != '!')
2073 chain = argv[optind++];
2074 break;
2075
2076 case 'E':
2077 add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
2078 invert);
2079 chain = optarg;
2080 if (optind < argc && argv[optind][0] != '-'
2081 && argv[optind][0] != '!')
2082 newname = argv[optind++];
M.P.Anand Babuc9f20d32000-06-09 09:22:38 +00002083 else
2084 exit_error(PARAMETER_PROBLEM,
2085 "-%c requires old-chain-name and "
2086 "new-chain-name",
2087 cmd2char(CMD_RENAME_CHAIN));
Marc Bouchere6869a82000-03-20 06:03:29 +00002088 break;
2089
2090 case 'P':
2091 add_command(&command, CMD_SET_POLICY, CMD_NONE,
2092 invert);
2093 chain = optarg;
2094 if (optind < argc && argv[optind][0] != '-'
2095 && argv[optind][0] != '!')
2096 policy = argv[optind++];
2097 else
2098 exit_error(PARAMETER_PROBLEM,
2099 "-%c requires a chain and a policy",
2100 cmd2char(CMD_SET_POLICY));
2101 break;
2102
2103 case 'h':
2104 if (!optarg)
2105 optarg = argv[optind];
2106
Rusty Russell2e0a3212000-04-19 11:23:18 +00002107 /* iptables -p icmp -h */
Martin Josefsson66aea6f2004-05-26 15:41:54 +00002108 if (!matches && protocol)
2109 find_match(protocol, TRY_LOAD, &matches);
Rusty Russell2e0a3212000-04-19 11:23:18 +00002110
Martin Josefsson66aea6f2004-05-26 15:41:54 +00002111 exit_printhelp(matches);
Marc Bouchere6869a82000-03-20 06:03:29 +00002112
2113 /*
2114 * Option selection
2115 */
2116 case 'p':
Harald Welteb77f1da2002-03-14 11:35:58 +00002117 check_inverse(optarg, &invert, &optind, argc);
Marc Bouchere6869a82000-03-20 06:03:29 +00002118 set_option(&options, OPT_PROTOCOL, &fw.ip.invflags,
2119 invert);
2120
2121 /* Canonicalize into lower case */
2122 for (protocol = argv[optind-1]; *protocol; protocol++)
2123 *protocol = tolower(*protocol);
2124
2125 protocol = argv[optind-1];
2126 fw.ip.proto = parse_protocol(protocol);
2127
2128 if (fw.ip.proto == 0
2129 && (fw.ip.invflags & IPT_INV_PROTO))
2130 exit_error(PARAMETER_PROBLEM,
2131 "rule would never match protocol");
Marc Bouchere6869a82000-03-20 06:03:29 +00002132 break;
2133
2134 case 's':
Harald Welteb77f1da2002-03-14 11:35:58 +00002135 check_inverse(optarg, &invert, &optind, argc);
Marc Bouchere6869a82000-03-20 06:03:29 +00002136 set_option(&options, OPT_SOURCE, &fw.ip.invflags,
2137 invert);
2138 shostnetworkmask = argv[optind-1];
Marc Bouchere6869a82000-03-20 06:03:29 +00002139 break;
2140
2141 case 'd':
Harald Welteb77f1da2002-03-14 11:35:58 +00002142 check_inverse(optarg, &invert, &optind, argc);
Marc Bouchere6869a82000-03-20 06:03:29 +00002143 set_option(&options, OPT_DESTINATION, &fw.ip.invflags,
2144 invert);
2145 dhostnetworkmask = argv[optind-1];
Marc Bouchere6869a82000-03-20 06:03:29 +00002146 break;
2147
Henrik Nordstrom17fc1632005-11-05 09:26:40 +00002148#ifdef IPT_F_GOTO
2149 case 'g':
2150 set_option(&options, OPT_JUMP, &fw.ip.invflags,
2151 invert);
2152 fw.ip.flags |= IPT_F_GOTO;
2153 jumpto = parse_target(optarg);
2154 break;
2155#endif
2156
Marc Bouchere6869a82000-03-20 06:03:29 +00002157 case 'j':
2158 set_option(&options, OPT_JUMP, &fw.ip.invflags,
2159 invert);
2160 jumpto = parse_target(optarg);
Rusty Russell859f7262000-08-24 06:00:33 +00002161 /* TRY_LOAD (may be chain name) */
2162 target = find_target(jumpto, TRY_LOAD);
Marc Bouchere6869a82000-03-20 06:03:29 +00002163
2164 if (target) {
Rusty Russell228e98d2000-04-27 10:28:06 +00002165 size_t size;
2166
Rusty Russell73f72f52000-07-03 10:17:57 +00002167 size = IPT_ALIGN(sizeof(struct ipt_entry_target))
2168 + target->size;
Marc Bouchere6869a82000-03-20 06:03:29 +00002169
Rusty Russell2e0a3212000-04-19 11:23:18 +00002170 target->t = fw_calloc(1, size);
Rusty Russell228e98d2000-04-27 10:28:06 +00002171 target->t->u.target_size = size;
2172 strcpy(target->t->u.user.name, jumpto);
Rusty Russell3aef54d2005-01-03 03:48:40 +00002173 set_revision(target->t->u.user.name,
2174 target->revision);
Pablo Neira8115e542005-02-14 13:13:04 +00002175 if (target->init != NULL)
2176 target->init(target->t, &fw.nfcache);
Sven Kochfb1279a2001-02-27 12:25:12 +00002177 opts = merge_options(opts, target->extra_opts, &target->option_offset);
Marc Bouchere6869a82000-03-20 06:03:29 +00002178 }
2179 break;
2180
2181
2182 case 'i':
Harald Welteb77f1da2002-03-14 11:35:58 +00002183 check_inverse(optarg, &invert, &optind, argc);
Marc Bouchere6869a82000-03-20 06:03:29 +00002184 set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags,
2185 invert);
2186 parse_interface(argv[optind-1],
2187 fw.ip.iniface,
2188 fw.ip.iniface_mask);
Marc Bouchere6869a82000-03-20 06:03:29 +00002189 break;
2190
2191 case 'o':
Harald Welteb77f1da2002-03-14 11:35:58 +00002192 check_inverse(optarg, &invert, &optind, argc);
Marc Bouchere6869a82000-03-20 06:03:29 +00002193 set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags,
2194 invert);
2195 parse_interface(argv[optind-1],
2196 fw.ip.outiface,
2197 fw.ip.outiface_mask);
Marc Bouchere6869a82000-03-20 06:03:29 +00002198 break;
2199
2200 case 'f':
2201 set_option(&options, OPT_FRAGMENT, &fw.ip.invflags,
2202 invert);
2203 fw.ip.flags |= IPT_F_FRAG;
Marc Bouchere6869a82000-03-20 06:03:29 +00002204 break;
2205
2206 case 'v':
2207 if (!verbose)
2208 set_option(&options, OPT_VERBOSE,
2209 &fw.ip.invflags, invert);
2210 verbose++;
2211 break;
2212
Rusty Russell52a51492000-05-02 16:44:29 +00002213 case 'm': {
2214 size_t size;
2215
Marc Bouchere6869a82000-03-20 06:03:29 +00002216 if (invert)
2217 exit_error(PARAMETER_PROBLEM,
2218 "unexpected ! flag before --match");
2219
Martin Josefsson78cafda2004-02-02 20:01:18 +00002220 m = find_match(optarg, LOAD_MUST_SUCCEED, &matches);
Rusty Russell73f72f52000-07-03 10:17:57 +00002221 size = IPT_ALIGN(sizeof(struct ipt_entry_match))
2222 + m->size;
Rusty Russell52a51492000-05-02 16:44:29 +00002223 m->m = fw_calloc(1, size);
2224 m->m->u.match_size = size;
Rusty Russell27ff3472000-05-12 14:04:50 +00002225 strcpy(m->m->u.user.name, m->name);
Rusty Russell3aef54d2005-01-03 03:48:40 +00002226 set_revision(m->m->u.user.name, m->revision);
Pablo Neira8115e542005-02-14 13:13:04 +00002227 if (m->init != NULL)
2228 m->init(m->m, &fw.nfcache);
Joszef Kadlecsika258ad72006-03-03 09:36:50 +00002229 if (m != m->next)
2230 /* Merge options for non-cloned matches */
2231 opts = merge_options(opts, m->extra_opts, &m->option_offset);
Rusty Russell52a51492000-05-02 16:44:29 +00002232 }
2233 break;
Marc Bouchere6869a82000-03-20 06:03:29 +00002234
2235 case 'n':
2236 set_option(&options, OPT_NUMERIC, &fw.ip.invflags,
2237 invert);
2238 break;
2239
2240 case 't':
2241 if (invert)
2242 exit_error(PARAMETER_PROBLEM,
2243 "unexpected ! flag before --table");
2244 *table = argv[optind-1];
2245 break;
2246
2247 case 'x':
2248 set_option(&options, OPT_EXPANDED, &fw.ip.invflags,
2249 invert);
2250 break;
2251
2252 case 'V':
2253 if (invert)
2254 printf("Not %s ;-)\n", program_version);
2255 else
2256 printf("%s v%s\n",
2257 program_name, program_version);
2258 exit(0);
2259
2260 case '0':
2261 set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags,
2262 invert);
2263 break;
2264
Harald Welte82dd2ec2000-12-19 05:18:15 +00002265 case 'M':
2266 modprobe = optarg;
2267 break;
2268
Harald Welteccd49e52001-01-23 22:54:34 +00002269 case 'c':
2270
2271 set_option(&options, OPT_COUNTERS, &fw.ip.invflags,
2272 invert);
2273 pcnt = optarg;
2274 if (optind < argc && argv[optind][0] != '-'
2275 && argv[optind][0] != '!')
2276 bcnt = argv[optind++];
2277 else
2278 exit_error(PARAMETER_PROBLEM,
2279 "-%c requires packet and byte counter",
2280 opt2char(OPT_COUNTERS));
2281
Martin Josefssona28d4952004-05-26 16:04:48 +00002282 if (sscanf(pcnt, "%llu", (unsigned long long *)&fw.counters.pcnt) != 1)
Harald Welteccd49e52001-01-23 22:54:34 +00002283 exit_error(PARAMETER_PROBLEM,
2284 "-%c packet counter not numeric",
2285 opt2char(OPT_COUNTERS));
2286
Martin Josefssona28d4952004-05-26 16:04:48 +00002287 if (sscanf(bcnt, "%llu", (unsigned long long *)&fw.counters.bcnt) != 1)
Harald Welteccd49e52001-01-23 22:54:34 +00002288 exit_error(PARAMETER_PROBLEM,
2289 "-%c byte counter not numeric",
2290 opt2char(OPT_COUNTERS));
2291
2292 break;
2293
2294
Marc Bouchere6869a82000-03-20 06:03:29 +00002295 case 1: /* non option */
2296 if (optarg[0] == '!' && optarg[1] == '\0') {
2297 if (invert)
2298 exit_error(PARAMETER_PROBLEM,
2299 "multiple consecutive ! not"
2300 " allowed");
2301 invert = TRUE;
2302 optarg[0] = '\0';
2303 continue;
2304 }
Rusty Russell9e1d2142000-04-23 09:11:12 +00002305 printf("Bad argument `%s'\n", optarg);
Marc Bouchere6869a82000-03-20 06:03:29 +00002306 exit_tryhelp(2);
2307
2308 default:
Marc Bouchere6869a82000-03-20 06:03:29 +00002309 if (!target
2310 || !(target->parse(c - target->option_offset,
2311 argv, invert,
2312 &target->tflags,
2313 &fw, &target->t))) {
Martin Josefsson78cafda2004-02-02 20:01:18 +00002314 for (matchp = matches; matchp; matchp = matchp->next) {
Joszef Kadlecsika258ad72006-03-03 09:36:50 +00002315 if (matchp->completed)
2316 continue;
Martin Josefsson78cafda2004-02-02 20:01:18 +00002317 if (matchp->match->parse(c - matchp->match->option_offset,
Marc Bouchere6869a82000-03-20 06:03:29 +00002318 argv, invert,
Martin Josefsson78cafda2004-02-02 20:01:18 +00002319 &matchp->match->mflags,
Marc Bouchere6869a82000-03-20 06:03:29 +00002320 &fw,
2321 &fw.nfcache,
Martin Josefsson78cafda2004-02-02 20:01:18 +00002322 &matchp->match->m))
Marc Bouchere6869a82000-03-20 06:03:29 +00002323 break;
2324 }
Martin Josefsson78cafda2004-02-02 20:01:18 +00002325 m = matchp ? matchp->match : NULL;
Harald Welte2d86b772002-08-26 12:21:44 +00002326
2327 /* If you listen carefully, you can
2328 actually hear this code suck. */
2329
2330 /* some explanations (after four different bugs
Joszef Kadlecsika258ad72006-03-03 09:36:50 +00002331 * in 3 different releases): If we encounter a
Harald Welte2d86b772002-08-26 12:21:44 +00002332 * parameter, that has not been parsed yet,
2333 * it's not an option of an explicitly loaded
2334 * match or a target. However, we support
2335 * implicit loading of the protocol match
2336 * extension. '-p tcp' means 'l4 proto 6' and
2337 * at the same time 'load tcp protocol match on
2338 * demand if we specify --dport'.
2339 *
2340 * To make this work, we need to make sure:
2341 * - the parameter has not been parsed by
2342 * a match (m above)
2343 * - a protocol has been specified
2344 * - the protocol extension has not been
2345 * loaded yet, or is loaded and unused
2346 * [think of iptables-restore!]
2347 * - the protocol extension can be successively
2348 * loaded
2349 */
2350 if (m == NULL
2351 && protocol
2352 && (!find_proto(protocol, DONT_LOAD,
Martin Josefsson78cafda2004-02-02 20:01:18 +00002353 options&OPT_NUMERIC, NULL)
Harald Welte2d86b772002-08-26 12:21:44 +00002354 || (find_proto(protocol, DONT_LOAD,
Martin Josefsson78cafda2004-02-02 20:01:18 +00002355 options&OPT_NUMERIC, NULL)
Harald Welte2d86b772002-08-26 12:21:44 +00002356 && (proto_used == 0))
2357 )
2358 && (m = find_proto(protocol, TRY_LOAD,
Martin Josefsson78cafda2004-02-02 20:01:18 +00002359 options&OPT_NUMERIC, &matches))) {
Harald Welte2d86b772002-08-26 12:21:44 +00002360 /* Try loading protocol */
2361 size_t size;
2362
2363 proto_used = 1;
2364
2365 size = IPT_ALIGN(sizeof(struct ipt_entry_match))
2366 + m->size;
2367
2368 m->m = fw_calloc(1, size);
2369 m->m->u.match_size = size;
2370 strcpy(m->m->u.user.name, m->name);
Rusty Russell3aef54d2005-01-03 03:48:40 +00002371 set_revision(m->m->u.user.name,
2372 m->revision);
Pablo Neira8115e542005-02-14 13:13:04 +00002373 if (m->init != NULL)
2374 m->init(m->m, &fw.nfcache);
Harald Welte2d86b772002-08-26 12:21:44 +00002375
2376 opts = merge_options(opts,
2377 m->extra_opts, &m->option_offset);
2378
2379 optind--;
2380 continue;
2381 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002382 if (!m)
2383 exit_error(PARAMETER_PROBLEM,
2384 "Unknown arg `%s'",
2385 argv[optind-1]);
2386 }
2387 }
2388 invert = FALSE;
2389 }
2390
Martin Josefsson78cafda2004-02-02 20:01:18 +00002391 for (matchp = matches; matchp; matchp = matchp->next)
2392 matchp->match->final_check(matchp->match->mflags);
Sven Kochfb1279a2001-02-27 12:25:12 +00002393
Marc Bouchere6869a82000-03-20 06:03:29 +00002394 if (target)
2395 target->final_check(target->tflags);
2396
2397 /* Fix me: must put inverse options checking here --MN */
2398
2399 if (optind < argc)
2400 exit_error(PARAMETER_PROBLEM,
2401 "unknown arguments found on commandline");
2402 if (!command)
2403 exit_error(PARAMETER_PROBLEM, "no command specified");
2404 if (invert)
2405 exit_error(PARAMETER_PROBLEM,
2406 "nothing appropriate following !");
2407
Harald Welte6336bfd2002-05-07 14:41:43 +00002408 if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002409 if (!(options & OPT_DESTINATION))
2410 dhostnetworkmask = "0.0.0.0/0";
2411 if (!(options & OPT_SOURCE))
2412 shostnetworkmask = "0.0.0.0/0";
2413 }
2414
2415 if (shostnetworkmask)
2416 parse_hostnetworkmask(shostnetworkmask, &saddrs,
2417 &(fw.ip.smsk), &nsaddrs);
2418
2419 if (dhostnetworkmask)
2420 parse_hostnetworkmask(dhostnetworkmask, &daddrs,
2421 &(fw.ip.dmsk), &ndaddrs);
2422
2423 if ((nsaddrs > 1 || ndaddrs > 1) &&
2424 (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
2425 exit_error(PARAMETER_PROBLEM, "! not allowed with multiple"
2426 " source or destination IP addresses");
2427
Marc Bouchere6869a82000-03-20 06:03:29 +00002428 if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
2429 exit_error(PARAMETER_PROBLEM, "Replacement rule does not "
2430 "specify a unique address");
2431
2432 generic_opt_check(command, options);
2433
2434 if (chain && strlen(chain) > IPT_FUNCTION_MAXNAMELEN)
2435 exit_error(PARAMETER_PROBLEM,
2436 "chain name `%s' too long (must be under %i chars)",
2437 chain, IPT_FUNCTION_MAXNAMELEN);
2438
Harald Welteae1ff9f2000-12-01 14:26:20 +00002439 /* only allocate handle if we weren't called with a handle */
Martin Josefsson8371e152003-05-05 19:33:40 +00002440 if (!*handle)
Harald Welteae1ff9f2000-12-01 14:26:20 +00002441 *handle = iptc_init(*table);
2442
Rusty Russell8beb0492004-12-22 00:37:10 +00002443 /* try to insmod the module if iptc_init failed */
Yasuyuki KOZAKAI740d7272006-11-13 05:09:16 +00002444 if (!*handle && load_iptables_ko(modprobe) != -1)
Harald Welte82dd2ec2000-12-19 05:18:15 +00002445 *handle = iptc_init(*table);
Harald Welte82dd2ec2000-12-19 05:18:15 +00002446
Marc Bouchere6869a82000-03-20 06:03:29 +00002447 if (!*handle)
2448 exit_error(VERSION_PROBLEM,
2449 "can't initialize iptables table `%s': %s",
2450 *table, iptc_strerror(errno));
2451
Harald Welte6336bfd2002-05-07 14:41:43 +00002452 if (command == CMD_APPEND
Marc Bouchere6869a82000-03-20 06:03:29 +00002453 || command == CMD_DELETE
2454 || command == CMD_INSERT
2455 || command == CMD_REPLACE) {
Rusty Russella4860fd2000-06-17 16:13:02 +00002456 if (strcmp(chain, "PREROUTING") == 0
2457 || strcmp(chain, "INPUT") == 0) {
2458 /* -o not valid with incoming packets. */
2459 if (options & OPT_VIANAMEOUT)
Marc Bouchere6869a82000-03-20 06:03:29 +00002460 exit_error(PARAMETER_PROBLEM,
2461 "Can't use -%c with %s\n",
2462 opt2char(OPT_VIANAMEOUT),
2463 chain);
2464 }
2465
Rusty Russella4860fd2000-06-17 16:13:02 +00002466 if (strcmp(chain, "POSTROUTING") == 0
2467 || strcmp(chain, "OUTPUT") == 0) {
2468 /* -i not valid with outgoing packets */
2469 if (options & OPT_VIANAMEIN)
Marc Bouchere6869a82000-03-20 06:03:29 +00002470 exit_error(PARAMETER_PROBLEM,
2471 "Can't use -%c with %s\n",
2472 opt2char(OPT_VIANAMEIN),
2473 chain);
2474 }
2475
2476 if (target && iptc_is_chain(jumpto, *handle)) {
2477 printf("Warning: using chain %s, not extension\n",
2478 jumpto);
2479
Martin Josefsson4dd5fed2004-05-18 18:09:43 +00002480 if (target->t)
2481 free(target->t);
2482
Marc Bouchere6869a82000-03-20 06:03:29 +00002483 target = NULL;
2484 }
2485
2486 /* If they didn't specify a target, or it's a chain
2487 name, use standard. */
2488 if (!target
2489 && (strlen(jumpto) == 0
2490 || iptc_is_chain(jumpto, *handle))) {
2491 size_t size;
Marc Bouchere6869a82000-03-20 06:03:29 +00002492
Rusty Russell52a51492000-05-02 16:44:29 +00002493 target = find_target(IPT_STANDARD_TARGET,
2494 LOAD_MUST_SUCCEED);
Marc Bouchere6869a82000-03-20 06:03:29 +00002495
2496 size = sizeof(struct ipt_entry_target)
Rusty Russell228e98d2000-04-27 10:28:06 +00002497 + target->size;
Rusty Russell2e0a3212000-04-19 11:23:18 +00002498 target->t = fw_calloc(1, size);
Rusty Russell228e98d2000-04-27 10:28:06 +00002499 target->t->u.target_size = size;
2500 strcpy(target->t->u.user.name, jumpto);
Pablo Neira0b905642005-11-17 13:04:49 +00002501 if (!iptc_is_chain(jumpto, *handle))
2502 set_revision(target->t->u.user.name,
2503 target->revision);
Pablo Neira8115e542005-02-14 13:13:04 +00002504 if (target->init != NULL)
2505 target->init(target->t, &fw.nfcache);
Marc Bouchere6869a82000-03-20 06:03:29 +00002506 }
2507
Rusty Russell7e53bf92000-03-20 07:03:28 +00002508 if (!target) {
Harald Weltef2a24bd2000-08-30 02:11:18 +00002509 /* it is no chain, and we can't load a plugin.
2510 * We cannot know if the plugin is corrupt, non
Rusty Russella4d3e1f2001-01-07 06:56:02 +00002511 * existant OR if the user just misspelled a
Harald Weltef2a24bd2000-08-30 02:11:18 +00002512 * chain. */
Henrik Nordstrom17fc1632005-11-05 09:26:40 +00002513#ifdef IPT_F_GOTO
2514 if (fw.ip.flags & IPT_F_GOTO)
2515 exit_error(PARAMETER_PROBLEM,
2516 "goto '%s' is not a chain\n", jumpto);
2517#endif
Harald Weltef2a24bd2000-08-30 02:11:18 +00002518 find_target(jumpto, LOAD_MUST_SUCCEED);
Marc Bouchere6869a82000-03-20 06:03:29 +00002519 } else {
Martin Josefsson78cafda2004-02-02 20:01:18 +00002520 e = generate_entry(&fw, matches, target->t);
Martin Josefsson4dd5fed2004-05-18 18:09:43 +00002521 free(target->t);
Marc Bouchere6869a82000-03-20 06:03:29 +00002522 }
2523 }
2524
2525 switch (command) {
2526 case CMD_APPEND:
2527 ret = append_entry(chain, e,
2528 nsaddrs, saddrs, ndaddrs, daddrs,
2529 options&OPT_VERBOSE,
2530 handle);
2531 break;
Marc Bouchere6869a82000-03-20 06:03:29 +00002532 case CMD_DELETE:
2533 ret = delete_entry(chain, e,
2534 nsaddrs, saddrs, ndaddrs, daddrs,
2535 options&OPT_VERBOSE,
Martin Josefsson78cafda2004-02-02 20:01:18 +00002536 handle, matches);
Marc Bouchere6869a82000-03-20 06:03:29 +00002537 break;
2538 case CMD_DELETE_NUM:
2539 ret = iptc_delete_num_entry(chain, rulenum - 1, handle);
2540 break;
2541 case CMD_REPLACE:
2542 ret = replace_entry(chain, e, rulenum - 1,
2543 saddrs, daddrs, options&OPT_VERBOSE,
2544 handle);
2545 break;
2546 case CMD_INSERT:
2547 ret = insert_entry(chain, e, rulenum - 1,
2548 nsaddrs, saddrs, ndaddrs, daddrs,
2549 options&OPT_VERBOSE,
2550 handle);
2551 break;
2552 case CMD_LIST:
2553 ret = list_entries(chain,
2554 options&OPT_VERBOSE,
2555 options&OPT_NUMERIC,
2556 options&OPT_EXPANDED,
2557 options&OPT_LINENUMBERS,
2558 handle);
2559 break;
2560 case CMD_FLUSH:
2561 ret = flush_entries(chain, options&OPT_VERBOSE, handle);
2562 break;
2563 case CMD_ZERO:
2564 ret = zero_entries(chain, options&OPT_VERBOSE, handle);
2565 break;
2566 case CMD_LIST|CMD_ZERO:
2567 ret = list_entries(chain,
2568 options&OPT_VERBOSE,
2569 options&OPT_NUMERIC,
2570 options&OPT_EXPANDED,
2571 options&OPT_LINENUMBERS,
2572 handle);
2573 if (ret)
2574 ret = zero_entries(chain,
2575 options&OPT_VERBOSE, handle);
2576 break;
2577 case CMD_NEW_CHAIN:
2578 ret = iptc_create_chain(chain, handle);
2579 break;
2580 case CMD_DELETE_CHAIN:
2581 ret = delete_chain(chain, options&OPT_VERBOSE, handle);
2582 break;
2583 case CMD_RENAME_CHAIN:
2584 ret = iptc_rename_chain(chain, newname, handle);
2585 break;
2586 case CMD_SET_POLICY:
Harald Welted8e65632001-01-05 15:20:07 +00002587 ret = iptc_set_policy(chain, policy, NULL, handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00002588 break;
2589 default:
2590 /* We should never reach this... */
2591 exit_tryhelp(2);
2592 }
2593
2594 if (verbose > 1)
2595 dump_entries(*handle);
2596
Martin Josefsson78cafda2004-02-02 20:01:18 +00002597 clear_rule_matches(&matches);
2598
Martin Josefsson4dd5fed2004-05-18 18:09:43 +00002599 if (e != NULL) {
2600 free(e);
2601 e = NULL;
2602 }
2603
keso6997cdf2004-07-04 15:20:53 +00002604 free(saddrs);
2605 free(daddrs);
Pablo Neiradfdcd642005-05-29 19:05:23 +00002606 free_opts(1);
Martin Josefsson4dd5fed2004-05-18 18:09:43 +00002607
Marc Bouchere6869a82000-03-20 06:03:29 +00002608 return ret;
2609}