]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added "client-nat" option for stateless, one-to-one
authorJames Yonan <james@openvpn.net>
Fri, 18 Feb 2011 17:48:25 +0000 (17:48 +0000)
committerJames Yonan <james@openvpn.net>
Fri, 18 Feb 2011 17:48:25 +0000 (17:48 +0000)
NAT on the client side.

Version 2.1.3i.

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6944 e7ae566f-a301-0410-adde-c780ea21d3b5

15 files changed:
Makefile.am
clinat.c [new file with mode: 0644]
clinat.h [new file with mode: 0644]
errlevel.h
forward.c
forward.h
multi.c
openvpn.8
openvpn.h
options.c
options.h
proto.h
push.c
syshead.h
version.m4

index 24649cde55aa29fd277623f9a6831dda1658c3be..97e0971f43378b0edaae5e7a76832eafc5eccc86 100644 (file)
@@ -78,7 +78,9 @@ openvpn_SOURCES = \
        basic.h \
        buffer.c buffer.h \
        circ_list.h \
+       clinat.c clinat.h \
        common.h \
+       config-win32.h \
        crypto.c crypto.h \
        dhcp.c dhcp.h \
        errlevel.h \
diff --git a/clinat.c b/clinat.c
new file mode 100644 (file)
index 0000000..8e85e22
--- /dev/null
+++ b/clinat.c
@@ -0,0 +1,263 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ *  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 published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "syshead.h"
+
+#if defined(ENABLE_CLIENT_NAT)
+
+#include "clinat.h"
+#include "proto.h"
+#include "socket.h"
+#include "memdbg.h"
+
+static bool
+add_entry(struct client_nat_option_list *dest,
+         const struct client_nat_entry *e)
+{
+  if (dest->n >= MAX_CLIENT_NAT)
+    {
+      msg (M_WARN, "WARNING: client-nat table overflow (max %d entries)", MAX_CLIENT_NAT);
+      return false;
+    }
+  else
+    {
+      dest->entries[dest->n++] = *e;
+      return true;
+    }
+}
+
+void
+print_client_nat_list(const struct client_nat_option_list *list, int msglevel)
+{
+  struct gc_arena gc = gc_new ();
+  int i;
+
+  msg (msglevel, "*** CNAT list");
+  if (list)
+    {
+      for (i = 0; i < list->n; ++i)
+       {
+         const struct client_nat_entry *e = &list->entries[i];
+         msg (msglevel, "  CNAT[%d] t=%d %s/%s/%s",
+              i,
+              e->type,
+              print_in_addr_t (e->network, IA_NET_ORDER, &gc),
+              print_in_addr_t (e->netmask, IA_NET_ORDER, &gc),
+              print_in_addr_t (e->foreign_network, IA_NET_ORDER, &gc));
+       }
+    }
+  gc_free (&gc);
+}
+
+struct client_nat_option_list *
+new_client_nat_list (struct gc_arena *gc)
+{
+  struct client_nat_option_list *ret;
+  ALLOC_OBJ_CLEAR_GC (ret, struct client_nat_option_list, gc);
+  return ret;
+}
+
+struct client_nat_option_list *
+clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc)
+{
+  struct client_nat_option_list *ret;
+  ALLOC_OBJ_GC (ret, struct client_nat_option_list, gc);
+  *ret = *src;
+  return ret;
+}
+
+void
+copy_client_nat_option_list (struct client_nat_option_list *dest,
+                            const struct client_nat_option_list *src)
+{
+  int i;
+  for (i = 0; i < src->n; ++i)
+    {
+      if (!add_entry(dest, &src->entries[i]))
+       break;
+    }
+}
+
+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)
+{
+  struct client_nat_entry e;
+  bool ok;
+
+  if (!strcmp(type, "snat"))
+    e.type = CN_SNAT;
+  else if (!strcmp(type, "dnat"))
+    e.type = CN_DNAT;
+  else
+    {
+      msg(msglevel, "client-nat: type must be 'snat' or 'dnat'");
+      return;
+    }
+
+  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)
+    {
+      msg(msglevel, "client-nat: bad netmask: %s", netmask);
+      return;
+    }
+  e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL);
+  if (!ok)
+    {
+      msg(msglevel, "client-nat: bad foreign network: %s", foreign_network);
+      return;
+    }
+
+  add_entry(dest, &e);
+}
+
+#if 0
+static void
+print_checksum (struct openvpn_iphdr *iph, const char *prefix)
+{
+  uint16_t *sptr;
+  unsigned int sum = 0;
+  int i = 0;
+  for (sptr = (uint16_t *)iph; (uint8_t *)sptr < (uint8_t *)iph + sizeof(struct openvpn_iphdr); sptr++)
+    {
+      i += 1;
+      sum += *sptr;
+    }
+  msg (M_INFO, "** CKSUM[%d] %s %08x", i, prefix, sum);
+}
+#endif
+
+static void
+print_pkt (struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel)
+{
+  struct gc_arena gc = gc_new ();
+
+  char *dirstr = "???";
+  if (direction == CN_OUTGOING)
+    dirstr = "OUT";
+  else if (direction == CN_INCOMING)
+    dirstr = "IN";
+
+  msg(msglevel, "** CNAT %s %s %s -> %s",
+      dirstr,
+      prefix,
+      print_in_addr_t (iph->saddr, IA_NET_ORDER, &gc),
+      print_in_addr_t (iph->daddr, IA_NET_ORDER, &gc));
+  
+  gc_free (&gc);
+}
+
+void
+client_nat_transform (const struct client_nat_option_list *list,
+                     struct buffer *ipbuf,
+                     const int direction)
+{
+  struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR (ipbuf);
+  int i;
+  uint32_t addr, *addr_ptr;
+  const uint32_t *from, *to;
+  int accumulate = 0;
+  unsigned int amask;
+  unsigned int alog = 0;
+
+  if (check_debug_level (D_CLIENT_NAT))
+    print_pkt (&h->ip, "BEFORE", direction, D_CLIENT_NAT);
+
+  for (i = 0; i < list->n; ++i)
+    {
+      const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */
+      if (e->type ^ direction)
+       {
+         addr = *(addr_ptr = &h->ip.daddr);
+         amask = 2;
+       }
+      else
+       {
+         addr = *(addr_ptr = &h->ip.saddr);
+         amask = 1;
+       }
+      if (direction)
+       {
+         from = &e->foreign_network;
+         to = &e->network;
+       }
+      else
+       {
+         from = &e->network;
+         to = &e->foreign_network;
+       }
+
+      if (((addr & e->netmask) == *from) && !(amask & alog))
+       {
+         /* pre-adjust IP checksum */
+         ADD_CHECKSUM_32(accumulate, addr);
+
+         /* do NAT transform */
+         addr = (addr & ~e->netmask) | *to;
+
+         /* post-adjust IP checksum */
+         SUB_CHECKSUM_32(accumulate, addr);
+
+         /* write the modified address to packet */
+         *addr_ptr = addr;
+
+         /* mark as modified */
+         alog |= amask;
+       }
+    }
+  if (alog)
+    {
+      if (check_debug_level (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);
+           }
+       }
+      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);
+           }
+       }
+    }
+}
+
+#endif
diff --git a/clinat.h b/clinat.h
new file mode 100644 (file)
index 0000000..d55a727
--- /dev/null
+++ b/clinat.h
@@ -0,0 +1,65 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ *  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 published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if !defined(CLINAT_H) && defined(ENABLE_CLIENT_NAT)
+#define CLINAT_H
+
+#include "buffer.h"
+
+#define MAX_CLIENT_NAT 64
+
+#define CN_OUTGOING 0
+#define CN_INCOMING 1
+
+struct client_nat_entry {
+# define CN_SNAT 0
+# define CN_DNAT 1
+  int type;
+  in_addr_t network;
+  in_addr_t netmask;
+  in_addr_t foreign_network;
+};
+
+struct client_nat_option_list {
+  int n;
+  struct client_nat_entry entries[MAX_CLIENT_NAT];
+};
+
+struct client_nat_option_list *new_client_nat_list (struct gc_arena *gc);
+struct client_nat_option_list *clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc);
+void copy_client_nat_option_list (struct client_nat_option_list *dest, const struct client_nat_option_list *src);
+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);
+
+void client_nat_transform (const struct client_nat_option_list *list,
+                          struct buffer *ipbuf,
+                          const int direction);
+
+#endif
index 1d6e8660df659d9f6a2bbb1ec91d06f28a99dd3c..a47edacbce8b97c911ac6e24a844bab7ba47e759 100644 (file)
 #define D_LINK_RW            LOGLEV(6, 60, M_DEBUG)  /* show TCP/UDP reads/writes (terse) */
 #define D_TUN_RW             LOGLEV(6, 60, M_DEBUG)  /* show TUN/TAP reads/writes */
 #define D_TAP_WIN32_DEBUG    LOGLEV(6, 60, M_DEBUG)  /* show TAP-Win32 driver debug info */
