Hi,

this is my first submission to the list and I hope that I'm doing in the
right way. :-)


Well, the features added to Network Address Translator are:

1) Allow the user to use the string "localhost" on the client-nat network
configuration in a way that is not necessary to inform the IP address
beforehand. Openvpn will set the dynamic received IP from DHCP.
Example:

client-nat snat localhost 255.255.255.255 172.20.1.15 # replaces the
'localhost' string with the DHCP address received from openvpn server.

2) Allow the user to enable the FTP NAT support through the
--enable-nat-ftp-support option.
This is useful for systems that don't have conntrack-tools support, for
example on Windows systems. On windows this feature is enabled by default.

enable-nat-ftp-support (yes | no)


The following patch was written based on release/2.3 branch.
--------------------------------------------------------------------------------------------------------------------------------------

>From d11957a025dc6c113874e7b04ce4c8e9513c3b02 Mon Sep 17 00:00:00 2001
From: venturus <venturus@venturus-virtual-machine.(none)>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Thu, 13 Aug 2015 08:26:36 -0300
Subject: [PATCH] Replaces the client-nat network string 'localhost' with the
 dynamic IP set to the tun/tap interface by the openvpn
 server. Example:

--client-nat snat localhost 255.255.255.255 172.20.1.15 # replaces the
'localhost' string with the DHCP address received from openvpn server.

Signed-off-by: Rafael Gava <rafael.olive...@venturus.org.br>
---
 src/openvpn/clinat.c |   57
++++++++++++++++++++++++++++++++++++++++++--------
 src/openvpn/clinat.h |    2 ++
 src/openvpn/init.c   |    4 ++++
 3 files changed, 54 insertions(+), 9 deletions(-)
 mode change 100644 => 100755 src/openvpn/clinat.c
 mode change 100644 => 100755 src/openvpn/clinat.h
 mode change 100644 => 100755 src/openvpn/init.c

diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
old mode 100644
new mode 100755
index af75fc9..2460185
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -107,11 +107,11 @@ copy_client_nat_option_list (struct
client_nat_option_list *dest,

 void
 add_client_nat_to_option_list (struct client_nat_option_list *dest,
-      const char *type,
-      const char *network,
-      const char *netmask,
-      const char *foreign_network,
-      int msglevel)
+            const char *type,
+            const char *network,
+            const char *netmask,
+            const char *foreign_network,
+            int msglevel)
 {
   struct client_nat_entry e;
   bool ok;
@@ -126,12 +126,19 @@ add_client_nat_to_option_list (struct
client_nat_option_list *dest,
       return;
     }

-  e.network = getaddr(0, network, 0, &ok, NULL);
-  if (!ok)
+  if (network && !strcmp(network, "localhost"))
     {
-      msg(msglevel, "client-nat: bad network: %s", network);
-      return;
+      msg (M_INFO, "*** client-nat localhost detected...");
+      e.network = 0xFFFFFFFF;
+    } else {
+      e.network = getaddr(0, network, 0, &ok, NULL);
+      if (!ok)
+      {
+        msg(msglevel, "client-nat: bad network: %s", network);
+        return;
+      }
     }
+
   e.netmask = getaddr(0, netmask, 0, &ok, NULL);
   if (!ok)
     {
@@ -148,6 +155,7 @@ add_client_nat_to_option_list (struct
client_nat_option_list *dest,
   add_entry(dest, &e);
 }

+
 #if 0
 static void
 print_checksum (struct openvpn_iphdr *iph, const char *prefix)
@@ -266,4 +274,35 @@ client_nat_transform (const struct
client_nat_option_list *list,
     }
 }

+/*
+* Replaces the localhost token with the IP received from OpenVPN
+*/
+bool
+update_localhost_nat(struct client_nat_option_list *dest, in_addr_t
local_ip)
+{
+  int i;
+  bool ret = false;
+
+  if (!dest)
+    return ret;
+
+  for (i=0; i <= dest->n; i++)
+    {
+      struct client_nat_entry *nat_entry = &dest->entries[i];
+      if (nat_entry && nat_entry->network == 0xFFFFFFFF)
+        {
+          struct in_addr addr;
+
+          nat_entry->network = ntohl(local_ip);
+          addr.s_addr = nat_entry->network;
+          char *dot_ip = inet_ntoa(addr);
+
+          msg (M_INFO, "Updating NAT table from localhost to: %s",
dot_ip);
+          ret = true;
+        }
+    }
+
+  return ret;
+}
+
 #endif
diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h
old mode 100644
new mode 100755
index d55a727..ce995d9
--- a/src/openvpn/clinat.h
+++ b/src/openvpn/clinat.h
@@ -62,4 +62,6 @@ void client_nat_transform (const struct
client_nat_option_list *list,
    struct buffer *ipbuf,
    const int direction);

+bool update_localhost_nat(struct client_nat_option_list *dest, in_addr_t
local_ip);
+
 #endif
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
old mode 100644
new mode 100755
index 71c91a2..4a63ee8
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1476,6 +1476,10 @@ do_open_tun (struct context *c)
        c->c1.tuntap->post_open_mtu,
        SET_MTU_TUN | SET_MTU_UPPER_BOUND);

+#ifdef ENABLE_CLIENT_NAT
+      update_localhost_nat(c->options.client_nat, c->c1.tuntap->local);
+#endif
+
       ret = true;
       static_context = c;
     }
-- 
1.7.9.5


>From 18b1411689df67feafeb15630c3519ab2cbd42d4 Mon Sep 17 00:00:00 2001
From: Rafael Gava <rafael.olive...@venturus.org.br>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Fri, 14 Aug 2015 15:27:50 -0300
Subject: [PATCH] Added FTP NAT support. This feature can be enabled via
 --enable-nat-ftp-support option.


Signed-off-by: Rafael Gava <rafael.olive...@venturus.org.br>
---
 src/openvpn/clinat.c  |  773
++++++++++++++++++++++++++++++++++++++++++++++---
 src/openvpn/clinat.h  |   15 +-
 src/openvpn/forward.c |   75 ++---
 src/openvpn/options.c |   12 +
 src/openvpn/options.h |    1 +
 5 files changed, 787 insertions(+), 89 deletions(-)
 mode change 100644 => 100755 src/openvpn/forward.c
 mode change 100644 => 100755 src/openvpn/options.c
 mode change 100644 => 100755 src/openvpn/options.h

diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
index 2460185..1d213f5 100755
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -36,6 +36,159 @@
 #include "proto.h"
 #include "socket.h"
 #include "memdbg.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+/* Delta Table Types */
+
+typedef struct delta_table_key {
+  uint32_t src_addr;
+  uint32_t dest_addr;
+  uint16_t src_port;
+  uint16_t dest_port;
+} delta_table_key_t;
+
+typedef struct delta_table_entry {
+  delta_table_key_t key;
+  uint16_t delta_out;
+  uint16_t delta_in;
+  uint8_t marked_to_remove;
+  uint8_t reserved[3];
+  uint32_t timestamp;
+  struct delta_table_entry *_next;
+} delta_table_entry_t;
+
+typedef struct delta_table {
+    struct delta_table_entry *head;
+} delta_table_t;
+
+
+// Global delta table
+//#define DEBUG_DELTA 1
+
+delta_table_t *table = NULL;
+
+#define TIME_TO_RESPOND 60 * 5 // 5 Minutes
+#define TIME_TO_LIVE 24 * 60 * 60
+
+/* Delta Table Functions */
+
+// In seconds, since epoch
+static uint32_t
+get_timestamp() {
+  return (uint32_t)time(NULL);
+}
+
+static void
+print_delta_table_entries(delta_table_t *table) {
+    delta_table_entry_t *current = table->head;
+
+  if (current == NULL) {
+    return;
+  }
+
+  while (current != NULL) {
+    printf("from %d -> to %d: removed: %s, timestamp: %d, delta_out: %d,
delta_in: %d\n",
+      current->key.src_addr, current->key.dest_addr,
current->marked_to_remove ? "true" : "false",
+      current->timestamp, current->delta_out, current->delta_in);
+    current = current->_next;
+  }
+}
+
+static struct delta_table *
+init_delta_table() {
+  delta_table_t *table = malloc(sizeof(delta_table_t));
+  table->head = NULL;
+  return table;
+}
+
+static struct delta_table_entry *
+add_delta_entry(delta_table_t *table, delta_table_entry_t
*new_delta_entry) {
+  if (table->head == NULL) {
+    table->head = new_delta_entry;
+    table->head->_next = NULL;
+  } else {
+    // Add element to HEAD, for performance gain
+    new_delta_entry->_next = table->head;
+    table->head = new_delta_entry;
+  }
+  return new_delta_entry;
+}
+
+static int
+remove_delta_entry(delta_table_t *table, delta_table_entry_t *delta_entry)
{
+  delta_table_entry_t *current = table->head;
+  delta_table_entry_t *before = NULL;
+  uint8_t found = 0;
+
+  //msg (M_INFO, "On remove_delta_entry - entry: %p", &delta_entry);
+
+  while (current != NULL) {
+    if(current == delta_entry) {
+      found = 1;
+      break;
+    }
+    before = current;
+    current = current->_next;
+  }
+
+  //Element not found
+  if (!found) {
+    return 0;
+  }
+
+  if(before==NULL){
+    table->head = table->head->_next;
+  } else {
+    before->_next = delta_entry->_next;
+  }
+
+  //msg (M_INFO, "On remove_delta_entry - entry: %p - freed",
&delta_entry);
+
+  free(delta_entry);
+  return 1;
+}
+
+static struct delta_table_entry *
+get_delta_entry(delta_table_t *table, delta_table_key_t key) {
+  delta_table_entry_t *current = table->head;
+  delta_table_entry_t *aux = NULL;
+  delta_table_entry_t *el = NULL;
+
+  while (current != NULL) {
+    // Check TTL and Timeout
+    if ((current->marked_to_remove && get_timestamp() - current->timestamp
>= TIME_TO_RESPOND) /* ||  get_timestamp() - current->timestamp >=
TIME_TO_LIVE */){
+      aux = current;
+      //If the CURRENT is to be removed, then dont return it
+      if (aux == el) {
+        el = NULL;
+      }
+      current = current->_next;
+      remove_delta_entry(table, aux);
+    } else {
+      if ((
+        // Regular connection
+        (current->key.src_addr == key.src_addr &&
+         current->key.src_port == key.src_port &&
+         current->key.dest_addr == key.dest_addr &&
+         current->key.dest_port == key.dest_port) ||
+        //Check if it is a returned connection
+        (current->key.dest_addr == key.src_addr &&
+         current->key.dest_port == key.src_port &&
+         current->key.src_addr == key.dest_addr &&
+         current->key.src_port == key.dest_port))) {
+        el = current;
+      }
+      current = current->_next;
+    }
+  }
+
+  return el;
+}
+
+/* Delta Table Functions End */
+

 static bool
 add_entry(struct client_nat_option_list *dest,
@@ -192,19 +345,533 @@ print_pkt (struct openvpn_iphdr *iph, const char
*prefix, const int direction, c
   gc_free (&gc);
 }

+#if DEBUG_DELTA
+
+#ifndef HEXDUMP_COLS
+#define HEXDUMP_COLS 8
+#endif
+
+static void hexdump(void *mem, unsigned int len)
+{
+  unsigned int i, j;
+
+  for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len %
HEXDUMP_COLS) : 0); i++)
+  {
+    /* print offset */
+    if(i % HEXDUMP_COLS == 0)
+    {
+      printf("0x%06x: ", i);
+    }
+
+    /* print hex data */
+    if(i < len)
+    {
+      printf("%02x ", 0xFF & ((char*)mem)[i]);
+    }
+    else /* end of block, just aligning for ASCII dump */
+    {
+      printf("   ");
+    }
+
+    /* print ASCII dump */
+    if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
+    {
+      for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
+      {
+        unsigned char ch = 0xFF & ((char*)mem)[j];
+
+        if(j >= len) /* end of block, not really printing */
+        {
+          putchar(' ');
+        }
+        else if (ch >= 0x80)
+        {
+          putchar('.');
+        }
+        else if(isprint(((char*)mem)[j])) /* printable char */
+        {
+          putchar(0xFF & ((char*)mem)[j]);
+        }
+        else /* other char */
+        {
+          putchar('.');
+        }
+      }
+      putchar('\n');
+    }
+  }
+}
+#endif
+
+static int try_number(const char *data, size_t dlen, uint32_t array[],
+          int array_size, char sep, char term)
+{
+  uint32_t i, len;
+
+  memset(array, 0, sizeof(array[0])*array_size);
+
+  /* Keep data pointing at next char. */
+  for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) {
+    if (*data >= '0' && *data <= '9') {
+      array[i] = array[i]*10 + *data - '0';
+    }
+    else if (*data == sep)
+      i++;
+    else {
+      /* Unexpected character; true if it's the
+         terminator and we're finished. */
+      if (*data == term && i == array_size - 1)
+        return len;
+
+      msg (M_ERRNO, "CNAT - try_number - Char %u (got %u nums) `%u'
unexpected\n", len, i, *data);
+      return 0;
+    }
+  }
+
+  msg (M_ERRNO, "CNAT - ERROR: Failed to fill %u numbers separated by
%c\n", array_size, sep);
+
+  return 0;
+}
+
+static int try_rfc959(const char *, size_t, u_int32_t [], char);
+
+static struct ftp_search {
+  int direction;
+  const char *pattern;
+  size_t plen;
+  char skip;
+  char term;
+  int (*getnum)(const char *, size_t, u_int32_t[], char);
+} search[] = {
+  {
+    CN_OUTGOING,
+    "PORT",  sizeof("PORT") - 1, ' ', '\r',
+    try_rfc959,
+  },
+  {
+    CN_INCOMING,
+    "227 ",  sizeof("227 ") - 1, '(', ')',
+    try_rfc959,
+  },
+};
+
+
+/* Returns 0, or length of numbers: 192,168,1,1,5,6 */
+static int
+try_rfc959(const char *data, size_t dlen, u_int32_t array[6],
+           char term)
+{
+  return try_number(data, dlen, array, 6, ',', term);
+}
+
+/* Grab port: number up to delimiter */
+static int
+get_port(const char *data, int start, size_t dlen, char delim,
+        u_int32_t array[2])
+{
+  u_int16_t port = 0;
+  int i;
+
+  for (i = start; i < dlen; i++) {
+    /* Finished? */
+    if (data[i] == delim) {
+      if (port == 0)
+        break;
+      array[0] = port >> 8;
+      array[1] = port;
+      return i + 1;
+    }
+    else if (data[i] >= '0' && data[i] <= '9')
+      port = port*10 + data[i] - '0';
+    else /* Some other crap */
+      break;
+  }
+  return 0;
+}
+
+/* Return 1 for match, 0 for accept, -1 for partial. */
+static int
+find_pattern(const char *data, size_t dlen,
+      const char *pattern, size_t plen,
+      char skip, char term,
+      unsigned int *numoff,
+      unsigned int *numlen,
+      u_int32_t array[6],
+      int (*getnum)(const char *, size_t, u_int32_t[], char))
+{
+  size_t i;
+
+  if (check_debug_level (D_CLIENT_NAT))
+    msg (M_INFO, "CNAT - find_pattern %s: dlen = %u\n", pattern, dlen);
+
+  if (dlen == 0)
+    return 0;
+
+  if (dlen <= plen) {
+    /* Short packet: try for partial? */
+    if (strncasecmp(data, pattern, dlen) == 0)
+      return -1;
+    else return 0;
+  }
+
+  if (strncasecmp(data, pattern, plen) != 0) {
+    return 0;
+  }
+
+  if (check_debug_level (D_CLIENT_NAT))
+    msg (M_INFO, "CNAT - Pattern matches!\n");
+
+  /* Now we've found the constant string, try to skip
+     to the 'skip' character */
+  for (i = plen; data[i] != skip; i++)
+    if (i == dlen - 1) return -1;
+
+  /* Skip over the last character */
+  i++;
+
+  if (check_debug_level (D_CLIENT_NAT))
+    msg (M_INFO, "CNAT - Skipped up to `%c'!\n", skip);
+
+  *numoff = i;
+  *numlen = getnum(data + i, dlen - i, array, term);
+  if (!*numlen)
+    return -1;
+
+  if (check_debug_level (D_CLIENT_NAT))
+    msg (M_INFO, "CNAT - Match succeeded!\n");
+
+  return 1;
+}
+
+static uint16_t
+tcp_checksum (const uint8_t *buf,
+        const int len_tcp,
+        const uint32_t src_addr,
+        const uint32_t dest_addr)
+{
+  uint16_t word16;
+  uint32_t sum = 0;
+  int i;
+  uint8_t * psrc_addr = (uint8_t *) &src_addr;
+  uint8_t * pdest_addr = (uint8_t *) &dest_addr;
+
+  /* make 16 bit words out of every two adjacent 8 bit words and  */
+  /* calculate the sum of all 16 bit words */
+  for (i = 0; i < len_tcp; i += 2){
+    word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_tcp) ? (buf[i+1] &
0xFF) : 0);
+    sum += word16;
+  }
+
+  /* add the TCP pseudo header which contains the IP source and
destination addresses */
+  for (i = 0; i < 4; i += 2){
+    word16 =((psrc_addr[i] << 8) & 0xFF00) + (psrc_addr[i+1] & 0xFF);
+    sum += word16;
+  }
+  for (i = 0; i < 4; i += 2){
+    word16 =((pdest_addr[i] << 8) & 0xFF00) + (pdest_addr[i+1] & 0xFF);
+    sum += word16;
+  }
+
+  /* the protocol number and the length of the TCP packet */
+  sum += (uint16_t) OPENVPN_IPPROTO_TCP + (uint16_t) len_tcp;
+
+  /* keep only the last 16 bits of the 32 bit calculated sum and add the
carries */
+  while (sum >> 16)
+    sum = (sum & 0xFFFF) + (sum >> 16);
+
+  /* Take the one's complement of sum */
+  return ((uint16_t) ~sum);
+}
+
+static uint16_t
+ip_checksum(const void *buf, uint16_t hdr_len) {
+  unsigned long sum = 0;
+  const uint16_t *ip1;
+
+  ip1 = buf;
+  while (hdr_len > 1) {
+    sum += *ip1++;
+    if (sum & 0x80000000)
+      sum = (sum & 0xFFFF) + (sum >> 16);
+    hdr_len -= 2;
+  }
+
+  while (sum >> 16)
+    sum = (sum & 0xFFFF) + (sum >> 16);
+
+  return(~sum);
+}
+
+static int
+client_nat_ftp_transform(struct buffer *ipbuf,
+          const int direction, const uint32_t from_address, uint32_t
replace_address) {
+
+  uint32_t array[6] = {0};
+  int ret = 0;
+  int data_len = 0;
+
+  struct ip_tcp_udp_hdr *hdr = (struct ip_tcp_udp_hdr *) BPTR (ipbuf);
+
+  if (hdr->ip.protocol != OPENVPN_IPPROTO_TCP)
+    return ret;
+
+  if (table == NULL)
+      table = init_delta_table();
+
+  delta_table_entry_t *entry = NULL;
+  delta_table_key_t delta_key;
+
+  // Because the address already was NATed, probably on OpenVPN Server
+  if (direction == CN_OUTGOING)
+    delta_key.src_addr = from_address;
+  else if (direction == CN_INCOMING)
+    delta_key.src_addr = hdr->ip.saddr;
+
+  delta_key.src_port = hdr->u.tcp.source;
+  delta_key.dest_addr = hdr->ip.daddr;
+  delta_key.dest_port = hdr->u.tcp.dest;
+
+#if DEBUG_DELTA
+  msg (M_INFO, "delta_key - saddr: %d, sport: %d, daddr: %d, dport: %d",
+  delta_key.src_addr, delta_key.src_port, delta_key.dest_addr,
delta_key.dest_port);
+
+  msg (M_INFO, "seq: %x, ack: %x",
+  hdr->u.tcp.seq, hdr->u.tcp.ack_seq);
+#endif
+
+  int tcp_data_offset = OPENVPN_TCPH_GET_DOFF (hdr->u.tcp.doff_res);
+
+  struct buffer tcpbuf = *ipbuf;
+  if (!buf_advance (&tcpbuf, sizeof(struct openvpn_iphdr) +
tcp_data_offset))
+    return ret;
+
+  uint8_t * tcp_data = (uint8_t *) BPTR (&tcpbuf);
+
+#if DEBUG_DELTA
+  msg (M_INFO, "TCP DATA BEFORE NAT:");
+  hexdump(tcp_data, BLEN(&tcpbuf));
+#endif
+
+  u_int32_t matchlen, matchoff;
+  int found_pattern = -1;
+  int i = 0;
+
+  for (i = 0; i < sizeof(search) / sizeof(search[0]); i++) {
+    if (search[i].direction != direction) continue;
+
+    found_pattern = find_pattern(tcp_data, BLEN(&tcpbuf),
+             search[i].pattern,
+             search[i].plen,
+             search[i].skip,
+             search[i].term,
+             &matchoff, &matchlen,
+             array,
+             search[i].getnum);
+    if (found_pattern) break;
+  }
+
+  if (found_pattern > 0)
+    {
+
+      if (check_debug_level (D_CLIENT_NAT))
+        {
+          msg (M_INFO, "client-nat FTP match: %.*s - data: %.*s\n",
+            matchoff, tcp_data, matchlen, &tcp_data[matchoff]);
+        }
+
+      data_len = BLEN(&tcpbuf) - matchoff;
+
+      uint32_t ip = htonl((array[0] << 24) | (array[1] << 16)
+        | (array[2] << 8) | array[3]);
+      uint16_t port = htons(array[4] << 8 | array[5]);
+      uint8_t * addr_tmp = (uint8_t *) &replace_address;
+
+      uint8_t new_tcp_data[32];
+      memset(&new_tcp_data[0], 0, sizeof(new_tcp_data));
+
+      int new_len = sprintf((char *) &new_tcp_data[0],
"%d,%d,%d,%d,%d,%d%.*s",
+        addr_tmp[0], addr_tmp[1], addr_tmp[2], addr_tmp[3], array[4],
array[5],
+        data_len - matchlen, (char *)&tcp_data[matchoff + matchlen]);
+
+      if (check_debug_level (D_CLIENT_NAT))
+        {
+          msg (M_INFO, "client-nat replaced address from: %.*s to: %.*s\n",
+            data_len, &tcp_data[matchoff], new_len, &new_tcp_data[0]);
+        }
+
+      //If the new len is greater than the old, there will be there an
adjustment
+      if (new_len > data_len)
+        {
+          //If the entry already exists
+          if (entry = get_delta_entry(table, delta_key))
+            {
+              if (direction == CN_OUTGOING)
+                {
+                  hdr->u.tcp.seq = htonl(ntohl(hdr->u.tcp.seq) +
(entry->delta_out));       // Need to update seq and ack
+                  hdr->u.tcp.ack_seq = htonl(ntohl(hdr->u.tcp.ack_seq) -
entry->delta_in);
+                  entry->delta_out += new_len - data_len;
+                }
+              else
+                {
+                  hdr->u.tcp.seq = htonl(ntohl(hdr->u.tcp.seq) +
(entry->delta_in));        // Need to update seq and ack
+                  hdr->u.tcp.ack_seq = htonl(ntohl(hdr->u.tcp.ack_seq) -
entry->delta_out);
+                  entry->delta_in += new_len - data_len;
+                }
+              //Update timestamp entry on delta entry, to keep this delta
alive
+              entry->timestamp = get_timestamp();
+            }
+          else
+            {
+              // No entry found. Add a new one.
+              entry = malloc(sizeof(delta_table_entry_t));
+              entry->key = delta_key;
+
+              if (direction == CN_OUTGOING)
+                {
+                  entry->delta_out = new_len - data_len;
+                  entry->delta_in = 0;
+                }
+              else
+                {
+                  entry->delta_in = new_len - data_len;
+                  entry->delta_out = 0;
+                }
+              entry->marked_to_remove = 0;
+              entry->timestamp = get_timestamp();
+
+              //Add it to delta table
+              add_delta_entry(table, entry);
+            }
+
+#if DEBUG_DELTA
+          print_delta_table_entries(table);
+#endif
+
+          //Increase the tcpbuf and ipbuf reflecting the delta chars added
to the segment.
+          ASSERT(buf_inc_len(&tcpbuf, new_len - data_len));
+          ASSERT(buf_inc_len(ipbuf, new_len - data_len));
+
+          //Update tot_len
+          hdr->ip.tot_len = htons(ntohs(hdr->ip.tot_len) + (new_len -
data_len));
+
+          // Readjust IP Checksum
+          uint16_t head_len = OPENVPN_IPH_GET_LEN(hdr->ip.version_len);
+          hdr->ip.check = 0;
+          uint16_t check = ip_checksum( BPTR (ipbuf), head_len);
+          hdr->ip.check = check;
+
+          //Use new_len here!
+          memcpy(&tcp_data[matchoff], new_tcp_data, new_len);
+        }
+      else
+        {
+          // The replace size is the lesser or iqual the original? Pad
with 0 if necessary.
+          memcpy(&tcp_data[matchoff], new_tcp_data, data_len);
+
+          //If the entry already exists
+          if (entry = get_delta_entry(table, delta_key))
+            {
+              if (direction == CN_OUTGOING)
+                {
+                  hdr->u.tcp.seq = htonl(ntohl(hdr->u.tcp.seq) +
(entry->delta_out));       // Need to update seq and ack
+                  hdr->u.tcp.ack_seq = htonl(ntohl(hdr->u.tcp.ack_seq) -
entry->delta_in);
+                }
+              else
+                {
+                  hdr->u.tcp.seq = htonl(ntohl(hdr->u.tcp.seq) +
(entry->delta_in));        // Need to update seq and ack
+                  hdr->u.tcp.ack_seq = htonl(ntohl(hdr->u.tcp.ack_seq) -
entry->delta_out);
+                }
+              //Update timestamp entry on delta entry, to keep this delta
alive
+              entry->timestamp = get_timestamp();
+            }
+
+        }
+
+      //Update TCP checksum
+      hdr->u.tcp.check = 0;
+
+      uint16_t tot_len = ntohs(hdr->ip.tot_len);
+      uint16_t head_len = OPENVPN_IPH_GET_LEN(hdr->ip.version_len);
+
+      uint16_t check = tcp_checksum(BPTR (ipbuf) + head_len,
+      tot_len - head_len, hdr->ip.saddr, hdr->ip.daddr);
+
+      hdr->u.tcp.check = htons(check);
+      ret = 1;
+    }
+  else
+    {
+      //No pattern found. Check if there is a delta entry for this
connection
+      if(entry = get_delta_entry(table, delta_key))
+        {
+          if (direction == CN_OUTGOING)
+            {
+              hdr->u.tcp.seq = htonl(ntohl(hdr->u.tcp.seq) +
entry->delta_out);
+              hdr->u.tcp.ack_seq = htonl(ntohl(hdr->u.tcp.ack_seq) -
entry->delta_in);
+            }
+          else
+            {
+              hdr->u.tcp.seq = htonl(ntohl(hdr->u.tcp.seq) +
entry->delta_in);
+              hdr->u.tcp.ack_seq = htonl(ntohl(hdr->u.tcp.ack_seq) -
entry->delta_out);
+            }
+
+          //Update TCP checksum
+          hdr->u.tcp.check = 0;
+
+          uint16_t tot_len = ntohs(hdr->ip.tot_len);
+          uint16_t head_len = OPENVPN_IPH_GET_LEN(hdr->ip.version_len);
+
+          uint16_t check = tcp_checksum(BPTR (ipbuf) + head_len,
+          tot_len - head_len, hdr->ip.saddr, hdr->ip.daddr);
+
+          hdr->u.tcp.check = htons(check);
+
+          //Update timestamp entry on delta entry
+          entry->timestamp = get_timestamp();
+
+          // If it is a FIN package, then remove entry from delta table
+          if (OPENVPN_TCPH_FIN_MASK & hdr->u.tcp.flags)
+            {
+              entry->marked_to_remove = 1;
+              msg (M_INFO, "Delta marked to be removed!");
+            }
+
+          ret = 1;
+        }
+      else
+        {
+#if DEBUG_DELTA
+          // Regular package!
+          msg (M_INFO, "Regular package!: tot_len %d, seq %x, ack %x\n",
ntohs(hdr->ip.tot_len), ntohl(hdr->u.tcp.seq), ntohl(hdr->u.tcp.ack_seq));
+#endif
+        }
+    }
+
+#if DEBUG_DELTA
+  msg (M_INFO, "TCP DATA AFTER NAT:");
+  hexdump(tcp_data, BLEN(&tcpbuf));
+#endif
+
+  return ret;
+}
+
 void
 client_nat_transform (const struct client_nat_option_list *list,
-      struct buffer *ipbuf,
-      const int direction)
+          struct buffer *ipbuf,
+          const int direction,
+          const bool enable_nat_ftp_support)
 {
   struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR (ipbuf);
   int i;
-  uint32_t addr, *addr_ptr;
+  uint32_t addr, *addr_ptr, from_addr;
   const uint32_t *from, *to;
   int accumulate = 0;
   unsigned int amask;
   unsigned int alog = 0;

+  uint32_t orig_saddr = h->ip.saddr;
+  uint32_t orig_daddr = h->ip.daddr;
+
   if (check_debug_level (D_CLIENT_NAT))
     print_pkt (&h->ip, "BEFORE", direction, D_CLIENT_NAT);

@@ -212,65 +879,81 @@ client_nat_transform (const struct
client_nat_option_list *list,
     {
       const struct client_nat_entry *e = &list->entries[i]; /* current NAT
rule */
       if (e->type ^ direction)
- {
-  addr = *(addr_ptr = &h->ip.daddr);
-  amask = 2;
- }
+        {
+          addr = *(addr_ptr = &h->ip.daddr);
+          amask = 2;
+        }
       else
- {
-  addr = *(addr_ptr = &h->ip.saddr);
-  amask = 1;
- }
+        {
+          addr = *(addr_ptr = &h->ip.saddr);
+          amask = 1;
+        }
       if (direction)
- {
-  from = &e->foreign_network;
-  to = &e->network;
- }
+        {
+          from = &e->foreign_network;
+          to = &e->network;
+        }
       else
- {
-  from = &e->network;
-  to = &e->foreign_network;
- }
+        {
+          from = &e->network;
+          to = &e->foreign_network;
+        }

       if (((addr & e->netmask) == *from) && !(amask & alog))
- {
-  /* pre-adjust IP checksum */
-  ADD_CHECKSUM_32(accumulate, addr);
+        {
+          from_addr = *from;
+
+          /* pre-adjust IP checksum */
+          ADD_CHECKSUM_32(accumulate, addr);

-  /* do NAT transform */
-  addr = (addr & ~e->netmask) | *to;
+          /* do NAT transform */
+          addr = (addr & ~e->netmask) | *to;

-  /* post-adjust IP checksum */
-  SUB_CHECKSUM_32(accumulate, addr);
+          /* post-adjust IP checksum */
+          SUB_CHECKSUM_32(accumulate, addr);

-  /* write the modified address to packet */
-  *addr_ptr = addr;
+          /* write the modified address to packet */
+          *addr_ptr = addr;

-  /* mark as modified */
-  alog |= amask;
- }
+          /* mark as modified */
+          alog |= amask;
+        }
     }
   if (alog)
     {
       if (check_debug_level (D_CLIENT_NAT))
- print_pkt (&h->ip, "AFTER", direction, D_CLIENT_NAT);
+        print_pkt (&h->ip, "AFTER", direction, D_CLIENT_NAT);

       ADJUST_CHECKSUM(accumulate, h->ip.check);

       if (h->ip.protocol == OPENVPN_IPPROTO_TCP)
- {
-  if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct
openvpn_tcphdr))
-    {
-      ADJUST_CHECKSUM(accumulate, h->u.tcp.check);
-    }
- }
+        {
+          if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct
openvpn_tcphdr))
+            {
+              ADJUST_CHECKSUM(accumulate, h->u.tcp.check);
+            }
+
+          uint32_t repl_addr = addr;
+
+          if (amask == 2)
+            {
+              if (direction)
+                repl_addr = orig_saddr;
+              else
+                repl_addr = orig_daddr;
+            }
+
+          if (enable_nat_ftp_support)
+            client_nat_ftp_transform(ipbuf, direction, from_addr,
repl_addr);
+
+        }
       else if (h->ip.protocol == OPENVPN_IPPROTO_UDP)
