[PATCH 2/3] conntrackd: cthelper: ftp: Fix debug print

2016-08-31 Thread Kevin Cernekee
matchoff is relative to dataoff, i.e. matchoff=0 (as utilized by
nfq_tcp_mangle_ipv4()) points to the first byte of the TCP payload.

Signed-off-by: Kevin Cernekee 
---
 src/helpers/ftp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/helpers/ftp.c b/src/helpers/ftp.c
index 3da6e56..27ab5eb 100644
--- a/src/helpers/ftp.c
+++ b/src/helpers/ftp.c
@@ -511,7 +511,7 @@ ftp_helper_cb(struct pkt_buff *pkt, uint32_t protoff,
goto out_update_nl;
 
pr_debug("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
-matchlen, pktb_network_header(pkt) + matchoff,
+matchlen, pktb_network_header(pkt) + dataoff + matchoff,
 matchlen, ntohl(th->seq) + matchoff);
 
/* We refer to the reverse direction ("!dir") tuples here,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/3] conntrackd: cthelper: ftp: Set match offset/len for PORT mangling

2016-08-31 Thread Kevin Cernekee
Currently matchoff and matchlen are 0, so IP mangling is performed in
the wrong place if NAT is used:

FTP_NAT: type 0, off 0 len 0

The resultant packet is clearly incorrect:

0x:  9410 3eb8 00ab 00e0 4c68 0012 0800 4510  ..>.LhE.
0x0010:  0081 9ed9 4000 4006 cd35 646b 0370 646b  @.@..5dk.pdk
0x0020:  0212 0015 87c5 8cc2 de50 aa28 4842 8018  .P.(HB..
0x0030:  00e3 459d  0101 080a e916 985e 2a3b  ..E..^*;
0x0040:  b82d 3530 3020 2731 3030 2c31 3037 2c32  .-500.'100,107,2
0x0050:  2c31 382c 3134 392c 3739 504f 5254 2031  ,18,149,79PORT.1
0x0060:  3932 2c31 3638 2c32 3534 2c32 2c31 3439  92,168,254,2,149
0x0070:  2c37 3927 3a20 636f 6d6d 616e 6420 6e6f  ,79':.command.no
0x0080:  7420 756e 6465 7273 746f 6f64 2e0d 0at.understood...

Add the missing assignments.

Signed-off-by: Kevin Cernekee 
---
 src/helpers/ftp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/helpers/ftp.c b/src/helpers/ftp.c
index 24ee877..3da6e56 100644
--- a/src/helpers/ftp.c
+++ b/src/helpers/ftp.c
@@ -293,6 +293,9 @@ static int ftp_find_pattern(struct pkt_buff *pkt,
if (!numlen)
return 0;
 
+   *matchoff = i;
+   *matchlen = numlen;
+
pr_debug("Match succeded!\n");
return 1;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[RFC 3/3] conntrackd: cthelper: ssdp: Track UPnP eventing

2016-08-31 Thread Kevin Cernekee
The UPnP Device Architecture spec provides a way for devices to connect
back to control points, called "Eventing" (chapter 4).  This sequence can
look something like:

1) Outbound multicast M-SEARCH packet (dst: 1900/udp)
 - Create expectation for unicast reply from  to source port

2) Inbound unicast reply (there may be several of these from different devices)
 - Find the device's URL, e.g.
   LOCATION: http://192.168.1.123:1400/xml/device_description.xml
 - Create expectation to track connections to this host:port (tcp)

3) Outbound connection to device's web server (there will be several of these)
 - Watch for a SUBSCRIBE request
 - Find the control point's callback URL, e.g.
   CALLBACK: 
 - Create expectation to open up inbound connections to this host:port

4) Inbound connection to control point's web server
 - Once this is complete, the subscription should work

Add the necessary code to add expectations for each of these connections
and rewrite the IP in the CALLBACK URL.

Signed-off-by: Kevin Cernekee 
---


This needs more testing on my end, so I'm posting it as an RFC to solicit
preliminary feedback.


 doc/helper/conntrackd.conf |  10 +-
 src/helpers/ssdp.c | 400 -
 2 files changed, 403 insertions(+), 7 deletions(-)

diff --git a/doc/helper/conntrackd.conf b/doc/helper/conntrackd.conf
index 5c07509..ec24e2a 100644
--- a/doc/helper/conntrackd.conf
+++ b/doc/helper/conntrackd.conf
@@ -74,7 +74,15 @@ Helper {
QueueNum 5
QueueLen 10240
Policy ssdp {
-   ExpectMax 1
+   ExpectMax 8
+   ExpectTimeout 300
+   }
+   }
+   Type ssdp inet tcp {
+   QueueNum 5
+   QueueLen 10240
+   Policy ssdp {
+   ExpectMax 8
ExpectTimeout 300
}
}
diff --git a/src/helpers/ssdp.c b/src/helpers/ssdp.c
index bc41087..d9c9a5a 100644
--- a/src/helpers/ssdp.c
+++ b/src/helpers/ssdp.c
@@ -1,5 +1,5 @@
 /*
- * SSDP connection tracking helper
+ * SSDP/UPnP connection tracking helper
  * (SSDP = Simple Service Discovery Protocol)
  * For documentation about SSDP see
  * http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol
@@ -8,6 +8,18 @@
  * Based on the SSDP conntrack helper (nf_conntrack_ssdp.c),
  * :http://marc.info/?t=13294577511&r=1&w=2
  *  (C) 2012 Ian Pilcher 
+ * Copyright (C) 2016 Google Inc.
+ *
+ * This requires Linux 3.12 or higher.  Usage:
+ *
+ * nfct add helper ssdp inet udp
+ * nfct add helper ssdp inet tcp
+ * iptables -t raw -A OUTPUT -p udp --dport 1900 -j CT --helper ssdp
+ * iptables -t raw -A PREROUTING -p udp --dport 1900 -j CT --helper ssdp
+ *
+ * This helper supports SNAT when used in conjunction with a daemon that
+ * forwards SSDP broadcasts/replies between interfaces, e.g.
+ * 
https://chromium.googlesource.com/chromiumos/platform2/+/master/arc-networkd/multicast_forwarder.h
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,8 +31,10 @@
 #include "myct.h"
 #include "log.h"
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -36,8 +50,94 @@
 #define SSDP_M_SEARCH  "M-SEARCH"
 #define SSDP_M_SEARCH_SIZE (sizeof SSDP_M_SEARCH - 1)
 
-static int ssdp_helper_cb(struct pkt_buff *pkt, uint32_t protoff,
- struct myct *myct, uint32_t ctinfo)
+/* So, this packet has hit the connection tracking matching code.
+   Mangle it, and change the expectation to match the new version. */
+static unsigned int nf_nat_ssdp(struct pkt_buff *pkt,
+   int ctinfo,
+   unsigned int matchoff,
+   unsigned int matchlen,
+   struct nf_conntrack *ct,
+   struct nf_expect *exp)
+{
+   union nfct_attr_grp_addr newip;
+   uint16_t port;
+   int dir = CTINFO2DIR(ctinfo);
+   char buffer[sizeof("255.255.255.255:65535")];
+   unsigned int buflen;
+   const struct nf_conntrack *expected;
+   struct nf_conntrack *nat_tuple;
+   uint16_t initial_port;
+
+   /* Connection will come from wherever this packet goes, hence !dir */
+   cthelper_get_addr_dst(ct, !dir, &newip);
+
+   expected = nfexp_get_attr(exp, ATTR_EXP_EXPECTED);
+
+   nat_tuple = nfct_new();
+   if (nat_tuple == NULL)
+   return NF_ACCEPT;
+
+   initial_port = nfct_get_attr_u16(expected, ATTR_PORT_DST);
+
+   nfexp_set_attr_u32(exp, ATTR_EXP_NAT_DIR, !dir);
+
+   /* libnetfilter_conntrack needs this */
+   nfct_set_attr_u8(nat_tuple, ATTR_L3PROTO, AF_INET);
+   nfct_set_attr_u32(nat_tuple, ATTR_IPV4_SRC, 0);
+   nfct_set_attr_u32(nat_t

Re: [PATCH nf-next] netfilter: ftp: Remove the useless dlen==0 condition check in find_pattern

2016-08-31 Thread Feng Gao
On Thu, Sep 1, 2016 at 10:14 AM,   wrote:
> From: Gao Feng 
>
> The caller function "help" has already make sure the datalen could not be zero
> before invoke find_pattern as a parameter by the following codes
>
> if (dataoff >= skb->len) {
> pr_debug("ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
>  skb->len);
> return NF_ACCEPT;
> }
> datalen = skb->len - dataoff;
>
> And the latter codes "ends_in_nl = (fb_ptr[datalen - 1] == '\n');" use datalen
> directly without checking if it is zero.
>
> So it is unneccessary to check it in find_pattern too.
>
> Signed-off-by: Gao Feng 
> ---
>  net/netfilter/nf_conntrack_ftp.c | 12 
>  1 file changed, 12 deletions(-)
>
> diff --git a/net/netfilter/nf_conntrack_ftp.c 
> b/net/netfilter/nf_conntrack_ftp.c
> index b6934b5..77f05ac 100644
> --- a/net/netfilter/nf_conntrack_ftp.c
> +++ b/net/netfilter/nf_conntrack_ftp.c
> @@ -301,8 +301,6 @@ static int find_pattern(const char *data, size_t dlen,
> size_t i = plen;
>
> pr_debug("find_pattern `%s': dlen = %Zu\n", pattern, dlen);
> -   if (dlen == 0)
> -   return 0;
>
> if (dlen <= plen) {
> /* Short packet: try for partial? */
> @@ -312,16 +310,6 @@ static int find_pattern(const char *data, size_t dlen,
> }
>
> if (strncasecmp(data, pattern, plen) != 0) {
> -#if 0
> -   size_t i;
> -
> -   pr_debug("ftp: string mismatch\n");
> -   for (i = 0; i < plen; i++) {
> -   pr_debug("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
> -i, data[i], data[i],
> -pattern[i], pattern[i]);
> -   }
> -#endif
> return 0;
> }
>
> --
> 1.9.1
>
>

Sorry, I forget one point. I also remove some codes which are
commented out by #if0.

Regards
Feng
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH nf-next] netfilter: ftp: Remove the useless dlen==0 condition check in find_pattern

2016-08-31 Thread fgao
From: Gao Feng 

The caller function "help" has already make sure the datalen could not be zero
before invoke find_pattern as a parameter by the following codes

if (dataoff >= skb->len) {
pr_debug("ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
 skb->len);
return NF_ACCEPT;
}
datalen = skb->len - dataoff;

And the latter codes "ends_in_nl = (fb_ptr[datalen - 1] == '\n');" use datalen
directly without checking if it is zero.

So it is unneccessary to check it in find_pattern too.

Signed-off-by: Gao Feng 
---
 net/netfilter/nf_conntrack_ftp.c | 12 
 1 file changed, 12 deletions(-)

diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index b6934b5..77f05ac 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -301,8 +301,6 @@ static int find_pattern(const char *data, size_t dlen,
size_t i = plen;
 
pr_debug("find_pattern `%s': dlen = %Zu\n", pattern, dlen);
-   if (dlen == 0)
-   return 0;
 
if (dlen <= plen) {
/* Short packet: try for partial? */
@@ -312,16 +310,6 @@ static int find_pattern(const char *data, size_t dlen,
}
 
if (strncasecmp(data, pattern, plen) != 0) {
-#if 0
-   size_t i;
-
-   pr_debug("ftp: string mismatch\n");
-   for (i = 0; i < plen; i++) {
-   pr_debug("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
-i, data[i], data[i],
-pattern[i], pattern[i]);
-   }
-#endif
return 0;
}
 
-- 
1.9.1


--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH nft] evaluate: display expression, statement and command name on debug

2016-08-31 Thread Pablo Neira Ayuso
Extend debugging knob for evaluation to display the command, the
expression and statement names.

 # nft --debug=eval add rule x y ip saddr 1.1.1.1 counter
 :1:1-37: Evaluate add
 add rule x y ip saddr 1.1.1.1 counter
 ^

 :1:14-29: Evaluate expression
 add rule x y ip saddr 1.1.1.1 counter
  
 ip saddr $1.1.1.1

 :1:14-29: Evaluate relational
 add rule x y ip saddr 1.1.1.1 counter
  
 ip saddr $1.1.1.1

 :1:14-21: Evaluate payload
 add rule x y ip saddr 1.1.1.1 counter
  
 ip saddr

 :1:23-29: Evaluate symbol
 add rule x y ip saddr 1.1.1.1 counter
   ^^^

 :1:23-29: Evaluate value
 add rule x y ip saddr 1.1.1.1 counter
   ^^^
 1.1.1.1

 :1:31-37: Evaluate counter
 add rule x y ip saddr 1.1.1.1 counter
   ^^^
 counter packets 0 bytes 0

Signed-off-by: Pablo Neira Ayuso 
---
 src/evaluate.c | 34 +++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 7eb28f2..89e40ca 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1585,7 +1585,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct 
expr **expr)
 #ifdef DEBUG
if (debug_level & DEBUG_EVALUATION) {
struct error_record *erec;
-   erec = erec_create(EREC_INFORMATIONAL, &(*expr)->location, 
"Evaluate");
+   erec = erec_create(EREC_INFORMATIONAL, &(*expr)->location,
+  "Evaluate %s", (*expr)->ops->name);
erec_print(stdout, erec); expr_print(*expr); printf("\n\n");
}
 #endif
@@ -2430,7 +2431,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 #ifdef DEBUG
if (debug_level & DEBUG_EVALUATION) {
struct error_record *erec;
-   erec = erec_create(EREC_INFORMATIONAL, &stmt->location, 
"Evaluate");
+   erec = erec_create(EREC_INFORMATIONAL, &stmt->location,
+  "Evaluate %s", stmt->ops->name);
erec_print(stdout, erec); stmt_print(stmt); printf("\n\n");
}
 #endif
@@ -2932,12 +2934,38 @@ static int cmd_evaluate_export(struct eval_ctx *ctx, 
struct cmd *cmd)
return cache_update(cmd->op, ctx->msgs);
 }
 
+#ifdef DEBUG
+static const char *cmd_op_name[] = {
+   [CMD_INVALID]   = "invalid",
+   [CMD_ADD]   = "add",
+   [CMD_REPLACE]   = "replace",
+   [CMD_CREATE]= "create",
+   [CMD_INSERT]= "insert",
+   [CMD_DELETE]= "delete",
+   [CMD_LIST]  = "list",
+   [CMD_FLUSH] = "flush",
+   [CMD_RENAME]= "rename",
+   [CMD_EXPORT]= "export",
+   [CMD_MONITOR]   = "monitor",
+   [CMD_DESCRIBE]  = "describe",
+};
+
+static const char *cmd_op_to_name(enum cmd_ops op)
+{
+   if (op > CMD_DESCRIBE)
+   return "unknown";
+
+   return cmd_op_name[op];
+}
+#endif
+
 int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
 {
 #ifdef DEBUG
if (debug_level & DEBUG_EVALUATION) {
struct error_record *erec;
-   erec = erec_create(EREC_INFORMATIONAL, &cmd->location, 
"Evaluate");
+   erec = erec_create(EREC_INFORMATIONAL, &cmd->location,
+  "Evaluate %s", cmd_op_to_name(cmd->op));
erec_print(stdout, erec); printf("\n\n");
}
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 5/5] net/netfilter/nf_conntrack_core: update memory barriers.

2016-08-31 Thread Eric Dumazet
On Wed, 2016-08-31 at 15:42 +0200, Manfred Spraul wrote:
> As explained in commit 51d7d5205d33
> ("powerpc: Add smp_mb() to arch_spin_is_locked()", for some architectures
> the ACQUIRE during spin_lock only applies to loading the lock, not to
> storing the lock state.
> 
> nf_conntrack_lock() does not handle this correctly:
> /* 1) Acquire the lock */
> spin_lock(lock);
> while (unlikely(nf_conntrack_locks_all)) {
> spin_unlock(lock);
> 
> spinlock_store_acquire() is missing between spin_lock and reading
> nf_conntrack_locks_all. In addition, reading nf_conntrack_locks_all
> needs ACQUIRE memory ordering.
> 
> 2nd, minor issue: If there would be many nf_conntrack_all_lock() callers,
> then nf_conntrack_lock() would loop forever.
> 
> Therefore: Change nf_conntrack_lock and nf_conntract_lock_all() to the
> approach used by ipc/sem.c:
> 
> - add spinlock_store_acquire()
> - add smp_load_acquire()
> - for nf_conntrack_lock, use spin_lock(&global_lock) instead of
>   spin_unlock_wait(&global_lock) and loop backward.
> - use smp_store_mb() instead of a raw smp_mb()
> 
> Signed-off-by: Manfred Spraul 
> Cc: Pablo Neira Ayuso 
> Cc: netfilter-devel@vger.kernel.org
> 
> ---
> 
> Question: Should I split this patch?
> First a patch that uses smp_mb(), with Cc: stable.
> The replace the smp_mb() with spinlock_store_acquire, not for stable

I guess it all depends on stable backports you believe are needed.

You probably should add the tags :
Fixes: <12-digit-sha1> "patch title"
that introduced the bug(s) you fix.

By doing this archaeological research you will likely have a better
answer ?

Thanks !


--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/5] net/netfilter/nf_conntrack_core: update memory barriers.

2016-08-31 Thread Manfred Spraul
As explained in commit 51d7d5205d33
("powerpc: Add smp_mb() to arch_spin_is_locked()", for some architectures
the ACQUIRE during spin_lock only applies to loading the lock, not to
storing the lock state.

nf_conntrack_lock() does not handle this correctly:
/* 1) Acquire the lock */
spin_lock(lock);
while (unlikely(nf_conntrack_locks_all)) {
spin_unlock(lock);

spinlock_store_acquire() is missing between spin_lock and reading
nf_conntrack_locks_all. In addition, reading nf_conntrack_locks_all
needs ACQUIRE memory ordering.

2nd, minor issue: If there would be many nf_conntrack_all_lock() callers,
then nf_conntrack_lock() would loop forever.

Therefore: Change nf_conntrack_lock and nf_conntract_lock_all() to the
approach used by ipc/sem.c:

- add spinlock_store_acquire()
- add smp_load_acquire()
- for nf_conntrack_lock, use spin_lock(&global_lock) instead of
  spin_unlock_wait(&global_lock) and loop backward.
- use smp_store_mb() instead of a raw smp_mb()

Signed-off-by: Manfred Spraul 
Cc: Pablo Neira Ayuso 
Cc: netfilter-devel@vger.kernel.org

---

Question: Should I split this patch?
First a patch that uses smp_mb(), with Cc: stable.
The replace the smp_mb() with spinlock_store_acquire, not for stable

 net/netfilter/nf_conntrack_core.c | 36 ++--
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/net/netfilter/nf_conntrack_core.c 
b/net/netfilter/nf_conntrack_core.c
index 7d90a5d..f840b0b 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -79,20 +79,29 @@ static __read_mostly bool nf_conntrack_locks_all;
 
 void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
 {
+   /* 1) Acquire the lock */
spin_lock(lock);
-   while (unlikely(nf_conntrack_locks_all)) {
-   spin_unlock(lock);
 
-   /*
-* Order the 'nf_conntrack_locks_all' load vs. the
-* spin_unlock_wait() loads below, to ensure
-* that 'nf_conntrack_locks_all_lock' is indeed held:
-*/
-   smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-   spin_unlock_wait(&nf_conntrack_locks_all_lock);
-   spin_lock(lock);
-   }
+   /* 2) Order storing the lock and reading nf_conntrack_locks_all */
+   spinlock_store_acquire();
+
+   /* 3) read nf_conntrack_locks_all, with ACQUIRE semantics */
+   if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
+   return;
+
+   /* fast path failed, unlock */
+   spin_unlock(lock);
+
+   /* Slow path 1) get global lock */
+   spin_lock(&nf_conntrack_locks_all_lock);
+
+   /* Slow path 2) get the lock we want */
+   spin_lock(lock);
+
+   /* Slow path 3) release the global lock */
+   spin_unlock(&nf_conntrack_locks_all_lock);
 }
+
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
 static void nf_conntrack_double_unlock(unsigned int h1, unsigned int h2)
@@ -132,15 +141,14 @@ static void nf_conntrack_all_lock(void)
int i;
 
spin_lock(&nf_conntrack_locks_all_lock);
-   nf_conntrack_locks_all = true;
 
/*
-* Order the above store of 'nf_conntrack_locks_all' against
+* Order the store of 'nf_conntrack_locks_all' against
 * the spin_unlock_wait() loads below, such that if
 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
 * we must observe nf_conntrack_locks[] held:
 */
-   smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
+   smp_store_mb(nf_conntrack_locks_all, true);
 
for (i = 0; i < CONNTRACK_LOCKS; i++) {
spin_unlock_wait(&nf_conntrack_locks[i]);
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH iptables v3] xtables-translate-restore: do not escape quotes

2016-08-31 Thread Pablo M. Bermudo Garay
If quotes are escaped, nft -f is unable to parse and load the translated
ruleset.

Signed-off-by: Pablo M. Bermudo Garay 
---

Changes in v3:
  - Add a new field to the iptables_command_state struct instead of
propagate 'bool restore' argument.

 iptables/xshared.h   | 1 +
 iptables/xtables-translate.c | 6 --
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/iptables/xshared.h b/iptables/xshared.h
index 6eb8eb8..18b1cf3 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -63,6 +63,7 @@ struct iptables_command_state {
int proto_used;
const char *jumpto;
char **argv;
+   bool restore;
 };
 
 typedef int (*mainfunc_t)(int, char **);
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 3c577ed..689533f 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -70,7 +70,7 @@ int xlate_action(const struct iptables_command_state *cs, 
bool goto_set,
.ip = (const void *)&cs->fw,
.target = cs->target->t,
.numeric= numeric,
-   .escape_quotes  = true,
+   .escape_quotes  = !cs->restore,
};
ret = cs->target->xlate(xl, ¶ms);
}
@@ -97,7 +97,7 @@ int xlate_matches(const struct iptables_command_state *cs, 
struct xt_xlate *xl)
.ip = (const void *)&cs->fw,
.match  = matchp->match->m,
.numeric= numeric,
-   .escape_quotes  = true,
+   .escape_quotes  = !cs->restore,
};
 
if (!matchp->match->xlate)
@@ -226,6 +226,8 @@ static int do_command_xlate(struct nft_handle *h, int argc, 
char *argv[],
 
do_parse(h, argc, argv, &p, &cs, &args);
 
+   cs.restore = restore;
+
if (!restore)
printf("nft ");
 
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html