• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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