- {
-  if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct
openvpn_udphdr))
-    {
-      ADJUST_CHECKSUM(accumulate, h->u.udp.check);
-    }
- }
+        {
+          if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct
openvpn_udphdr))
+           {
+              ADJUST_CHECKSUM(accumulate, h->u.udp.check);
+            }
+        }
     }
 }

@@ -297,7 +980,7 @@ update_localhost_nat(struct client_nat_option_list
*dest, in_addr_t local_ip)
           addr.s_addr = nat_entry->network;
           char *dot_ip = inet_ntoa(addr);

-          msg (M_INFO, "Updating NAT table from localhost to: %s",
dot_ip);
+          msg (M_INFO, "CNAT - Updating NAT table from localhost to: %s",
dot_ip);
           ret = true;
         }
     }
diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h
index ce995d9..a58da5d 100755
--- a/src/openvpn/clinat.h
+++ b/src/openvpn/clinat.h
@@ -52,15 +52,16 @@ void copy_client_nat_option_list (struct
client_nat_option_list *dest, const str
 void print_client_nat_list(const struct client_nat_option_list *list, int
msglevel);

 void add_client_nat_to_option_list (struct client_nat_option_list *dest,
-    const char *type,
-    const char *network,
-    const char *netmask,
-    const char *foreign_network,
-    int msglevel);
+            const char *type,
+            const char *network,
+            const char *netmask,
+            const char *foreign_network,
+            int msglevel);

 void client_nat_transform (const struct client_nat_option_list *list,
-   struct buffer *ipbuf,
-   const int direction);
+            struct buffer *ipbuf,
+            const int direction,
+            const bool enable_nat_ftp_support);

 bool update_localhost_nat(struct client_nat_option_list *dest, in_addr_t
local_ip);

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
old mode 100644
new mode 100755
index 217fbb3..615db7a
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -980,9 +980,6 @@ process_incoming_tun (struct context *c)

   perf_push (PERF_PROC_IN_TUN);

