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