+#define D_CLIENT_NAT         LOGLEV(6, 60, M_DEBUG)  /* show client NAT debug info */
 
 #define D_SHOW_KEYS          LOGLEV(7, 70, M_DEBUG)  /* show data channel encryption keys */
 #define D_SHOW_KEY_SOURCE    LOGLEV(7, 70, M_DEBUG)  /* show data channel key source entropy */
index 5d34472186abaeaad0adadac55d92edeaabd9bf0..ce0a7c4c2fb2bc8b3dbfb2a0fade5bc0006b3bf7 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -977,7 +977,7 @@ process_incoming_tun (struct context *c)
        * The --passtos and --mssfix options require
        * us to examine the IPv4 header.
        */
-      process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf);
+      process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
 
 #ifdef PACKET_TRUNCATION_CHECK
       /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
@@ -1035,6 +1035,14 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
              if (flags & PIPV4_MSSFIX)
                mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
 
+#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);
+               }
+#endif
              /* possibly extract a DHCP router message */
              if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
                {
@@ -1196,7 +1204,7 @@ process_outgoing_tun (struct context *c)
    * The --mssfix option requires
    * us to examine the IPv4 header.
    */
-  process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_OUTGOING, &c->c2.to_tun);
+  process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
 
   if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))
     {
index 17cc9280578dc92c62556da5ebd4987f249cd63e..76d8b9ebe24a16bbc805372139103496b2fbe8dd 100644 (file)
--- a/forward.h
+++ b/forward.h
@@ -76,6 +76,7 @@ bool send_control_channel_string (struct context *c, const char *str, int msglev
 #define PIPV4_MSSFIX          (1<<1)
 #define PIPV4_OUTGOING        (1<<2)
 #define PIPV4_EXTRACT_DHCP_ROUTER (1<<3)
+#define PIPV4_CLIENT_NAT      (1<<4)
 
 void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf);
 
diff --git a/multi.c b/multi.c
index 2808c9b72d661dbcfa3eca19a0e1a9897e35b230..2d1b0ab38bf5ca3112e38dd8a562bec9924889b1 100644 (file)
--- a/multi.c
+++ b/multi.c
@@ -1200,6 +1200,9 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
       mi->context.c2.push_ifconfig_defined = true;
       mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
       mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
+#ifdef ENABLE_CLIENT_NAT
+      mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias;
+#endif
     }
   else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */
     {
index 164b58ec7e35fcf6d08c7178c58174ca0b8d2568..c5eb3caa93e4cb0ed336550c49c55103c330bc80 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -1067,6 +1067,31 @@ and
 .B --route-gateway.
 .\"*********************************************************
 .TP
+.B --client-nat snat|dnat network netmask alias
+This pushable client option sets up a stateless one-to-one NAT
+rule on packet addresses (not ports), and is useful in cases
+where routes or ifconfig settings pushed to the client would
+create an IP numbering conflict.
+
+.B network/netmask
+(for example 192.168.0.0/255.255.0.0)
+defines the local view of a resource from the client perspective, while
+.B alias/netmask
+(for example 10.64.0.0/255.255.0.0)
+defines the remote view from the server perspective.
+
+Use
+.B snat
+(source NAT) for resources owned by the client and
+.B dnat
+(destination NAT) for remote resources.
+
+Set
+.B --verb 6
+for debugging info showing the transformation of src/dest
+addresses in packets.
+.\"*********************************************************
+.TP
 .B --redirect-gateway flags...
 (Experimental) Automatically execute routing commands to cause all outgoing IP traffic
 to be redirected over the VPN.
@@ -2706,7 +2731,7 @@ This option is deprecated, and should be replaced with
 which is functionally equivalent.
 .\"*********************************************************
 .TP
-.B --ifconfig-push local remote-netmask
+.B --ifconfig-push local remote-netmask [alias]
 Push virtual IP endpoints for client tunnel,
 overriding the --ifconfig-pool dynamic allocation.
 
@@ -2725,6 +2750,15 @@ are from the perspective of the client, not the server.  They may be
 DNS names rather than IP addresses, in which case they will be resolved
 on the server at the time of client connection.
 
+The optional
+.B alias
+parameter may be used in cases where NAT causes the client view
+of its local endpoint to differ from the server view.  In this case
+.B local/remote-netmask
+will refer to the server view while
+.B alias/remote-netmask
+will refer to the client view.
+
 This option must be associated with a specific client instance,
 which means that it must be specified either in a client
 instance config file using
index 0757eb11703f1e5a62116bc7498d384972fdd9f0..0c4ff1acda17e090c28f11145a5efe57bb92f59f 100644 (file)
--- a/openvpn.h
+++ b/openvpn.h
@@ -416,6 +416,9 @@ struct context_2
   bool push_ifconfig_defined;
   in_addr_t push_ifconfig_local;
   in_addr_t push_ifconfig_remote_netmask;
+#ifdef ENABLE_CLIENT_NAT
+  in_addr_t push_ifconfig_local_alias;
+#endif
 
   /* client authentication state, CAS_SUCCEEDED must be 0 */
 # define CAS_SUCCEEDED 0
index a4b2d49cbc8f149119c5fa2bb675a59b6ee1b6bf..dfba941759df83aa2469e4f3406e323067dcb002 100644 (file)
--- a/options.c
+++ b/options.c
@@ -198,6 +198,9 @@ static const char usage_message[] =
   "                  Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
   "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
   "                  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"
+#endif
 #ifdef ENABLE_PUSH_PEER_INFO
   "--push-peer-info : (client only) push client info to server.\n"
 #endif
@@ -1086,6 +1089,9 @@ options_detach (struct options *o)
 {
   gc_detach (&o->gc);
   o->routes = NULL;
+#ifdef ENABLE_CLIENT_NAT
+  o->client_nat = NULL;
+#endif
 #if P2MP_SERVER
   clone_push_list(o);
 #endif
@@ -1098,6 +1104,15 @@ rol_check_alloc (struct options *options)
     options->routes = new_route_option_list (options->max_routes, &options->gc);
 }
 
+#ifdef ENABLE_CLIENT_NAT
+static void
+cnol_check_alloc (struct options *options)
+{
+  if (!options->client_nat)
+    options->client_nat = new_client_nat_list (&options->gc);
+}
+#endif
+
 #ifdef ENABLE_DEBUG
 static void
 show_connection_entry (const struct connection_entry *o)
@@ -1288,6 +1303,11 @@ show_settings (const struct options *o)
   SHOW_BOOL (allow_pull_fqdn);
   if (o->routes)
     print_route_options (o->routes, D_SHOW_PARMS);
+  
+#ifdef ENABLE_CLIENT_NAT
+  if (o->client_nat)
+    print_client_nat_list(o->client_nat, D_SHOW_PARMS);
+#endif
 
 #ifdef ENABLE_MANAGEMENT
   SHOW_STR (management_addr);
@@ -2337,6 +2357,13 @@ pre_pull_save (struct options *o)
          o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc);
          o->pre_pull->routes_defined = true;
        }
