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