extensions: S/DNPT: add missing save function

Jean-Michel DILLY reports that `ip6tables -S` exits with

	Target `DNPT' is missing save function

when a DNPT rule is invoked. Fix this omission.

References: http://marc.info/?l=netfilter&m=135904831220440&w=2
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
diff --git a/extensions/libip6t_DNPT.c b/extensions/libip6t_DNPT.c
index 7439816..703adf6 100644
--- a/extensions/libip6t_DNPT.c
+++ b/extensions/libip6t_DNPT.c
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <string.h>
 #include <xtables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_NPT.h>
@@ -53,6 +54,23 @@
 				 npt->dst_pfx_len);
 }
 
+static void DNPT_save(const void *ip, const struct xt_entry_target *target)
+{
+	static const struct in6_addr zero_addr;
+	const struct ip6t_npt_tginfo *info = (const void *)target->data;
+
+	if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
+	    info->src_pfx_len != 0)
+		printf("--src-pfx %s/%u ",
+		       xtables_ip6addr_to_numeric(&info->src_pfx.in6),
+		       info->src_pfx_len);
+	if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
+	    info->dst_pfx_len != 0)
+		printf("--dst-pfx %s/%u ",
+		       xtables_ip6addr_to_numeric(&info->dst_pfx.in6),
+		       info->dst_pfx_len);
+}
+
 static struct xtables_target snpt_tg_reg = {
 	.name		= "DNPT",
 	.version	= XTABLES_VERSION,
@@ -62,6 +80,7 @@
 	.help		= DNPT_help,
 	.x6_parse	= DNPT_parse,
 	.print		= DNPT_print,
+	.save		= DNPT_save,
 	.x6_options	= DNPT_options,
 };
 
diff --git a/extensions/libip6t_SNPT.c b/extensions/libip6t_SNPT.c
index 26a86c5..7ed80b2 100644
--- a/extensions/libip6t_SNPT.c
+++ b/extensions/libip6t_SNPT.c
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <string.h>
 #include <xtables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter_ipv6/ip6t_NPT.h>
@@ -53,6 +54,23 @@
 				 npt->dst_pfx_len);
 }
 
+static void SNPT_save(const void *ip, const struct xt_entry_target *target)
+{
+	static const struct in6_addr zero_addr;
+	const struct ip6t_npt_tginfo *info = (const void *)target->data;
+
+	if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
+	    info->src_pfx_len != 0)
+		printf("--src-pfx %s/%u ",
+		       xtables_ip6addr_to_numeric(&info->src_pfx.in6),
+		       info->src_pfx_len);
+	if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
+	    info->dst_pfx_len != 0)
+		printf("--dst-pfx %s/%u ",
+		       xtables_ip6addr_to_numeric(&info->dst_pfx.in6),
+		       info->dst_pfx_len);
+}
+
 static struct xtables_target snpt_tg_reg = {
 	.name		= "SNPT",
 	.version	= XTABLES_VERSION,
@@ -62,6 +80,7 @@
 	.help		= SNPT_help,
 	.x6_parse	= SNPT_parse,
 	.print		= SNPT_print,
+	.save		= SNPT_save,
 	.x6_options	= SNPT_options,
 };