+#ifdef ENABLE_CLIENT_NAT
+      if (o->client_nat)
+       {
+         o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc);
+         o->pre_pull->client_nat_defined = true;
+       }
+#endif
     }
 }
 
@@ -2358,6 +2385,16 @@ pre_pull_restore (struct options *o)
       else
        o->routes = NULL;
 
+#ifdef ENABLE_CLIENT_NAT
+      if (pp->client_nat_defined)
+       {
+         cnol_check_alloc (o);
+         copy_client_nat_option_list (o->client_nat, pp->client_nat);
+       }
+      else
+       o->client_nat = NULL;
+#endif
+
       o->foreign_option_index = pp->foreign_option_index;
     }
 
@@ -4564,6 +4601,14 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_PERSIST_IP);
       options->persist_remote_ip = true;
     }
+#ifdef ENABLE_CLIENT_NAT
+  else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4])
+    {
+      VERIFY_PERMISSION (OPT_P_ROUTE);
+      cnol_check_alloc (options);
+      add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel);
+    }
+#endif
   else if (streq (p[0], "route") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_ROUTE);
@@ -5085,6 +5130,10 @@ add_option (struct options *options,
          options->push_ifconfig_defined = true;
          options->push_ifconfig_local = local;
          options->push_ifconfig_remote_netmask = remote_netmask;
+#ifdef ENABLE_CLIENT_NAT
+         if (p[3])
+           options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL);
+#endif
        }
       else
        {
index 4a567017f4db1e9d456c3ea08be97a3221637fff..fd9eb7c3e0f4bd09d3eed6746c2ae8bd08c8ea61 100644 (file)
--- a/options.h
+++ b/options.h
@@ -41,6 +41,7 @@
 #include "proxy.h"
 #include "lzo.h"
 #include "pushlist.h"
+#include "clinat.h"
 
 /*
  * Maximum number of parameters associated with an option,
@@ -67,6 +68,11 @@ struct options_pre_pull
   bool routes_defined;
   struct route_option_list *routes;
 
+#ifdef ENABLE_CLIENT_NAT
+  bool client_nat_defined;
+  struct client_nat_option_list *client_nat;
+#endif
+
   int foreign_option_index;
 };
 
@@ -329,6 +335,10 @@ struct options
   bool route_gateway_via_dhcp;
   bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
 
+#ifdef ENABLE_CLIENT_NAT
+  struct client_nat_option_list *client_nat;
+#endif
+
 #ifdef ENABLE_OCC
   /* Enable options consistency check between peers */
   bool occ;
@@ -401,6 +411,9 @@ struct options
   bool push_ifconfig_defined;
   in_addr_t push_ifconfig_local;
   in_addr_t push_ifconfig_remote_netmask;
+#ifdef ENABLE_CLIENT_NAT
+  in_addr_t push_ifconfig_local_alias;
+#endif
   bool push_ifconfig_constraint_defined;
   in_addr_t push_ifconfig_constraint_network;
   in_addr_t push_ifconfig_constraint_netmask;
diff --git a/proto.h b/proto.h
index 55f0832853f529b45a05f68a7e2efa4a3b1c9d03..7e4523115a9a6d60d0c0b5af3aeae635d3bcedf5 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -149,6 +149,14 @@ struct openvpn_tcphdr {
 #define        OPENVPN_TCPOPT_MAXSEG  2
 #define OPENVPN_TCPOLEN_MAXSEG 4
 
+struct ip_tcp_udp_hdr {
+  struct openvpn_iphdr ip;
+  union {
+    struct openvpn_tcphdr tcp;
+    struct openvpn_udphdr udp;
+  } u;
+};
+
 #pragma pack()
 
 /*
@@ -160,19 +168,30 @@ struct openvpn_tcphdr {
  * is the checksum value to be updated.
  */
 #define ADJUST_CHECKSUM(acc, cksum) { \
-  (acc) += (cksum); \
-  if ((acc) < 0) { \
-    (acc) = -(acc); \
-    (acc) = ((acc) >> 16) + ((acc) & 0xffff); \
-    (acc) += (acc) >> 16; \
-    (cksum) = (uint16_t) ~(acc); \
+  int _acc = acc; \
+  _acc += (cksum); \
+  if (_acc < 0) { \
+    _acc = -_acc; \
+    _acc = (_acc >> 16) + (_acc & 0xffff); \
+    _acc += _acc >> 16; \
+    (cksum) = (uint16_t) ~_acc; \
   } else { \
-    (acc) = ((acc) >> 16) + ((acc) & 0xffff); \
-    (acc) += (acc) >> 16; \
-    (cksum) = (uint16_t) (acc); \
+    _acc = (_acc >> 16) + (_acc & 0xffff); \
+    _acc += _acc >> 16; \
+    (cksum) = (uint16_t) _acc; \
   } \
 }
 
+#define ADD_CHECKSUM_32(acc, u32) { \
+  acc += (u32) & 0xffff; \
+  acc += (u32) >> 16;   \
+}
+
+#define SUB_CHECKSUM_32(acc, u32) { \
+  acc -= (u32) & 0xffff; \
+  acc -= (u32) >> 16;   \
+}
+
 /*
  * We are in a "liberal" position with respect to MSS,
  * i.e. we assume that MSS can be calculated from MTU
diff --git a/push.c b/push.c
index 0db826a4be3d53e799eba2589307cace77e60c80..298031d10e252f0456778c171708ad2e69202460 100644 (file)
--- a/push.c
+++ b/push.c
@@ -185,7 +185,7 @@ send_push_reply (struct context *c)
   struct push_entry *e = c->options.push_list.head;
   bool multi_push = false;
   static char cmd[] = "PUSH_REPLY";
-  const int extra = 64; /* extra space for possible trailing ifconfig and push-continuation */
+  const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */
   const int safe_cap = BCAP (&buf) - extra;
 
   buf_printf (&buf, cmd);