-  if (c->c2.buf.len > 0)
-    c->c2.tun_read_bytes += c->c2.buf.len;
-
 #ifdef LOG_RW
   if (c->c2.log_rw && c->c2.buf.len > 0)
     fprintf (stderr, "r");
@@ -999,6 +996,9 @@ process_incoming_tun (struct context *c)
        */
       process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT,
&c->c2.buf);

+      if (c->c2.buf.len > 0)
+        c->c2.tun_read_bytes += c->c2.buf.len;
+
 #ifdef PACKET_TRUNCATION_CHECK
       /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
       ipv4_packet_size_verify (BPTR (&c->c2.buf),
@@ -1041,43 +1041,44 @@ process_ip_header (struct context *c, unsigned int
flags, struct buffer *buf)
 #else
       if (flags & PIP_MSSFIX)
 #endif
- {
-  struct buffer ipbuf = *buf;
-  if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
-    {
-#if PASSTOS_CAPABILITY
-      /* extract TOS from IP header */
-      if (flags & PIPV4_PASSTOS)
- link_socket_extract_tos (c->c2.link_socket, &ipbuf);
-#endif
-
-      /* possibly alter the TCP MSS */
-      if (flags & PIP_MSSFIX)
- mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
+        {
+          if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), buf))
+            {

 #ifdef ENABLE_CLIENT_NAT
-      /* possibly do NAT on packet */
-      if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
- {
-  const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING :
CN_OUTGOING;
-  client_nat_transform (c->options.client_nat, &ipbuf, direction);
- }
+              /* possibly do NAT on packet */
+              if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
+                {
+                  const int direction = (flags & PIPV4_OUTGOING) ?
CN_INCOMING : CN_OUTGOING;
+                  client_nat_transform(c->options.client_nat, buf,
direction, c->options.enable_nat_ftp_support);
+                }
 #endif
-      /* possibly extract a DHCP router message */
-      if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
- {
-  const in_addr_t dhcp_router = dhcp_extract_router_msg (&ipbuf);
-  if (dhcp_router)
-    route_list_add_vpn_gateway (c->c1.route_list, c->c2.es, dhcp_router);
- }
-    }
-  else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
-    {
-      /* possibly alter the TCP MSS */
-      if (flags & PIP_MSSFIX)
- mss_fixup_ipv6 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
-    }
- }
+
+#if PASSTOS_CAPABILITY
+              /* extract TOS from IP header */
+              if (flags & PIPV4_PASSTOS)
+                link_socket_extract_tos (c->c2.link_socket, buf);
+#endif
+
+              /* possibly alter the TCP MSS */
+              if (flags & PIP_MSSFIX)
+                mss_fixup_ipv4 (buf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC
(&c->c2.frame)));
+
+              /* possibly extract a DHCP router message */
+              if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
+                {
+                  const in_addr_t dhcp_router = dhcp_extract_router_msg
(buf);
+                  if (dhcp_router)
+                    route_list_add_vpn_gateway (c->c1.route_list, c->c2.es,
dhcp_router);
+                }
+            }
+          else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), buf))
+            {
+              /* possibly alter the TCP MSS */
+              if (flags & PIP_MSSFIX)
+                mss_fixup_ipv6 (buf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC
(&c->c2.frame)));
+            }
+        }
     }
 }

