iptables.c revision 31da96d07b8abb35297201000f7f752019258cf6
1/* 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 *
6 * (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 *
13 *	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 <stdbool.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <ctype.h>
36#include <stdarg.h>
37#include <limits.h>
38#include <unistd.h>
39#include <iptables.h>
40#include <xtables.h>
41#include <fcntl.h>
42#include "xshared.h"
43
44#ifndef TRUE
45#define TRUE 1
46#endif
47#ifndef FALSE
48#define FALSE 0
49#endif
50
51#define FMT_NUMERIC	0x0001
52#define FMT_NOCOUNTS	0x0002
53#define FMT_KILOMEGAGIGA 0x0004
54#define FMT_OPTIONS	0x0008
55#define FMT_NOTABLE	0x0010
56#define FMT_NOTARGET	0x0020
57#define FMT_VIA		0x0040
58#define FMT_NONEWLINE	0x0080
59#define FMT_LINENUMBERS 0x0100
60
61#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \
62			| FMT_NUMERIC | FMT_NOTABLE)
63#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
64
65
66#define CMD_NONE		0x0000U
67#define CMD_INSERT		0x0001U
68#define CMD_DELETE		0x0002U
69#define CMD_DELETE_NUM		0x0004U
70#define CMD_REPLACE		0x0008U
71#define CMD_APPEND		0x0010U
72#define CMD_LIST		0x0020U
73#define CMD_FLUSH		0x0040U
74#define CMD_ZERO		0x0080U
75#define CMD_NEW_CHAIN		0x0100U
76#define CMD_DELETE_CHAIN	0x0200U
77#define CMD_SET_POLICY		0x0400U
78#define CMD_RENAME_CHAIN	0x0800U
79#define CMD_LIST_RULES		0x1000U
80#define CMD_ZERO_NUM		0x2000U
81#define CMD_CHECK		0x4000U
82#define NUMBER_OF_CMD	16
83static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
84				 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
85
86#define OPT_FRAGMENT    0x00800U
87#define NUMBER_OF_OPT	ARRAY_SIZE(optflags)
88static const char optflags[]
89= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
90
91static struct option original_opts[] = {
92	{.name = "append",        .has_arg = 1, .val = 'A'},
93	{.name = "delete",        .has_arg = 1, .val = 'D'},
94	{.name = "check",         .has_arg = 1, .val = 'C'},
95	{.name = "insert",        .has_arg = 1, .val = 'I'},
96	{.name = "replace",       .has_arg = 1, .val = 'R'},
97	{.name = "list",          .has_arg = 2, .val = 'L'},
98	{.name = "list-rules",    .has_arg = 2, .val = 'S'},
99	{.name = "flush",         .has_arg = 2, .val = 'F'},
100	{.name = "zero",          .has_arg = 2, .val = 'Z'},
101	{.name = "new-chain",     .has_arg = 1, .val = 'N'},
102	{.name = "delete-chain",  .has_arg = 2, .val = 'X'},
103	{.name = "rename-chain",  .has_arg = 1, .val = 'E'},
104	{.name = "policy",        .has_arg = 1, .val = 'P'},
105	{.name = "source",        .has_arg = 1, .val = 's'},
106	{.name = "destination",   .has_arg = 1, .val = 'd'},
107	{.name = "src",           .has_arg = 1, .val = 's'}, /* synonym */
108	{.name = "dst",           .has_arg = 1, .val = 'd'}, /* synonym */
109	{.name = "protocol",      .has_arg = 1, .val = 'p'},
110	{.name = "in-interface",  .has_arg = 1, .val = 'i'},
111	{.name = "jump",          .has_arg = 1, .val = 'j'},
112	{.name = "table",         .has_arg = 1, .val = 't'},
113	{.name = "match",         .has_arg = 1, .val = 'm'},
114	{.name = "numeric",       .has_arg = 0, .val = 'n'},
115	{.name = "out-interface", .has_arg = 1, .val = 'o'},
116	{.name = "verbose",       .has_arg = 0, .val = 'v'},
117	{.name = "exact",         .has_arg = 0, .val = 'x'},
118	{.name = "fragments",     .has_arg = 0, .val = 'f'},
119	{.name = "version",       .has_arg = 0, .val = 'V'},
120	{.name = "help",          .has_arg = 2, .val = 'h'},
121	{.name = "line-numbers",  .has_arg = 0, .val = '0'},
122	{.name = "modprobe",      .has_arg = 1, .val = 'M'},
123	{.name = "set-counters",  .has_arg = 1, .val = 'c'},
124	{.name = "goto",          .has_arg = 1, .val = 'g'},
125	{.name = "ipv4",          .has_arg = 0, .val = '4'},
126	{.name = "ipv6",          .has_arg = 0, .val = '6'},
127	{NULL},
128};
129
130void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
131
132struct xtables_globals iptables_globals = {
133	.option_offset = 0,
134	.program_version = IPTABLES_VERSION,
135	.orig_opts = original_opts,
136	.exit_err = iptables_exit_error,
137};
138
139/* Table of legal combinations of commands and options.  If any of the
140 * given commands make an option legal, that option is legal (applies to
141 * CMD_LIST and CMD_ZERO only).
142 * Key:
143 *  +  compulsory
144 *  x  illegal
145 *     optional
146 */
147
148static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
149/* Well, it's better than "Re: Linux vs FreeBSD" */
150{
151	/*     -n  -s  -d  -p  -j  -v  -x  -i  -o --line -c -f */
152/*INSERT*/    {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
153/*DELETE*/    {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
154/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
155/*REPLACE*/   {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
156/*APPEND*/    {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
157/*LIST*/      {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
158/*FLUSH*/     {'x','x','x','x','x',' ','x','x','x','x','x','x'},
159/*ZERO*/      {'x','x','x','x','x',' ','x','x','x','x','x','x'},
160/*ZERO_NUM*/  {'x','x','x','x','x',' ','x','x','x','x','x','x'},
161/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
162/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
163/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
164/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'},
165/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
166/*CHECK*/     {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
167};
168
169static const int inverse_for_options[NUMBER_OF_OPT] =
170{
171/* -n */ 0,
172/* -s */ IPT_INV_SRCIP,
173/* -d */ IPT_INV_DSTIP,
174/* -p */ XT_INV_PROTO,
175/* -j */ 0,
176/* -v */ 0,
177/* -x */ 0,
178/* -i */ IPT_INV_VIA_IN,
179/* -o */ IPT_INV_VIA_OUT,
180/*--line*/ 0,
181/* -c */ 0,
182/* -f */ IPT_INV_FRAG,
183};
184
185#define opts iptables_globals.opts
186#define prog_name iptables_globals.program_name
187#define prog_vers iptables_globals.program_version
188
189static void __attribute__((noreturn))
190exit_tryhelp(int status)
191{
192	if (line != -1)
193		fprintf(stderr, "Error occurred at line: %d\n", line);
194	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
195			prog_name, prog_name);
196	xtables_free_opts(1);
197	exit(status);
198}
199
200static void
201exit_printhelp(const struct xtables_rule_match *matches)
202{
203	printf("%s v%s\n\n"
204"Usage: %s -[ACD] chain rule-specification [options]\n"
205"       %s -I chain [rulenum] rule-specification [options]\n"
206"       %s -R chain rulenum rule-specification [options]\n"
207"       %s -D chain rulenum [options]\n"
208"       %s -[LS] [chain [rulenum]] [options]\n"
209"       %s -[FZ] [chain] [options]\n"
210"       %s -[NX] chain\n"
211"       %s -E old-chain-name new-chain-name\n"
212"       %s -P chain target [options]\n"
213"       %s -h (print this help information)\n\n",
214	       prog_name, prog_vers, prog_name, prog_name,
215	       prog_name, prog_name, prog_name, prog_name,
216	       prog_name, prog_name, prog_name, prog_name);
217
218	printf(
219"Commands:\n"
220"Either long or short options are allowed.\n"
221"  --append  -A chain		Append to chain\n"
222"  --check   -C chain		Check for the existence of a rule\n"
223"  --delete  -D chain		Delete matching rule from chain\n"
224"  --delete  -D chain rulenum\n"
225"				Delete rule rulenum (1 = first) from chain\n"
226"  --insert  -I chain [rulenum]\n"
227"				Insert in chain as rulenum (default 1=first)\n"
228"  --replace -R chain rulenum\n"
229"				Replace rule rulenum (1 = first) in chain\n"
230"  --list    -L [chain [rulenum]]\n"
231"				List the rules in a chain or all chains\n"
232"  --list-rules -S [chain [rulenum]]\n"
233"				Print the rules in a chain or all chains\n"
234"  --flush   -F [chain]		Delete all rules in  chain or all chains\n"
235"  --zero    -Z [chain [rulenum]]\n"
236"				Zero counters in chain or all chains\n"
237"  --new     -N chain		Create a new user-defined chain\n"
238"  --delete-chain\n"
239"            -X [chain]		Delete a user-defined chain\n"
240"  --policy  -P chain target\n"
241"				Change policy on chain to target\n"
242"  --rename-chain\n"
243"            -E old-chain new-chain\n"
244"				Change chain name, (moving any references)\n"
245
246"Options:\n"
247"    --ipv4	-4		Nothing (line is ignored by ip6tables-restore)\n"
248"    --ipv6	-6		Error (line is ignored by iptables-restore)\n"
249"[!] --proto	-p proto	protocol: by number or name, eg. `tcp'\n"
250"[!] --source	-s address[/mask][...]\n"
251"				source specification\n"
252"[!] --destination -d address[/mask][...]\n"
253"				destination specification\n"
254"[!] --in-interface -i input name[+]\n"
255"				network interface name ([+] for wildcard)\n"
256" --jump	-j target\n"
257"				target for rule (may load target extension)\n"
258#ifdef IPT_F_GOTO
259"  --goto      -g chain\n"
260"                              jump to chain with no return\n"
261#endif
262"  --match	-m match\n"
263"				extended match (may load extension)\n"
264"  --numeric	-n		numeric output of addresses and ports\n"
265"[!] --out-interface -o output name[+]\n"
266"				network interface name ([+] for wildcard)\n"
267"  --table	-t table	table to manipulate (default: `filter')\n"
268"  --verbose	-v		verbose mode\n"
269"  --line-numbers		print line numbers when listing\n"
270"  --exact	-x		expand numbers (display exact values)\n"
271"[!] --fragment	-f		match second or further fragments only\n"
272"  --modprobe=<command>		try to insert modules using this command\n"
273"  --set-counters PKTS BYTES	set the counter during insert/append\n"
274"[!] --version	-V		print package version.\n");
275
276	print_extension_helps(xtables_targets, matches);
277	exit(0);
278}
279
280void
281iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
282{
283	va_list args;
284
285	va_start(args, msg);
286	fprintf(stderr, "%s v%s: ", prog_name, prog_vers);
287	vfprintf(stderr, msg, args);
288	va_end(args);
289	fprintf(stderr, "\n");
290	if (status == PARAMETER_PROBLEM)
291		exit_tryhelp(status);
292	if (status == VERSION_PROBLEM)
293		fprintf(stderr,
294			"Perhaps iptables or your kernel needs to be upgraded.\n");
295	/* On error paths, make sure that we don't leak memory */
296	xtables_free_opts(1);
297	exit(status);
298}
299
300static void
301generic_opt_check(int command, int options)
302{
303	int i, j, legal = 0;
304
305	/* Check that commands are valid with options.  Complicated by the
306	 * fact that if an option is legal with *any* command given, it is
307	 * legal overall (ie. -z and -l).
308	 */
309	for (i = 0; i < NUMBER_OF_OPT; i++) {
310		legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
311
312		for (j = 0; j < NUMBER_OF_CMD; j++) {
313			if (!(command & (1<<j)))
314				continue;
315
316			if (!(options & (1<<i))) {
317				if (commands_v_options[j][i] == '+')
318					xtables_error(PARAMETER_PROBLEM,
319						   "You need to supply the `-%c' "
320						   "option for this command\n",
321						   optflags[i]);
322			} else {
323				if (commands_v_options[j][i] != 'x')
324					legal = 1;
325				else if (legal == 0)
326					legal = -1;
327			}
328		}
329		if (legal == -1)
330			xtables_error(PARAMETER_PROBLEM,
331				   "Illegal option `-%c' with this command\n",
332				   optflags[i]);
333	}
334}
335
336static char
337opt2char(int option)
338{
339	const char *ptr;
340	for (ptr = optflags; option > 1; option >>= 1, ptr++);
341
342	return *ptr;
343}
344
345static char
346cmd2char(int option)
347{
348	const char *ptr;
349	for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
350
351	return *ptr;
352}
353
354static void
355add_command(unsigned int *cmd, const int newcmd, const int othercmds,
356	    int invert)
357{
358	if (invert)
359		xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
360	if (*cmd & (~othercmds))
361		xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
362			   cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
363	*cmd |= newcmd;
364}
365
366/*
367 *	All functions starting with "parse" should succeed, otherwise
368 *	the program fails.
369 *	Most routines return pointers to static data that may change
370 *	between calls to the same or other routines with a few exceptions:
371 *	"host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
372 *	return global static data.
373*/
374
375/* Christophe Burki wants `-p 6' to imply `-m tcp'.  */
376/* Can't be zero. */
377static int
378parse_rulenumber(const char *rule)
379{
380	unsigned int rulenum;
381
382	if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
383		xtables_error(PARAMETER_PROBLEM,
384			   "Invalid rule number `%s'", rule);
385
386	return rulenum;
387}
388
389static const char *
390parse_target(const char *targetname)
391{
392	const char *ptr;
393
394	if (strlen(targetname) < 1)
395		xtables_error(PARAMETER_PROBLEM,
396			   "Invalid target name (too short)");
397
398	if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
399		xtables_error(PARAMETER_PROBLEM,
400			   "Invalid target name `%s' (%u chars max)",
401			   targetname, XT_EXTENSION_MAXNAMELEN - 1);
402
403	for (ptr = targetname; *ptr; ptr++)
404		if (isspace(*ptr))
405			xtables_error(PARAMETER_PROBLEM,
406				   "Invalid target name `%s'", targetname);
407	return targetname;
408}
409
410static void
411set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
412	   int invert)
413{
414	if (*options & option)
415		xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
416			   opt2char(option));
417	*options |= option;
418
419	if (invert) {
420		unsigned int i;
421		for (i = 0; 1 << i != option; i++);
422
423		if (!inverse_for_options[i])
424			xtables_error(PARAMETER_PROBLEM,
425				   "cannot have ! before -%c",
426				   opt2char(option));
427		*invflg |= inverse_for_options[i];
428	}
429}
430
431static void
432print_num(uint64_t number, unsigned int format)
433{
434	if (format & FMT_KILOMEGAGIGA) {
435		if (number > 99999) {
436			number = (number + 500) / 1000;
437			if (number > 9999) {
438				number = (number + 500) / 1000;
439				if (number > 9999) {
440					number = (number + 500) / 1000;
441					if (number > 9999) {
442						number = (number + 500) / 1000;
443						printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
444					}
445					else printf(FMT("%4lluG ","%lluG "), (unsigned long long)number);
446				}
447				else printf(FMT("%4lluM ","%lluM "), (unsigned long long)number);
448			} else
449				printf(FMT("%4lluK ","%lluK "), (unsigned long long)number);
450		} else
451			printf(FMT("%5llu ","%llu "), (unsigned long long)number);
452	} else
453		printf(FMT("%8llu ","%llu "), (unsigned long long)number);
454}
455
456
457static void
458print_header(unsigned int format, const char *chain, struct xtc_handle *handle)
459{
460	struct xt_counters counters;
461	const char *pol = iptc_get_policy(chain, &counters, handle);
462	printf("Chain %s", chain);
463	if (pol) {
464		printf(" (policy %s", pol);
465		if (!(format & FMT_NOCOUNTS)) {
466			fputc(' ', stdout);
467			print_num(counters.pcnt, (format|FMT_NOTABLE));
468			fputs("packets, ", stdout);
469			print_num(counters.bcnt, (format|FMT_NOTABLE));
470			fputs("bytes", stdout);
471		}
472		printf(")\n");
473	} else {
474		unsigned int refs;
475		if (!iptc_get_references(&refs, chain, handle))
476			printf(" (ERROR obtaining refs)\n");
477		else
478			printf(" (%u references)\n", refs);
479	}
480
481	if (format & FMT_LINENUMBERS)
482		printf(FMT("%-4s ", "%s "), "num");
483	if (!(format & FMT_NOCOUNTS)) {
484		if (format & FMT_KILOMEGAGIGA) {
485			printf(FMT("%5s ","%s "), "pkts");
486			printf(FMT("%5s ","%s "), "bytes");
487		} else {
488			printf(FMT("%8s ","%s "), "pkts");
489			printf(FMT("%10s ","%s "), "bytes");
490		}
491	}
492	if (!(format & FMT_NOTARGET))
493		printf(FMT("%-9s ","%s "), "target");
494	fputs(" prot ", stdout);
495	if (format & FMT_OPTIONS)
496		fputs("opt", stdout);
497	if (format & FMT_VIA) {
498		printf(FMT(" %-6s ","%s "), "in");
499		printf(FMT("%-6s ","%s "), "out");
500	}
501	printf(FMT(" %-19s ","%s "), "source");
502	printf(FMT(" %-19s "," %s "), "destination");
503	printf("\n");
504}
505
506
507static int
508print_match(const struct xt_entry_match *m,
509	    const struct ipt_ip *ip,
510	    int numeric)
511{
512	const struct xtables_match *match =
513		xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL);
514
515	if (match) {
516		if (match->print)
517			match->print(ip, m, numeric);
518		else
519			printf("%s ", match->name);
520	} else {
521		if (m->u.user.name[0])
522			printf("UNKNOWN match `%s' ", m->u.user.name);
523	}
524	/* Don't stop iterating. */
525	return 0;
526}
527
528/* e is called `fw' here for historical reasons */
529static void
530print_firewall(const struct ipt_entry *fw,
531	       const char *targname,
532	       unsigned int num,
533	       unsigned int format,
534	       struct xtc_handle *const handle)
535{
536	const struct xtables_target *target = NULL;
537	const struct xt_entry_target *t;
538	uint8_t flags;
539	char buf[BUFSIZ];
540
541	if (!iptc_is_chain(targname, handle))
542		target = xtables_find_target(targname, XTF_TRY_LOAD);
543	else
544		target = xtables_find_target(XT_STANDARD_TARGET,
545		         XTF_LOAD_MUST_SUCCEED);
546
547	t = ipt_get_target((struct ipt_entry *)fw);
548	flags = fw->ip.flags;
549
550	if (format & FMT_LINENUMBERS)
551		printf(FMT("%-4u ", "%u "), num);
552
553	if (!(format & FMT_NOCOUNTS)) {
554		print_num(fw->counters.pcnt, format);
555		print_num(fw->counters.bcnt, format);
556	}
557
558	if (!(format & FMT_NOTARGET))
559		printf(FMT("%-9s ", "%s "), targname);
560
561	fputc(fw->ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
562	{
563		const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
564		if (pname)
565			printf(FMT("%-5s", "%s "), pname);
566		else
567			printf(FMT("%-5hu", "%hu "), fw->ip.proto);
568	}
569
570	if (format & FMT_OPTIONS) {
571		if (format & FMT_NOTABLE)
572			fputs("opt ", stdout);
573		fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
574		fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
575		fputc(' ', stdout);
576	}
577
578	if (format & FMT_VIA) {
579		char iface[IFNAMSIZ+2];
580
581		if (fw->ip.invflags & IPT_INV_VIA_IN) {
582			iface[0] = '!';
583			iface[1] = '\0';
584		}
585		else iface[0] = '\0';
586
587		if (fw->ip.iniface[0] != '\0') {
588			strcat(iface, fw->ip.iniface);
589		}
590		else if (format & FMT_NUMERIC) strcat(iface, "*");
591		else strcat(iface, "any");
592		printf(FMT(" %-6s ","in %s "), iface);
593
594		if (fw->ip.invflags & IPT_INV_VIA_OUT) {
595			iface[0] = '!';
596			iface[1] = '\0';
597		}
598		else iface[0] = '\0';
599
600		if (fw->ip.outiface[0] != '\0') {
601			strcat(iface, fw->ip.outiface);
602		}
603		else if (format & FMT_NUMERIC) strcat(iface, "*");
604		else strcat(iface, "any");
605		printf(FMT("%-6s ","out %s "), iface);
606	}
607
608	fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
609	if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
610		printf(FMT("%-19s ","%s "), "anywhere");
611	else {
612		if (format & FMT_NUMERIC)
613			strcpy(buf, xtables_ipaddr_to_numeric(&fw->ip.src));
614		else
615			strcpy(buf, xtables_ipaddr_to_anyname(&fw->ip.src));
616		strcat(buf, xtables_ipmask_to_numeric(&fw->ip.smsk));
617		printf(FMT("%-19s ","%s "), buf);
618	}
619
620	fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
621	if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
622		printf(FMT("%-19s ","-> %s"), "anywhere");
623	else {
624		if (format & FMT_NUMERIC)
625			strcpy(buf, xtables_ipaddr_to_numeric(&fw->ip.dst));
626		else
627			strcpy(buf, xtables_ipaddr_to_anyname(&fw->ip.dst));
628		strcat(buf, xtables_ipmask_to_numeric(&fw->ip.dmsk));
629		printf(FMT("%-19s ","-> %s"), buf);
630	}
631
632	if (format & FMT_NOTABLE)
633		fputs("  ", stdout);
634
635#ifdef IPT_F_GOTO
636	if(fw->ip.flags & IPT_F_GOTO)
637		printf("[goto] ");
638#endif
639
640	IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
641
642	if (target) {
643		if (target->print)
644			/* Print the target information. */
645			target->print(&fw->ip, t, format & FMT_NUMERIC);
646	} else if (t->u.target_size != sizeof(*t))
647		printf("[%u bytes of unknown target data] ",
648		       (unsigned int)(t->u.target_size - sizeof(*t)));
649
650	if (!(format & FMT_NONEWLINE))
651		fputc('\n', stdout);
652}
653
654static void
655print_firewall_line(const struct ipt_entry *fw,
656		    struct xtc_handle *const h)
657{
658	struct xt_entry_target *t;
659
660	t = ipt_get_target((struct ipt_entry *)fw);
661	print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h);
662}
663
664static int
665append_entry(const xt_chainlabel chain,
666	     struct ipt_entry *fw,
667	     unsigned int nsaddrs,
668	     const struct in_addr saddrs[],
669	     const struct in_addr smasks[],
670	     unsigned int ndaddrs,
671	     const struct in_addr daddrs[],
672	     const struct in_addr dmasks[],
673	     int verbose,
674	     struct xtc_handle *handle)
675{
676	unsigned int i, j;
677	int ret = 1;
678
679	for (i = 0; i < nsaddrs; i++) {
680		fw->ip.src.s_addr = saddrs[i].s_addr;
681		fw->ip.smsk.s_addr = smasks[i].s_addr;
682		for (j = 0; j < ndaddrs; j++) {
683			fw->ip.dst.s_addr = daddrs[j].s_addr;
684			fw->ip.dmsk.s_addr = dmasks[j].s_addr;
685			if (verbose)
686				print_firewall_line(fw, handle);
687			ret &= iptc_append_entry(chain, fw, handle);
688		}
689	}
690
691	return ret;
692}
693
694static int
695replace_entry(const xt_chainlabel chain,
696	      struct ipt_entry *fw,
697	      unsigned int rulenum,
698	      const struct in_addr *saddr, const struct in_addr *smask,
699	      const struct in_addr *daddr, const struct in_addr *dmask,
700	      int verbose,
701	      struct xtc_handle *handle)
702{
703	fw->ip.src.s_addr = saddr->s_addr;
704	fw->ip.dst.s_addr = daddr->s_addr;
705	fw->ip.smsk.s_addr = smask->s_addr;
706	fw->ip.dmsk.s_addr = dmask->s_addr;
707
708	if (verbose)
709		print_firewall_line(fw, handle);
710	return iptc_replace_entry(chain, fw, rulenum, handle);
711}
712
713static int
714insert_entry(const xt_chainlabel chain,
715	     struct ipt_entry *fw,
716	     unsigned int rulenum,
717	     unsigned int nsaddrs,
718	     const struct in_addr saddrs[],
719	     const struct in_addr smasks[],
720	     unsigned int ndaddrs,
721	     const struct in_addr daddrs[],
722	     const struct in_addr dmasks[],
723	     int verbose,
724	     struct xtc_handle *handle)
725{
726	unsigned int i, j;
727	int ret = 1;
728
729	for (i = 0; i < nsaddrs; i++) {
730		fw->ip.src.s_addr = saddrs[i].s_addr;
731		fw->ip.smsk.s_addr = smasks[i].s_addr;
732		for (j = 0; j < ndaddrs; j++) {
733			fw->ip.dst.s_addr = daddrs[j].s_addr;
734			fw->ip.dmsk.s_addr = dmasks[j].s_addr;
735			if (verbose)
736				print_firewall_line(fw, handle);
737			ret &= iptc_insert_entry(chain, fw, rulenum, handle);
738		}
739	}
740
741	return ret;
742}
743
744static unsigned char *
745make_delete_mask(const struct xtables_rule_match *matches,
746		 const struct xtables_target *target)
747{
748	/* Establish mask for comparison */
749	unsigned int size;
750	const struct xtables_rule_match *matchp;
751	unsigned char *mask, *mptr;
752
753	size = sizeof(struct ipt_entry);
754	for (matchp = matches; matchp; matchp = matchp->next)
755		size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
756
757	mask = xtables_calloc(1, size
758			 + XT_ALIGN(sizeof(struct xt_entry_target))
759			 + target->size);
760
761	memset(mask, 0xFF, sizeof(struct ipt_entry));
762	mptr = mask + sizeof(struct ipt_entry);
763
764	for (matchp = matches; matchp; matchp = matchp->next) {
765		memset(mptr, 0xFF,
766		       XT_ALIGN(sizeof(struct xt_entry_match))
767		       + matchp->match->userspacesize);
768		mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
769	}
770
771	memset(mptr, 0xFF,
772	       XT_ALIGN(sizeof(struct xt_entry_target))
773	       + target->userspacesize);
774
775	return mask;
776}
777
778static int
779delete_entry(const xt_chainlabel chain,
780	     struct ipt_entry *fw,
781	     unsigned int nsaddrs,
782	     const struct in_addr saddrs[],
783	     const struct in_addr smasks[],
784	     unsigned int ndaddrs,
785	     const struct in_addr daddrs[],
786	     const struct in_addr dmasks[],
787	     int verbose,
788	     struct xtc_handle *handle,
789	     struct xtables_rule_match *matches,
790	     const struct xtables_target *target)
791{
792	unsigned int i, j;
793	int ret = 1;
794	unsigned char *mask;
795
796	mask = make_delete_mask(matches, target);
797	for (i = 0; i < nsaddrs; i++) {
798		fw->ip.src.s_addr = saddrs[i].s_addr;
799		fw->ip.smsk.s_addr = smasks[i].s_addr;
800		for (j = 0; j < ndaddrs; j++) {
801			fw->ip.dst.s_addr = daddrs[j].s_addr;
802			fw->ip.dmsk.s_addr = dmasks[j].s_addr;
803			if (verbose)
804				print_firewall_line(fw, handle);
805			ret &= iptc_delete_entry(chain, fw, mask, handle);
806		}
807	}
808	free(mask);
809
810	return ret;
811}
812
813static int
814check_entry(const xt_chainlabel chain, struct ipt_entry *fw,
815	    unsigned int nsaddrs, const struct in_addr *saddrs,
816	    const struct in_addr *smasks, unsigned int ndaddrs,
817	    const struct in_addr *daddrs, const struct in_addr *dmasks,
818	    bool verbose, struct xtc_handle *handle,
819	    struct xtables_rule_match *matches,
820	    const struct xtables_target *target)
821{
822	unsigned int i, j;
823	int ret = 1;
824	unsigned char *mask;
825
826	mask = make_delete_mask(matches, target);
827	for (i = 0; i < nsaddrs; i++) {
828		fw->ip.src.s_addr = saddrs[i].s_addr;
829		fw->ip.smsk.s_addr = smasks[i].s_addr;
830		for (j = 0; j < ndaddrs; j++) {
831			fw->ip.dst.s_addr = daddrs[j].s_addr;
832			fw->ip.dmsk.s_addr = dmasks[j].s_addr;
833			if (verbose)
834				print_firewall_line(fw, handle);
835			ret &= iptc_check_entry(chain, fw, mask, handle);
836		}
837	}
838
839	free(mask);
840	return ret;
841}
842
843int
844for_each_chain4(int (*fn)(const xt_chainlabel, int, struct xtc_handle *),
845	       int verbose, int builtinstoo, struct xtc_handle *handle)
846{
847        int ret = 1;
848	const char *chain;
849	char *chains;
850	unsigned int i, chaincount = 0;
851
852	chain = iptc_first_chain(handle);
853	while (chain) {
854		chaincount++;
855		chain = iptc_next_chain(handle);
856        }
857
858	chains = xtables_malloc(sizeof(xt_chainlabel) * chaincount);
859	i = 0;
860	chain = iptc_first_chain(handle);
861	while (chain) {
862		strcpy(chains + i*sizeof(xt_chainlabel), chain);
863		i++;
864		chain = iptc_next_chain(handle);
865        }
866
867	for (i = 0; i < chaincount; i++) {
868		if (!builtinstoo
869		    && iptc_builtin(chains + i*sizeof(xt_chainlabel),
870				    handle) == 1)
871			continue;
872	        ret &= fn(chains + i*sizeof(xt_chainlabel), verbose, handle);
873	}
874
875	free(chains);
876        return ret;
877}
878
879int
880flush_entries4(const xt_chainlabel chain, int verbose,
881	      struct xtc_handle *handle)
882{
883	if (!chain)
884		return for_each_chain4(flush_entries4, verbose, 1, handle);
885
886	if (verbose)
887		fprintf(stdout, "Flushing chain `%s'\n", chain);
888	return iptc_flush_entries(chain, handle);
889}
890
891static int
892zero_entries(const xt_chainlabel chain, int verbose,
893	     struct xtc_handle *handle)
894{
895	if (!chain)
896		return for_each_chain4(zero_entries, verbose, 1, handle);
897
898	if (verbose)
899		fprintf(stdout, "Zeroing chain `%s'\n", chain);
900	return iptc_zero_entries(chain, handle);
901}
902
903int
904delete_chain4(const xt_chainlabel chain, int verbose,
905	     struct xtc_handle *handle)
906{
907	if (!chain)
908		return for_each_chain4(delete_chain4, verbose, 0, handle);
909
910	if (verbose)
911		fprintf(stdout, "Deleting chain `%s'\n", chain);
912	return iptc_delete_chain(chain, handle);
913}
914
915static int
916list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
917	     int expanded, int linenumbers, struct xtc_handle *handle)
918{
919	int found = 0;
920	unsigned int format;
921	const char *this;
922
923	format = FMT_OPTIONS;
924	if (!verbose)
925		format |= FMT_NOCOUNTS;
926	else
927		format |= FMT_VIA;
928
929	if (numeric)
930		format |= FMT_NUMERIC;
931
932	if (!expanded)
933		format |= FMT_KILOMEGAGIGA;
934
935	if (linenumbers)
936		format |= FMT_LINENUMBERS;
937
938	for (this = iptc_first_chain(handle);
939	     this;
940	     this = iptc_next_chain(handle)) {
941		const struct ipt_entry *i;
942		unsigned int num;
943
944		if (chain && strcmp(chain, this) != 0)
945			continue;
946
947		if (found) printf("\n");
948
949		if (!rulenum)
950			print_header(format, this, handle);
951		i = iptc_first_rule(this, handle);
952
953		num = 0;
954		while (i) {
955			num++;
956			if (!rulenum || num == rulenum)
957				print_firewall(i,
958					       iptc_get_target(i, handle),
959					       num,
960					       format,
961					       handle);
962			i = iptc_next_rule(i, handle);
963		}
964		found = 1;
965	}
966
967	errno = ENOENT;
968	return found;
969}
970
971static void print_proto(uint16_t proto, int invert)
972{
973	if (proto) {
974		unsigned int i;
975		const char *invertstr = invert ? " !" : "";
976
977		const struct protoent *pent = getprotobynumber(proto);
978		if (pent) {
979			printf("%s -p %s", invertstr, pent->p_name);
980			return;
981		}
982
983		for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
984			if (xtables_chain_protos[i].num == proto) {
985				printf("%s -p %s",
986				       invertstr, xtables_chain_protos[i].name);
987				return;
988			}
989
990		printf("%s -p %u", invertstr, proto);
991	}
992}
993
994#define IP_PARTS_NATIVE(n)			\
995(unsigned int)((n)>>24)&0xFF,			\
996(unsigned int)((n)>>16)&0xFF,			\
997(unsigned int)((n)>>8)&0xFF,			\
998(unsigned int)((n)&0xFF)
999
1000#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
1001
1002/* This assumes that mask is contiguous, and byte-bounded. */
1003static void
1004print_iface(char letter, const char *iface, const unsigned char *mask,
1005	    int invert)
1006{
1007	unsigned int i;
1008
1009	if (mask[0] == 0)
1010		return;
1011
1012	printf("%s -%c ", invert ? " !" : "", letter);
1013
1014	for (i = 0; i < IFNAMSIZ; i++) {
1015		if (mask[i] != 0) {
1016			if (iface[i] != '\0')
1017				printf("%c", iface[i]);
1018		} else {
1019			/* we can access iface[i-1] here, because
1020			 * a few lines above we make sure that mask[0] != 0 */
1021			if (iface[i-1] != '\0')
1022				printf("+");
1023			break;
1024		}
1025	}
1026}
1027
1028static int print_match_save(const struct xt_entry_match *e,
1029			const struct ipt_ip *ip)
1030{
1031	const struct xtables_match *match =
1032		xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL);
1033
1034	if (match) {
1035		printf(" -m %s", e->u.user.name);
1036
1037		/* some matches don't provide a save function */
1038		if (match->save)
1039			match->save(ip, e);
1040	} else {
1041		if (e->u.match_size) {
1042			fprintf(stderr,
1043				"Can't find library for match `%s'\n",
1044				e->u.user.name);
1045			exit(1);
1046		}
1047	}
1048	return 0;
1049}
1050
1051/* print a given ip including mask if neccessary */
1052static void print_ip(const char *prefix, uint32_t ip,
1053		     uint32_t mask, int invert)
1054{
1055	uint32_t bits, hmask = ntohl(mask);
1056	int i;
1057
1058	if (!mask && !ip && !invert)
1059		return;
1060
1061	printf("%s %s %u.%u.%u.%u",
1062		invert ? " !" : "",
1063		prefix,
1064		IP_PARTS(ip));
1065
1066	if (mask == 0xFFFFFFFFU) {
1067		printf("/32");
1068		return;
1069	}
1070
1071	i    = 32;
1072	bits = 0xFFFFFFFEU;
1073	while (--i >= 0 && hmask != bits)
1074		bits <<= 1;
1075	if (i >= 0)
1076		printf("/%u", i);
1077	else
1078		printf("/%u.%u.%u.%u", IP_PARTS(mask));
1079}
1080
1081/* We want this to be readable, so only print out neccessary fields.
1082 * Because that's the kind of world I want to live in.  */
1083void print_rule4(const struct ipt_entry *e,
1084		struct xtc_handle *h, const char *chain, int counters)
1085{
1086	const struct xt_entry_target *t;
1087	const char *target_name;
1088
1089	/* print counters for iptables-save */
1090	if (counters > 0)
1091		printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
1092
1093	/* print chain name */
1094	printf("-A %s", chain);
1095
1096	/* Print IP part. */
1097	print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
1098			e->ip.invflags & IPT_INV_SRCIP);
1099
1100	print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
1101			e->ip.invflags & IPT_INV_DSTIP);
1102
1103	print_iface('i', e->ip.iniface, e->ip.iniface_mask,
1104		    e->ip.invflags & IPT_INV_VIA_IN);
1105
1106	print_iface('o', e->ip.outiface, e->ip.outiface_mask,
1107		    e->ip.invflags & IPT_INV_VIA_OUT);
1108
1109	print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO);
1110
1111	if (e->ip.flags & IPT_F_FRAG)
1112		printf("%s -f",
1113		       e->ip.invflags & IPT_INV_FRAG ? " !" : "");
1114
1115	/* Print matchinfo part */
1116	if (e->target_offset) {
1117		IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
1118	}
1119
1120	/* print counters for iptables -R */
1121	if (counters < 0)
1122		printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
1123
1124	/* Print target name */
1125	target_name = iptc_get_target(e, h);
1126	if (target_name && (*target_name != '\0'))
1127#ifdef IPT_F_GOTO
1128		printf(" -%c %s", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
1129#else
1130		printf(" -j %s", target_name);
1131#endif
1132
1133	/* Print targinfo part */
1134	t = ipt_get_target((struct ipt_entry *)e);
1135	if (t->u.user.name[0]) {
1136		const struct xtables_target *target =
1137			xtables_find_target(t->u.user.name, XTF_TRY_LOAD);
1138
1139		if (!target) {
1140			fprintf(stderr, "Can't find library for target `%s'\n",
1141				t->u.user.name);
1142			exit(1);
1143		}
1144
1145		if (target->save)
1146			target->save(&e->ip, t);
1147		else {
1148			/* If the target size is greater than xt_entry_target
1149			 * there is something to be saved, we just don't know
1150			 * how to print it */
1151			if (t->u.target_size !=
1152			    sizeof(struct xt_entry_target)) {
1153				fprintf(stderr, "Target `%s' is missing "
1154						"save function\n",
1155					t->u.user.name);
1156				exit(1);
1157			}
1158		}
1159	}
1160	printf("\n");
1161}
1162
1163static int
1164list_rules(const xt_chainlabel chain, int rulenum, int counters,
1165	     struct xtc_handle *handle)
1166{
1167	const char *this = NULL;
1168	int found = 0;
1169
1170	if (counters)
1171	    counters = -1;		/* iptables -c format */
1172
1173	/* Dump out chain names first,
1174	 * thereby preventing dependency conflicts */
1175	if (!rulenum) for (this = iptc_first_chain(handle);
1176	     this;
1177	     this = iptc_next_chain(handle)) {
1178		if (chain && strcmp(this, chain) != 0)
1179			continue;
1180
1181		if (iptc_builtin(this, handle)) {
1182			struct xt_counters count;
1183			printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
1184			if (counters)
1185			    printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
1186			printf("\n");
1187		} else {
1188			printf("-N %s\n", this);
1189		}
1190	}
1191
1192	for (this = iptc_first_chain(handle);
1193	     this;
1194	     this = iptc_next_chain(handle)) {
1195		const struct ipt_entry *e;
1196		int num = 0;
1197
1198		if (chain && strcmp(this, chain) != 0)
1199			continue;
1200
1201		/* Dump out rules */
1202		e = iptc_first_rule(this, handle);
1203		while(e) {
1204			num++;
1205			if (!rulenum || num == rulenum)
1206			    print_rule4(e, handle, this, counters);
1207			e = iptc_next_rule(e, handle);
1208		}
1209		found = 1;
1210	}
1211
1212	errno = ENOENT;
1213	return found;
1214}
1215
1216static struct ipt_entry *
1217generate_entry(const struct ipt_entry *fw,
1218	       struct xtables_rule_match *matches,
1219	       struct xt_entry_target *target)
1220{
1221	unsigned int size;
1222	struct xtables_rule_match *matchp;
1223	struct ipt_entry *e;
1224
1225	size = sizeof(struct ipt_entry);
1226	for (matchp = matches; matchp; matchp = matchp->next)
1227		size += matchp->match->m->u.match_size;
1228
1229	e = xtables_malloc(size + target->u.target_size);
1230	*e = *fw;
1231	e->target_offset = size;
1232	e->next_offset = size + target->u.target_size;
1233
1234	size = 0;
1235	for (matchp = matches; matchp; matchp = matchp->next) {
1236		memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
1237		size += matchp->match->m->u.match_size;
1238	}
1239	memcpy(e->elems + size, target, target->u.target_size);
1240
1241	return e;
1242}
1243
1244static void clear_rule_matches(struct xtables_rule_match **matches)
1245{
1246	struct xtables_rule_match *matchp, *tmp;
1247
1248	for (matchp = *matches; matchp;) {
1249		tmp = matchp->next;
1250		if (matchp->match->m) {
1251			free(matchp->match->m);
1252			matchp->match->m = NULL;
1253		}
1254		if (matchp->match == matchp->match->next) {
1255			free(matchp->match);
1256			matchp->match = NULL;
1257		}
1258		free(matchp);
1259		matchp = tmp;
1260	}
1261
1262	*matches = NULL;
1263}
1264
1265static void command_jump(struct iptables_command_state *cs)
1266{
1267	size_t size;
1268
1269	set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, cs->invert);
1270	cs->jumpto = parse_target(optarg);
1271	/* TRY_LOAD (may be chain name) */
1272	cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
1273
1274	if (cs->target == NULL)
1275		return;
1276
1277	size = XT_ALIGN(sizeof(struct xt_entry_target))
1278		+ cs->target->size;
1279
1280	cs->target->t = xtables_calloc(1, size);
1281	cs->target->t->u.target_size = size;
1282	if (cs->target->real_name == NULL) {
1283		strcpy(cs->target->t->u.user.name, cs->jumpto);
1284	} else {
1285		/* Alias support for userspace side */
1286		strcpy(cs->target->t->u.user.name, cs->target->real_name);
1287		fprintf(stderr, "WARNING: The %s target is obsolete. "
1288		        "Use %s instead.\n",
1289		        cs->jumpto, cs->target->real_name);
1290	}
1291	cs->target->t->u.user.revision = cs->target->revision;
1292
1293	xs_init_target(cs->target);
1294
1295	if (cs->target->x6_options != NULL)
1296		opts = xtables_options_xfrm(iptables_globals.orig_opts, opts,
1297					    cs->target->x6_options,
1298					    &cs->target->option_offset);
1299	else
1300		opts = xtables_merge_options(iptables_globals.orig_opts, opts,
1301					     cs->target->extra_opts,
1302					     &cs->target->option_offset);
1303	if (opts == NULL)
1304		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
1305}
1306
1307static void command_match(struct iptables_command_state *cs)
1308{
1309	struct xtables_match *m;
1310	size_t size;
1311
1312	if (cs->invert)
1313		xtables_error(PARAMETER_PROBLEM,
1314			   "unexpected ! flag before --match");
1315
1316	m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
1317	size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
1318	m->m = xtables_calloc(1, size);
1319	m->m->u.match_size = size;
1320	if (m->real_name == NULL) {
1321		strcpy(m->m->u.user.name, m->name);
1322	} else {
1323		strcpy(m->m->u.user.name, m->real_name);
1324		fprintf(stderr, "WARNING: The %s match is obsolete. "
1325		        "Use %s instead.\n", m->name, m->real_name);
1326	}
1327	m->m->u.user.revision = m->revision;
1328
1329	xs_init_match(m);
1330	if (m == m->next)
1331		return;
1332	/* Merge options for non-cloned matches */
1333	if (m->x6_options != NULL)
1334		opts = xtables_options_xfrm(iptables_globals.orig_opts, opts,
1335					    m->x6_options, &m->option_offset);
1336	else if (m->extra_opts != NULL)
1337		opts = xtables_merge_options(iptables_globals.orig_opts, opts,
1338					     m->extra_opts, &m->option_offset);
1339	if (opts == NULL)
1340		xtables_error(OTHER_PROBLEM, "can't alloc memory!");
1341}
1342
1343int do_command4(int argc, char *argv[], char **table, struct xtc_handle **handle)
1344{
1345	struct iptables_command_state cs;
1346	struct ipt_entry *e = NULL;
1347	unsigned int nsaddrs = 0, ndaddrs = 0;
1348	struct in_addr *saddrs = NULL, *smasks = NULL;
1349	struct in_addr *daddrs = NULL, *dmasks = NULL;
1350
1351	int verbose = 0;
1352	const char *chain = NULL;
1353	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
1354	const char *policy = NULL, *newname = NULL;
1355	unsigned int rulenum = 0, command = 0;
1356	const char *pcnt = NULL, *bcnt = NULL;
1357	int ret = 1;
1358	struct xtables_match *m;
1359	struct xtables_rule_match *matchp;
1360	struct xtables_target *t;
1361	unsigned long long cnt;
1362
1363	memset(&cs, 0, sizeof(cs));
1364	cs.jumpto = "";
1365	cs.argv = argv;
1366
1367	/* re-set optind to 0 in case do_command4 gets called
1368	 * a second time */
1369	optind = 0;
1370
1371	/* clear mflags in case do_command4 gets called a second time
1372	 * (we clear the global list of all matches for security)*/
1373	for (m = xtables_matches; m; m = m->next)
1374		m->mflags = 0;
1375
1376	for (t = xtables_targets; t; t = t->next) {
1377		t->tflags = 0;
1378		t->used = 0;
1379	}
1380
1381	/* Suppress error messages: we may add new options if we
1382           demand-load a protocol. */
1383	opterr = 0;
1384
1385	opts = xt_params->orig_opts;
1386	while ((cs.c = getopt_long(argc, argv,
1387	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:46",
1388					   opts, NULL)) != -1) {
1389		switch (cs.c) {
1390			/*
1391			 * Command selection
1392			 */
1393		case 'A':
1394			add_command(&command, CMD_APPEND, CMD_NONE,
1395				    cs.invert);
1396			chain = optarg;
1397			break;
1398
1399		case 'C':
1400			add_command(&command, CMD_CHECK, CMD_NONE,
1401				    cs.invert);
1402			chain = optarg;
1403			break;
1404
1405		case 'D':
1406			add_command(&command, CMD_DELETE, CMD_NONE,
1407				    cs.invert);
1408			chain = optarg;
1409			if (optind < argc && argv[optind][0] != '-'
1410			    && argv[optind][0] != '!') {
1411				rulenum = parse_rulenumber(argv[optind++]);
1412				command = CMD_DELETE_NUM;
1413			}
1414			break;
1415
1416		case 'R':
1417			add_command(&command, CMD_REPLACE, CMD_NONE,
1418				    cs.invert);
1419			chain = optarg;
1420			if (optind < argc && argv[optind][0] != '-'
1421			    && argv[optind][0] != '!')
1422				rulenum = parse_rulenumber(argv[optind++]);
1423			else
1424				xtables_error(PARAMETER_PROBLEM,
1425					   "-%c requires a rule number",
1426					   cmd2char(CMD_REPLACE));
1427			break;
1428
1429		case 'I':
1430			add_command(&command, CMD_INSERT, CMD_NONE,
1431				    cs.invert);
1432			chain = optarg;
1433			if (optind < argc && argv[optind][0] != '-'
1434			    && argv[optind][0] != '!')
1435				rulenum = parse_rulenumber(argv[optind++]);
1436			else rulenum = 1;
1437			break;
1438
1439		case 'L':
1440			add_command(&command, CMD_LIST,
1441				    CMD_ZERO | CMD_ZERO_NUM, cs.invert);
1442			if (optarg) chain = optarg;
1443			else if (optind < argc && argv[optind][0] != '-'
1444				 && argv[optind][0] != '!')
1445				chain = argv[optind++];
1446			if (optind < argc && argv[optind][0] != '-'
1447			    && argv[optind][0] != '!')
1448				rulenum = parse_rulenumber(argv[optind++]);
1449			break;
1450
1451		case 'S':
1452			add_command(&command, CMD_LIST_RULES,
1453				    CMD_ZERO|CMD_ZERO_NUM, cs.invert);
1454			if (optarg) chain = optarg;
1455			else if (optind < argc && argv[optind][0] != '-'
1456				 && argv[optind][0] != '!')
1457				chain = argv[optind++];
1458			if (optind < argc && argv[optind][0] != '-'
1459			    && argv[optind][0] != '!')
1460				rulenum = parse_rulenumber(argv[optind++]);
1461			break;
1462
1463		case 'F':
1464			add_command(&command, CMD_FLUSH, CMD_NONE,
1465				    cs.invert);
1466			if (optarg) chain = optarg;
1467			else if (optind < argc && argv[optind][0] != '-'
1468				 && argv[optind][0] != '!')
1469				chain = argv[optind++];
1470			break;
1471
1472		case 'Z':
1473			add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
1474				    cs.invert);
1475			if (optarg) chain = optarg;
1476			else if (optind < argc && argv[optind][0] != '-'
1477				&& argv[optind][0] != '!')
1478				chain = argv[optind++];
1479			if (optind < argc && argv[optind][0] != '-'
1480				&& argv[optind][0] != '!') {
1481				rulenum = parse_rulenumber(argv[optind++]);
1482				command = CMD_ZERO_NUM;
1483			}
1484			break;
1485
1486		case 'N':
1487			if (optarg && (*optarg == '-' || *optarg == '!'))
1488				xtables_error(PARAMETER_PROBLEM,
1489					   "chain name not allowed to start "
1490					   "with `%c'\n", *optarg);
1491			if (xtables_find_target(optarg, XTF_TRY_LOAD))
1492				xtables_error(PARAMETER_PROBLEM,
1493					   "chain name may not clash "
1494					   "with target name\n");
1495			add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
1496				    cs.invert);
1497			chain = optarg;
1498			break;
1499
1500		case 'X':
1501			add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
1502				    cs.invert);
1503			if (optarg) chain = optarg;
1504			else if (optind < argc && argv[optind][0] != '-'
1505				 && argv[optind][0] != '!')
1506				chain = argv[optind++];
1507			break;
1508
1509		case 'E':
1510			add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
1511				    cs.invert);
1512			chain = optarg;
1513			if (optind < argc && argv[optind][0] != '-'
1514			    && argv[optind][0] != '!')
1515				newname = argv[optind++];
1516			else
1517				xtables_error(PARAMETER_PROBLEM,
1518					   "-%c requires old-chain-name and "
1519					   "new-chain-name",
1520					    cmd2char(CMD_RENAME_CHAIN));
1521			break;
1522
1523		case 'P':
1524			add_command(&command, CMD_SET_POLICY, CMD_NONE,
1525				    cs.invert);
1526			chain = optarg;
1527			if (optind < argc && argv[optind][0] != '-'
1528			    && argv[optind][0] != '!')
1529				policy = argv[optind++];
1530			else
1531				xtables_error(PARAMETER_PROBLEM,
1532					   "-%c requires a chain and a policy",
1533					   cmd2char(CMD_SET_POLICY));
1534			break;
1535
1536		case 'h':
1537			if (!optarg)
1538				optarg = argv[optind];
1539
1540			/* iptables -p icmp -h */
1541			if (!cs.matches && cs.protocol)
1542				xtables_find_match(cs.protocol,
1543					XTF_TRY_LOAD, &cs.matches);
1544
1545			exit_printhelp(cs.matches);
1546
1547			/*
1548			 * Option selection
1549			 */
1550		case 'p':
1551			set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags,
1552				   cs.invert);
1553
1554			/* Canonicalize into lower case */
1555			for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
1556				*cs.protocol = tolower(*cs.protocol);
1557
1558			cs.protocol = optarg;
1559			cs.fw.ip.proto = xtables_parse_protocol(cs.protocol);
1560
1561			if (cs.fw.ip.proto == 0
1562			    && (cs.fw.ip.invflags & XT_INV_PROTO))
1563				xtables_error(PARAMETER_PROBLEM,
1564					   "rule would never match protocol");
1565			break;
1566
1567		case 's':
1568			set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags,
1569				   cs.invert);
1570			shostnetworkmask = optarg;
1571			break;
1572
1573		case 'd':
1574			set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags,
1575				   cs.invert);
1576			dhostnetworkmask = optarg;
1577			break;
1578
1579#ifdef IPT_F_GOTO
1580		case 'g':
1581			set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
1582				   cs.invert);
1583			cs.fw.ip.flags |= IPT_F_GOTO;
1584			cs.jumpto = parse_target(optarg);
1585			break;
1586#endif
1587
1588		case 'j':
1589			command_jump(&cs);
1590			break;
1591
1592
1593		case 'i':
1594			if (*optarg == '\0')
1595				xtables_error(PARAMETER_PROBLEM,
1596					"Empty interface is likely to be "
1597					"undesired");
1598			set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags,
1599				   cs.invert);
1600			xtables_parse_interface(optarg,
1601					cs.fw.ip.iniface,
1602					cs.fw.ip.iniface_mask);
1603			break;
1604
1605		case 'o':
1606			if (*optarg == '\0')
1607				xtables_error(PARAMETER_PROBLEM,
1608					"Empty interface is likely to be "
1609					"undesired");
1610			set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags,
1611				   cs.invert);
1612			xtables_parse_interface(optarg,
1613					cs.fw.ip.outiface,
1614					cs.fw.ip.outiface_mask);
1615			break;
1616
1617		case 'f':
1618			set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags,
1619				   cs.invert);
1620			cs.fw.ip.flags |= IPT_F_FRAG;
1621			break;
1622
1623		case 'v':
1624			if (!verbose)
1625				set_option(&cs.options, OPT_VERBOSE,
1626					   &cs.fw.ip.invflags, cs.invert);
1627			verbose++;
1628			break;
1629
1630		case 'm':
1631			command_match(&cs);
1632			break;
1633
1634		case 'n':
1635			set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags,
1636				   cs.invert);
1637			break;
1638
1639		case 't':
1640			if (cs.invert)
1641				xtables_error(PARAMETER_PROBLEM,
1642					   "unexpected ! flag before --table");
1643			*table = optarg;
1644			break;
1645
1646		case 'x':
1647			set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags,
1648				   cs.invert);
1649			break;
1650
1651		case 'V':
1652			if (cs.invert)
1653				printf("Not %s ;-)\n", prog_vers);
1654			else
1655				printf("%s v%s\n",
1656				       prog_name, prog_vers);
1657			exit(0);
1658
1659		case '0':
1660			set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags,
1661				   cs.invert);
1662			break;
1663
1664		case 'M':
1665			xtables_modprobe_program = optarg;
1666			break;
1667
1668		case 'c':
1669
1670			set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags,
1671				   cs.invert);
1672			pcnt = optarg;
1673			bcnt = strchr(pcnt + 1, ',');
1674			if (bcnt)
1675			    bcnt++;
1676			if (!bcnt && optind < argc && argv[optind][0] != '-'
1677			    && argv[optind][0] != '!')
1678				bcnt = argv[optind++];
1679			if (!bcnt)
1680				xtables_error(PARAMETER_PROBLEM,
1681					"-%c requires packet and byte counter",
1682					opt2char(OPT_COUNTERS));
1683
1684			if (sscanf(pcnt, "%llu", &cnt) != 1)
1685				xtables_error(PARAMETER_PROBLEM,
1686					"-%c packet counter not numeric",
1687					opt2char(OPT_COUNTERS));
1688			cs.fw.counters.pcnt = cnt;
1689
1690			if (sscanf(bcnt, "%llu", &cnt) != 1)
1691				xtables_error(PARAMETER_PROBLEM,
1692					"-%c byte counter not numeric",
1693					opt2char(OPT_COUNTERS));
1694			cs.fw.counters.bcnt = cnt;
1695			break;
1696
1697		case '4':
1698			/* This is indeed the IPv4 iptables */
1699			break;
1700
1701		case '6':
1702			/* This is not the IPv6 ip6tables */
1703			if (line != -1)
1704				return 1; /* success: line ignored */
1705			fprintf(stderr, "This is the IPv4 version of iptables.\n");
1706			exit_tryhelp(2);
1707
1708		case 1: /* non option */
1709			if (optarg[0] == '!' && optarg[1] == '\0') {
1710				if (cs.invert)
1711					xtables_error(PARAMETER_PROBLEM,
1712						   "multiple consecutive ! not"
1713						   " allowed");
1714				cs.invert = TRUE;
1715				optarg[0] = '\0';
1716				continue;
1717			}
1718			fprintf(stderr, "Bad argument `%s'\n", optarg);
1719			exit_tryhelp(2);
1720
1721		default:
1722			if (command_default(&cs, &iptables_globals) == 1)
1723				/* cf. ip6tables.c */
1724				continue;
1725			break;
1726		}
1727		cs.invert = FALSE;
1728	}
1729
1730	if (strcmp(*table, "nat") == 0 &&
1731	    ((policy != NULL && strcmp(policy, "DROP") == 0) ||
1732	    (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
1733		xtables_error(PARAMETER_PROBLEM,
1734			"\nThe \"nat\" table is not intended for filtering, "
1735		        "the use of DROP is therefore inhibited.\n\n");
1736
1737	for (matchp = cs.matches; matchp; matchp = matchp->next)
1738		xtables_option_mfcall(matchp->match);
1739	if (cs.target != NULL)
1740		xtables_option_tfcall(cs.target);
1741
1742	/* Fix me: must put inverse options checking here --MN */
1743
1744	if (optind < argc)
1745		xtables_error(PARAMETER_PROBLEM,
1746			   "unknown arguments found on commandline");
1747	if (!command)
1748		xtables_error(PARAMETER_PROBLEM, "no command specified");
1749	if (cs.invert)
1750		xtables_error(PARAMETER_PROBLEM,
1751			   "nothing appropriate following !");
1752
1753	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
1754		if (!(cs.options & OPT_DESTINATION))
1755			dhostnetworkmask = "0.0.0.0/0";
1756		if (!(cs.options & OPT_SOURCE))
1757			shostnetworkmask = "0.0.0.0/0";
1758	}
1759
1760	if (shostnetworkmask)
1761		xtables_ipparse_multiple(shostnetworkmask, &saddrs,
1762					 &smasks, &nsaddrs);
1763
1764	if (dhostnetworkmask)
1765		xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
1766					 &dmasks, &ndaddrs);
1767
1768	if ((nsaddrs > 1 || ndaddrs > 1) &&
1769	    (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
1770		xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
1771			   " source or destination IP addresses");
1772
1773	if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
1774		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1775			   "specify a unique address");
1776
1777	generic_opt_check(command, cs.options);
1778
1779	if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
1780		xtables_error(PARAMETER_PROBLEM,
1781			   "chain name `%s' too long (must be under %u chars)",
1782			   chain, XT_EXTENSION_MAXNAMELEN);
1783
1784	/* only allocate handle if we weren't called with a handle */
1785	if (!*handle)
1786		*handle = iptc_init(*table);
1787
1788	/* try to insmod the module if iptc_init failed */
1789	if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1)
1790		*handle = iptc_init(*table);
1791
1792	if (!*handle)
1793		xtables_error(VERSION_PROBLEM,
1794			   "can't initialize iptables table `%s': %s",
1795			   *table, iptc_strerror(errno));
1796
1797	if (command == CMD_APPEND
1798	    || command == CMD_DELETE
1799	    || command == CMD_CHECK
1800	    || command == CMD_INSERT
1801	    || command == CMD_REPLACE) {
1802		if (strcmp(chain, "PREROUTING") == 0
1803		    || strcmp(chain, "INPUT") == 0) {
1804			/* -o not valid with incoming packets. */
1805			if (cs.options & OPT_VIANAMEOUT)
1806				xtables_error(PARAMETER_PROBLEM,
1807					   "Can't use -%c with %s\n",
1808					   opt2char(OPT_VIANAMEOUT),
1809					   chain);
1810		}
1811
1812		if (strcmp(chain, "POSTROUTING") == 0
1813		    || strcmp(chain, "OUTPUT") == 0) {
1814			/* -i not valid with outgoing packets */
1815			if (cs.options & OPT_VIANAMEIN)
1816				xtables_error(PARAMETER_PROBLEM,
1817					   "Can't use -%c with %s\n",
1818					   opt2char(OPT_VIANAMEIN),
1819					   chain);
1820		}
1821
1822		if (cs.target && iptc_is_chain(cs.jumpto, *handle)) {
1823			fprintf(stderr,
1824				"Warning: using chain %s, not extension\n",
1825				cs.jumpto);
1826
1827			if (cs.target->t)
1828				free(cs.target->t);
1829
1830			cs.target = NULL;
1831		}
1832
1833		/* If they didn't specify a target, or it's a chain
1834		   name, use standard. */
1835		if (!cs.target
1836		    && (strlen(cs.jumpto) == 0
1837			|| iptc_is_chain(cs.jumpto, *handle))) {
1838			size_t size;
1839
1840			cs.target = xtables_find_target(XT_STANDARD_TARGET,
1841					 XTF_LOAD_MUST_SUCCEED);
1842
1843			size = sizeof(struct xt_entry_target)
1844				+ cs.target->size;
1845			cs.target->t = xtables_calloc(1, size);
1846			cs.target->t->u.target_size = size;
1847			strcpy(cs.target->t->u.user.name, cs.jumpto);
1848			if (!iptc_is_chain(cs.jumpto, *handle))
1849				cs.target->t->u.user.revision = cs.target->revision;
1850			xs_init_target(cs.target);
1851		}
1852
1853		if (!cs.target) {
1854			/* it is no chain, and we can't load a plugin.
1855			 * We cannot know if the plugin is corrupt, non
1856			 * existant OR if the user just misspelled a
1857			 * chain. */
1858#ifdef IPT_F_GOTO
1859			if (cs.fw.ip.flags & IPT_F_GOTO)
1860				xtables_error(PARAMETER_PROBLEM,
1861					   "goto '%s' is not a chain\n",
1862					   cs.jumpto);
1863#endif
1864			xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED);
1865		} else {
1866			e = generate_entry(&cs.fw, cs.matches, cs.target->t);
1867			free(cs.target->t);
1868		}
1869	}
1870
1871	switch (command) {
1872	case CMD_APPEND:
1873		ret = append_entry(chain, e,
1874				   nsaddrs, saddrs, smasks,
1875				   ndaddrs, daddrs, dmasks,
1876				   cs.options&OPT_VERBOSE,
1877				   *handle);
1878		break;
1879	case CMD_DELETE:
1880		ret = delete_entry(chain, e,
1881				   nsaddrs, saddrs, smasks,
1882				   ndaddrs, daddrs, dmasks,
1883				   cs.options&OPT_VERBOSE,
1884				   *handle, cs.matches, cs.target);
1885		break;
1886	case CMD_DELETE_NUM:
1887		ret = iptc_delete_num_entry(chain, rulenum - 1, *handle);
1888		break;
1889	case CMD_CHECK:
1890		ret = check_entry(chain, e,
1891				   nsaddrs, saddrs, smasks,
1892				   ndaddrs, daddrs, dmasks,
1893				   cs.options&OPT_VERBOSE,
1894				   *handle, cs.matches, cs.target);
1895		break;
1896	case CMD_REPLACE:
1897		ret = replace_entry(chain, e, rulenum - 1,
1898				    saddrs, smasks, daddrs, dmasks,
1899				    cs.options&OPT_VERBOSE, *handle);
1900		break;
1901	case CMD_INSERT:
1902		ret = insert_entry(chain, e, rulenum - 1,
1903				   nsaddrs, saddrs, smasks,
1904				   ndaddrs, daddrs, dmasks,
1905				   cs.options&OPT_VERBOSE,
1906				   *handle);
1907		break;
1908	case CMD_FLUSH:
1909		ret = flush_entries4(chain, cs.options&OPT_VERBOSE, *handle);
1910		break;
1911	case CMD_ZERO:
1912		ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle);
1913		break;
1914	case CMD_ZERO_NUM:
1915		ret = iptc_zero_counter(chain, rulenum, *handle);
1916		break;
1917	case CMD_LIST:
1918	case CMD_LIST|CMD_ZERO:
1919	case CMD_LIST|CMD_ZERO_NUM:
1920		ret = list_entries(chain,
1921				   rulenum,
1922				   cs.options&OPT_VERBOSE,
1923				   cs.options&OPT_NUMERIC,
1924				   cs.options&OPT_EXPANDED,
1925				   cs.options&OPT_LINENUMBERS,
1926				   *handle);
1927		if (ret && (command & CMD_ZERO))
1928			ret = zero_entries(chain,
1929					   cs.options&OPT_VERBOSE, *handle);
1930		if (ret && (command & CMD_ZERO_NUM))
1931			ret = iptc_zero_counter(chain, rulenum, *handle);
1932		break;
1933	case CMD_LIST_RULES:
1934	case CMD_LIST_RULES|CMD_ZERO:
1935	case CMD_LIST_RULES|CMD_ZERO_NUM:
1936		ret = list_rules(chain,
1937				   rulenum,
1938				   cs.options&OPT_VERBOSE,
1939				   *handle);
1940		if (ret && (command & CMD_ZERO))
1941			ret = zero_entries(chain,
1942					   cs.options&OPT_VERBOSE, *handle);
1943		if (ret && (command & CMD_ZERO_NUM))
1944			ret = iptc_zero_counter(chain, rulenum, *handle);
1945		break;
1946	case CMD_NEW_CHAIN:
1947		ret = iptc_create_chain(chain, *handle);
1948		break;
1949	case CMD_DELETE_CHAIN:
1950		ret = delete_chain4(chain, cs.options&OPT_VERBOSE, *handle);
1951		break;
1952	case CMD_RENAME_CHAIN:
1953		ret = iptc_rename_chain(chain, newname,	*handle);
1954		break;
1955	case CMD_SET_POLICY:
1956		ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle);
1957		break;
1958	default:
1959		/* We should never reach this... */
1960		exit_tryhelp(2);
1961	}
1962
1963	if (verbose > 1)
1964		dump_entries(*handle);
1965
1966	clear_rule_matches(&cs.matches);
1967
1968	if (e != NULL) {
1969		free(e);
1970		e = NULL;
1971	}
1972
1973	free(saddrs);
1974	free(smasks);
1975	free(daddrs);
1976	free(dmasks);
1977	xtables_free_opts(1);
1978
1979	return ret;
1980}
1981