summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--clinat.c263
-rw-r--r--clinat.h65
-rw-r--r--errlevel.h1
-rw-r--r--forward.c12
-rw-r--r--forward.h1
-rw-r--r--multi.c3
-rw-r--r--openvpn.836
-rw-r--r--openvpn.h3
-rw-r--r--options.c49
-rw-r--r--options.h13
-rw-r--r--proto.h37
-rw-r--r--push.c15
-rw-r--r--syshead.h5
-rw-r--r--version.m42
15 files changed, 490 insertions, 17 deletions
diff --git a/Makefile.am b/Makefile.am
index 24649cd..97e0971 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
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
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
diff --git a/errlevel.h b/errlevel.h
index 1d6e866..a47edac 100644
--- a/errlevel.h
+++ b/errlevel.h
@@ -111,6 +111,7 @@
#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 */
diff --git a/forward.c b/forward.c
index 5d34472..ce0a7c4 100644
--- 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))
{
diff --git a/forward.h b/forward.h
index 17cc928..76d8b9e 100644
--- 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 2808c9b..2d1b0ab 100644
--- 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 */
{
diff --git a/openvpn.8 b/openvpn.8
index 164b58e..c5eb3ca 100644
--- 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
diff --git a/openvpn.h b/openvpn.h
index 0757eb1..0c4ff1a 100644
--- 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
diff --git a/options.c b/options.c
index a4b2d49..dfba941 100644
--- 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
{
diff --git a/options.h b/options.h
index 4a56701..fd9eb7c 100644
--- 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 55f0832..7e45231 100644
--- 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 0db826a..298031d 100644
--- 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");
diff --git a/syshead.h b/syshead.h
index 4e6ef08..1c894c9 100644
--- 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
diff --git a/version.m4 b/version.m4
index 72d6ea2..f89b007 100644
--- a/version.m4
+++ b/version.m4
@@ -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])