diff --git a/src/openvpn/options.c b/src/openvpn/options.c
old mode 100644
new mode 100755
index 007bd8c..73b615a
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -236,6 +236,7 @@ static const char usage_message[] =
   "                  the default gateway.  Useful when pushing private
subnets.\n"
 #ifdef ENABLE_CLIENT_NAT
   "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT
rule.\n"
+  "--enable-nat-ftp-support : Enable NAT FTP Support, updating the IP
address on FTP PORT commands or PASV responses\n"
 #endif
 #ifdef ENABLE_PUSH_PEER_INFO
   "--push-peer-info : (client only) push client info to server.\n"
@@ -789,6 +790,11 @@ init_options (struct options *o, const bool init_gc)
   o->max_routes = MAX_ROUTES_DEFAULT;
   o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
   o->proto_force = -1;
+
+#ifdef ENABLE_CLIENT_NAT
+  o->enable_nat_ftp_support = false;
+#endif
+
 #ifdef ENABLE_OCC
   o->occ = true;
 #endif
@@ -1535,6 +1541,8 @@ show_settings (const struct options *o)
 #ifdef ENABLE_CLIENT_NAT
   if (o->client_nat)
     print_client_nat_list(o->client_nat, D_SHOW_PARMS);
+
+  SHOW_BOOL(enable_nat_ftp_support);
 #endif

 #ifdef ENABLE_MANAGEMENT
