iptables-save - suggest patch to add functionality

Message ID d32e7ad2-ddf5-22a5-e8ef-f9ed1432c24b@zordhak.fr
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series
  • iptables-save - suggest patch to add functionality
Related show

Commit Message

Alban Vidal Jan. 23, 2018, 10:44 a.m.
Package: iptables

Dear Maintainers,
 
Please find attached a suggest patch to add functionality in iptables-save.

-------------------------------------------------------------------------------

1) Adding -z or --zero option: Reset to zero counters of the chains.

Example without:

iptables-save
# Generated by iptables-save v1.6.1 on Tue Jan  9 21:42:51 2018
*nat
:PREROUTING ACCEPT [923:217673]
:INPUT ACCEPT [309:97481]
(...)

Example with:

iptables-save -z
# Generated by iptables-save v1.6.1 on Tue Jan  9 21:42:26 2018
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
(...)

-------------------------------------------------------------------------------

2) Adding -h or --help option: print help/usage (inspired by manpage)

Content:

iptables-save -h
iptables-save and ip6tables-save are provides from iptables package — version 1.6.1

iptables-save and ip6tables-save are used to dump the contents of IP or IPv6 Table in easily parseable format to STDOUT. Use I/O-redirection provided by your shell to write to a file.

Usage: iptables-save  [-h] [-M modprobe] [-c] [-z] [-t table]
       ip6tables-save [-h] [-M modprobe] [-c] [-z] [-t table]

Options:
Either long or short options are allowed.

  -h, --help
      Print this help usage.

  -M, --modprobe modprobe_program
      Specify the path to the modprobe program. By default, iptables-save will inspect /proc/sys/kernel/mod‐probe to determine the executable's path.

  -c, --counters
      Include the current values of all packet and byte counters in the output.

  -z, --zero
      Reset to zero counters of the chains.

  -t, --table tablename
      Restrict output to only one table. If not specified, output includes all available tables.

  -f, --file filename
      Specify a filename to log the output to. If not specified, iptables-save will log to STDOUT.

 -------------------------------------------------------------------------------

3) Layout layout: uppercase, dot...


Best regards,

Alban Vidal

----------------------
-- System Information:
Debian Release: 9.3
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.9.0-5-amd64 (SMP w/4 CPU cores)
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8), LANGUAGE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Comments

Pablo Neira Ayuso March 11, 2018, 8:57 p.m. | #1
Hi Alban,

On Tue, Jan 23, 2018 at 11:44:22AM +0100, Alban Vidal wrote:
> Package: iptables
> 
> Dear Maintainers,
>  
> Please find attached a suggest patch to add functionality in iptables-save.
> 
> -------------------------------------------------------------------------------
> 
> 1) Adding -z or --zero option: Reset to zero counters of the chains.
> 
> Example without:
> 
> iptables-save
> # Generated by iptables-save v1.6.1 on Tue Jan  9 21:42:51 2018
> *nat
> :PREROUTING ACCEPT [923:217673]
> :INPUT ACCEPT [309:97481]
> (...)
> 
> Example with:
> 
> iptables-save -z
> # Generated by iptables-save v1.6.1 on Tue Jan  9 21:42:26 2018
> *nat
> :PREROUTING ACCEPT [0:0]
> :INPUT ACCEPT [0:0]
> (...)

I have no objections to this -z feature, but better use -Z uppercase
instead, so we match it with the existing -Z in iptables that only
refers to chains too.

A single patch for this new feature is prefered.

> -------------------------------------------------------------------------------
> 
> 2) Adding -h or --help option: print help/usage (inspired by manpage)
> 
> Content:
> 
> iptables-save -h
> iptables-save and ip6tables-save are provides from iptables package — version 1.6.1
> 
> iptables-save and ip6tables-save are used to dump the contents of IP or IPv6 Table in easily parseable format to STDOUT. Use I/O-redirection provided by your shell to write to a file.
> 
> Usage: iptables-save  [-h] [-M modprobe] [-c] [-z] [-t table]
>        ip6tables-save [-h] [-M modprobe] [-c] [-z] [-t table]

Fine, but place this in a separated patch, no need for common file.
Don't bother about copy and paste.

Could you also update xtables-save BTW? This is the compat tool to
save iptables-compat listings from nftables.

> diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
> index 8e3a6afd..466ce0ce 100644
> --- a/iptables/ip6tables-save.c
> +++ b/iptables/ip6tables-save.c
> @@ -3,6 +3,8 @@
>   * Original code: iptables-save
>   * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
>   *          Harald Welte <laforge@gnumonks.org>
> + * Contributor: Alban Vidal <alban.vidal@zordhak.fr>

These days, git already registers this, previous lines are just there
for historical reasons. So please, remove this.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alban Vidal March 12, 2018, 10:58 p.m. | #2
Package: iptables

Dear Maintainers,

Le 11/03/2018 à 21:57, Pablo Neira Ayuso a écrit :
> Hi Alban,
>
> On Tue, Jan 23, 2018 at 11:44:22AM +0100, Alban Vidal wrote:
>> 1) Adding -z or --zero option: Reset to zero counters of the chains.
> I have no objections to this -z feature, but better use -Z uppercase
> instead, so we match it with the existing -Z in iptables that only
> refers to chains too.
>
> A single patch for this new feature is prefered.
> Could you also update xtables-save BTW? This is the compat tool to
> save iptables-compat listings from nftables.

The first patch is join, I have changed with -Z uppercase option, and
updated the man page.
« xtables-save » is also updated.

Output examples :

iptables-save -Z
# Generated by iptables-save v1.6.2 on Mon Mar 12 23:30:16 2018
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
(...)

xtables-multi save4 -Z
# Generated by iptables-save v1.6.2 on Mon Mar 12 23:30:42 2018
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
(...)

>> 2) Adding -h or --help option: print help/usage (inspired by manpage)
> Fine, but place this in a separated patch, no need for common file.
> Don't bother about copy and paste.

I send you the second patch for -h option after you are pushed the first.

>> diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
>> index 8e3a6afd..466ce0ce 100644
>> --- a/iptables/ip6tables-save.c
>> +++ b/iptables/ip6tables-save.c
>> @@ -3,6 +3,8 @@
>>   * Original code: iptables-save
>>   * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
>>   *          Harald Welte <laforge@gnumonks.org>
>> + * Contributor: Alban Vidal <alban.vidal@zordhak.fr>
> These days, git already registers this, previous lines are just there
> for historical reasons. So please, remove this.
It's done ! Removed from source code.

Best regards,
Alban Vidal
diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
index 8e3a6afd..a94beffc 100644
--- a/iptables/ip6tables-save.c
+++ b/iptables/ip6tables-save.c
@@ -19,11 +19,15 @@
 #include "ip6tables.h"
 #include "ip6tables-multi.h"
 
-static int show_counters;
+static int show_counters = false;
+
+/* if true (opt -Z, --zero): Reset to zero counters of the chains */
+static int rst_chain_counters = false;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -96,7 +100,13 @@ static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       ip6tc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if (!rst_chain_counters) {
+				/* Default value, print count */
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			} else {
+				/* Reset to zero counters of the chains */
+				printf("[0:0]\n");
+			}
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -146,15 +156,17 @@ int ip6tables_save_main(int argc, char *argv[])
 	init_extensions6();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
 			break;
 		case 'c':
-			show_counters = 1;
+			show_counters = true;
+			break;
+		case 'Z':
+			rst_chain_counters = true;
 			break;
