From 2f52379841217e55201fbc93872be9a21fa5d443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Kis-Szab=C3=B3?= Date: Tue, 27 Feb 2001 09:59:48 +0000 Subject: forgot to add those two... --- ip6tables-restore.c | 299 +++++++++++++++++++++++++++++++++++++++++++++ ip6tables-save.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 640 insertions(+) create mode 100644 ip6tables-restore.c create mode 100644 ip6tables-save.c diff --git a/ip6tables-restore.c b/ip6tables-restore.c new file mode 100644 index 00000000..9ebc5775 --- /dev/null +++ b/ip6tables-restore.c @@ -0,0 +1,299 @@ +/* Code to restore the iptables state, from file by ip6tables-save. + * Author: Andras Kis-Szabo + * + * based on iptables-restore + * Authors: + * Harald Welte + * Rusty Russell + * + */ + +#include +#include +#include +#include +#include +#include "ip6tables.h" +#include "libiptc/libip6tc.h" + +#ifdef DEBUG +#define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#else +#define DEBUGP(x, args...) +#endif + +extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), int verbose, int builtinstoo, ip6tc_handle_t *handle); +extern int flush_entries(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle); +extern int delete_chain(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle); + +static int binary = 0, counters = 0, verbose = 0, noflush = 0; + +/* Keeping track of external matches and targets. */ +static struct option options[] = { + { "binary", 0, 0, 'b' }, + { "counters", 0, 0, 'c' }, +/* { "verbose", 1, 0, 'v' }, */ + { "help", 0, 0, 'h' }, + { "noflush", 0, 0, 'n'}, + { 0 } +}; + +static void print_usage(const char *name, const char *version) __attribute__((noreturn)); + +static void print_usage(const char *name, const char *version) +{ + fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-h]\n" + " [ --binary ]\n" + " [ --counters ]\n" + " [ --verbose ]\n" + " [ --help ]\n" + " [ --noflush ]\n", name); + + exit(1); +} + +ip6tc_handle_t create_handle(const char *tablename) +{ + ip6tc_handle_t handle; + + handle = ip6tc_init(tablename); + if (!handle) { + exit_error(PARAMETER_PROBLEM, "%s: unable to initialize" + "table '%s'\n", program_name, tablename); + exit(1); + } + return handle; +} + +int parse_counters(char *string, struct ip6t_counters *ctr) +{ + return (sscanf(string, "[%llu:%llu]", &ctr->pcnt, &ctr->bcnt) == 2); +} + +int main(int argc, char *argv[]) +{ + ip6tc_handle_t handle; + char buffer[10240]; + unsigned int line = 0; + int c; + char curtable[IP6T_TABLE_MAXNAMELEN + 1]; + char curchain[IP6T_FUNCTION_MAXNAMELEN + 1]; + FILE *in; + + program_name = "ip6tables-restore"; + program_version = NETFILTER_VERSION; + + while ((c = getopt_long(argc, argv, "bcvhn", options, NULL)) != -1) { + switch (c) { + case 'b': + binary = 1; + break; + case 'c': + counters = 1; + break; + case 'h': + print_usage("ip6tables-restore", + NETFILTER_VERSION); + break; + case 'n': + noflush = 1; + break; + } + } + + if (optind == argc - 1) { + in = fopen(argv[optind], "r"); + if (!in) { + fprintf(stderr, "Can't open %s: %s", argv[optind], + strerror(errno)); + exit(1); + } + } + else if (optind < argc) { + fprintf(stderr, "Unknown arguments found on commandline"); + exit(1); + } + else in = stdin; +/* + handle = iptc_init("filter"); + if (!handle) + exit_error(VERSION_PROBLEM, + "can't initialize iptables-restore: %s", + iptc_strerror(errno)); + + if (!clean_slate(&handle)) + exit_error(OTHER_PROBLEM, "Deleting old chains: %s", + iptc_strerror(errno)); +*/ + /* Grab standard input. */ + while (fgets(buffer, sizeof(buffer), in)) { + int ret; + + line++; + if (buffer[0] == '\n') continue; + else if (buffer[0] == '#') { + if (verbose) fputs(buffer, stdout); + continue; + } else if (strcmp(buffer, "COMMIT\n") == 0) { + DEBUGP("Calling commit\n"); + ret = ip6tc_commit(&handle); + } else if (buffer[0] == '*') { + /* New table */ + char *table; + + table = strtok(buffer+1, " \t\n"); + DEBUGP("line %u, table '%s'\n", line, table); + if (!table) { + exit_error(PARAMETER_PROBLEM, + "%s: line %u table name invalid\n", + program_name, line); + exit(1); + } + strncpy(curtable, table, IP6T_TABLE_MAXNAMELEN); + + handle = create_handle(table); + if (noflush == 0) { + DEBUGP("Cleaning all chains of table '%s'\n", + table); + for_each_chain(flush_entries, verbose, 1, + &handle); + + DEBUGP("Deleting all user-defined chains " + "of table '%s'\n", table); + for_each_chain(delete_chain, verbose, 0, + &handle) ; + } + + ret = 1; + + } else if (buffer[0] == ':') { + /* New chain. */ + char *policy, *chain; + + chain = strtok(buffer+1, " \t\n"); + DEBUGP("line %u, chain '%s'\n", line, chain); + if (!chain) { + exit_error(PARAMETER_PROBLEM, + "%s: line %u chain name invalid\n", + program_name, line); + exit(1); + } + strncpy(curchain, chain, IP6T_FUNCTION_MAXNAMELEN); + + /* why the f... does iptc_builtin not work here ? */ + /* FIXME: abort if chain creation fails --RR */ +// if (!iptc_builtin(curchain, &handle)) { + DEBUGP("Creating new chain '%s'\n", curchain); + if (!ip6tc_create_chain(curchain, &handle)) + DEBUGP("unable to create chain '%s':%s\n", curchain, + strerror(errno)); +// } + + policy = strtok(NULL, " \t\n"); + DEBUGP("line %u, policy '%s'\n", line, policy); + if (!policy) { + exit_error(PARAMETER_PROBLEM, + "%s: line %u policy invalid\n", + program_name, line); + exit(1); + } + + if (strcmp(policy, "-") != 0) { + struct ip6t_counters count; + + if (counters) { + char *ctrs; + ctrs = strtok(NULL, " \t\n"); + + parse_counters(ctrs, &count); + + } else { + memset(&count, 0, + sizeof(struct ip6t_counters)); + } + + DEBUGP("Setting policy of chain %s to %s\n", + chain, policy); + + if (!ip6tc_set_policy(chain, policy, &count, + &handle)) + exit_error(OTHER_PROBLEM, + "Can't set policy `%s'" + " on `%s' line %u: %s\n", + chain, policy, line, + ip6tc_strerror(errno)); + } + + ret = 1; + + } else { + char *newargv[1024]; + int i,a, argvsize; + char *ptr = buffer; + char *pcnt = NULL; + char *bcnt = NULL; + + if (buffer[0] == '[') { + ptr = strchr(buffer, ']'); + if (!ptr) + exit_error(PARAMETER_PROBLEM, + "Bad line %u: need ]\n", + line); + pcnt = strtok(buffer+1, ":"); + bcnt = strtok(NULL, "]"); + } + + newargv[0] = argv[0]; + newargv[1] = "-t"; + newargv[2] = (char *) &curtable; + newargv[3] = "-A"; + newargv[4] = (char *) &curchain; + argvsize = 5; + + if (counters && pcnt && bcnt) { + newargv[5] = "--set-counters"; + newargv[6] = (char *) pcnt; + newargv[7] = (char *) bcnt; + argvsize = 8; + } + + // strtok initcialize! + if ( buffer[0]!='[' ) + { + if (!(newargv[argvsize] = strtok(buffer, " \t\n"))) + goto ImLaMeR; + //break; + argvsize++; + } + + /* strtok: a function only a coder could love */ + for (i = argvsize; i < sizeof(newargv)/sizeof(char *); + i++) { + if (!(newargv[i] = strtok(NULL, " \t\n"))) + break; + ptr = NULL; + } +ImLaMeR: if (i == sizeof(newargv)/sizeof(char *)) { + fprintf(stderr, + "%s: line %u too many arguments\n", + program_name, line); + exit(1); + } + + DEBUGP("===>calling do_command6(%u, argv, &%s, handle):\n", + i, curtable); + + for (a = 0; a <= i; a++) + DEBUGP("argv[%u]: %s\n", a, newargv[a]); + + ret = do_command6(i, newargv, &newargv[2], &handle); + } + if (!ret) { + fprintf(stderr, "%s: line %u failed\n", + program_name, line); + exit(1); + } + } + + return 0; +} diff --git a/ip6tables-save.c b/ip6tables-save.c new file mode 100644 index 00000000..8957e137 --- /dev/null +++ b/ip6tables-save.c @@ -0,0 +1,341 @@ +/* Code to save the ip6tables state, in human readable-form. */ +/* Author: Andras Kis-Szabo + * Original code: iptables-save + * Authors: Paul 'Rusty' Russel and + * Harald Welte + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libiptc/libip6tc.h" +#include "ip6tables.h" + +#ifndef IP6T_LIB_DIR +#define IP6T_LIB_DIR "/usr/local/lib/iptables" +#endif + +static int binary = 0, counters = 0; + +static struct option options[] = { + { "binary", 0, 0, 'b' }, + { "counters", 0, 0, 'c' }, + { "dump", 0, 0, 'd' }, + { "table", 1, 0, 't' }, + { 0 } +}; + +extern struct ip6tables_match *find_match(const char *name, enum ip6t_tryload tryload); +extern struct ip6tables_target *find_target(const char *name, enum ip6t_tryload tryload); + +/* This assumes that mask is contiguous, and byte-bounded. */ +static void +print_iface(char letter, const char *iface, const unsigned char *mask, + int invert) +{ + unsigned int i; + + if (mask[0] == 0) + return; + + printf("-%c %s", letter, invert ? "! " : ""); + + for (i = 0; i < IFNAMSIZ; i++) { + if (mask[i] != 0) { + if (iface[i] != '\0') + printf("%c", iface[i]); + } else { + if (iface[i] != '\0') + printf("+"); + break; + } + } + + printf(" "); +} + +/* These are hardcoded backups in ip6tables.c, so they are safe */ +struct pprot { + char *name; + u_int8_t num; +}; + +static const struct pprot chain_protos[] = { + { "tcp", IPPROTO_TCP }, + { "udp", IPPROTO_UDP }, + { "icmp", IPPROTO_ICMP }, + { "esp", IPPROTO_ESP }, + { "ah", IPPROTO_AH }, +}; + +/* The ip6tables looks up the /etc/protocols. */ +static void print_proto(u_int16_t proto, int invert) +{ + if (proto) { + unsigned int i; + const char *invertstr = invert ? "! " : ""; + + struct protoent *pent = getprotobynumber(proto); + if (pent) { + printf("-p %s%s ", + invertstr, pent->p_name); + return; + } + + for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++) + if (chain_protos[i].num == proto) { + printf("-p %s%s ", + invertstr, chain_protos[i].name); + return; + } + + printf("-p %s%u ", invertstr, proto); + } +} + +static int print_match(const struct ip6t_entry_match *e, + const struct ip6t_ip6 *ip) +{ + struct ip6tables_match *match + = find_match(e->u.user.name, TRY_LOAD); + + if (match) { + printf("-m %s ", e->u.user.name); + + /* some matches don't provide a save function */ + if (match->save) + match->save(ip, e); + } else { + if (e->u.match_size) { + fprintf(stderr, + "Can't find library for match `%s'\n", + e->u.user.name); + exit(1); + } + } + return 0; +} + +/* print a given ip including mask if neccessary */ +static void print_ip(char *prefix, const struct in6_addr *ip, const struct in6_addr *mask, int invert) +{ + char buf[51]; + int l = ipv6_prefix_length(mask); + + if (!mask && !ip) + return; + + printf("%s %s%s/", + prefix, + invert ? "! " : "", + inet_ntop(AF_INET6, ip, buf, sizeof buf)); + + if (l == -1) + printf("%s ", inet_ntop(AF_INET6, mask, buf, sizeof buf)); + else + printf("%d ", l); + +#if 0 + if (mask != 0xffffffff) + printf("/%u.%u.%u.%u ", IP_PARTS(mask)); + else + printf(" "); +#endif +} + +/* We want this to be readable, so only print out neccessary fields. + * Because that's the kind of world I want to live in. */ +static void print_rule(const struct ip6t_entry *e, + ip6tc_handle_t *h, int counters) +{ + struct ip6t_entry_target *t; + + /* print counters */ + if (counters) + printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt); + + /* Print IP part. */ + print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk), + e->ipv6.invflags & IP6T_INV_SRCIP); + + print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), + e->ipv6.invflags & IP6T_INV_DSTIP); + + print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, + e->ipv6.invflags & IP6T_INV_VIA_IN); + + print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, + e->ipv6.invflags & IP6T_INV_VIA_OUT); + + print_proto(e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO); + +#if 0 + // not definied in ipv6 + // FIXME: linux/netfilter_ipv6/ip6_tables: IP6T_INV_FRAG why definied? + if (e->ipv6.flags & IPT_F_FRAG) + printf("%s-f ", + e->ipv6.invflags & IP6T_INV_FRAG ? "! " : ""); +#endif + + // TODO: i've got some problem with the code - under understanding ;) + // How can I set this? + if (e->ipv6.flags & IP6T_F_TOS) + printf("%s-? %d ", + e->ipv6.invflags & IP6T_INV_TOS ? "! " : "", + e->ipv6.tos); + + /* Print matchinfo part */ + if (e->target_offset) { + IP6T_MATCH_ITERATE(e, print_match, &e->ipv6); + } + + /* Print target name */ + printf("-j %s ", ip6tc_get_target(e, h)); + + /* Print targinfo part */ + t = ip6t_get_target((struct ip6t_entry *)e); + if (t->u.user.name[0]) { + struct ip6tables_target *target + = find_target(t->u.user.name, TRY_LOAD); + + if (target) + target->save(&e->ipv6, t); + else { + /* If some bits are non-zero, it implies we *need* + to understand it */ + if (t->u.target_size) { + fprintf(stderr, + "Can't find library for target `%s'\n", + t->u.user.name); + exit(1); + } + } + } + printf("\n"); +} + +/* Debugging prototype. */ +static int for_each_table(int (*func)(const char *tablename)) +{ + int ret = 1; + FILE *procfile = NULL; + char tablename[IP6T_TABLE_MAXNAMELEN+1]; + + procfile = fopen("/proc/net/ip6_tables_names", "r"); + if (!procfile) + return 0; + + while (fgets(tablename, sizeof(tablename), procfile)) { + if (tablename[strlen(tablename) - 1] != '\n') + exit_error(OTHER_PROBLEM, + "Badly formed tablename `%s'\n", + tablename); + tablename[strlen(tablename) - 1] = '\0'; + ret &= func(tablename); + } + + return ret; +} + + +static int do_output(const char *tablename) +{ + ip6tc_handle_t h; + const char *chain = NULL; + + if (!tablename) + return for_each_table(&do_output); + + h = ip6tc_init(tablename); + if (!h) + exit_error(OTHER_PROBLEM, "Can't initialize: %s\n", + ip6tc_strerror(errno)); + + if (!binary) { + time_t now = time(NULL); + + printf("# Generated by ip6tables-save v%s on %s", + NETFILTER_VERSION, ctime(&now)); + printf("*%s\n", tablename); + + /* Dump out chain names */ + for (chain = ip6tc_first_chain(&h); + chain; + chain = ip6tc_next_chain(&h)) { + const struct ip6t_entry *e; + + printf(":%s ", chain); + if (ip6tc_builtin(chain, h)) { + struct ip6t_counters count; + printf("%s ", + ip6tc_get_policy(chain, &count, &h)); + printf("[%llu:%llu]\n", count.pcnt, count.bcnt); + } else { + printf("- [0:0]\n"); + } + + /* Dump out rules */ + e = ip6tc_first_rule(chain, &h); + while(e) { + print_rule(e, &h, counters); + e = ip6tc_next_rule(e, &h); + } + } + + now = time(NULL); + printf("COMMIT\n"); + printf("# Completed on %s", ctime(&now)); + } else { + /* Binary, huh? OK. */ + exit_error(OTHER_PROBLEM, "Binary NYI\n"); + } + + return 1; +} + +/* Format: + * :Chain name POLICY packets bytes + * rule + */ +int main(int argc, char *argv[]) +{ + const char *tablename = NULL; + int c; + + program_name = "ip6tables-save"; + program_version = NETFILTER_VERSION; + + while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) { + switch (c) { + case 'b': + binary = 1; + break; + + case 'c': + counters = 1; + break; + + case 't': + /* Select specific table. */ + tablename = optarg; + break; + + case 'd': + do_output(tablename); + exit(0); + } + } + + if (optind < argc) { + fprintf(stderr, "Unknown arguments found on commandline"); + exit(1); + } + + return !do_output(tablename); +} -- cgit v1.2.3