@@ -5287,6 +5295,10 @@ add_option (struct options *options,
       cnol_check_alloc (options);
       add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3],
p[4], msglevel);
     }
+  else if (streq (p[0], "enable_nat_ftp_support"))
+    {
+      options->enable_nat_ftp_support = true;
+    }
 #endif
   else if (streq (p[0], "route") && p[1])
     {
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
old mode 100644
new mode 100755
index af9a47f..2b27368
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -347,6 +347,7 @@ struct options
   bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for
certain parameters */

 #ifdef ENABLE_CLIENT_NAT
+  bool enable_nat_ftp_support;
   struct client_nat_option_list *client_nat;
 #endif

-- 
1.7.9.5


>From 0aa64f57ecf653cd067dbef2b2378bdfc4f9a754 Mon Sep 17 00:00:00 2001
From: Rafael Gava <rafael.olive...@venturus.org.br>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Fri, 14 Aug 2015 16:46:13 -0300
Subject: [PATCH] Removed debug messages.


Signed-off-by: Rafael Gava <rafael.olive...@venturus.org.br>
---
 src/openvpn/clinat.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
index 1d213f5..991ea75 100755
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -833,7 +833,9 @@ client_nat_ftp_transform(struct buffer *ipbuf,
           if (OPENVPN_TCPH_FIN_MASK & hdr->u.tcp.flags)
             {
               entry->marked_to_remove = 1;
+#if DEBUG_DELTA
               msg (M_INFO, "Delta marked to be removed!");
+#endif
             }

           ret = 1;
-- 
1.7.9.5


>From cf7af4e4784c83a64b8c1e12601d33bdc5b14d59 Mon Sep 17 00:00:00 2001
From: Rafael Gava <rafael.olive...@venturus.org.br>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Thu, 20 Aug 2015 08:47:08 -0300
Subject: [PATCH] Fixed FTP NAT IP address.


Signed-off-by: Rafael Gava <rafael.olive...@venturus.org.br>
---
 src/openvpn/clinat.c |   30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
index 991ea75..ef400de 100755
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -423,7 +423,7 @@ static int try_number(const char *data, size_t dlen,
uint32_t array[],
       if (*data == term && i == array_size - 1)
         return len;

-      msg (M_ERRNO, "CNAT - try_number - Char %u (got %u nums) `%u'
unexpected\n", len, i, *data);
+      msg (M_ERRNO, "CNAT - try_number - Char %u (got %u nums) '%u'
unexpected\n", len, i, *data);
       return 0;
     }
   }
@@ -433,7 +433,7 @@ static int try_number(const char *data, size_t dlen,
uint32_t array[],
   return 0;
 }

-static int try_rfc959(const char *, size_t, u_int32_t [], char);
+static int try_rfc959(const char *, size_t, uint32_t [], char);

 static struct ftp_search {
   int direction;
@@ -441,7 +441,7 @@ static struct ftp_search {
   size_t plen;
   char skip;
   char term;
-  int (*getnum)(const char *, size_t, u_int32_t[], char);
+  int (*getnum)(const char *, size_t, uint32_t[], char);
 } search[] = {
   {
     CN_OUTGOING,
@@ -458,7 +458,7 @@ static struct ftp_search {

 /* Returns 0, or length of numbers: 192,168,1,1,5,6 */
 static int
-try_rfc959(const char *data, size_t dlen, u_int32_t array[6],
+try_rfc959(const char *data, size_t dlen, uint32_t array[6],
            char term)
 {
   return try_number(data, dlen, array, 6, ',', term);
@@ -467,9 +467,9 @@ try_rfc959(const char *data, size_t dlen, u_int32_t
array[6],
 /* Grab port: number up to delimiter */
 static int
 get_port(const char *data, int start, size_t dlen, char delim,
-        u_int32_t array[2])
+        uint32_t array[2])
 {
-  u_int16_t port = 0;
+  uint16_t port = 0;
   int i;

   for (i = start; i < dlen; i++) {
@@ -496,13 +496,13 @@ find_pattern(const char *data, size_t dlen,
       char skip, char term,
       unsigned int *numoff,
       unsigned int *numlen,
-      u_int32_t array[6],
-      int (*getnum)(const char *, size_t, u_int32_t[], char))
+      uint32_t array[6],
+      int (*getnum)(const char *, size_t, uint32_t[], char))
 {
   size_t i;

   if (check_debug_level (D_CLIENT_NAT))
-    msg (M_INFO, "CNAT - find_pattern %s: dlen = %u\n", pattern, dlen);
+    msg (M_INFO, "CNAT - find_pattern %s: dlen = %u\n", pattern,
(uint32_t) dlen);

   if (dlen == 0)
     return 0;
@@ -530,7 +530,7 @@ find_pattern(const char *data, size_t dlen,
   i++;

   if (check_debug_level (D_CLIENT_NAT))
-    msg (M_INFO, "CNAT - Skipped up to `%c'!\n", skip);
+    msg (M_INFO, "CNAT - Skipped up to '%c' (%d)!\n", skip, skip);

   *numoff = i;
   *numlen = getnum(data + i, dlen - i, array, term);
@@ -652,7 +652,7 @@ client_nat_ftp_transform(struct buffer *ipbuf,
   hexdump(tcp_data, BLEN(&tcpbuf));
 #endif

-  u_int32_t matchlen, matchoff;
+  uint32_t matchlen, matchoff;
   int found_pattern = -1;
   int i = 0;

@@ -689,7 +689,7 @@ client_nat_ftp_transform(struct buffer *ipbuf,
       uint8_t new_tcp_data[32];
       memset(&new_tcp_data[0], 0, sizeof(new_tcp_data));

-      int new_len = sprintf((char *) &new_tcp_data[0],
"%d,%d,%d,%d,%d,%d%.*s",
+      int new_len = sprintf((char *) &new_tcp_data[0],
"%03d,%03d,%03d,%03d,%03d,%03d%.*s",
         addr_tmp[0], addr_tmp[1], addr_tmp[2], addr_tmp[3], array[4],
array[5],
         data_len - matchlen, (char *)&tcp_data[matchoff + matchlen]);

@@ -700,7 +700,7 @@ client_nat_ftp_transform(struct buffer *ipbuf,
         }

       //If the new len is greater than the old, there will be there an
adjustment
-      if (new_len > data_len)
+      if (replace_address != ip && new_len > data_len)
         {
           //If the entry already exists
           if (entry = get_delta_entry(table, delta_key))
@@ -765,8 +765,8 @@ client_nat_ftp_transform(struct buffer *ipbuf,
         }
       else
         {
-          // The replace size is the lesser or iqual the original? Pad
with 0 if necessary.
-          memcpy(&tcp_data[matchoff], new_tcp_data, data_len);
+          if (replace_address != ip)
+            memcpy(&tcp_data[matchoff], new_tcp_data, data_len);

           //If the entry already exists
           if (entry = get_delta_entry(table, delta_key))
-- 
1.7.9.5


>From 63b1ddad1628eb1a179c2bf5010b781284d2bc4f Mon Sep 17 00:00:00 2001
From: Rafael Gava <rafael.olive...@venturus.org.br>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Sat, 15 Aug 2015 16:58:45 -0300
Subject: [PATCH] Fixed options parameter name enable-nat-ftp-support.


Signed-off-by: Rafael Gava <rafael.olive...@venturus.org.br>
---
 src/openvpn/options.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 73b615a..1a012e4 100755
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -5295,7 +5295,7 @@ add_option (struct options *options,
       cnol_check_alloc (options);
       add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3],
p[4], msglevel);
     }
-  else if (streq (p[0], "enable_nat_ftp_support"))
+  else if (streq (p[0], "enable-nat-ftp-support"))
     {
       options->enable_nat_ftp_support = true;
     }
-- 
1.7.9.5


>From 2f5ac96c0c2c5d9d06a11e0b08ae958e09c2e9b5 Mon Sep 17 00:00:00 2001
From: Rafael Gava <rafael.olive...@venturus.org.br>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Mon, 24 Aug 2015 09:15:34 -0300
Subject: [PATCH] Allows set yes/no option to enable-nat-ftp-support feature.


Signed-off-by: Rafael Gava <rafael.olive...@venturus.org.br>
---
 src/openvpn/options.c |   21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 1a012e4..4d73d87 100755
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -236,7 +236,9 @@ static const char usage_message[] =
   "                  the default gateway.  Useful when pushing private
subnets.\n"
 #ifdef ENABLE_CLIENT_NAT
   "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT
rule.\n"
-  "--enable-nat-ftp-support : Enable NAT FTP Support, updating the IP
address on FTP PORT commands or PASV responses\n"
+  "--enable-nat-ftp-support : Enable NAT FTP Support, replacing the IP
address on FTP PORT commands or PASV responses?\n"
+  "                  'no'    -- No, disable this feature.\n"
+  "                  'yes'   -- Yes, enable this feature (Enabled by
default on Windows).\n"
 #endif
 #ifdef ENABLE_PUSH_PEER_INFO
   "--push-peer-info : (client only) push client info to server.\n"
@@ -792,8 +794,12 @@ init_options (struct options *o, const bool init_gc)
   o->proto_force = -1;

 #ifdef ENABLE_CLIENT_NAT
+#ifdef WIN32
+  o->enable_nat_ftp_support = true;
+#else
   o->enable_nat_ftp_support = false;
 #endif
+#endif

 #ifdef ENABLE_OCC
   o->occ = true;
@@ -5297,7 +5303,18 @@ add_option (struct options *options,
     }
   else if (streq (p[0], "enable-nat-ftp-support"))
     {
-      options->enable_nat_ftp_support = true;
+      if (p[1])
+        {
+          if (streq (p[1], "yes"))
+            options->enable_nat_ftp_support = true;
+          else if (streq (p[1], "no"))
+            options->enable_nat_ftp_support = false;
+          else
+            {
+              msg (msglevel, "bad enable-nat-ftp-support option: %s --
must be 'yes' or 'no'", p[1]);
+              goto err;
+            }
+        }
     }
 #endif
   else if (streq (p[0], "route") && p[1])
-- 
1.7.9.5

Reply via email to