• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "config.h"
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 <netinet/ether.h>
40 #include <iptables.h>
41 #include <xtables.h>
42 #include <fcntl.h>
43 #include "xshared.h"
44 #include "nft-shared.h"
45 #include "nft.h"
46 
47 static struct option original_opts[] = {
48 	{.name = "append",	  .has_arg = 1, .val = 'A'},
49 	{.name = "delete",	  .has_arg = 1, .val = 'D'},
50 	{.name = "check",	  .has_arg = 1, .val = 'C'},
51 	{.name = "insert",	  .has_arg = 1, .val = 'I'},
52 	{.name = "replace",	  .has_arg = 1, .val = 'R'},
53 	{.name = "list",	  .has_arg = 2, .val = 'L'},
54 	{.name = "list-rules",	  .has_arg = 2, .val = 'S'},
55 	{.name = "flush",	  .has_arg = 2, .val = 'F'},
56 	{.name = "zero",	  .has_arg = 2, .val = 'Z'},
57 	{.name = "new-chain",	  .has_arg = 1, .val = 'N'},
58 	{.name = "delete-chain",  .has_arg = 2, .val = 'X'},
59 	{.name = "rename-chain",  .has_arg = 1, .val = 'E'},
60 	{.name = "policy",	  .has_arg = 1, .val = 'P'},
61 	{.name = "source",	  .has_arg = 1, .val = 's'},
62 	{.name = "destination",   .has_arg = 1, .val = 'd'},
63 	{.name = "src",		  .has_arg = 1, .val = 's'}, /* synonym */
64 	{.name = "dst",		  .has_arg = 1, .val = 'd'}, /* synonym */
65 	{.name = "protocol",	  .has_arg = 1, .val = 'p'},
66 	{.name = "in-interface",  .has_arg = 1, .val = 'i'},
67 	{.name = "jump",	  .has_arg = 1, .val = 'j'},
68 	{.name = "table",	  .has_arg = 1, .val = 't'},
69 	{.name = "match",	  .has_arg = 1, .val = 'm'},
70 	{.name = "numeric",	  .has_arg = 0, .val = 'n'},
71 	{.name = "out-interface", .has_arg = 1, .val = 'o'},
72 	{.name = "verbose",	  .has_arg = 0, .val = 'v'},
73 	{.name = "wait",	  .has_arg = 2, .val = 'w'},
74 	{.name = "wait-interval", .has_arg = 2, .val = 'W'},
75 	{.name = "exact",	  .has_arg = 0, .val = 'x'},
76 	{.name = "fragments",	  .has_arg = 0, .val = 'f'},
77 	{.name = "version",	  .has_arg = 0, .val = 'V'},
78 	{.name = "help",	  .has_arg = 2, .val = 'h'},
79 	{.name = "line-numbers",  .has_arg = 0, .val = '0'},
80 	{.name = "modprobe",	  .has_arg = 1, .val = 'M'},
81 	{.name = "set-counters",  .has_arg = 1, .val = 'c'},
82 	{.name = "goto",	  .has_arg = 1, .val = 'g'},
83 	{.name = "ipv4",	  .has_arg = 0, .val = '4'},
84 	{.name = "ipv6",	  .has_arg = 0, .val = '6'},
85 	{NULL},
86 };
87 
88 struct xtables_globals xtables_globals = {
89 	.option_offset = 0,
90 	.program_version = PACKAGE_VERSION " (nf_tables)",
91 	.orig_opts = original_opts,
92 	.compat_rev = nft_compatible_revision,
93 };
94 
95 /*
96  *	All functions starting with "parse" should succeed, otherwise
97  *	the program fails.
98  *	Most routines return pointers to static data that may change
99  *	between calls to the same or other routines with a few exceptions:
100  *	"host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
101  *	return global static data.
102 */
103 
104 /* Christophe Burki wants `-p 6' to imply `-m tcp'.  */
105 
106 static int
list_entries(struct nft_handle * h,const char * chain,const char * table,int rulenum,int verbose,int numeric,int expanded,int linenumbers)107 list_entries(struct nft_handle *h, const char *chain, const char *table,
108 	     int rulenum, int verbose, int numeric, int expanded,
109 	     int linenumbers)
110 {
111 	unsigned int format;
112 
113 	format = FMT_OPTIONS;
114 	if (!verbose)
115 		format |= FMT_NOCOUNTS;
116 	else
117 		format |= FMT_VIA;
118 
119 	if (numeric)
120 		format |= FMT_NUMERIC;
121 
122 	if (!expanded)
123 		format |= FMT_KILOMEGAGIGA;
124 
125 	if (linenumbers)
126 		format |= FMT_LINENUMBERS;
127 
128 	return nft_cmd_rule_list(h, chain, table, rulenum, format);
129 }
130 
131 static int
list_rules(struct nft_handle * h,const char * chain,const char * table,int rulenum,int counters)132 list_rules(struct nft_handle *h, const char *chain, const char *table,
133 	   int rulenum, int counters)
134 {
135 	if (counters)
136 	    counters = -1;		/* iptables -c format */
137 
138 	return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
139 }
140 
do_commandx(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)141 int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
142 		bool restore)
143 {
144 	int ret = 1;
145 	struct xt_cmd_parse p = {
146 		.table		= *table,
147 		.restore	= restore,
148 		.line		= line,
149 		.ops		= &h->ops->cmd_parse,
150 	};
151 	struct iptables_command_state cs = {
152 		.jumpto = "",
153 		.argv = argv,
154 	};
155 	struct xtables_args args = {
156 		.family = h->family,
157 	};
158 
159 	if (h->ops->init_cs)
160 		h->ops->init_cs(&cs);
161 
162 	do_parse(argc, argv, &p, &cs, &args);
163 	h->verbose = p.verbose;
164 
165 	if (!nft_table_builtin_find(h, p.table))
166 		xtables_error(VERSION_PROBLEM,
167 			      "table '%s' does not exist",
168 			      p.table);
169 	switch (p.command) {
170 	case CMD_APPEND:
171 		ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args,
172 					cs.options & OPT_VERBOSE, true,
173 					p.rulenum - 1);
174 		break;
175 	case CMD_DELETE:
176 		ret = h->ops->delete_entry(h, p.chain, p.table, &cs, &args,
177 					   cs.options & OPT_VERBOSE);
178 		break;
179 	case CMD_DELETE_NUM:
180 		ret = nft_cmd_rule_delete_num(h, p.chain, p.table,
181 					      p.rulenum - 1, p.verbose);
182 		break;
183 	case CMD_CHECK:
184 		ret = h->ops->check_entry(h, p.chain, p.table, &cs, &args,
185 					  cs.options & OPT_VERBOSE);
186 		break;
187 	case CMD_REPLACE:
188 		ret = h->ops->replace_entry(h, p.chain, p.table, &cs, &args,
189 					    cs.options & OPT_VERBOSE,
190 					    p.rulenum - 1);
191 		break;
192 	case CMD_INSERT:
193 		ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args,
194 					cs.options & OPT_VERBOSE, false,
195 					p.rulenum - 1);
196 		break;
197 	case CMD_FLUSH:
198 		ret = nft_cmd_rule_flush(h, p.chain, p.table,
199 					 cs.options & OPT_VERBOSE);
200 		break;
201 	case CMD_ZERO:
202 		ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
203 						  cs.options & OPT_VERBOSE);
204 		break;
205 	case CMD_ZERO_NUM:
206 		ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
207 					     p.rulenum - 1);
208 		break;
209 	case CMD_LIST:
210 	case CMD_LIST|CMD_ZERO:
211 	case CMD_LIST|CMD_ZERO_NUM:
212 		ret = list_entries(h, p.chain, p.table, p.rulenum,
213 				   cs.options & OPT_VERBOSE,
214 				   cs.options & OPT_NUMERIC,
215 				   cs.options & OPT_EXPANDED,
216 				   cs.options & OPT_LINENUMBERS);
217 		if (ret && (p.command & CMD_ZERO)) {
218 			ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
219 						      cs.options & OPT_VERBOSE);
220 		}
221 		if (ret && (p.command & CMD_ZERO_NUM)) {
222 			ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
223 						     p.rulenum - 1);
224 		}
225 		nft_check_xt_legacy(h->family, false);
226 		break;
227 	case CMD_LIST_RULES:
228 	case CMD_LIST_RULES|CMD_ZERO:
229 	case CMD_LIST_RULES|CMD_ZERO_NUM:
230 		ret = list_rules(h, p.chain, p.table, p.rulenum,
231 				 cs.options & OPT_VERBOSE);
232 		if (ret && (p.command & CMD_ZERO)) {
233 			ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
234 						      cs.options & OPT_VERBOSE);
235 		}
236 		if (ret && (p.command & CMD_ZERO_NUM)) {
237 			ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
238 						     p.rulenum - 1);
239 		}
240 		nft_check_xt_legacy(h->family, false);
241 		break;
242 	case CMD_NEW_CHAIN:
243 		ret = nft_cmd_chain_user_add(h, p.chain, p.table);
244 		break;
245 	case CMD_DELETE_CHAIN:
246 		ret = nft_cmd_chain_del(h, p.chain, p.table,
247 					cs.options & OPT_VERBOSE);
248 		break;
249 	case CMD_RENAME_CHAIN:
250 		ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
251 		break;
252 	case CMD_SET_POLICY:
253 		ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
254 		break;
255 	case CMD_NONE:
256 	/* do_parse ignored the line (eg: -4 with ip6tables-restore) */
257 		break;
258 	default:
259 		/* We should never reach this... */
260 		exit_tryhelp(2, line);
261 	}
262 
263 	*table = p.table;
264 
265 	h->ops->clear_cs(&cs);
266 
267 	xtables_clear_args(&args);
268 	xtables_free_opts(1);
269 
270 	return ret;
271 }
272