@@ -218,9 +218,16 @@ send_push_reply (struct context *c)
     }
 
   if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask)
-    buf_printf (&buf, ",ifconfig %s %s",
-               print_in_addr_t (c->c2.push_ifconfig_local, 0, &gc),
-               print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc));
+    {
+      in_addr_t ifconfig_local = c->c2.push_ifconfig_local;
+#ifdef ENABLE_CLIENT_NAT
+      if (c->c2.push_ifconfig_local_alias)
+       ifconfig_local = c->c2.push_ifconfig_local_alias;
+#endif
+      buf_printf (&buf, ",ifconfig %s %s",
+                 print_in_addr_t (ifconfig_local, 0, &gc),
+                 print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc));
+    }
   if (multi_push)
     buf_printf (&buf, ",push-continuation 1");
 
index 4e6ef0896f486e715b07ec07cdf3d9757e1ee39b..1c894c91c78a8821f1d8666249e6ade3ddc5982f 100644 (file)
--- a/syshead.h
+++ b/syshead.h
@@ -692,4 +692,9 @@ socket_defined (const socket_descriptor_t sd)
  */
 #define ENABLE_PUSH_PEER_INFO
 
+/*
+ * Do we support internal client-side NAT?
+ */
+#define ENABLE_CLIENT_NAT
+
 #endif
index 72d6ea27b1aa8244c624fe2450febf67552fec01..f89b007295c8ed67e089cbc2a6eca6336a2bc5e1 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.3h])
+define(PRODUCT_VERSION,[2.1.3i])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])