1 /*
2 * (C) 2014 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
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <iptables.h>
15 #include <time.h>
16 #include "xtables-multi.h"
17 #include "nft.h"
18
19 #include <string.h>
20 #include <netdb.h>
21 #include <errno.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <limits.h>
28 #include <unistd.h>
29 #include <iptables.h>
30 #include <xtables.h>
31 #include <libiptc/libxtc.h>
32 #include <fcntl.h>
33 #include <getopt.h>
34 #include "xshared.h"
35 #include "nft-shared.h"
36
xlate_ifname(struct xt_xlate * xl,const char * nftmeta,const char * ifname,bool invert)37 void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname,
38 bool invert)
39 {
40 char iface[IFNAMSIZ];
41 int ifaclen;
42
43 if (ifname[0] == '\0')
44 return;
45
46 strcpy(iface, ifname);
47 ifaclen = strlen(iface);
48 if (iface[ifaclen - 1] == '+')
49 iface[ifaclen - 1] = '*';
50
51 xt_xlate_add(xl, "%s %s%s ", nftmeta, invert ? "!= " : "", iface);
52 }
53
xlate_action(const struct iptables_command_state * cs,bool goto_set,struct xt_xlate * xl)54 int xlate_action(const struct iptables_command_state *cs, bool goto_set,
55 struct xt_xlate *xl)
56 {
57 int ret = 1, numeric = cs->options & OPT_NUMERIC;
58
59 /* If no target at all, add nothing (default to continue) */
60 if (cs->target != NULL) {
61 /* Standard target? */
62 if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
63 xt_xlate_add(xl, "accept");
64 else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
65 xt_xlate_add(xl, "drop");
66 else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
67 xt_xlate_add(xl, "return");
68 else if (cs->target->xlate) {
69 struct xt_xlate_tg_params params = {
70 .ip = (const void *)&cs->fw,
71 .target = cs->target->t,
72 .numeric = numeric,
73 .escape_quotes = !cs->restore,
74 };
75 ret = cs->target->xlate(xl, ¶ms);
76 }
77 else
78 return 0;
79 } else if (strlen(cs->jumpto) > 0) {
80 /* Not standard, then it's a go / jump to chain */
81 if (goto_set)
82 xt_xlate_add(xl, "goto %s", cs->jumpto);
83 else
84 xt_xlate_add(xl, "jump %s", cs->jumpto);
85 }
86
87 return ret;
88 }
89
xlate_matches(const struct iptables_command_state * cs,struct xt_xlate * xl)90 int xlate_matches(const struct iptables_command_state *cs, struct xt_xlate *xl)
91 {
92 struct xtables_rule_match *matchp;
93 int ret = 1, numeric = cs->options & OPT_NUMERIC;
94
95 for (matchp = cs->matches; matchp; matchp = matchp->next) {
96 struct xt_xlate_mt_params params = {
97 .ip = (const void *)&cs->fw,
98 .match = matchp->match->m,
99 .numeric = numeric,
100 .escape_quotes = !cs->restore,
101 };
102
103 if (!matchp->match->xlate)
104 return 0;
105
106 ret = matchp->match->xlate(xl, ¶ms);
107
108 if (strcmp(matchp->match->name, "comment") != 0)
109 xt_xlate_add(xl, " ");
110
111 if (!ret)
112 break;
113 }
114 return ret;
115 }
116
xlate_find_match(const struct iptables_command_state * cs,const char * p_name)117 bool xlate_find_match(const struct iptables_command_state *cs, const char *p_name)
118 {
119 struct xtables_rule_match *matchp;
120
121 /* Skip redundant protocol, eg. ip protocol tcp tcp dport */
122 for (matchp = cs->matches; matchp; matchp = matchp->next) {
123 if (strcmp(matchp->match->name, p_name) == 0)
124 return true;
125 }
126 return false;
127 }
128
129 const char *family2str[] = {
130 [NFPROTO_IPV4] = "ip",
131 [NFPROTO_IPV6] = "ip6",
132 };
133
nft_rule_xlate_add(struct nft_handle * h,const struct nft_xt_cmd_parse * p,const struct iptables_command_state * cs,bool append)134 static int nft_rule_xlate_add(struct nft_handle *h,
135 const struct nft_xt_cmd_parse *p,
136 const struct iptables_command_state *cs,
137 bool append)
138 {
139 struct xt_xlate *xl = xt_xlate_alloc(10240);
140 int ret;
141
142 if (append) {
143 xt_xlate_add(xl, "add rule %s %s %s ",
144 family2str[h->family], p->table, p->chain);
145 } else {
146 xt_xlate_add(xl, "insert rule %s %s %s ",
147 family2str[h->family], p->table, p->chain);
148 }
149
150 ret = h->ops->xlate(cs, xl);
151 if (ret)
152 printf("%s\n", xt_xlate_get(xl));
153
154 xt_xlate_free(xl);
155 return ret;
156 }
157
xlate(struct nft_handle * h,struct nft_xt_cmd_parse * p,struct iptables_command_state * cs,struct xtables_args * args,bool append,int (* cb)(struct nft_handle * h,const struct nft_xt_cmd_parse * p,const struct iptables_command_state * cs,bool append))158 static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
159 struct iptables_command_state *cs,
160 struct xtables_args *args, bool append,
161 int (*cb)(struct nft_handle *h,
162 const struct nft_xt_cmd_parse *p,
163 const struct iptables_command_state *cs,
164 bool append))
165 {
166 unsigned int i, j;
167 int ret = 1;
168
169 for (i = 0; i < args->s.naddrs; i++) {
170 switch (h->family) {
171 case AF_INET:
172 cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
173 cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
174 for (j = 0; j < args->d.naddrs; j++) {
175 cs->fw.ip.dst.s_addr =
176 args->d.addr.v4[j].s_addr;
177 cs->fw.ip.dmsk.s_addr =
178 args->d.mask.v4[j].s_addr;
179 ret = cb(h, p, cs, append);
180 }
181 break;
182 case AF_INET6:
183 memcpy(&cs->fw6.ipv6.src,
184 &args->s.addr.v6[i], sizeof(struct in6_addr));
185 memcpy(&cs->fw6.ipv6.smsk,
186 &args->s.mask.v6[i], sizeof(struct in6_addr));
187 for (j = 0; j < args->d.naddrs; j++) {
188 memcpy(&cs->fw6.ipv6.dst,
189 &args->d.addr.v6[j],
190 sizeof(struct in6_addr));
191 memcpy(&cs->fw6.ipv6.dmsk,
192 &args->d.mask.v6[j],
193 sizeof(struct in6_addr));
194 ret = cb(h, p, cs, append);
195 }
196 break;
197 }
198 }
199
200 return ret;
201 }
202
print_ipt_cmd(int argc,char * argv[])203 static void print_ipt_cmd(int argc, char *argv[])
204 {
205 int i;
206
207 printf("# ");
208 for (i = 1; i < argc; i++)
209 printf("%s ", argv[i]);
210
211 printf("\n");
212 }
213
do_command_xlate(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)214 static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
215 char **table, bool restore)
216 {
217 int ret = 0;
218 struct nft_xt_cmd_parse p = {
219 .table = *table,
220 .restore = restore,
221 };
222 struct iptables_command_state cs;
223 struct xtables_args args = {
224 .family = h->family,
225 };
226
227 do_parse(h, argc, argv, &p, &cs, &args);
228
229 cs.restore = restore;
230
231 if (!restore)
232 printf("nft ");
233
234 switch (p.command) {
235 case CMD_APPEND:
236 ret = 1;
237 if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add)) {
238 print_ipt_cmd(argc, argv);
239 }
240 break;
241 case CMD_DELETE:
242 break;
243 case CMD_DELETE_NUM:
244 break;
245 case CMD_CHECK:
246 break;
247 case CMD_REPLACE:
248 break;
249 case CMD_INSERT:
250 ret = 1;
251 if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add)) {
252 print_ipt_cmd(argc, argv);
253 }
254 break;
255 case CMD_FLUSH:
256 if (p.chain) {
257 printf("flush chain %s %s %s\n",
258 family2str[h->family], p.table, p.chain);
259 } else {
260 printf("flush table %s %s\n",
261 family2str[h->family], p.table);
262 }
263 ret = 1;
264 break;
265 case CMD_ZERO:
266 break;
267 case CMD_ZERO_NUM:
268 break;
269 case CMD_LIST:
270 case CMD_LIST|CMD_ZERO:
271 case CMD_LIST|CMD_ZERO_NUM:
272 printf("list table %s %s\n",
273 family2str[h->family], p.table);
274 ret = 1;
275 break;
276 case CMD_LIST_RULES:
277 case CMD_LIST_RULES|CMD_ZERO:
278 case CMD_LIST_RULES|CMD_ZERO_NUM:
279 break;
280 case CMD_NEW_CHAIN:
281 printf("add chain %s %s %s\n",
282 family2str[h->family], p.table, p.chain);
283 ret = 1;
284 break;
285 case CMD_DELETE_CHAIN:
286 printf("delete chain %s %s %s\n",
287 family2str[h->family], p.table, p.chain);
288 ret = 1;
289 break;
290 case CMD_RENAME_CHAIN:
291 break;
292 case CMD_SET_POLICY:
293 break;
294 default:
295 /* We should never reach this... */
296 printf("Unsupported command?\n");
297 exit(1);
298 }
299
300 xtables_rule_matches_free(&cs.matches);
301
302 if (h->family == AF_INET) {
303 free(args.s.addr.v4);
304 free(args.s.mask.v4);
305 free(args.d.addr.v4);
306 free(args.d.mask.v4);
307 } else if (h->family == AF_INET6) {
308 free(args.s.addr.v6);
309 free(args.s.mask.v6);
310 free(args.d.addr.v6);
311 free(args.d.mask.v6);
312 }
313 xtables_free_opts(1);
314
315 return ret;
316 }
317
print_usage(const char * name,const char * version)318 static void print_usage(const char *name, const char *version)
319 {
320 fprintf(stderr, "%s %s "
321 "(c) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>\n"
322 "Usage: %s [-h] [-f]\n"
323 " [ --help ]\n"
324 " [ --file=<FILE> ]\n", name, version, name);
325 exit(1);
326 }
327
328 static const struct option options[] = {
329 { .name = "help", .has_arg = false, .val = 'h' },
330 { .name = "file", .has_arg = true, .val = 'f' },
331 { NULL },
332 };
333
xlate_chain_user_add(struct nft_handle * h,const char * chain,const char * table)334 static int xlate_chain_user_add(struct nft_handle *h, const char *chain,
335 const char *table)
336 {
337 printf("add chain %s %s %s\n", family2str[h->family], table, chain);
338 return 0;
339 }
340
commit(struct nft_handle * h)341 static int commit(struct nft_handle *h)
342 {
343 return 1;
344 }
345
xlate_table_new(struct nft_handle * h,const char * table)346 static void xlate_table_new(struct nft_handle *h, const char *table)
347 {
348 printf("add table %s %s\n", family2str[h->family], table);
349 }
350
xlate_chain_set(struct nft_handle * h,const char * table,const char * chain,const char * policy,const struct xt_counters * counters)351 static int xlate_chain_set(struct nft_handle *h, const char *table,
352 const char *chain, const char *policy,
353 const struct xt_counters *counters)
354 {
355 const char *type = "filter";
356
357 if (strcmp(table, "nat") == 0)
358 type = "nat";
359
360 printf("add chain %s %s %s { type %s ",
361 family2str[h->family], table, chain, type);
362 if (strcmp(chain, "PREROUTING") == 0)
363 printf("hook prerouting priority 0; ");
364 else if (strcmp(chain, "INPUT") == 0)
365 printf("hook input priority 0; ");
366 else if (strcmp(chain, "FORWARD") == 0)
367 printf("hook forward priority 0; ");
368 else if (strcmp(chain, "OUTPUT") == 0)
369 printf("hook output priority 0; ");
370 else if (strcmp(chain, "POSTROUTING") == 0)
371 printf("hook postrouting priority 0; ");
372
373 if (strcmp(policy, "ACCEPT") == 0)
374 printf("policy accept; ");
375 else if (strcmp(policy, "DROP") == 0)
376 printf("policy drop; ");
377
378 printf("}\n");
379 return 1;
380 }
381
382 static struct nft_xt_restore_cb cb_xlate = {
383 .table_new = xlate_table_new,
384 .chain_set = xlate_chain_set,
385 .chain_user_add = xlate_chain_user_add,
386 .do_command = do_command_xlate,
387 .commit = commit,
388 .abort = commit,
389 };
390
xtables_xlate_main(int family,const char * progname,int argc,char * argv[])391 static int xtables_xlate_main(int family, const char *progname, int argc,
392 char *argv[])
393 {
394 int ret;
395 char *table = "filter";
396 struct nft_handle h = {
397 .family = family,
398 };
399
400 xtables_globals.program_name = progname;
401 ret = xtables_init_all(&xtables_globals, family);
402 if (ret < 0) {
403 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
404 xtables_globals.program_name,
405 xtables_globals.program_version);
406 exit(1);
407 }
408 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
409 init_extensions();
410 init_extensions4();
411 #endif
412
413 if (nft_init(&h, xtables_ipv4) < 0) {
414 fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
415 xtables_globals.program_name,
416 xtables_globals.program_version,
417 strerror(errno));
418 nft_fini(&h);
419 exit(EXIT_FAILURE);
420 }
421
422 ret = do_command_xlate(&h, argc, argv, &table, false);
423 if (!ret)
424 fprintf(stderr, "Translation not implemented\n");
425
426 nft_fini(&h);
427 exit(!ret);
428 }
429
xtables_restore_xlate_main(int family,const char * progname,int argc,char * argv[])430 static int xtables_restore_xlate_main(int family, const char *progname,
431 int argc, char *argv[])
432 {
433 int ret;
434 struct nft_handle h = {
435 .family = family,
436 };
437 const char *file = NULL;
438 struct nft_xt_restore_parse p = {};
439 time_t now = time(NULL);
440 int c;
441
442 xtables_globals.program_name = progname;
443 ret = xtables_init_all(&xtables_globals, family);
444 if (ret < 0) {
445 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
446 xtables_globals.program_name,
447 xtables_globals.program_version);
448 exit(1);
449 }
450 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
451 init_extensions();
452 init_extensions4();
453 #endif
454
455 if (nft_init(&h, xtables_ipv4) < 0) {
456 fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
457 xtables_globals.program_name,
458 xtables_globals.program_version,
459 strerror(errno));
460 nft_fini(&h);
461 exit(EXIT_FAILURE);
462 }
463
464 opterr = 0;
465 while ((c = getopt_long(argc, argv, "hf:", options, NULL)) != -1) {
466 switch (c) {
467 case 'h':
468 print_usage(argv[0], IPTABLES_VERSION);
469 exit(0);
470 case 'f':
471 file = optarg;
472 break;
473 }
474 }
475
476 if (file == NULL) {
477 fprintf(stderr, "ERROR: missing file name\n");
478 print_usage(argv[0], IPTABLES_VERSION);
479 exit(0);
480 }
481
482 p.in = fopen(file, "r");
483 if (p.in == NULL) {
484 fprintf(stderr, "Cannot open file %s\n", file);
485 exit(1);
486 }
487
488 printf("# Translated by %s v%s on %s",
489 argv[0], IPTABLES_VERSION, ctime(&now));
490 xtables_restore_parse(&h, &p, &cb_xlate, argc, argv);
491 printf("# Completed on %s", ctime(&now));
492
493 nft_fini(&h);
494 fclose(p.in);
495 exit(0);
496 }
497
xtables_ip4_xlate_main(int argc,char * argv[])498 int xtables_ip4_xlate_main(int argc, char *argv[])
499 {
500 return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate",
501 argc, argv);
502 }
503
xtables_ip6_xlate_main(int argc,char * argv[])504 int xtables_ip6_xlate_main(int argc, char *argv[])
505 {
506 return xtables_xlate_main(NFPROTO_IPV6, "ip6tables-translate",
507 argc, argv);
508 }
509
xtables_ip4_xlate_restore_main(int argc,char * argv[])510 int xtables_ip4_xlate_restore_main(int argc, char *argv[])
511 {
512 return xtables_restore_xlate_main(NFPROTO_IPV4,
513 "iptables-translate-restore",
514 argc, argv);
515 }
516
xtables_ip6_xlate_restore_main(int argc,char * argv[])517 int xtables_ip6_xlate_restore_main(int argc, char *argv[])
518 {
519 return xtables_restore_xlate_main(NFPROTO_IPV6,
520 "ip6tables-translate-restore",
521 argc, argv);
522 }
523