-
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 51e11f3e..200d6448 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -24,10 +24,10 @@ iptables-save \(em dump iptables rules
 ip6tables-save \(em dump iptables rules
 .SH SYNOPSIS
 \fBiptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .P
 \fBip6tables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .SH DESCRIPTION
 .PP
 .B iptables-save
@@ -45,19 +45,24 @@ Specify a filename to log the output to. If not specified, iptables-save
 will log to STDOUT.
 .TP
 \fB\-c\fR, \fB\-\-counters\fR
-include the current values of all packet and byte counters in the output
+Include the current values of all packet and byte counters in the output.
+.TP
+\fB\-Z\fR, \fB\-\-zero\fR
+Reset to zero counters of the chains.
 .TP
 \fB\-t\fR, \fB\-\-table\fR \fItablename\fP
-restrict output to only one table. If not specified, output includes all
+Restrict output to only one table. If not specified, output includes all
 available tables.
 .SH BUGS
 None known as of iptables-1.2.1 release
 .SH AUTHORS
-Harald Welte <laforge@gnumonks.org>
+Harald Welte <laforge@gnumonks.org>,
+.br
+Rusty Russell <rusty@rustcorp.com.au>,
 .br
-Rusty Russell <rusty@rustcorp.com.au>
+Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save,
 .br
-Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save.
+Alban Vidal <alban.vidal@zordhak.fr> contributed ip[6]tables-save.
 .SH SEE ALSO
 \fBiptables\-restore\fP(8), \fBiptables\fP(8)
 .PP
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index d59bd34a..7e16684d 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -18,11 +18,15 @@
 #include "iptables.h"
 #include "iptables-multi.h"
 
-static int show_counters;
+static int show_counters = false;
+
+/* if true (opt -Z, --zero): Reset to zero counters of the chains */
+static int rst_chain_counters = false;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -94,7 +98,13 @@ static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       iptc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if (!rst_chain_counters) {
+				/* Default value, print count */
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			} else {
+				/* Reset to zero counters of the chains */
+				printf("[0:0]\n");
+			}
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -145,15 +155,17 @@ iptables_save_main(int argc, char *argv[])
 	init_extensions4();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
 			break;
 		case 'c':
-			show_counters = 1;
+			show_counters = true;
+			break;
+		case 'Z':
+			rst_chain_counters = true;
 			break;
-
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 5b498b04..6167bc71 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -28,9 +28,13 @@
 
 static bool show_counters = false;
 
+/* if true (opt -Z, --zero): Reset to zero counters of the chains */
+static int rst_chain_counters = false;
+
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -107,7 +111,7 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:46", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:46", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -115,7 +119,9 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
 		case 'c':
 			show_counters = true;
 			break;
-
+		case 'Z':
+			rst_chain_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
Pablo Neira Ayuso March 13, 2018, 2:57 p.m. | #3
On Mon, Mar 12, 2018 at 11:58:01PM +0100, Alban Vidal wrote:
[...]
> diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
> index 8e3a6afd..a94beffc 100644

Please, send us patches in git-format-patch, include a patch
description and add your Signed-off-by tag.

More comments below.

> --- a/iptables/ip6tables-save.c
> +++ b/iptables/ip6tables-save.c
> @@ -19,11 +19,15 @@
>  #include "ip6tables.h"
>  #include "ip6tables-multi.h"
>  
> -static int show_counters;
> +static int show_counters = false;

No need to initialize code that is implicitly initialized because of
being in the bss.

> +
> +/* if true (opt -Z, --zero): Reset to zero counters of the chains */

No need for comment.

> +static int rst_chain_counters = false;

I would call this:

        display_zero_counters

This is not resetting counters, it just displays them as zero. Same
comment applies to documentation.

>  static const struct option options[] = {
>  	{.name = "counters", .has_arg = false, .val = 'c'},
>  	{.name = "dump",     .has_arg = false, .val = 'd'},
> +	{.name = "zero",     .has_arg = false, .val = 'Z'},
>  	{.name = "table",    .has_arg = true,  .val = 't'},
>  	{.name = "modprobe", .has_arg = true,  .val = 'M'},
>  	{.name = "file",     .has_arg = true,  .val = 'f'},
> @@ -96,7 +100,13 @@ static int do_output(const char *tablename)
>  			struct xt_counters count;
>  			printf("%s ",
>  			       ip6tc_get_policy(chain, &count, h));
> -			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
> +			if (!rst_chain_counters) {
> +				/* Default value, print count */

No need for comment above.

> +				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
> +			} else {
> +				/* Reset to zero counters of the chains */
> +				printf("[0:0]\n");
> +			}
>  		} else {
>  			printf("- [0:0]\n");
>  		}
> @@ -146,15 +156,17 @@ int ip6tables_save_main(int argc, char *argv[])
>  	init_extensions6();
>  #endif
>  
> -	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
> +	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
>  		switch (c) {
>  		case 'b':
>  			fprintf(stderr, "-b/--binary option is not implemented\n");
>  			break;
>  		case 'c':
> -			show_counters = 1;
> +			show_counters = true;

Do this update in a separated patch: One patch per logical change.

> +			break;
> +		case 'Z':
> +			rst_chain_counters = true;
>  			break;
> -
>  		case 't':
>  			/* Select specific table. */
>  			tablename = optarg;
> diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
> index 51e11f3e..200d6448 100644
> --- a/iptables/iptables-save.8.in
> +++ b/iptables/iptables-save.8.in
> @@ -24,10 +24,10 @@ iptables-save \(em dump iptables rules
>  ip6tables-save \(em dump iptables rules
>  .SH SYNOPSIS
>  \fBiptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
> -[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
> +[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
>  .P
>  \fBip6tables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
> -[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
> +[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
>  .SH DESCRIPTION
>  .PP
>  .B iptables-save
> @@ -45,19 +45,24 @@ Specify a filename to log the output to. If not specified, iptables-save
>  will log to STDOUT.
>  .TP
>  \fB\-c\fR, \fB\-\-counters\fR
> -include the current values of all packet and byte counters in the output
> +Include the current values of all packet and byte counters in the output.
   ^

Same thing as above, no unrelated changes in this patch.

> +.TP
> +\fB\-Z\fR, \fB\-\-zero\fR
> +Reset to zero counters of the chains.

This is not resetting anything, instead I'd propose:

Display zero packet and byte chain counters when saving the ruleset.

>  .TP
>  \fB\-t\fR, \fB\-\-table\fR \fItablename\fP
> -restrict output to only one table. If not specified, output includes all
> +Restrict output to only one table. If not specified, output includes all
>  available tables.
>  .SH BUGS
>  None known as of iptables-1.2.1 release
>  .SH AUTHORS
> -Harald Welte <laforge@gnumonks.org>
> +Harald Welte <laforge@gnumonks.org>,
> +.br
> +Rusty Russell <rusty@rustcorp.com.au>,
>  .br
> -Rusty Russell <rusty@rustcorp.com.au>
> +Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save,
>  .br
> -Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save.
> +Alban Vidal <alban.vidal@zordhak.fr> contributed ip[6]tables-save.

Again, this information is there for historical reasons: git is
already leaving a record on this. *A lot* of people have contributed
to iptables and they are not listed there :-).

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alban Vidal March 13, 2018, 6:37 p.m. | #4
Dear Maintainers,

Le 13/03/2018 à 15:57, Pablo Neira Ayuso a écrit :
> Please, send us patches in git-format-patch, include a patch
> description and add your Signed-off-by tag.
Please find attached the patch in git-format-patch format.

>> +/* if true (opt -Z, --zero): Reset to zero counters of the chains */
> No need for comment.
Comments removed.

>> +static int rst_chain_counters = false;
> I would call this:
>
>         display_zero_counters
>
> This is not resetting counters, it just displays them as zero. Same
> comment applies to documentation.
Variable name changed.

>>  		case 'c':
>> -			show_counters = 1;
>> +			show_counters = true;
> Do this update in a separated patch: One patch per logical change.
Sending in a future patch.

>> -include the current values of all packet and byte counters in the output
>> +Include the current values of all packet and byte counters in the output.
>    ^
>
> Same thing as above, no unrelated changes in this patch.
Sending in a future patch.

>> +\fB\-Z\fR, \fB\-\-zero\fR
>> +Reset to zero counters of the chains.
> This is not resetting anything, instead I'd propose:
>
> Display zero packet and byte chain counters when saving the ruleset.
Man page updated.

>> +Alban Vidal <alban.vidal@zordhak.fr> contributed ip[6]tables-save.
> Again, this information is there for historical reasons: git is
> already leaving a record on this. *A lot* of people have contributed
> to iptables and they are not listed there :-).
Removed :)


Best regards,

Alban Vidal
From 5779285507ab2398453f0e562f229d3032d809b6 Mon Sep 17 00:00:00 2001
From: Alban Vidal <alban.vidal@zordhak.fr>
Date: Tue, 13 Mar 2018 19:22:25 +0100
Subject: [PATCH] ipXtables-saves: adding -Z, --zero option

Display zero packet and byte chain counters when saving the ruleset.

Signed-off-by: Alban Vidal <alban.vidal@zordhak.fr>
---
 iptables/ip6tables-save.c   | 14 +++++++++++---
 iptables/iptables-save.8.in |  7 +++++--
 iptables/iptables-save.c    | 14 +++++++++++---
 iptables/xtables-save.c     |  8 ++++++--
 4 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
index 8e3a6afd..8a6ae699 100644
--- a/iptables/ip6tables-save.c
+++ b/iptables/ip6tables-save.c
@@ -20,10 +20,12 @@
 #include "ip6tables-multi.h"
 
 static int show_counters;
+static bool display_zero_counters;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -96,7 +98,11 @@ static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       ip6tc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if(!display_zero_counters) {
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			} else {
+				printf("[0:0]\n");
+			}
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -146,7 +152,7 @@ int ip6tables_save_main(int argc, char *argv[])
 	init_extensions6();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -154,7 +160,9 @@ int ip6tables_save_main(int argc, char *argv[])
 		case 'c':
 			show_counters = 1;
 			break;
-
+		case 'Z':
+			display_zero_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 51e11f3e..76ea4ee0 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -24,10 +24,10 @@ iptables-save \(em dump iptables rules
 ip6tables-save \(em dump iptables rules
 .SH SYNOPSIS
 \fBiptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .P
 \fBip6tables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .SH DESCRIPTION
 .PP
 .B iptables-save
@@ -47,6 +47,9 @@ will log to STDOUT.
 \fB\-c\fR, \fB\-\-counters\fR
 include the current values of all packet and byte counters in the output
 .TP
+\fB\-Z\fR, \fB\-\-zero\fR
+Display zero packet and byte chain counters when saving the ruleset.
+.TP
 \fB\-t\fR, \fB\-\-table\fR \fItablename\fP
 restrict output to only one table. If not specified, output includes all
 available tables.
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index d59bd34a..0885cb9f 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -19,10 +19,12 @@
 #include "iptables-multi.h"
 
 static int show_counters;
+static bool display_zero_counters;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -94,7 +96,11 @@ static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       iptc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if(!display_zero_counters) {
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			} else {
+				printf("[0:0]\n");
+			}
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -145,7 +151,7 @@ iptables_save_main(int argc, char *argv[])
 	init_extensions4();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -153,7 +159,9 @@ iptables_save_main(int argc, char *argv[])
 		case 'c':
 			show_counters = 1;
 			break;
-
+		case 'Z':
+			display_zero_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 5b498b04..2c5d7cd3 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -27,10 +27,12 @@
 #endif
 
 static bool show_counters = false;
+static bool display_zero_counters = false;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -107,7 +109,7 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:46", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:46", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -115,7 +117,9 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
 		case 'c':
 			show_counters = true;
 			break;
-
+		case 'Z':
+			display_zero_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
Alban Vidal July 22, 2018, 9:04 a.m. | #5
Dear Maintainers,

Do you have any news for the following patch ?
For remember, this patch is about iptables-save, it add option '-Z' to show 0:0 on counters.

If the patch is too old, i can make a new.

Thank you.

Best regards,
Alban Vidal


Le 13/03/2018 à 19:37, Alban Vidal a écrit :
> Dear Maintainers,
>
> Le 13/03/2018 à 15:57, Pablo Neira Ayuso a écrit :
>> Please, send us patches in git-format-patch, include a patch
>> description and add your Signed-off-by tag.
> Please find attached the patch in git-format-patch format.
>
>>> +/* if true (opt -Z, --zero): Reset to zero counters of the chains */
>> No need for comment.
> Comments removed.
>
>>> +static int rst_chain_counters = false;
>> I would call this:
>>
>>         display_zero_counters
>>
>> This is not resetting counters, it just displays them as zero. Same
>> comment applies to documentation.
> Variable name changed.
>
>>>  		case 'c':
>>> -			show_counters = 1;
>>> +			show_counters = true;
>> Do this update in a separated patch: One patch per logical change.
> Sending in a future patch.
>
>>> -include the current values of all packet and byte counters in the output
>>> +Include the current values of all packet and byte counters in the output.
>>    ^
>>
>> Same thing as above, no unrelated changes in this patch.
> Sending in a future patch.
>
>>> +\fB\-Z\fR, \fB\-\-zero\fR
>>> +Reset to zero counters of the chains.
>> This is not resetting anything, instead I'd propose:
>>
>> Display zero packet and byte chain counters when saving the ruleset.
> Man page updated.
>
>>> +Alban Vidal <alban.vidal@zordhak.fr> contributed ip[6]tables-save.
>> Again, this information is there for historical reasons: git is
>> already leaving a record on this. *A lot* of people have contributed
>> to iptables and they are not listed there :-).
> Removed :)
>
>
> Best regards,
>
> Alban Vidal
From 5779285507ab2398453f0e562f229d3032d809b6 Mon Sep 17 00:00:00 2001
From: Alban Vidal <alban.vidal@zordhak.fr>
Date: Tue, 13 Mar 2018 19:22:25 +0100
Subject: [PATCH] ipXtables-saves: adding -Z, --zero option

Display zero packet and byte chain counters when saving the ruleset.

Signed-off-by: Alban Vidal <alban.vidal@zordhak.fr>
---
 iptables/ip6tables-save.c   | 14 +++++++++++---
 iptables/iptables-save.8.in |  7 +++++--
 iptables/iptables-save.c    | 14 +++++++++++---
 iptables/xtables-save.c     |  8 ++++++--
 4 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
index 8e3a6afd..8a6ae699 100644
--- a/iptables/ip6tables-save.c
+++ b/iptables/ip6tables-save.c
@@ -20,10 +20,12 @@
 #include "ip6tables-multi.h"
 
 static int show_counters;
+static bool display_zero_counters;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -96,7 +98,11 @@ static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       ip6tc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if(!display_zero_counters) {
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			} else {
+				printf("[0:0]\n");
+			}
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -146,7 +152,7 @@ int ip6tables_save_main(int argc, char *argv[])
 	init_extensions6();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -154,7 +160,9 @@ int ip6tables_save_main(int argc, char *argv[])
 		case 'c':
 			show_counters = 1;
 			break;
-
+		case 'Z':
+			display_zero_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 51e11f3e..76ea4ee0 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -24,10 +24,10 @@ iptables-save \(em dump iptables rules
 ip6tables-save \(em dump iptables rules
 .SH SYNOPSIS
 \fBiptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .P
 \fBip6tables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+[\fB\-Z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .SH DESCRIPTION
 .PP
 .B iptables-save
@@ -47,6 +47,9 @@ will log to STDOUT.
 \fB\-c\fR, \fB\-\-counters\fR
 include the current values of all packet and byte counters in the output
 .TP
+\fB\-Z\fR, \fB\-\-zero\fR
+Display zero packet and byte chain counters when saving the ruleset.
+.TP
 \fB\-t\fR, \fB\-\-table\fR \fItablename\fP
 restrict output to only one table. If not specified, output includes all
 available tables.
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index d59bd34a..0885cb9f 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -19,10 +19,12 @@
 #include "iptables-multi.h"
 
 static int show_counters;
+static bool display_zero_counters;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -94,7 +96,11 @@ static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       iptc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if(!display_zero_counters) {
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			} else {
+				printf("[0:0]\n");
+			}
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -145,7 +151,7 @@ iptables_save_main(int argc, char *argv[])
 	init_extensions4();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -153,7 +159,9 @@ iptables_save_main(int argc, char *argv[])
 		case 'c':
 			show_counters = 1;
 			break;
-
+		case 'Z':
+			display_zero_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 5b498b04..2c5d7cd3 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -27,10 +27,12 @@
 #endif
 
 static bool show_counters = false;
+static bool display_zero_counters = false;
 
 static const struct option options[] = {
 	{.name = "counters", .has_arg = false, .val = 'c'},
 	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'Z'},
 	{.name = "table",    .has_arg = true,  .val = 't'},
 	{.name = "modprobe", .has_arg = true,  .val = 'M'},
 	{.name = "file",     .has_arg = true,  .val = 'f'},
@@ -107,7 +109,7 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:46", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bcZdt:M:f:46", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -115,7 +117,9 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
 		case 'c':
 			show_counters = true;
 			break;
-
+		case 'Z':
+			display_zero_counters = true;
+			break;
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;

Patch

diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c
index 8e3a6afd..466ce0ce 100644
--- a/iptables/ip6tables-save.c
+++ b/iptables/ip6tables-save.c
@@ -3,6 +3,8 @@ 
  * Original code: iptables-save
  * Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
  *          Harald Welte <laforge@gnumonks.org>
+ * Contributor: Alban Vidal <alban.vidal@zordhak.fr>
+ *
  * This code is distributed under the terms of GNU GPL v2
  */
 #include <getopt.h>
@@ -18,18 +20,12 @@ 
 #include "libiptc/libip6tc.h"
 #include "ip6tables.h"
 #include "ip6tables-multi.h"
+#include "ipXtables-save-common.c" /* Common code for iptables-save.c and ip6tables-save.c */
 
-static int show_counters;
-
-static const struct option options[] = {
-	{.name = "counters", .has_arg = false, .val = 'c'},
-	{.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'},
-	{NULL},
-};
+static int show_counters = 0;
 
+/* if = 1 (opt -z): Reset to zero counters of the chains */
+static int rst_chain_counters = 0;
 
 /* Debugging prototype. */
 static int for_each_table(int (*func)(const char *tablename))
@@ -96,7 +92,10 @@  static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       ip6tc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if (rst_chain_counters > 0)
+				printf("[0:0]\n"); /* Reset to zero counters of the chains */
+			else
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -146,7 +145,7 @@  int ip6tables_save_main(int argc, char *argv[])
 	init_extensions6();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bhcdzt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -154,14 +153,20 @@  int ip6tables_save_main(int argc, char *argv[])
 		case 'c':
 			show_counters = 1;
 			break;
-
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
 			break;
+		case 'h':
+			/* Print Help and quit */
+			print_help_usage();
+			break;
 		case 'M':
 			xtables_modprobe_program = optarg;
 			break;
+		case 'z':
+			rst_chain_counters = 1;
+			break;
 		case 'f':
 			file = fopen(optarg, "w");
 			if (file == NULL) {
diff --git a/iptables/ipXtables-save-common.c b/iptables/ipXtables-save-common.c
index e69de29b..3287fc51 100644
--- a/iptables/ipXtables-save-common.c
+++ b/iptables/ipXtables-save-common.c
@@ -0,0 +1,63 @@ 
+/* Common code for iptables-save.c and ip6tables-save.c */
+/* (C) 2018 by Alban Vidal <alban.vidal@zordhak.fr>
+ *
+ * This code is distributed under the terms of GNU GPL v2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>  /* struct option */
+#include <stdbool.h> /* true/false */
+
+/* Summary help usage */
+static void print_help_usage()
+{
+	printf(
+	    "iptables-save and ip6tables-save are provides from iptables package — version %s\n"
+	    "\n"
+	    "iptables-save and ip6tables-save are used to dump the contents of IP or "
+	    "IPv6 Table in easily parseable format to STDOUT. Use I/O-redirection "
+	    "provided by your shell to write to a file.\n"
+	    "\n"
+	    "Usage: iptables-save  [-h] [-M modprobe] [-c] [-z] [-t table] [-f filename]\n"
+	    "       ip6tables-save [-h] [-M modprobe] [-c] [-z] [-t table] [-f filename]\n"
+	    "\n"
+	    "Options:\n"
+	    "Either long or short options are allowed.\n"
+	    "\n"
+	    "  -h, --help\n"
+	    "      Print this help usage.\n"
+	    "\n"
+	    "  -M, --modprobe modprobe_program\n"
+	    "      Specify the path to the modprobe program. By default, iptables-save "
+	    "will inspect /proc/sys/kernel/mod‐probe to determine the executable's path.\n"
+	    "\n"
+	    "  -c, --counters\n"
+	    "      Include the current values of all packet and byte counters in the output.\n"
+	    "\n"
+	    "  -z, --zero\n"
+	    "      Reset to zero counters of the chains.\n"
+	    "\n"
+	    "  -t, --table tablename\n"
+	    "      Restrict output to only one table. If not specified, output includes "
+	    "all available tables.\n"
+	    "\n"
+	    "  -f, --file filename\n"
+	    "      Specify a filename to log the output to. If not specified, iptables-save "
+	    "will log to STDOUT.\n"
+	    , IPTABLES_VERSION
+	);
+
+	exit(0);
+}
+
+static const struct option options[] = {
+	{.name = "help",     .has_arg = false, .val = 'h'},
+	{.name = "counters", .has_arg = false, .val = 'c'},
+	{.name = "dump",     .has_arg = false, .val = 'd'},
+	{.name = "zero",     .has_arg = false, .val = 'z'},
+	{.name = "table",    .has_arg = true,  .val = 't'},
+	{.name = "modprobe", .has_arg = true,  .val = 'M'},
+	{.name = "file",     .has_arg = true,  .val = 'f'},
+	{NULL},
+};
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 51e11f3e..0ee0f513 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -23,11 +23,11 @@  iptables-save \(em dump iptables rules
 .P
 ip6tables-save \(em dump iptables rules
 .SH SYNOPSIS
-\fBiptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+\fBiptables\-save\fP  [\fB\-h\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
+[\fB\-z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .P
-\fBip6tables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
-[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
+\fBip6tables\-save\fP [\fB\-h\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
+[\fB\-z\fP] [\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP]
 .SH DESCRIPTION
 .PP
 .B iptables-save
@@ -36,6 +36,9 @@  and
 are used to dump the contents of IP or IPv6 Table in easily parseable format
 either to STDOUT or to a specified file.
 .TP
+\fB\-h\fR, \fB\-\-help\fR
+Print help usage and quit.
+.TP
 \fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe_program\fP
 Specify the path to the modprobe program. By default, iptables-save will
 inspect /proc/sys/kernel/modprobe to determine the executable's path.
@@ -45,19 +48,24 @@  Specify a filename to log the output to. If not specified, iptables-save
 will log to STDOUT.
 .TP
 \fB\-c\fR, \fB\-\-counters\fR
-include the current values of all packet and byte counters in the output
+Include the current values of all packet and byte counters in the output.
+.TP
+\fB\-z\fR, \fB\-\-zero\fR
+Reset to zero counters of the chains.
 .TP
 \fB\-t\fR, \fB\-\-table\fR \fItablename\fP
-restrict output to only one table. If not specified, output includes all
+Restrict output to only one table. If not specified, output includes all
 available tables.
 .SH BUGS
-None known as of iptables-1.2.1 release
+None known as of iptables-1.2.1 release.
 .SH AUTHORS
-Harald Welte <laforge@gnumonks.org>
+Harald Welte <laforge@gnumonks.org>,
+.br
+Rusty Russell <rusty@rustcorp.com.au>,
 .br
-Rusty Russell <rusty@rustcorp.com.au>
+Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save,
 .br
-Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save.
+Alban Vidal <alban.vidal@zordhak.fr> contributed ip[6]tables-save.
 .SH SEE ALSO
 \fBiptables\-restore\fP(8), \fBiptables\fP(8)
 .PP
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index d59bd34a..d6abdb93 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -1,6 +1,8 @@ 
 /* Code to save the iptables state, in human readable-form. */
 /* (C) 1999 by Paul 'Rusty' Russell <rusty@rustcorp.com.au> and
  * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ * Contributor:
+ * (C) 2018 by Alban Vidal <alban.vidal@zordhak.fr>
  *
  * This code is distributed under the terms of GNU GPL v2
  *
@@ -17,17 +19,12 @@ 
 #include "libiptc/libiptc.h"
 #include "iptables.h"
 #include "iptables-multi.h"
+#include "ipXtables-save-common.c" /* Common code for iptables-save.c and ip6tables-save.c */
 
-static int show_counters;
+static int show_counters = 0;
 
-static const struct option options[] = {
-	{.name = "counters", .has_arg = false, .val = 'c'},
-	{.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'},
-	{NULL},
-};
+/* if = 1 (opt -z): Reset to zero counters of the chains */
+static int rst_chain_counters = 0;
 
 /* Debugging prototype. */
 static int for_each_table(int (*func)(const char *tablename))
@@ -94,7 +91,10 @@  static int do_output(const char *tablename)
 			struct xt_counters count;
 			printf("%s ",
 			       iptc_get_policy(chain, &count, h));
-			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
+			if (rst_chain_counters > 0)
+				printf("[0:0]\n"); /* Reset to zero counters of the chains */
+			else
+				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
 		} else {
 			printf("- [0:0]\n");
 		}
@@ -145,7 +145,7 @@  iptables_save_main(int argc, char *argv[])
 	init_extensions4();
 #endif
 
-	while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "bhcdzt:M:f:", options, NULL)) != -1) {
 		switch (c) {
 		case 'b':
 			fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -153,14 +153,20 @@  iptables_save_main(int argc, char *argv[])
 		case 'c':
 			show_counters = 1;
 			break;
-
 		case 't':
 			/* Select specific table. */
 			tablename = optarg;
 			break;
+		case 'h':
+			/* Print Help and quit */
+			print_help_usage();
+			break;
 		case 'M':
 			xtables_modprobe_program = optarg;
 			break;
+		case 'z':
+			rst_chain_counters = 1;
+			break;
 		case 'f':
 			file = fopen(optarg, "w");
 			if (file == NULL) {