1 /*
2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10 */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <xtables.h>
15 #include "nft.h"
16 #include "nft-cmd.h"
17 #include <libnftnl/set.h>
18
nft_cmd_new(struct nft_handle * h,int command,const char * table,const char * chain,struct iptables_command_state * state,int rulenum,bool verbose)19 struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
20 const char *table, const char *chain,
21 struct iptables_command_state *state,
22 int rulenum, bool verbose)
23 {
24 struct nft_rule_ctx ctx = {
25 .command = command,
26 };
27 struct nftnl_rule *rule;
28 struct nft_cmd *cmd;
29
30 cmd = xtables_calloc(1, sizeof(struct nft_cmd));
31 INIT_LIST_HEAD(&cmd->head);
32 cmd->error.lineno = h->error.lineno;
33 cmd->command = command;
34 cmd->table = xtables_strdup(table);
35 if (chain)
36 cmd->chain = xtables_strdup(chain);
37 cmd->rulenum = rulenum;
38 cmd->verbose = verbose;
39
40 if (state) {
41 rule = nft_rule_new(h, &ctx, chain, table, state);
42 if (!rule) {
43 nft_cmd_free(cmd);
44 return NULL;
45 }
46
47 cmd->obj.rule = rule;
48
49 if (!state->target && strlen(state->jumpto) > 0)
50 cmd->jumpto = xtables_strdup(state->jumpto);
51 }
52
53 list_add_tail(&cmd->head, &h->cmd_list);
54
55 return cmd;
56 }
57
nft_cmd_free(struct nft_cmd * cmd)58 void nft_cmd_free(struct nft_cmd *cmd)
59 {
60 free((void *)cmd->table);
61 free((void *)cmd->chain);
62 free((void *)cmd->policy);
63 free((void *)cmd->rename);
64 free((void *)cmd->jumpto);
65
66 switch (cmd->command) {
67 case NFT_COMPAT_RULE_CHECK:
68 case NFT_COMPAT_RULE_DELETE:
69 case NFT_COMPAT_RULE_CHANGE_COUNTERS:
70 if (cmd->obj.rule)
71 nftnl_rule_free(cmd->obj.rule);
72 break;
73 default:
74 break;
75 }
76
77 list_del(&cmd->head);
78 free(cmd);
79 }
80
nft_cmd_rule_bridge(struct nft_handle * h,const struct nft_cmd * cmd)81 static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
82 {
83 const struct builtin_table *t;
84
85 t = nft_table_builtin_find(h, cmd->table);
86 if (!t)
87 return;
88
89 /* Since ebtables user-defined chain policies are implemented as last
90 * rule in nftables, rule cache is required here to treat them right.
91 */
92 if (h->family == NFPROTO_BRIDGE &&
93 !nft_chain_builtin_find(t, cmd->chain))
94 nft_cache_level_set(h, NFT_CL_RULES, cmd);
95 else
96 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
97 }
98
nft_cmd_rule_append(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * state,bool verbose)99 int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
100 const char *table, struct iptables_command_state *state,
101 bool verbose)
102 {
103 struct nft_cmd *cmd;
104
105 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
106 verbose);
107 if (!cmd)
108 return 0;
109
110 nft_cmd_rule_bridge(h, cmd);
111
112 return 1;
113 }
114
nft_cmd_rule_insert(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * state,int rulenum,bool verbose)115 int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
116 const char *table, struct iptables_command_state *state,
117 int rulenum, bool verbose)
118 {
119 struct nft_cmd *cmd;
120
121 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
122 rulenum, verbose);
123 if (!cmd)
124 return 0;
125
126 nft_cmd_rule_bridge(h, cmd);
127
128 if (cmd->rulenum > 0)
129 nft_cache_level_set(h, NFT_CL_RULES, cmd);
130 else
131 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
132
133 return 1;
134 }
135
nft_cmd_rule_delete(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * state,bool verbose)136 int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
137 const char *table, struct iptables_command_state *state,
138 bool verbose)
139 {
140 struct nft_cmd *cmd;
141
142 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, state,
143 -1, verbose);
144 if (!cmd)
145 return 0;
146
147 nft_cache_level_set(h, NFT_CL_RULES, cmd);
148
149 return 1;
150 }
151
nft_cmd_rule_delete_num(struct nft_handle * h,const char * chain,const char * table,int rulenum,bool verbose)152 int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
153 const char *table, int rulenum, bool verbose)
154 {
155 struct nft_cmd *cmd;
156
157 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, NULL,
158 rulenum, verbose);
159 if (!cmd)
160 return 0;
161
162 nft_cache_level_set(h, NFT_CL_RULES, cmd);
163
164 return 1;
165 }
166
nft_cmd_rule_flush(struct nft_handle * h,const char * chain,const char * table,bool verbose)167 int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
168 const char *table, bool verbose)
169 {
170 struct nft_cmd *cmd;
171
172 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_FLUSH, table, chain, NULL, -1,
173 verbose);
174 if (!cmd)
175 return 0;
176
177 if (h->family == NFPROTO_BRIDGE)
178 nft_cache_level_set(h, NFT_CL_RULES, cmd);
179 else if (chain || verbose)
180 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
181 else
182 nft_cache_level_set(h, NFT_CL_TABLES, cmd);
183
184 return 1;
185 }
186
nft_cmd_chain_zero_counters(struct nft_handle * h,const char * chain,const char * table,bool verbose)187 int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
188 const char *table, bool verbose)
189 {
190 struct nft_cmd *cmd;
191
192 cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_ZERO, table, chain, NULL, -1,
193 verbose);
194 if (!cmd)
195 return 0;
196
197 nft_cache_level_set(h, NFT_CL_RULES, cmd);
198
199 return 1;
200 }
201
nft_cmd_chain_user_add(struct nft_handle * h,const char * chain,const char * table)202 int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
203 const char *table)
204 {
205 struct nft_cmd *cmd;
206
207 cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_ADD, table, chain, NULL, -1,
208 false);
209 if (!cmd)
210 return 0;
211
212 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
213
214 return 1;
215 }
216
nft_cmd_chain_del(struct nft_handle * h,const char * chain,const char * table,bool verbose)217 int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
218 const char *table, bool verbose)
219 {
220 struct nft_cmd *cmd;
221
222 cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_DEL, table, chain, NULL, -1,
223 verbose);
224 if (!cmd)
225 return 0;
226
227 /* This triggers nft_bridge_chain_postprocess() when fetching the
228 * rule cache.
229 */
230 if (h->family == NFPROTO_BRIDGE || !chain)
231 nft_cache_level_set(h, NFT_CL_RULES, cmd);
232 else
233 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
234
235 return 1;
236 }
237
nft_cmd_chain_user_rename(struct nft_handle * h,const char * chain,const char * table,const char * newname)238 int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
239 const char *table, const char *newname)
240 {
241 struct nft_cmd *cmd;
242
243 cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RENAME, table, chain, NULL, -1,
244 false);
245 if (!cmd)
246 return 0;
247
248 cmd->rename = xtables_strdup(newname);
249
250 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
251
252 return 1;
253 }
254
nft_cmd_rule_list(struct nft_handle * h,const char * chain,const char * table,int rulenum,unsigned int format)255 int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
256 const char *table, int rulenum, unsigned int format)
257 {
258 struct nft_cmd *cmd;
259
260 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_LIST, table, chain, NULL, rulenum,
261 false);
262 if (!cmd)
263 return 0;
264
265 cmd->format = format;
266
267 nft_cache_level_set(h, NFT_CL_RULES, cmd);
268
269 return 1;
270 }
271
nft_cmd_rule_replace(struct nft_handle * h,const char * chain,const char * table,void * data,int rulenum,bool verbose)272 int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
273 const char *table, void *data, int rulenum,
274 bool verbose)
275 {
276 struct nft_cmd *cmd;
277
278 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_REPLACE, table, chain, data,
279 rulenum, verbose);
280 if (!cmd)
281 return 0;
282
283 nft_cache_level_set(h, NFT_CL_RULES, cmd);
284
285 return 1;
286 }
287
nft_cmd_rule_check(struct nft_handle * h,const char * chain,const char * table,void * data,bool verbose)288 int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
289 const char *table, void *data, bool verbose)
290 {
291 struct nft_cmd *cmd;
292
293 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHECK, table, chain, data, -1,
294 verbose);
295 if (!cmd)
296 return 0;
297
298 nft_cache_level_set(h, NFT_CL_RULES, cmd);
299
300 return 1;
301 }
302
nft_cmd_chain_set(struct nft_handle * h,const char * table,const char * chain,const char * policy,const struct xt_counters * counters)303 int nft_cmd_chain_set(struct nft_handle *h, const char *table,
304 const char *chain, const char *policy,
305 const struct xt_counters *counters)
306 {
307 struct nft_cmd *cmd;
308
309 cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_UPDATE, table, chain, NULL, -1,
310 false);
311 if (!cmd)
312 return 0;
313
314 cmd->policy = xtables_strdup(policy);
315 if (counters)
316 cmd->counters = *counters;
317
318 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
319
320 return 1;
321 }
322
nft_cmd_table_flush(struct nft_handle * h,const char * table,bool verbose)323 int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose)
324 {
325 struct nft_cmd *cmd;
326
327 if (verbose) {
328 return nft_cmd_rule_flush(h, NULL, table, verbose) &&
329 nft_cmd_chain_del(h, NULL, table, verbose);
330 }
331
332 cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
333 false);
334 if (!cmd)
335 return 0;
336
337 nft_cache_level_set(h, NFT_CL_TABLES, cmd);
338
339 return 1;
340 }
341
nft_cmd_chain_restore(struct nft_handle * h,const char * chain,const char * table)342 int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
343 const char *table)
344 {
345 struct nft_cmd *cmd;
346
347 cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RESTORE, table, chain, NULL, -1,
348 false);
349 if (!cmd)
350 return 0;
351
352 nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
353
354 return 1;
355 }
356
nft_cmd_rule_zero_counters(struct nft_handle * h,const char * chain,const char * table,int rulenum)357 int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
358 const char *table, int rulenum)
359 {
360 struct nft_cmd *cmd;
361
362 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_ZERO, table, chain, NULL, rulenum,
363 false);
364 if (!cmd)
365 return 0;
366
367 nft_cache_level_set(h, NFT_CL_RULES, cmd);
368
369 return 1;
370 }
371
nft_cmd_rule_list_save(struct nft_handle * h,const char * chain,const char * table,int rulenum,int counters)372 int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
373 const char *table, int rulenum, int counters)
374 {
375 struct nft_cmd *cmd;
376
377 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_SAVE, table, chain, NULL, rulenum,
378 false);
379 if (!cmd)
380 return 0;
381
382 cmd->counters_save = counters;
383
384 nft_cache_level_set(h, NFT_CL_RULES, cmd);
385
386 return 1;
387 }
388
ebt_cmd_user_chain_policy(struct nft_handle * h,const char * table,const char * chain,const char * policy)389 int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
390 const char *chain, const char *policy)
391 {
392 struct nft_cmd *cmd;
393
394 cmd = nft_cmd_new(h, NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE, table, chain,
395 NULL, -1, false);
396 if (!cmd)
397 return 0;
398
399 cmd->policy = xtables_strdup(policy);
400
401 nft_cache_level_set(h, NFT_CL_RULES, cmd);
402
403 return 1;
404 }
405
nft_cmd_rule_change_counters(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,int rule_nr,uint8_t counter_op,bool verbose)406 int nft_cmd_rule_change_counters(struct nft_handle *h,
407 const char *chain, const char *table,
408 struct iptables_command_state *cs,
409 int rule_nr, uint8_t counter_op, bool verbose)
410 {
411 struct nft_cmd *cmd;
412
413 cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHANGE_COUNTERS, table, chain,
414 rule_nr == -1 ? cs : NULL, rule_nr, verbose);
415 if (!cmd)
416 return 0;
417
418 cmd->counter_op = counter_op;
419 cmd->counters = cs->counters;
420
421 nft_cache_level_set(h, NFT_CL_RULES, cmd);
422
423 return 1;
424 }
425