/* Code to save the xtables state, in human readable-form. */ /* (C) 1999 by Paul 'Rusty' Russell and * (C) 2000-2002 by Harald Welte * (C) 2012 by Pablo Neira Ayuso * * This code is distributed under the terms of GNU GPL v2 * */ #include #include #include #include #include #include #include #include #include #include "libiptc/libiptc.h" #include "iptables.h" #include "xtables-multi.h" #include "nft.h" #include #ifndef NO_SHARED_LIBS #include #endif #define prog_name xtables_globals.program_name #define prog_vers xtables_globals.program_version static bool show_counters = false; static const struct option options[] = { {.name = "counters", .has_arg = false, .val = 'c'}, {.name = "version", .has_arg = false, .val = 'V'}, {.name = "dump", .has_arg = false, .val = 'd'}, {.name = "table", .has_arg = true, .val = 't'}, {.name = "modprobe", .has_arg = true, .val = 'M'}, {.name = "file", .has_arg = true, .val = 'f'}, {.name = "ipv4", .has_arg = false, .val = '4'}, {.name = "ipv6", .has_arg = false, .val = '6'}, {NULL}, }; static int __do_output(struct nft_handle *h, const char *tablename, bool counters) { struct nftnl_chain_list *chain_list; if (!nft_table_find(h, tablename)) { printf("Table `%s' does not exist\n", tablename); return 1; } if (!nft_is_table_compatible(h, tablename)) { printf("# Table `%s' is incompatible, use 'nft' tool.\n", tablename); return 0; } chain_list = nft_chain_dump(h); time_t now = time(NULL); printf("# Generated by xtables-save v%s on %s", IPTABLES_VERSION, ctime(&now)); printf("*%s\n", tablename); /* Dump out chain names first, * thereby preventing dependency conflicts */ nft_chain_save(h, chain_list, tablename); nft_rule_save(h, tablename, counters ? 0 : FMT_NOCOUNTS); now = time(NULL); printf("COMMIT\n"); printf("# Completed on %s", ctime(&now)); return 0; } static int do_output(struct nft_handle *h, const char *tablename, bool counters) { int ret; if (!tablename) { ret = nft_for_each_table(h, __do_output, counters); nft_check_xt_legacy(h->family, true); return !!ret; } ret = __do_output(h, tablename, counters); nft_check_xt_legacy(h->family, true); return ret; } /* Format: * :Chain name POLICY packets bytes * rule */ static int xtables_save_main(int family, const char *progname, int argc, char *argv[]) { struct builtin_table *tables; const char *tablename = NULL; bool dump = false; struct nft_handle h = { .family = family, }; FILE *file = NULL; int ret, c; xtables_globals.program_name = progname; c = xtables_init_all(&xtables_globals, family); if (c < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", xtables_globals.program_name, xtables_globals.program_version); exit(1); } while ((c = getopt_long(argc, argv, "bcdt:M:f:46V", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); break; case 'c': show_counters = true; break; case 't': /* Select specific table. */ tablename = optarg; break; case 'M': xtables_modprobe_program = optarg; break; case 'f': file = fopen(optarg, "w"); if (file == NULL) { fprintf(stderr, "Failed to open file, error: %s\n", strerror(errno)); exit(1); } ret = dup2(fileno(file), STDOUT_FILENO); if (ret == -1) { fprintf(stderr, "Failed to redirect stdout, error: %s\n", strerror(errno)); exit(1); } fclose(file); break; case 'd': dump = true; break; case '4': h.family = AF_INET; break; case '6': h.family = AF_INET6; xtables_set_nfproto(AF_INET6); break; case 'V': printf("%s v%s (nf_tables)\n", prog_name, prog_vers); exit(0); default: fprintf(stderr, "Look at manual page `xtables-save.8' for more information.\n"); exit(1); } } if (optind < argc) { fprintf(stderr, "Unknown arguments found on commandline\n"); exit(1); } switch (family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthough, same table */ #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); #endif tables = xtables_ipv4; break; case NFPROTO_ARP: tables = xtables_arp; break; case NFPROTO_BRIDGE: tables = xtables_bridge; break; default: fprintf(stderr, "Unknown family %d\n", family); return 1; } if (nft_init(&h, tables) < 0) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, strerror(errno)); exit(EXIT_FAILURE); } if (dump) { do_output(&h, tablename, show_counters); exit(0); } return do_output(&h, tablename, show_counters); } int xtables_ip4_save_main(int argc, char *argv[]) { return xtables_save_main(NFPROTO_IPV4, "iptables-save", argc, argv); } int xtables_ip6_save_main(int argc, char *argv[]) { return xtables_save_main(NFPROTO_IPV6, "ip6tables-save", argc, argv); } static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters) { struct nftnl_chain_list *chain_list; static bool first = true; time_t now; if (!nft_table_find(h, tablename)) { printf("Table `%s' does not exist\n", tablename); return 1; } if (!nft_is_table_compatible(h, tablename)) { printf("# Table `%s' is incompatible, use 'nft' tool.\n", tablename); return 0; } chain_list = nft_chain_dump(h); if (first) { now = time(NULL); printf("# Generated by ebtables-save v%s on %s", IPTABLES_VERSION, ctime(&now)); first = false; } printf("*%s\n", tablename); /* Dump out chain names first, * thereby preventing dependency conflicts */ nft_chain_save(h, chain_list, tablename); nft_rule_save(h, tablename, FMT_EBT_SAVE | (counters ? 0 : FMT_NOCOUNTS)); printf("\n"); return 0; } int xtables_eb_save_main(int argc_, char *argv_[]) { const char *ctr = getenv("EBTABLES_SAVE_COUNTER"); struct nft_handle h = { .family = NFPROTO_BRIDGE, }; int c; if (ctr && strcmp(ctr, "yes")) ctr = NULL; xtables_globals.program_name = "ebtables-save"; c = xtables_init_all(&xtables_globals, h.family); if (c < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", xtables_globals.program_name, xtables_globals.program_version); exit(1); } if (nft_init(&h, xtables_bridge) < 0) { fprintf(stderr, "%s/%s Failed to initialize nft: %s\n", xtables_globals.program_name, xtables_globals.program_version, strerror(errno)); exit(EXIT_FAILURE); } nft_for_each_table(&h, __ebt_save, !!ctr); return 0; }