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