diff -ruN iptables.ori/include/libiptc/libip6tc.h iptables.new_without_fluff/include/libiptc/libip6tc.h --- iptables.ori/include/libiptc/libip6tc.h 2003-05-05 21:33:40.000000000 +0200 +++ iptables.new_without_fluff/include/libiptc/libip6tc.h 2004-08-28 03:28:39.000000000 +0200 @@ -29,6 +29,9 @@ /* Cleanup after ip6tc_init(). */ void ip6tc_free(ip6tc_handle_t *h); +/* Enable not to commit anything to the kernel. */ +void ip6tc_set_nocommit(ip6tc_handle_t *h); + /* Iterator functions to run through the chains. Returns NULL at end. */ const char *ip6tc_first_chain(ip6tc_handle_t *handle); const char *ip6tc_next_chain(ip6tc_handle_t *handle); diff -ruN iptables.ori/include/libiptc/libiptc.h iptables.new_without_fluff/include/libiptc/libiptc.h --- iptables.ori/include/libiptc/libiptc.h 2003-05-02 17:30:11.000000000 +0200 +++ iptables.new_without_fluff/include/libiptc/libiptc.h 2004-08-28 03:28:39.000000000 +0200 @@ -37,6 +37,9 @@ /* Cleanup after iptc_init(). */ void iptc_free(iptc_handle_t *h); +/* Enable not to commit anything to the kernel. */ +void iptc_set_nocommit(iptc_handle_t *h); + /* Iterator functions to run through the chains. Returns NULL at end. */ const char *iptc_first_chain(iptc_handle_t *handle); const char *iptc_next_chain(iptc_handle_t *handle); diff -ruN iptables.ori/ip6tables-restore.8 iptables.new_without_fluff/ip6tables-restore.8 --- iptables.ori/ip6tables-restore.8 2002-06-14 09:39:58.000000000 +0200 +++ iptables.new_without_fluff/ip6tables-restore.8 2004-08-28 03:28:39.000000000 +0200 @@ -21,7 +21,7 @@ .SH NAME ip6tables-restore \- Restore IPv6 Tables .SH SYNOPSIS -.BR "ip6tables-restore " "[-c] [-n]" +.BR "ip6tables-restore " "[-c] [-n] [-t table] [-M cmd] [-v] [-S] [-h]" .br .SH DESCRIPTION .PP @@ -30,15 +30,37 @@ I/O redirection provided by your shell to read from a file .TP \fB\-c\fR, \fB\-\-counters\fR -restore the values of all packet and byte counters -.TP -\fB\-n\fR, \fB\-\-noflush\fR +restore the values of all packet and byte counters. .TP +\fB\-n\fR, \fB\-\-noflush\fR don't flush the previous contents of the table. If not specified, .B ip6tables-restore -flushes (deletes) all previous contents of the respective IPv6 Table. +flush (delete) all previous contents of the respective IPv6 Table. +.TP +\fB\-t\fR, \fB\-\-table\fR \fBtablename\fR +restrict restoration to only one table, even if multiple tables are +present in the input file. When this option is specified, other tables +in the input file are not parsed, thus not validated. +.TP +\fB\-M\fR \fBcommand\fR, \fB\-\-modprobe\fR \fBcommand\fR +if iptables needs to load kernel modules, load them with this command. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +verbose output. +.TP +\fB\-S\fR, \fB\-\-simulate\fR +simulate the restoration, do not commit ruleset changes to the kernel. +Yet, this is not a pure virtual simulation, as it may have the side +effect of loading iptable_* kernel modules and their possible +dependencies. +.\" (add later, as nat table is not implemented yet) @@ +.\" , notably ip_conntrack, which can lead to performance issues +.\" after the simulation. +.TP +\fB\-h\fR, \fB\-\-help\fR +display help message. .SH BUGS -None known as of iptables-1.2.1 release +None known as of iptables-1.2.10 release .SH AUTHORS Harald Welte .br diff -ruN iptables.ori/ip6tables-restore.c iptables.new_without_fluff/ip6tables-restore.c --- iptables.ori/ip6tables-restore.c 2004-05-26 18:04:48.000000000 +0200 +++ iptables.new_without_fluff/ip6tables-restore.c 2004-08-28 03:28:39.000000000 +0200 @@ -1,4 +1,4 @@ -/* Code to restore the iptables state, from file by ip6tables-save. +/* Code to restore the ip6tables state, from file by ip6tables-save. * Author: Andras Kis-Szabo * * based on iptables-restore @@ -24,53 +24,52 @@ #define DEBUGP(x, args...) #endif -static int binary = 0, counters = 0, verbose = 0, noflush = 0; +static int 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", 0, 0, 'v' }, - { "test", 0, 0, 't' }, + { "table", 1, 0, 't' }, { "help", 0, 0, 'h' }, - { "noflush", 0, 0, 'n'}, - { "modprobe", 1, 0, 'M'}, + { "noflush", 0, 0, 'n' }, + { "modprobe", 1, 0, 'M' }, + { "simulate", 0, 0, 'S' }, { 0 } }; -static void print_usage(const char *name, const char *version) __attribute__((noreturn)); - -static void print_usage(const char *name, const char *version) +static void +print_usage(const char *name, const char *version) { - fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n" - " [ --binary ]\n" + fprintf(stderr, "%s v%s\n\n" + "Usage: %s [-c] [-n] [-t table] [-M cmd] [-S] [-v] [-h]\n" " [ --counters ]\n" - " [ --verbose ]\n" - " [ --test ]\n" - " [ --help ]\n" " [ --noflush ]\n" - " [ --modprobe=]\n", name); - - exit(1); + " [ --table name ]\n" + " [ --modprobe= ]\n" + " [ --simulate ]\n" + " [ --verbose ]\n" + " [ --help ]\n", + name, version, name); } -ip6tc_handle_t create_handle(const char *tablename, const char* modprobe) +ip6tc_handle_t create_handle(const char *tablename, const char* modprobe, int simulate) { ip6tc_handle_t handle; handle = ip6tc_init(tablename); if (!handle) { - /* try to insmod the module if iptc_init failed */ + /* try to insmod the module if ip6tc_init failed */ ip6tables_insmod("ip6_tables", modprobe); handle = ip6tc_init(tablename); } - if (!handle) { + if (!handle) exit_error(PARAMETER_PROBLEM, "%s: unable to initialize" "table '%s'\n", program_name, tablename); - exit(1); - } + if (simulate) + ip6tc_set_nocommit(&handle); return handle; } @@ -109,8 +108,9 @@ int c; char curtable[IP6T_TABLE_MAXNAMELEN + 1]; FILE *in; - const char *modprobe = 0; - int in_table = 0, testing = 0; + const char *modprobe = NULL; + int in_table = 0, simulate = 0; + const char *tablename = NULL; program_name = "ip6tables-restore"; program_version = IPTABLES_VERSION; @@ -120,23 +120,16 @@ init_extensions(); #endif - while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "cvt:nM:Sh", options, NULL)) != -1) { switch (c) { - case 'b': - binary = 1; - break; case 'c': counters = 1; break; case 'v': verbose = 1; break; - case 't': - testing = 1; - break; - case 'h': - print_usage("ip6tables-restore", - IPTABLES_VERSION); + case 't': /* Select specific table. */ + tablename = optarg; break; case 'n': noflush = 1; @@ -144,62 +137,66 @@ case 'M': modprobe = optarg; break; + case 'S': + simulate = 1; + break; + case 'h': + print_usage(program_name, IPTABLES_VERSION); + exit(0); + case '?': + exit_tryhelp(PARAMETER_PROBLEM); } } if (optind == argc - 1) { in = fopen(argv[optind], "r"); if (!in) { - fprintf(stderr, "Can't open %s: %s", argv[optind], + fprintf(stderr, "Can't open %s: %s\n", argv[optind], strerror(errno)); exit(1); } } else if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline"); + fprintf(stderr, "%s: unknown arguments found on commandline\n", + program_name); exit(1); } else in = stdin; /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { - int ret = 0; + int ret = 0; /* error by default */ line++; if (buffer[0] == '\n') continue; - else if (buffer[0] == '#') { + else if (buffer[0] == '#') { /* comment */ if (verbose) fputs(buffer, stdout); continue; - } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { - if (!testing) { - DEBUGP("Calling commit\n"); - ret = ip6tc_commit(&handle); - } else { - DEBUGP("Not calling commit, testing\n"); - ret = 1; - } + } else if (in_table && !strcmp(buffer, "COMMIT\n")) { + DEBUGP("Calling commit\n"); + ret = ip6tc_commit(&handle); in_table = 0; - } else if ((buffer[0] == '*') && (!in_table)) { - /* New table */ - char *table; - - table = strtok(buffer+1, " \t\n"); + } else if (!in_table && buffer[0] == '*') { /* new table */ + char *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); - } + if (!table) + exit_error(PARAMETER_PROBLEM, + "%s: line %u table name invalid\n", + program_name, line); + + if (tablename != NULL && strcmp(tablename, table)) + continue; /* not the selected table */ + strncpy(curtable, table, IP6T_TABLE_MAXNAMELEN); curtable[IP6T_TABLE_MAXNAMELEN] = '\0'; if (handle) ip6tc_free(&handle); - handle = create_handle(table, modprobe); + handle = create_handle(table, modprobe, simulate); + if (noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); @@ -212,21 +209,17 @@ &handle) ; } - ret = 1; in_table = 1; - - } else if ((buffer[0] == ':') && (in_table)) { - /* New chain. */ + continue; /* ok */ + } else if (in_table && buffer[0] == ':') { /* new chain */ char *policy, *chain; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); - if (!chain) { + if (!chain) exit_error(PARAMETER_PROBLEM, "%s: line %u chain name invalid\n", program_name, line); - exit(1); - } if (!ip6tc_builtin(chain, handle)) { DEBUGP("Creating new chain '%s'\n", chain); @@ -234,31 +227,32 @@ exit_error(PARAMETER_PROBLEM, "error creating chain " "'%s':%s\n", chain, - strerror(errno)); + ip6tc_strerror(errno)); } policy = strtok(NULL, " \t\n"); DEBUGP("line %u, policy '%s'\n", line, policy); - if (!policy) { + if (!policy) exit_error(PARAMETER_PROBLEM, "%s: line %u policy invalid\n", program_name, line); - exit(1); - } - if (strcmp(policy, "-") != 0) { + if (strcmp(policy, "-") != 0) { /* builtin chain? */ struct ip6t_counters count; if (counters) { - char *ctrs; - ctrs = strtok(NULL, " \t\n"); - - parse_counters(ctrs, &count); - - } else { - memset(&count, 0, + char *ctrs = strtok(NULL, " \t\n"); + if (ctrs != NULL) + parse_counters(ctrs, &count); + else { + fprintf(stderr, "%s: Warning: no counter could be found at line %u. Assuming [0:0].\n", + program_name, line); + memset(&count, 0, + sizeof(struct ip6t_counters)); + } + } else + memset(&count, 0, sizeof(struct ip6t_counters)); - } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); @@ -271,9 +265,7 @@ chain, policy, line, ip6tc_strerror(errno)); } - - ret = 1; - + continue; /* ok */ } else if (in_table) { int a; char *ptr = buffer; @@ -368,12 +360,10 @@ /* check if table name specified */ if (!strncmp(param_buffer, "-t", 3) - || !strncmp(param_buffer, "--table", 8)) { - exit_error(PARAMETER_PROBLEM, + || !strncmp(param_buffer, "--table", 8)) + exit_error(PARAMETER_PROBLEM, "Line %u seems to have a " "-t table option.\n", line); - exit(1); - } add_argv(param_buffer); param_start += param_len + 1; @@ -392,10 +382,12 @@ &newargv[2], &handle); free_argv(); - } + } else if (tablename != NULL) + continue; + if (!ret) { - fprintf(stderr, "%s: line %u failed\n", - program_name, line); + fprintf(stderr, "%s: line %u failed: %s\n", + program_name, line, ip6tc_strerror(errno)); exit(1); } } diff -ruN iptables.ori/ip6tables-save.8 iptables.new_without_fluff/ip6tables-save.8 --- iptables.ori/ip6tables-save.8 2002-06-14 09:39:58.000000000 +0200 +++ iptables.new_without_fluff/ip6tables-save.8 2004-08-28 03:28:39.000000000 +0200 @@ -21,7 +21,7 @@ .SH NAME ip6tables-save \- Save IPv6 Tables .SH SYNOPSIS -.BR "ip6tables-save " "[-c] [-t table]" +.BR "ip6tables-save " "[-c] [-t table] [-C] [-h]" .br .SH DESCRIPTION .PP @@ -33,9 +33,14 @@ include the current values of all packet and byte counters in the output .TP \fB\-t\fR, \fB\-\-table\fR \fBtablename\fR -.TP restrict output to only one table. If not specified, output includes all available tables. +.TP +\fB\-C\fR, \fB\-\-no-comments\fR +do not output any comment. Useful for comparing two dump files. +.TP +\fB\-h\fR, \fB\-\-help\fR +display help message. .SH BUGS None known as of iptables-1.2.1 release .SH AUTHORS diff -ruN iptables.ori/ip6tables-save.c iptables.new_without_fluff/ip6tables-save.c --- iptables.ori/ip6tables-save.c 2004-05-26 18:04:48.000000000 +0200 +++ iptables.new_without_fluff/ip6tables-save.c 2004-08-28 03:28:39.000000000 +0200 @@ -18,16 +18,27 @@ #include "libiptc/libip6tc.h" #include "ip6tables.h" -static int binary = 0, counters = 0; +static int counters = 0, no_comments = 0; static struct option options[] = { - { "binary", 0, 0, 'b' }, { "counters", 0, 0, 'c' }, - { "dump", 0, 0, 'd' }, { "table", 1, 0, 't' }, + { "no-comments", 0, 0, 'C' }, + { "help", 0, 0, 'h' }, { 0 } }; +static void +print_usage(const char *name, const char *version) +{ + fprintf(stderr, "%s v%s\n\n" + "Usage: %s [-c] [-t table] [-C] [-h]\n" + " [ --counters ]\n" + " [ --table name ]\n" + " [ --no-comments ]\n" + " [ --help ]\n", + name, version, name); +} /* This assumes that mask is contiguous, and byte-bounded. */ static void @@ -250,6 +261,7 @@ { ip6tc_handle_t h; const char *chain = NULL; + time_t now; if (!tablename) return for_each_table(&do_output); @@ -259,50 +271,48 @@ exit_error(OTHER_PROBLEM, "Can't initialize: %s\n", ip6tc_strerror(errno)); - if (!binary) { - time_t now = time(NULL); - + if (!no_comments) { + now = time(NULL); printf("# Generated by ip6tables-save v%s on %s", IPTABLES_VERSION, ctime(&now)); - printf("*%s\n", tablename); - - /* Dump out chain names first, - * thereby preventing dependency conflicts */ - for (chain = ip6tc_first_chain(&h); - chain; - chain = ip6tc_next_chain(&h)) { - - printf(":%s ", chain); - if (ip6tc_builtin(chain, h)) { - struct ip6t_counters count; - printf("%s ", - ip6tc_get_policy(chain, &count, &h)); - printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); - } else { - printf("- [0:0]\n"); - } - } + } + printf("*%s\n", tablename); + /* Dump out chain names first, + * thereby preventing dependency conflicts */ + for (chain = ip6tc_first_chain(&h); + chain; + chain = ip6tc_next_chain(&h)) { + printf(":%s ", chain); + if (ip6tc_builtin(chain, h)) { + struct ip6t_counters count; + printf("%s", ip6tc_get_policy(chain, &count, &h)); + if (counters) + printf(" [%llu:%llu]", + (unsigned long long)count.pcnt, + (unsigned long long)count.bcnt); + } else + putchar('-'); + putchar('\n'); + } - for (chain = ip6tc_first_chain(&h); - chain; - chain = ip6tc_next_chain(&h)) { - const struct ip6t_entry *e; - - /* Dump out rules */ - e = ip6tc_first_rule(chain, &h); - while(e) { - print_rule(e, &h, chain, counters); - e = ip6tc_next_rule(e, &h); - } + for (chain = ip6tc_first_chain(&h); + chain; + chain = ip6tc_next_chain(&h)) { + const struct ip6t_entry *e; + + /* Dump out rules */ + e = ip6tc_first_rule(chain, &h); + while (e) { + print_rule(e, &h, chain, counters); + e = ip6tc_next_rule(e, &h); } + } + puts("COMMIT"); + if (!no_comments) { now = time(NULL); - printf("COMMIT\n"); printf("# Completed on %s", ctime(&now)); - } else { - /* Binary, huh? OK. */ - exit_error(OTHER_PROBLEM, "Binary NYI\n"); } ip6tc_free(&h); @@ -326,28 +336,29 @@ init_extensions(); #endif - while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "ct:Ch", 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); + case 'C': + no_comments = 1; + break; + case 'h': + print_usage(program_name, IPTABLES_VERSION); exit(0); + case '?': + exit_tryhelp(PARAMETER_PROBLEM); } } if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline"); + fprintf(stderr, "%s: unknown arguments found on commandline\n", + program_name); exit(1); } diff -ruN iptables.ori/ip6tables.8.in iptables.new_without_fluff/ip6tables.8.in --- iptables.ori/ip6tables.8.in 2004-07-08 19:15:08.000000000 +0200 +++ iptables.new_without_fluff/ip6tables.8.in 2004-08-28 03:28:39.000000000 +0200 @@ -145,7 +145,7 @@ versions of this command: the rule can be specified as a number in the chain (starting at 1 for the first rule) or a rule to match. .TP -.B "-I, --insert" +.BR "-I, --insert " "\fIchain\fP [\fIrulenum\fP] \fIrule-specification\fP" Insert one or more rules in the selected chain as the given rule number. So, if the rule number is 1, the rule or rules are inserted at the head of the chain. This is also the default if no rule number @@ -272,8 +272,8 @@ incremented. .TP .BR "-i, --in-interface " "[!] \fIname\fP" -Name of an interface via which a packet is going to be received (only for -packets entering the +Name of an interface via which a packet was received (only for +packets entering the .BR INPUT , .B FORWARD and @@ -348,6 +348,15 @@ When adding or inserting rules into a chain, use .B command to load any necessary modules (targets, match extensions, etc). +.TP +.B "-S, --simulate" +simulate the restoration, do not commit ruleset changes to the kernel. +Yet, this is not a pure virtual simulation, as it may have the side +effect of loading iptable_* kernel modules and their possible +dependencies. +.\" (add later, as nat table is not implemented yet) @@ +.\" , notably ip_conntrack, which can lead to performance issues +.\" after the simulation. .SH MATCH EXTENSIONS ip6tables can use extended packet matching modules. These are loaded in two ways: implicitly, when diff -ruN iptables.ori/ip6tables.c iptables.new_without_fluff/ip6tables.c --- iptables.ori/ip6tables.c 2004-07-08 14:54:38.000000000 +0200 +++ iptables.new_without_fluff/ip6tables.c 2004-08-28 03:28:39.000000000 +0200 @@ -139,14 +139,15 @@ { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, { "set-counters", 1, 0, 'c' }, + { "simulate", 0, 0, 'S' }, { 0 } }; /* we need this for ip6tables-restore. ip6tables-restore.c sets line to the * current line of the input file, in order to give a more precise error * message. ip6tables itself doesn't need this, so it is initialized to the - * magic number of -1 */ -int line = -1; + * magic number of 0 */ +int line = 0; #ifndef __OPTIMIZE__ struct ip6t_entry_target * @@ -284,7 +285,7 @@ void exit_tryhelp(int status) { - if (line != -1) + if (line != 0) fprintf(stderr, "Error occurred at line: %d\n", line); fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", program_name, program_name ); @@ -298,17 +299,19 @@ struct ip6tables_target *t = NULL; printf("%s v%s\n\n" -"Usage: %s -[AD] chain rule-specification [options]\n" -" %s -[RI] chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LFZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" +"Usage: %s [-t table] -[AD] chain rule-specification [options]\n" +" %s [-t table] -I chain [rulenum] rule-specification [options]\n" +" %s [-t table] -R chain rulenum rule-specification [options]\n" +" %s [-t table] -D chain rulenum [options]\n" +" %s [-t table] -[LFZ] [chain] [options]\n" +" %s [-t table] -N chain\n" +" %s [-t table] -X [chain]\n" +" %s [-t table] -P chain target [options]\n" +" %s [-t table] -E old-chain-name new-chain-name\n" " %s -h (print this help information)\n\n", program_name, program_version, program_name, program_name, program_name, program_name, program_name, program_name, - program_name, program_name); + program_name, program_name, program_name, program_name); printf( "Commands:\n" @@ -349,17 +352,19 @@ " --out-interface -o [!] output name[+]\n" " network interface name ([+] for wildcard)\n" " --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" /*"[!] --fragment -f match second or further fragments only\n"*/ -" --modprobe= try to insert modules using this command\n" " --set-counters PKTS BYTES set the counter during insert/append\n" + +" --verbose -v verbose mode\n" +" --simulate -S simulate the restoration (no kernel commit)\n" +" --modprobe= try to insert modules using this command\n" "[!] --version -V print package version.\n"); - /* Print out any special helps. A user might like to be able to add a --help - to the commandline, and see expected results. So we call help for all - specified matches & targets */ + /* Print out any special helps. A user might like to be able + to add a --help to the commandline, and see expected + results. So we call help for all specified matches & targets */ for (t = ip6tables_targets; t; t = t->next) { if (t->used) { printf("\n"); @@ -1700,7 +1705,7 @@ unsigned int nsaddrs = 0, ndaddrs = 0; struct in6_addr *saddrs = NULL, *daddrs = NULL; - int c, verbose = 0; + int c, verbose = 0, simulate = 0; const char *chain = NULL; const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; @@ -1739,7 +1744,7 @@ opterr = 0; while ((c = getopt_long(argc, argv, - "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:", + "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:vnt:m:xc:S", opts, NULL)) != -1) { switch (c) { /* @@ -2039,6 +2044,9 @@ break; + case 'S': + simulate = 1; + break; case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { @@ -2197,6 +2205,9 @@ "can't initialize ip6tables table `%s': %s", *table, ip6tc_strerror(errno)); + if (simulate) + ip6tc_set_nocommit(handle); + if (command == CMD_APPEND || command == CMD_DELETE || command == CMD_INSERT diff -ruN iptables.ori/iptables-restore.8 iptables.new_without_fluff/iptables-restore.8 --- iptables.ori/iptables-restore.8 2002-06-14 09:39:58.000000000 +0200 +++ iptables.new_without_fluff/iptables-restore.8 2004-08-28 03:28:39.000000000 +0200 @@ -21,7 +21,7 @@ .SH NAME iptables-restore \- Restore IP Tables .SH SYNOPSIS -.BR "iptables-restore " "[-c] [-n]" +.BR "iptables-restore " "[-c] [-n] [-t table] [-M cmd] [-v] [-S] [-h]" .br .SH DESCRIPTION .PP @@ -30,15 +30,35 @@ I/O redirection provided by your shell to read from a file .TP \fB\-c\fR, \fB\-\-counters\fR -restore the values of all packet and byte counters -.TP -\fB\-n\fR, \fB\-\-noflush\fR +restore the values of all packet and byte counters. .TP +\fB\-n\fR, \fB\-\-noflush\fR don't flush the previous contents of the table. If not specified, .B iptables-restore -flushes (deletes) all previous contents of the respective IP Table. +flush (delete) all previous contents of the respective IP Table. +.TP +\fB\-t\fR, \fB\-\-table\fR \fBtablename\fR +restrict restoration to only one table, even if multiple tables are +present in the input file. When this option is specified, other tables +in the input file are not parsed, thus not validated. +.TP +\fB\-M\fR \fBcommand\fR, \fB\-\-modprobe\fR \fBcommand\fR +if iptables needs to load kernel modules, load them with this command. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +verbose output. +.TP +\fB\-S\fR, \fB\-\-simulate\fR +simulate the restoration, do not commit ruleset changes to the kernel. +Yet, this is not a pure virtual simulation, as it may have the side +effect of loading iptable_* kernel modules and their possible +dependencies, notably ip_conntrack, which can lead to performance +issues after the simulation. +.TP +\fB\-h\fR, \fB\-\-help\fR +display help message. .SH BUGS -None known as of iptables-1.2.1 release +None known as of iptables-1.2.10 release .SH AUTHOR Harald Welte .SH SEE ALSO diff -ruN iptables.ori/iptables-restore.c iptables.new_without_fluff/iptables-restore.c --- iptables.ori/iptables-restore.c 2004-06-25 13:18:57.000000000 +0200 +++ iptables.new_without_fluff/iptables-restore.c 2004-08-28 03:51:35.000000000 +0200 @@ -21,37 +21,36 @@ #define DEBUGP(x, args...) #endif -static int binary = 0, counters = 0, verbose = 0, noflush = 0; +static int 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", 0, 0, 'v' }, - { "test", 0, 0, 't' }, + { "table", 1, 0, 't' }, { "help", 0, 0, 'h' }, - { "noflush", 0, 0, 'n'}, - { "modprobe", 1, 0, 'M'}, + { "noflush", 0, 0, 'n' }, + { "modprobe", 1, 0, 'M' }, + { "simulate", 0, 0, 'S' }, { 0 } }; -static void print_usage(const char *name, const char *version) __attribute__((noreturn)); - -static void print_usage(const char *name, const char *version) +static void +print_usage(const char *name, const char *version) { - fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n" - " [ --binary ]\n" + fprintf(stderr, "%s v%s\n\n" + "Usage: %s [-c] [-n] [-t table] [-M cmd] [-S] [-v] [-h]\n" " [ --counters ]\n" - " [ --verbose ]\n" - " [ --test ]\n" - " [ --help ]\n" " [ --noflush ]\n" - " [ --modprobe=]\n", name); - - exit(1); + " [ --table name ]\n" + " [ --modprobe= ]\n" + " [ --simulate ]\n" + " [ --verbose ]\n" + " [ --help ]\n", + name, version, name); } -iptc_handle_t create_handle(const char *tablename, const char* modprobe ) +iptc_handle_t create_handle(const char *tablename, const char* modprobe, int simulate) { iptc_handle_t handle; @@ -63,11 +62,11 @@ handle = iptc_init(tablename); } - if (!handle) { + if (!handle) exit_error(PARAMETER_PROBLEM, "%s: unable to initialize" - "table '%s'\n", program_name, tablename); - exit(1); - } + "table '%s'\n", program_name, tablename); + if (simulate) + iptc_set_nocommit(&handle); return handle; } @@ -112,8 +111,9 @@ int c; char curtable[IPT_TABLE_MAXNAMELEN + 1]; FILE *in; - const char *modprobe = 0; - int in_table = 0, testing = 0; + const char *modprobe = NULL; + int in_table = 0, simulate = 0; + const char *tablename = NULL; program_name = "iptables-restore"; program_version = IPTABLES_VERSION; @@ -123,23 +123,16 @@ init_extensions(); #endif - while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "cvt:nM:Sh", options, NULL)) != -1) { switch (c) { - case 'b': - binary = 1; - break; case 'c': counters = 1; break; case 'v': verbose = 1; break; - case 't': - testing = 1; - break; - case 'h': - print_usage("iptables-restore", - IPTABLES_VERSION); + case 't': /* Select specific table. */ + tablename = optarg; break; case 'n': noflush = 1; @@ -147,62 +140,66 @@ case 'M': modprobe = optarg; break; + case 'S': + simulate = 1; + break; + case 'h': + print_usage(program_name, IPTABLES_VERSION); + exit(0); + case '?': + exit_tryhelp(PARAMETER_PROBLEM); } } if (optind == argc - 1) { in = fopen(argv[optind], "r"); if (!in) { - fprintf(stderr, "Can't open %s: %s", argv[optind], + fprintf(stderr, "Can't open %s: %s\n", argv[optind], strerror(errno)); exit(1); } } else if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline"); + fprintf(stderr, "%s: unknown arguments found on commandline\n", + program_name); exit(1); } else in = stdin; /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { - int ret = 0; + int ret = 0; /* error by default */ line++; if (buffer[0] == '\n') continue; - else if (buffer[0] == '#') { + else if (buffer[0] == '#') { /* comment */ if (verbose) fputs(buffer, stdout); continue; - } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { - if (!testing) { - DEBUGP("Calling commit\n"); - ret = iptc_commit(&handle); - } else { - DEBUGP("Not calling commit, testing\n"); - ret = 1; - } + } else if (in_table && !strcmp(buffer, "COMMIT\n")) { + DEBUGP("Calling commit\n"); + ret = iptc_commit(&handle); in_table = 0; - } else if ((buffer[0] == '*') && (!in_table)) { - /* New table */ - char *table; - - table = strtok(buffer+1, " \t\n"); + } else if (!in_table && buffer[0] == '*') { /* new table */ + char *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); - } + if (!table) + exit_error(PARAMETER_PROBLEM, + "%s: line %u table name invalid\n", + program_name, line); + + if (tablename != NULL && strcmp(tablename, table)) + continue; /* not the selected table */ + strncpy(curtable, table, IPT_TABLE_MAXNAMELEN); curtable[IPT_TABLE_MAXNAMELEN] = '\0'; if (handle) iptc_free(&handle); - handle = create_handle(table, modprobe); + handle = create_handle(table, modprobe, simulate); + if (noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); @@ -215,53 +212,50 @@ &handle) ; } - ret = 1; in_table = 1; - - } else if ((buffer[0] == ':') && (in_table)) { - /* New chain. */ + continue; /* ok */ + } else if (in_table && buffer[0] == ':') { /* new chain */ char *policy, *chain; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); - if (!chain) { + if (!chain) exit_error(PARAMETER_PROBLEM, "%s: line %u chain name invalid\n", program_name, line); - exit(1); - } if (!iptc_builtin(chain, handle)) { DEBUGP("Creating new chain '%s'\n", chain); if (!iptc_create_chain(chain, &handle)) exit_error(PARAMETER_PROBLEM, "error creating chain " - "'%s':%s\n", chain, - strerror(errno)); + "'%s':%s\n", chain, + iptc_strerror(errno)); } policy = strtok(NULL, " \t\n"); DEBUGP("line %u, policy '%s'\n", line, policy); - if (!policy) { + if (!policy) exit_error(PARAMETER_PROBLEM, "%s: line %u policy invalid\n", program_name, line); - exit(1); - } - if (strcmp(policy, "-") != 0) { + if (strcmp(policy, "-") != 0) { /* builtin chain? */ struct ipt_counters count; if (counters) { - char *ctrs; - ctrs = strtok(NULL, " \t\n"); - - parse_counters(ctrs, &count); - - } else { - memset(&count, 0, + char *ctrs = strtok(NULL, " \t\n"); + if (ctrs != NULL) + parse_counters(ctrs, &count); + else { + fprintf(stderr, "%s: Warning: no counter could be found at line %u. Assuming [0:0].\n", + program_name, line); + memset(&count, 0, + sizeof(struct ipt_counters)); + } + } else + memset(&count, 0, sizeof(struct ipt_counters)); - } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); @@ -274,9 +268,7 @@ chain, policy, line, iptc_strerror(errno)); } - - ret = 1; - + continue; /* ok */ } else if (in_table) { int a; char *ptr = buffer; @@ -371,12 +363,10 @@ /* check if table name specified */ if (!strncmp(param_buffer, "-t", 3) - || !strncmp(param_buffer, "--table", 8)) { + || !strncmp(param_buffer, "--table", 8)) exit_error(PARAMETER_PROBLEM, "Line %u seems to have a " "-t table option.\n", line); - exit(1); - } add_argv(param_buffer); param_start += param_len + 1; @@ -395,10 +385,12 @@ &newargv[2], &handle); free_argv(); - } + } else if (tablename != NULL) + continue; + if (!ret) { - fprintf(stderr, "%s: line %u failed\n", - program_name, line); + fprintf(stderr, "%s: line %u failed: %s\n", + program_name, line, iptc_strerror(errno)); exit(1); } } diff -ruN iptables.ori/iptables-save.8 iptables.new_without_fluff/iptables-save.8 --- iptables.ori/iptables-save.8 2002-06-14 09:39:58.000000000 +0200 +++ iptables.new_without_fluff/iptables-save.8 2004-08-28 03:28:39.000000000 +0200 @@ -21,7 +21,7 @@ .SH NAME iptables-save \- Save IP Tables .SH SYNOPSIS -.BR "iptables-save " "[-c] [-t table]" +.BR "iptables-save " "[-c] [-t table] [-C] [-h]" .br .SH DESCRIPTION .PP @@ -33,9 +33,14 @@ include the current values of all packet and byte counters in the output .TP \fB\-t\fR, \fB\-\-table\fR \fBtablename\fR -.TP restrict output to only one table. If not specified, output includes all available tables. +.TP +\fB\-C\fR, \fB\-\-no-comments\fR +do not output any comment. Useful for comparing two dump files. +.TP +\fB\-h\fR, \fB\-\-help\fR +display help message. .SH BUGS None known as of iptables-1.2.1 release .SH AUTHOR diff -ruN iptables.ori/iptables-save.c iptables.new_without_fluff/iptables-save.c --- iptables.ori/iptables-save.c 2004-06-25 13:18:57.000000000 +0200 +++ iptables.new_without_fluff/iptables-save.c 2004-08-28 03:28:39.000000000 +0200 @@ -17,16 +17,6 @@ #include "libiptc/libiptc.h" #include "iptables.h" -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 } -}; - #define IP_PARTS_NATIVE(n) \ (unsigned int)((n)>>24)&0xFF, \ (unsigned int)((n)>>16)&0xFF, \ @@ -35,6 +25,28 @@ #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) +static int counters = 0, no_comments = 0; + +static struct option options[] = { + { "counters", 0, 0, 'c' }, + { "table", 1, 0, 't' }, + { "no-comments", 0, 0, 'C' }, + { "help", 0, 0, 'h' }, + { 0 } +}; + +static void +print_usage(const char *name, const char *version) +{ + fprintf(stderr, "%s v%s\n\n" + "Usage: %s [-c] [-t table] [-C] [-h]\n" + " [ --counters ]\n" + " [ --table name ]\n" + " [ --no-comments ]\n" + " [ --help ]\n", + name, version, name); +} + /* This assumes that mask is contiguous, and byte-bounded. */ static void print_iface(char letter, const char *iface, const unsigned char *mask, @@ -257,6 +269,7 @@ { iptc_handle_t h; const char *chain = NULL; + time_t now; if (!tablename) return for_each_table(&do_output); @@ -266,50 +279,48 @@ exit_error(OTHER_PROBLEM, "Can't initialize: %s\n", iptc_strerror(errno)); - if (!binary) { - time_t now = time(NULL); - + if (!no_comments) { + now = time(NULL); printf("# Generated by iptables-save v%s on %s", IPTABLES_VERSION, ctime(&now)); - printf("*%s\n", tablename); + } + printf("*%s\n", tablename); - /* Dump out chain names first, - * thereby preventing dependency conflicts */ - for (chain = iptc_first_chain(&h); - chain; - chain = iptc_next_chain(&h)) { - - printf(":%s ", chain); - if (iptc_builtin(chain, h)) { - struct ipt_counters count; - printf("%s ", - iptc_get_policy(chain, &count, &h)); - printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); - } else { - printf("- [0:0]\n"); - } - } - + /* Dump out chain names first, + * thereby preventing dependency conflicts */ + for (chain = iptc_first_chain(&h); + chain; + chain = iptc_next_chain(&h)) { + printf(":%s ", chain); + if (iptc_builtin(chain, h)) { + struct ipt_counters count; + printf("%s", iptc_get_policy(chain, &count, &h)); + if (counters) + printf(" [%llu:%llu]", + (unsigned long long)count.pcnt, + (unsigned long long)count.bcnt); + } else + putchar('-'); + putchar('\n'); + } - for (chain = iptc_first_chain(&h); - chain; - chain = iptc_next_chain(&h)) { - const struct ipt_entry *e; - - /* Dump out rules */ - e = iptc_first_rule(chain, &h); - while(e) { - print_rule(e, &h, chain, counters); - e = iptc_next_rule(e, &h); - } + for (chain = iptc_first_chain(&h); + chain; + chain = iptc_next_chain(&h)) { + const struct ipt_entry *e; + + /* Dump out rules */ + e = iptc_first_rule(chain, &h); + while (e) { + print_rule(e, &h, chain, counters); + e = iptc_next_rule(e, &h); } + } + puts("COMMIT"); + if (!no_comments) { now = time(NULL); - printf("COMMIT\n"); printf("# Completed on %s", ctime(&now)); - } else { - /* Binary, huh? OK. */ - exit_error(OTHER_PROBLEM, "Binary NYI\n"); } iptc_free(&h); @@ -339,28 +350,29 @@ init_extensions(); #endif - while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "ct:Ch", 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); + case 'C': + no_comments = 1; + break; + case 'h': + print_usage(program_name, IPTABLES_VERSION); exit(0); + case '?': + exit_tryhelp(PARAMETER_PROBLEM); } } if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline"); + fprintf(stderr, "%s: unknown arguments found on commandline\n", + program_name); exit(1); } diff -ruN iptables.ori/iptables.8.in iptables.new_without_fluff/iptables.8.in --- iptables.ori/iptables.8.in 2004-07-08 19:14:35.000000000 +0200 +++ iptables.new_without_fluff/iptables.8.in 2004-08-28 03:28:39.000000000 +0200 @@ -354,6 +354,13 @@ When adding or inserting rules into a chain, use .B command to load any necessary modules (targets, match extensions, etc). +.TP +.B "-S, --simulate" +simulate the restoration, do not commit ruleset changes to the kernel. +Yet, this is not a pure virtual simulation, as it may have the side +effect of loading iptable_* kernel modules and their possible +dependencies, notably ip_conntrack, which can lead to performance +issues after the simulation. .SH MATCH EXTENSIONS iptables can use extended packet matching modules. These are loaded in two ways: implicitly, when diff -ruN iptables.ori/iptables.c iptables.new_without_fluff/iptables.c --- iptables.ori/iptables.c 2004-07-08 14:54:48.000000000 +0200 +++ iptables.new_without_fluff/iptables.c 2004-08-28 03:28:39.000000000 +0200 @@ -138,14 +138,15 @@ { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, { "set-counters", 1, 0, 'c' }, + { "simulate", 0, 0, 'S' }, { 0 } }; /* we need this for iptables-restore. iptables-restore.c sets line to the * current line of the input file, in order to give a more precise error * message. iptables itself doesn't need this, so it is initialized to the - * magic number of -1 */ -int line = -1; + * magic number of 0 */ +int line = 0; #ifndef __OPTIMIZE__ struct ipt_entry_target * @@ -338,7 +339,7 @@ void exit_tryhelp(int status) { - if (line != -1) + if (line != 0) fprintf(stderr, "Error occurred at line: %d\n", line); fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", program_name, program_name ); @@ -352,17 +353,19 @@ struct iptables_target *t = NULL; printf("%s v%s\n\n" -"Usage: %s -[AD] chain rule-specification [options]\n" -" %s -[RI] chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LFZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" +"Usage: %s [-t table] -[AD] chain rule-specification [options]\n" +" %s [-t table] -I chain [rulenum] rule-specification [options]\n" +" %s [-t table] -R chain rulenum rule-specification [options]\n" +" %s [-t table] -D chain rulenum [options]\n" +" %s [-t table] -[LFZ] [chain] [options]\n" +" %s [-t table] -N chain\n" +" %s [-t table] -X [chain]\n" +" %s [-t table] -P chain target [options]\n" +" %s [-t table] -E old-chain-name new-chain-name\n" " %s -h (print this help information)\n\n", program_name, program_version, program_name, program_name, program_name, program_name, program_name, program_name, - program_name, program_name); + program_name, program_name, program_name, program_name); printf( "Commands:\n" @@ -403,12 +406,14 @@ " --out-interface -o [!] output name[+]\n" " network interface name ([+] for wildcard)\n" " --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" "[!] --fragment -f match second or further fragments only\n" -" --modprobe= try to insert modules using this command\n" " --set-counters PKTS BYTES set the counter during insert/append\n" + +" --verbose -v verbose mode\n" +" --simulate -S simulate the restoration (no kernel commit)\n" +" --modprobe= try to insert modules using this command\n" "[!] --version -V print package version.\n"); /* Print out any special helps. A user might like to be able @@ -1698,7 +1703,7 @@ unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *daddrs = NULL; - int c, verbose = 0; + int c, verbose = 0, simulate = 0; const char *chain = NULL; const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; @@ -1736,7 +1741,7 @@ opterr = 0; while ((c = getopt_long(argc, argv, - "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:", + "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fvnt:m:xc:S", opts, NULL)) != -1) { switch (c) { /* @@ -2040,6 +2045,9 @@ break; + case 'S': + simulate = 1; + break; case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { @@ -2197,6 +2205,9 @@ "can't initialize iptables table `%s': %s", *table, iptc_strerror(errno)); + if (simulate) + iptc_set_nocommit(handle); + if (command == CMD_APPEND || command == CMD_DELETE || command == CMD_INSERT diff -ruN iptables.ori/libiptc/libip4tc.c iptables.new_without_fluff/libiptc/libip4tc.c --- iptables.ori/libiptc/libip4tc.c 2004-05-26 18:04:49.000000000 +0200 +++ iptables.new_without_fluff/libiptc/libip4tc.c 2004-08-28 03:28:39.000000000 +0200 @@ -92,6 +92,7 @@ #define TC_GET_RAW_SOCKET iptc_get_raw_socket #define TC_INIT iptc_init #define TC_FREE iptc_free +#define TC_SET_NOCOMMIT iptc_set_nocommit #define TC_COMMIT iptc_commit #define TC_STRERROR iptc_strerror diff -ruN iptables.ori/libiptc/libip6tc.c iptables.new_without_fluff/libiptc/libip6tc.c --- iptables.ori/libiptc/libip6tc.c 2004-05-26 18:04:49.000000000 +0200 +++ iptables.new_without_fluff/libiptc/libip6tc.c 2004-08-28 03:28:39.000000000 +0200 @@ -87,6 +87,7 @@ #define TC_GET_RAW_SOCKET ip6tc_get_raw_socket #define TC_INIT ip6tc_init #define TC_FREE ip6tc_free +#define TC_SET_NOCOMMIT ip6tc_set_nocommit #define TC_COMMIT ip6tc_commit #define TC_STRERROR ip6tc_strerror diff -ruN iptables.ori/libiptc/libiptc.c iptables.new_without_fluff/libiptc/libiptc.c --- iptables.ori/libiptc/libiptc.c 2004-05-26 18:04:49.000000000 +0200 +++ iptables.new_without_fluff/libiptc/libiptc.c 2004-08-28 03:28:39.000000000 +0200 @@ -78,6 +78,8 @@ STRUCT_TC_HANDLE { + /* Do not commit anything to the kernel if this flag is set. */ + int nocommit; /* Have changes been made? */ int changed; /* Size in here reflects original state. */ @@ -109,6 +111,12 @@ h->changed = 1; } +void +TC_SET_NOCOMMIT(TC_HANDLE_T *h) +{ + (*h)->nocommit = 1; +} + #ifdef IPTC_DEBUG static void do_check(TC_HANDLE_T h, unsigned int line); #define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) @@ -230,6 +238,7 @@ } h->changed = 0; + h->nocommit = 0; h->cache_num_chains = 0; h->cache_chain_heads = NULL; h->counter_map = (void *)h @@ -854,6 +863,7 @@ if (!newh) return 0; newh->info = newinfo; + newh->nocommit = (*handle)->nocommit; /* Copy pre... */ memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset); @@ -1732,17 +1742,17 @@ CHECK(*handle); - counterlen = sizeof(STRUCT_COUNTERS_INFO) - + sizeof(STRUCT_COUNTERS) * (*handle)->new_number; - #if 0 TC_DUMP_ENTRIES(*handle); #endif - /* Don't commit if nothing changed. */ - if (!(*handle)->changed) + /* Don't commit if nothing changed or if we are is nocommit mode. */ + if (!(*handle)->changed || (*handle)->nocommit) goto finished; + counterlen = sizeof(STRUCT_COUNTERS_INFO) + + sizeof(STRUCT_COUNTERS) * (*handle)->new_number; + repl = malloc(sizeof(*repl) + (*handle)->entries.size); if (!repl) { errno = ENOMEM;