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 37void 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 54int 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 90int 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 117bool 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 129const char *family2str[] = { 130 [NFPROTO_IPV4] = "ip", 131 [NFPROTO_IPV6] = "ip6", 132}; 133 134static 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 158static 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 203static 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 214static 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 318static 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 328static const struct option options[] = { 329 { .name = "help", .has_arg = false, .val = 'h' }, 330 { .name = "file", .has_arg = true, .val = 'f' }, 331 { NULL }, 332}; 333 334static 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 341static int commit(struct nft_handle *h) 342{ 343 return 1; 344} 345 346static 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 351static 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 382static 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 391static 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 430static 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 498int xtables_ip4_xlate_main(int argc, char *argv[]) 499{ 500 return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate", 501 argc, argv); 502} 503 504int xtables_ip6_xlate_main(int argc, char *argv[]) 505{ 506 return xtables_xlate_main(NFPROTO_IPV6, "ip6tables-translate", 507 argc, argv); 508} 509 510int 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 517int 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