[Openvpn-devel] [PATCH v3 (release/2.3)] Drop recursively routed packets

2016-09-17 Thread Lev Stipakov
From: Lev Stipakov <lev.stipa...@f-secure.com>

v3: Use better way of figuring out IP proto version which
does not break TAP mode. Add an option to allow recursive
routing, could be useful when packets sent by openvpn itself
are not subject to the routing tables that would move packets
into the tunnel.

v2: better method naming

On certain OSes (Windows, OS X) when network adapter is
disabled (ethernet cable pulled off, Wi-Fi hardware switch disabled),
operating system starts to use tun as an external interface.
Outgoing packets are routed to tun, UDP encapsulated, given to
routing table and sent to.. tun.

As a consequence, system starts talking to itself on full power,
traffic counters skyrocket and user is not happy.

To prevent that, drop packets which have gateway IP as
destination address.

Tested on Win7/10, OS X.
---
 doc/openvpn.8 |  4 +++
 src/openvpn/forward.c | 71 +++
 src/openvpn/options.c | 10 
 src/openvpn/options.h |  4 +++
 src/openvpn/proto.h   | 32 +++
 5 files changed, 121 insertions(+)

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index d9bb77c..0decc54 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -3796,6 +3796,10 @@ rather than waiting for a timeout.  The
 parameter (default=1) controls the maximum number of attempts that the client
 will try to resend the exit notification message.  OpenVPN will not send any 
exit
 notifications unless this option is enabled.
+.TP
+.B \-\-allow\-recursive\-routing
+When this option is set, OpenVPN will not drop incoming tun packets
+with same destination as host.
 .\"*
 .SS Data Channel Encryption Options:
 These options are meaningful for both Static & TLS-negotiated key modes
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 5ba6fcb..d725f8d 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -968,6 +968,75 @@ read_incoming_tun (struct context *c)
   perf_pop ();
 }
 
+/**
+ * Drops UDP packets which OS decided to route via tun.
+ *
+ * On Windows and OS X when netwotk adapter is disabled or
+ * disconnected, platform starts to use tun as external interface.
+ * When packet is sent to tun, it comes to openvpn, encapsulated
+ * and sent to routing table, which sends it again to tun.
+ */
+static void
+drop_if_recursive_routing (struct context *c, struct buffer *buf)
+{
+  bool drop = false;
+  struct openvpn_sockaddr tun_sa;
+
+  if (c->c2.to_link_addr == NULL) /* no remote addr known */
+return;
+
+  tun_sa = c->c2.to_link_addr->dest;
+
+  int proto_ver = get_tun_ip_ver (TUNNEL_TYPE (c->c1.tuntap), >c2.buf);
+
+  if (proto_ver == 4)
+{
+  const struct openvpn_iphdr *pip;
+
+  /* make sure we got whole IP header */
+  if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr))
+   return;
+
+  /* skip ipv4 packets for ipv6 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET)
+   return;
+
+  pip = (struct openvpn_iphdr *) BPTR (buf);
+
+  /* drop packets with same dest addr as gateway */
+  if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr)
+   drop = true;
+}
+  else if (proto_ver == 6)
+{
+  const struct openvpn_ipv6hdr *pip6;
+
+  /* make sure we got whole IPv6 header */
+  if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr))
+   return;
+
+  /* skip ipv6 packets for ipv4 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET6)
+   return;
+
+  /* drop packets with same dest addr as gateway */
+  pip6 = (struct openvpn_ipv6hdr *) BPTR(buf);
+  if (IN6_ARE_ADDR_EQUAL(_sa.addr.in6.sin6_addr, >daddr))
+   drop = true;
+}
+
+  if (drop)
+{
+  struct gc_arena gc = gc_new ();
+
+  c->c2.buf.len = 0;
+
+  msg(D_LOW, "Recursive routing detected, drop tun packet to %s",
+   print_link_socket_actual(c->c2.to_link_addr, ));
+  gc_free ();
+}
+}
+
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_link
@@ -993,6 +1062,8 @@ process_incoming_tun (struct context *c)
 
   if (c->c2.buf.len > 0)
 {
+  if ((c->options.mode == MODE_POINT_TO_POINT) && 
(!c->options.allow_recursive_routing))
+   drop_if_recursive_routing (c, >c2.buf);
   /*
* The --passtos and --mssfix options require
* us to examine the IP header (IPv4 or IPv6).
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 1ef0299..0ecaad9 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -500,6 +500,8 @@ static const char usage_message[] =
   "--server-poll-timeout n : when polling possible remote servers to connect 
to\n"
   "  in a round-robin fashion, spend no more than n seconds\n"
   "  waiting for a response before trying the next server.\n"
+  "--allow-recursive-routing : When this option is s

[Openvpn-devel] [PATCH v3] Support for disabled peer-id

2016-09-17 Thread Lev Stipakov
From: Lev Stipakov <lev.stipa...@f-secure.com>

v3:
* move assert outside of loop
* add max-clients value check to options

v2:
* Add round brackets for clarity
* Rephrase comment

Support for disabled peer-id

When peer-id value is 0xFF, server should ignore it and treat packet
in a same way as P_DATA_V1.
---
 src/openvpn/mudp.c| 13 ++---
 src/openvpn/multi.c   |  3 ++-
 src/openvpn/options.c |  5 +
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 21a7e97..59795eb 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -64,12 +64,16 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
   struct hash_bucket *bucket = hash_bucket (hash, hv);
   uint8_t* ptr = BPTR(>top.c2.buf);
   uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+  bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
+  bool peer_id_disabled = false;
 
   /* make sure buffer has enough length to read opcode (1 byte) and 
peer-id (3 bytes) */
-  if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
+  if (v2)
{
  uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
- if ((peer_id < m->max_clients) && (m->instances[peer_id]))
+ peer_id_disabled = (peer_id == 0xFF);
+
+ if (!peer_id_disabled && (peer_id < m->max_clients) && 
(m->instances[peer_id]))
{
  mi = m->instances[peer_id];
 
@@ -84,7 +88,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  }
}
}
-  else
+  if (!v2 || peer_id_disabled)
{
  he = hash_lookup_fast (hash, bucket, , hv);
  if (he)
@@ -107,6 +111,9 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
  hash_add_fast (hash, bucket, >real, hv, mi);
  mi->did_real_hash = true;
 
+ /* max_clients must be less then max peer-id value */
+ ASSERT(m->max_clients < 0xFF);
+
  for (i = 0; i < m->max_clients; ++i)
{
  if (!m->instances[i])
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index ba7f2c0..73b211e 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -605,7 +605,8 @@ multi_close_instance (struct multi_context *m,
}
 #endif
 
-  m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
+  if (mi->context.c2.tls_multi->peer_id != 0xFF)
+   m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
 
   schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
 
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index c9688c3..493ffe6 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -5893,6 +5893,11 @@ add_option (struct options *options,
  msg (msglevel, "--max-clients must be at least 1");
  goto err;
}
+  if (max_clients >= 0xFF) /* max peer-id value */
+   {
+ msg (msglevel, "--max-clients must be less than 0xFF");
+ goto err;
+   }
   options->max_clients = max_clients;
 }
   else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2])
-- 
1.9.1


--
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] [PATCH v4] Support for disabled peer-id

2016-09-17 Thread Lev Stipakov
From: Lev Stipakov <lev.stipa...@f-secure.com>

v4:
- replace magic number with define
- show user a decimal value instead of hex

v3:
* move assert outside of loop
* add max-clients value check to options

v2:
* Add round brackets for clarity
* Rephrase comment

Support for disabled peer-id

When peer-id value is 0xFF, server should ignore it and treat packet
in a same way as P_DATA_V1.
---
 src/openvpn/mudp.c| 13 ++---
 src/openvpn/multi.c   |  3 ++-
 src/openvpn/openvpn.h |  2 ++
 src/openvpn/options.c |  5 +
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 21a7e97..fec5e8d 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -64,12 +64,16 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
   struct hash_bucket *bucket = hash_bucket (hash, hv);
   uint8_t* ptr = BPTR(>top.c2.buf);
   uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+  bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
+  bool peer_id_disabled = false;
 
   /* make sure buffer has enough length to read opcode (1 byte) and 
peer-id (3 bytes) */
-  if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
+  if (v2)
{
  uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
- if ((peer_id < m->max_clients) && (m->instances[peer_id]))
+ peer_id_disabled = (peer_id == MAX_PEER_ID);
+
+ if (!peer_id_disabled && (peer_id < m->max_clients) && 
(m->instances[peer_id]))
{
  mi = m->instances[peer_id];
 
@@ -84,7 +88,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  }
}
}
-  else
+  if (!v2 || peer_id_disabled)
{
  he = hash_lookup_fast (hash, bucket, , hv);
  if (he)
@@ -107,6 +111,9 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
  hash_add_fast (hash, bucket, >real, hv, mi);
  mi->did_real_hash = true;
 
+ /* max_clients must be less then max peer-id value */
+ ASSERT(m->max_clients < MAX_PEER_ID);
+
  for (i = 0; i < m->max_clients; ++i)
{
  if (!m->instances[i])
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index ba7f2c0..3bc6ee9 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -605,7 +605,8 @@ multi_close_instance (struct multi_context *m,
}
 #endif
 
-  m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
+  if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID)
+   m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
 
   schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
 
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index 1a458f1..ec8075d 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -595,4 +595,6 @@ struct context
 #define CIPHER_ENABLED(c) (false)
 #endif
 
+#define MAX_PEER_ID 0xFF
+
 #endif
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index c9688c3..29c76a6 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -5893,6 +5893,11 @@ add_option (struct options *options,
  msg (msglevel, "--max-clients must be at least 1");
  goto err;
}
+  if (max_clients >= MAX_PEER_ID) /* max peer-id value */
+   {
+ msg (msglevel, "--max-clients must be less than 16777215");
+ goto err;
+   }
   options->max_clients = max_clients;
 }
   else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2])
-- 
1.9.1


--
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] [PATCH v5] Support for disabled peer-id

2016-09-18 Thread Lev Stipakov
From: Lev Stipakov <lev.stipa...@f-secure.com>

v5:
* Few more nickpicks

v4:
* replace magic number with define
* show user a decimal value instead of hex

v3:
* move assert outside of loop
* add max-clients value check to options

v2:
* Add round brackets for clarity
* Rephrase comment

Support for disabled peer-id

When peer-id value is 0xFF, server should ignore it and treat packet
in a same way as P_DATA_V1.
---
 src/openvpn/mudp.c| 13 ++---
 src/openvpn/multi.c   |  3 ++-
 src/openvpn/openvpn.h |  3 +++
 src/openvpn/options.c |  5 +
 4 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 21a7e97..fec5e8d 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -64,12 +64,16 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
   struct hash_bucket *bucket = hash_bucket (hash, hv);
   uint8_t* ptr = BPTR(>top.c2.buf);
   uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+  bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
+  bool peer_id_disabled = false;
 
   /* make sure buffer has enough length to read opcode (1 byte) and 
peer-id (3 bytes) */
-  if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
+  if (v2)
{
  uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
- if ((peer_id < m->max_clients) && (m->instances[peer_id]))
+ peer_id_disabled = (peer_id == MAX_PEER_ID);
+
+ if (!peer_id_disabled && (peer_id < m->max_clients) && 
(m->instances[peer_id]))
{
  mi = m->instances[peer_id];
 
@@ -84,7 +88,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  }
}
}
-  else
+  if (!v2 || peer_id_disabled)
{
  he = hash_lookup_fast (hash, bucket, , hv);
  if (he)
@@ -107,6 +111,9 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
  hash_add_fast (hash, bucket, >real, hv, mi);
  mi->did_real_hash = true;
 
+ /* max_clients must be less then max peer-id value */
+ ASSERT(m->max_clients < MAX_PEER_ID);
+
  for (i = 0; i < m->max_clients; ++i)
{
  if (!m->instances[i])
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index ba7f2c0..3bc6ee9 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -605,7 +605,8 @@ multi_close_instance (struct multi_context *m,
}
 #endif
 
-  m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
+  if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID)
+   m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
 
   schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
 
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index 1a458f1..65a183a 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -595,4 +595,7 @@ struct context
 #define CIPHER_ENABLED(c) (false)
 #endif
 
+/* this represents "disabled peer-id" */
+#define MAX_PEER_ID 0xFF
+
 #endif
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index c9688c3..4b7203d 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -5893,6 +5893,11 @@ add_option (struct options *options,
  msg (msglevel, "--max-clients must be at least 1");
  goto err;
}
+  if (max_clients >= MAX_PEER_ID) /* max peer-id value */
+   {
+ msg (msglevel, "--max-clients must be less than %d", MAX_PEER_ID);
+ goto err;
+   }
   options->max_clients = max_clients;
 }
   else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2])
-- 
1.9.1


--
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] [PATCH] Fix duplicated PUSH_REPLY options

2016-09-24 Thread Lev Stipakov
Starting from 
https://github.com/OpenVPN/openvpn/commit/3a5a46cf2b7f6a8b8520c2513a8054deb48bfcbe,
we add peer-id and cipher values to context->options->push_list instead of 
adding those directly
to buf (as done for client-specific values, like ifconfig). Since push_list is 
per child context,
when options are added and context is reused - we got duplicates.

Fixed by adding options to buffer, as it was done previously.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/push.c | 83 +++---
 1 file changed, 22 insertions(+), 61 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index a1b999e..5220bf0 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -40,30 +40,6 @@
 
 #if P2MP
 
-/**
- * Add an option to the push list by providing a format string.
- *
- * The string added to the push options is allocated in o->gc, so the caller
- * does not have to preserve anything.
- *
- * @param oThe current connection's options
- * @param msglevel The message level to use when printing errors
- * @param fmt  Format string for the option
- * @param ...  Format string arguments
- *
- * @return true on success, false on failure.
- */
-static bool push_option_fmt(struct options *o, int msglevel,
-const char *fmt, ...)
-#ifdef __GNUC__
-#if __USE_MINGW_ANSI_STDIO
-__attribute__ ((format (gnu_printf, 3, 4)))
-#else
-__attribute__ ((format (__printf__, 3, 4)))
-#endif
-#endif
-;
-
 /*
  * Auth username/password
  *
@@ -293,31 +269,31 @@ send_push_request (struct context *c)
 #if P2MP_SERVER
 
 /**
- * Prepare push options, based on local options and available peer info.
+ * Add peer specific options, based on local options and peer info.
  *
- * @param options  Connection options
  * @param tls_multiTLS state structure for the current tunnel
+ * @param options  Connection options
+ * @param buf  buffer to where options are added
  *
- * @return true on success, false on failure.
  */
-static bool
-prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
+static void
+add_peer_specific_opts (struct tls_multi *tls_multi, struct options *o, struct 
buffer *buf)
 {
-  const char *optstr = NULL;
   const char * const peer_info = tls_multi->peer_info;
-
+  const char *optstr = NULL;
+  
   /* Send peer-id if client supports it */
-  optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
+  optstr = peer_info ? strstr (peer_info, "IV_PROTO=") : NULL;
   if (optstr)
-{
-  int proto = 0;
-  int r = sscanf(optstr, "IV_PROTO=%d", );
-  if ((r == 1) && (proto >= 2))
-   {
- push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id);
-   }
-}
-
+  {
+int proto = 0;
+int r = sscanf (optstr, "IV_PROTO=%d", );
+if ((r == 1) && (proto >= 2))
+  {
+   buf_printf (buf, ",peer-id %d", tls_multi->peer_id);
+  }
+  }
+   
   /* Push cipher if client supports Negotiable Crypto Parameters */
   if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled)
 {
@@ -335,12 +311,11 @@ prepare_push_reply (struct options *o, struct tls_multi 
*tls_multi)
{
  /* Push the first cipher from --ncp-ciphers to the client.
   * TODO: actual negotiation, instead of server dictatorship. */
- char *push_cipher = string_alloc(o->ncp_ciphers, >gc);
+ char *push_cipher = string_alloc (o->ncp_ciphers, >gc);
  o->ciphername = strtok (push_cipher, ":");
- push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
+ buf_printf (buf, ",cipher %s", o->ciphername);
}
 }
-  return true;
 }
 
 static bool
@@ -414,6 +389,8 @@ send_push_reply (struct context *c)
   if (multi_push)
 buf_printf (, ",push-continuation 1");
 
+  add_peer_specific_opts (c->c2.tls_multi, >options, );
+
   if (BLEN () > sizeof(cmd)-1)
 {
   const bool status = send_control_channel_string (c, BSTR (), D_PUSH);
@@ -501,21 +478,6 @@ push_options (struct options *o, char **p, int msglevel, 
struct gc_arena *gc)
   push_option (o, opt, msglevel);
 }
 
-static bool push_option_fmt(struct options *o, int msglevel,
-const char *format, ...)
-{
-  va_list arglist;
-  char tmp[256] = {0};
-  int len = -1;
-  va_start (arglist, format);
-  len = vsnprintf (tmp, sizeof(tmp), format, arglist);
-  va_end (arglist);
-  if (len > sizeof(tmp)-1)
-return false;
-  push_option (o, string_alloc (tmp, >gc), msglevel);
-  return true;
-}
-
 void
 push_reset (struct options *o)
 {
@@ -580,8 +542,7 @@ process_incoming_push_request (struct context *c)
}
   else
{
- if (prepare_push_reply(>options, c->c

[Openvpn-devel] [PATCH 2.3] Exclude peer-id from pulled options digest

2016-09-24 Thread Lev Stipakov
Peer-id might change on restart and this should not trigger reopening
tun.

Trac #649
---
 src/openvpn/push.c | 38 --
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 71f39c1..6feaa2a 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -473,20 +473,30 @@ process_incoming_push_msg (struct context *c,
  permission_mask,
  option_types_found,
  c->c2.es))
-   switch (c->options.push_continuation)
- {
- case 0:
- case 1:
-   md5_state_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   md5_state_final (>c2.pulled_options_state, 
>c2.pulled_options_digest);
-   c->c2.pulled_options_md5_init_done = false;
-   ret = PUSH_MSG_REPLY;
-   break;
- case 2:
-   md5_state_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   ret = PUSH_MSG_CONTINUATION;
-   break;
- }
+   {
+ char line[OPTION_PARM_SIZE];
+ while (buf_parse (_orig, ',', line, sizeof (line)))
+   {
+ /* peer-id might change on restart and this should not 
trigger reopening tun */
+ if (strstr (line, "peer-id ") != line)
+   {
+ md_ctx_update (>c2.pulled_options_state, (const 
uint8_t *) line, strlen(line));
+   }
+   }
+ switch (c->options.push_continuation)
+   {
+ case 0:
+ case 1:
+   md_ctx_final (>c2.pulled_options_state, 
c->c2.pulled_options_digest.digest);
+   md_ctx_cleanup (>c2.pulled_options_state);
+   c->c2.pulled_options_md5_init_done = false;
+   ret = PUSH_MSG_REPLY;
+   break;
+ case 2:
+   ret = PUSH_MSG_CONTINUATION;
+   break;
+   }
+   }
}
   else if (ch == '\0')
{
-- 
1.9.1


--
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] [PATCH master] Exclude peer-id from pulled options digest

2016-09-24 Thread Lev Stipakov
Peer-id might change on restart and this should not trigger reopening
tun.

Trac #649
---
 src/openvpn/push.c | 39 ---
 1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index a1b999e..d7d54bf 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -636,21 +636,30 @@ process_incoming_push_msg (struct context *c,
  permission_mask,
  option_types_found,
  c->c2.es))
-   switch (c->options.push_continuation)
- {
- case 0:
- case 1:
-   md_ctx_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   md_ctx_final (>c2.pulled_options_state, 
c->c2.pulled_options_digest.digest);
-   md_ctx_cleanup (>c2.pulled_options_state);
-   c->c2.pulled_options_md5_init_done = false;
-   ret = PUSH_MSG_REPLY;
-   break;
- case 2:
-   md_ctx_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   ret = PUSH_MSG_CONTINUATION;
-   break;
- }
+   {
+ char line[OPTION_PARM_SIZE];
+ while (buf_parse (_orig, ',', line, sizeof (line)))
+   {
+ /* peer-id might change on restart and this should not 
trigger reopening tun */
+ if (strstr (line, "peer-id ") != line)
+   {
+ md_ctx_update (>c2.pulled_options_state, (const 
uint8_t *) line, strlen(line));
+   }
+   }
+ switch (c->options.push_continuation)
+   {
+ case 0:
+ case 1:
+   md_ctx_final (>c2.pulled_options_state, 
c->c2.pulled_options_digest.digest);
+   md_ctx_cleanup (>c2.pulled_options_state);
+   c->c2.pulled_options_md5_init_done = false;
+   ret = PUSH_MSG_REPLY;
+   break;
+ case 2:
+   ret = PUSH_MSG_CONTINUATION;
+   break;
+   }
+   }
}
   else if (ch == '\0')
{
-- 
1.9.1


--
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


Re: [Openvpn-devel] [PATCH] Fix duplicated PUSH_REPLY options

2016-10-01 Thread Lev Stipakov
Hi,

ACK from me - tested that peer-id and cipher are not duplicated in
PUSH_REPLY when client reconnects and push-continuation works.

-Lev

2016-09-29 20:49 GMT+03:00 Steffan Karger <stef...@karger.me>:

> Hi,
>
> On 24 September 2016 at 12:23, Lev Stipakov <lstipa...@gmail.com> wrote:
> > Starting from https://github.com/OpenVPN/openvpn/commit/
> 3a5a46cf2b7f6a8b8520c2513a8054deb48bfcbe,
> > we add peer-id and cipher values to context->options->push_list instead
> of adding those directly
> > to buf (as done for client-specific values, like ifconfig). Since
> push_list is per child context,
> > when options are added and context is reused - we got duplicates.
> >
> > Fixed by adding options to buffer, as it was done previously.
>
> NAK.  This reintroduces another issue, where the added options might
> not fit into buf, because we can't reserve space for variable-sized
> options (peer-id would be possible, by cipher would already be
> trickier).
>
> This is a bug though (sorry!), so attached a different proposal to fix
> this.  I didn't test this yet (need to leave now), but lev just
> announced on IRC that he was willing to test it.
>
> -Steffan
>



-- 
-Lev
--
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] Fwd: [PATCH] Fix duplicated PUSH_REPLY options

2016-10-01 Thread Lev Stipakov
Hi,

Attempt #2 - now with attached patch.

ACK from me - tested that peer-id and cipher are not duplicated in
PUSH_REPLY when client reconnects and push-continuation works.

-Lev


-- Forwarded message --
From: Steffan Karger <stef...@karger.me>
Date: 2016-09-29 20:49 GMT+03:00
Subject: Re: [Openvpn-devel] [PATCH] Fix duplicated PUSH_REPLY options
To: Lev Stipakov <lstipa...@gmail.com>


Hi,

On 24 September 2016 at 12:23, Lev Stipakov <lstipa...@gmail.com> wrote:
> Starting from https://github.com/OpenVPN/openvpn/commit/3a5a46cf2b7f6a8b85
20c2513a8054deb48bfcbe,
> we add peer-id and cipher values to context->options->push_list instead
of adding those directly
> to buf (as done for client-specific values, like ifconfig). Since
push_list is per child context,
> when options are added and context is reused - we got duplicates.
>
> Fixed by adding options to buffer, as it was done previously.

NAK.  This reintroduces another issue, where the added options might
not fit into buf, because we can't reserve space for variable-sized
options (peer-id would be possible, by cipher would already be
trickier).

This is a bug though (sorry!), so attached a different proposal to fix
this.  I didn't test this yet (need to leave now), but lev just
announced on IRC that he was willing to test it.

-Steffan



-- 
-Lev
From 957c54a7f4cefdc05e5e876195ef31a52c00f2b3 Mon Sep 17 00:00:00 2001
From: Steffan Karger <stef...@karger.me>
Date: Thu, 29 Sep 2016 19:48:29 +0200
Subject: [PATCH] Fix duplicate PUSH_REPLY options

As reported by Lev Stipakov, starting from 3a5a46cf we add peer-id and
cipher values to context->options->push_list instead of adding those
directly to buf. Since push_list is preserved over sigusr1 restarts,
we add duplicate values for peer-id and cipher.

Fixed by removing the previous values from the list before adding new ones.

Signed-off-by: Steffan Karger <stef...@karger.me>
---
 src/openvpn/errlevel.h | 1 +
 src/openvpn/options.c  | 1 +
 src/openvpn/push.c | 6 --
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h
index da600ab..ae1f8f4 100644
--- a/src/openvpn/errlevel.h
+++ b/src/openvpn/errlevel.h
@@ -147,6 +147,7 @@
 #define D_PID_DEBUG  LOGLEV(7, 70, M_DEBUG)  /* show packet-id debugging info */
 #define D_PF_DROPPED_BCAST   LOGLEV(7, 71, M_DEBUG)  /* packet filter dropped a broadcast packet */
 #define D_PF_DEBUG   LOGLEV(7, 72, M_DEBUG)  /* packet filter debugging, must also define PF_DEBUG in pf.h */
+#define D_PUSH_DEBUG LOGLEV(7, 73, M_DEBUG)  /* show push/pull debugging info */
 
 #define D_HANDSHAKE_VERBOSE  LOGLEV(8, 70, M_DEBUG)  /* show detailed description of each handshake */
 #define D_TLS_DEBUG_MED  LOGLEV(8, 70, M_DEBUG)  /* limited info from tls_session routines */
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 53b4617..ccb6b28 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -5781,6 +5781,7 @@ add_option (struct options *options,
   else if (streq (p[0], "push-remove") && p[1] && !p[2])
 {
   VERIFY_PERMISSION (OPT_P_INSTANCE);
+  msg (D_PUSH, "PUSH_REMOVE '%s'", p[1]);
   push_remove_option (options,p[1]);
 }
   else if (streq (p[0], "ifconfig-pool") && p[1] && p[2] && !p[4])
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index a1b999e..4d1dd34 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -314,6 +314,7 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
   int r = sscanf(optstr, "IV_PROTO=%d", );
   if ((r == 1) && (proto >= 2))
 	{
+	  push_remove_option(o, "peer-id");
 	  push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id);
 	}
 }
@@ -337,6 +338,7 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
 	   * TODO: actual negotiation, instead of server dictatorship. */
 	  char *push_cipher = string_alloc(o->ncp_ciphers, >gc);
 	  o->ciphername = strtok (push_cipher, ":");
+	  push_remove_option(o, "cipher");
 	  push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
 	}
 }
@@ -525,7 +527,7 @@ push_reset (struct options *o)
 void
 push_remove_option (struct options *o, const char *p)
 {
-  msg( D_PUSH, "PUSH_REMOVE '%s'", p );
+  msg (D_PUSH_DEBUG, "PUSH_REMOVE searching for: '%s'", p);
 
   /* ifconfig-ipv6 is special, as not part of the push list */
   if ( streq( p, "ifconfig-ipv6" ))
@@ -544,7 +546,7 @@ push_remove_option (struct options *o, const char *p)
 	  if ( e->enable &&
strncmp( e->option, p, strlen(p) ) == 0 )
 	{
-	  msg (D_PUSH, "PUSH_REMOVE removing: '%s'", e->option);
+	  msg (D_PUSH_DEBUG, "PUSH_

[Openvpn-devel] [PATCH v2 2.3] Exclude peer-id from pulled options digest

2016-10-04 Thread Lev Stipakov
v2:
 - Use md5_* methods
 - Move digest update to separate method

Peer-id might change on restart and this should not trigger reopening
tun.

Trac #649
---
 src/openvpn/push.c | 43 +--
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 71f39c1..402c158 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -407,6 +407,20 @@ push_reset (struct options *o)
 }
 #endif
 
+static void
+push_update_digest(struct md5_state *ctx, struct buffer *buf)
+{
+  char line[OPTION_PARM_SIZE];
+  while (buf_parse (buf, ',', line, sizeof (line)))
+{
+  /* peer-id might change on restart and this should not trigger reopening 
tun */
+  if (strstr (line, "peer-id ") != line)
+   {
+ md5_state_update (ctx, line, strlen(line));
+   }
+}
+}
+
 int
 process_incoming_push_msg (struct context *c,
   const struct buffer *buffer,
@@ -473,20 +487,21 @@ process_incoming_push_msg (struct context *c,
  permission_mask,
  option_types_found,
  c->c2.es))
-   switch (c->options.push_continuation)
- {
- case 0:
- case 1:
-   md5_state_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   md5_state_final (>c2.pulled_options_state, 
>c2.pulled_options_digest);
-   c->c2.pulled_options_md5_init_done = false;
-   ret = PUSH_MSG_REPLY;
-   break;
- case 2:
-   md5_state_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   ret = PUSH_MSG_CONTINUATION;
-   break;
- }
+   {
+ push_update_digest (>c2.pulled_options_state, _orig);
+ switch (c->options.push_continuation)
+   {
+ case 0:
+ case 1:
+   md5_state_final (>c2.pulled_options_state, 
>c2.pulled_options_digest);
+   c->c2.pulled_options_md5_init_done = false;
+   ret = PUSH_MSG_REPLY;
+   break;
+ case 2:
+   ret = PUSH_MSG_CONTINUATION;
+   break;
+   }
+   }
}
   else if (ch == '\0')
{
-- 
1.9.1


--
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] [PATCH v2] Exclude peer-id from pulled options digest

2016-10-04 Thread Lev Stipakov
v2:
 - Move digest update to separate method

Peer-id might change on restart and this should not trigger reopening
tun.

Trac #649
---
 src/openvpn/push.c | 45 ++---
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index a1b999e..c0c78a0 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -597,6 +597,20 @@ process_incoming_push_request (struct context *c)
 }
 #endif
 
+static void
+push_update_digest(md_ctx_t *ctx, struct buffer *buf)
+{
+  char line[OPTION_PARM_SIZE];
+  while (buf_parse (buf, ',', line, sizeof (line)))
+{
+  /* peer-id might change on restart and this should not trigger reopening 
tun */
+  if (strstr (line, "peer-id ") != line)
+   {
+ md_ctx_update (ctx, (const uint8_t *) line, strlen(line));
+   }
+}
+}
+
 int
 process_incoming_push_msg (struct context *c,
   const struct buffer *buffer,
@@ -636,21 +650,22 @@ process_incoming_push_msg (struct context *c,
  permission_mask,
  option_types_found,
  c->c2.es))
-   switch (c->options.push_continuation)
- {
- case 0:
- case 1:
-   md_ctx_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   md_ctx_final (>c2.pulled_options_state, 
c->c2.pulled_options_digest.digest);
-   md_ctx_cleanup (>c2.pulled_options_state);
-   c->c2.pulled_options_md5_init_done = false;
-   ret = PUSH_MSG_REPLY;
-   break;
- case 2:
-   md_ctx_update (>c2.pulled_options_state, BPTR(_orig), 
BLEN(_orig));
-   ret = PUSH_MSG_CONTINUATION;
-   break;
- }
+   {
+ push_update_digest (>c2.pulled_options_state, _orig);
+ switch (c->options.push_continuation)
+   {
+ case 0:
+ case 1:
+   md_ctx_final (>c2.pulled_options_state, 
c->c2.pulled_options_digest.digest);
+   md_ctx_cleanup (>c2.pulled_options_state);
+   c->c2.pulled_options_md5_init_done = false;
+   ret = PUSH_MSG_REPLY;
+   break;
+ case 2:
+   ret = PUSH_MSG_CONTINUATION;
+   break;
+   }
+   }
}
   else if (ch == '\0')
{
-- 
1.9.1


--
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


Re: [Openvpn-devel] [PATCH 2.3] Fix compilation in pedantic mode

2016-10-05 Thread Lev Stipakov
Hi,


I am, and the first version is what we do in (most?) other places, so I'll
> change that on the fly.
>

Got it.


> Also, the patch introduces spurious tab<->whitespace changes "close to
> comments" in a few places - will undo those, too.


I noticed that in few places indentation is a bit off - like 8 whitespaces
instead of tab so I decided to "fix" it.

Should I just ignore those things or do it in separate PR?

-- 
-Lev
--
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


Re: [Openvpn-devel] [PATCH v3] Floating: Add support for floating in TLS mode

2014-01-03 Thread Lev Stipakov
Hi Arne,

I am researching how "session id" can be added to packet. Could you please 
clarify the statement "If we choose the session id to be 3 or 7 byte we 
would not need the "hack" for the packets with
session id." ?

I am currently at very beginning, so questions might look odd.

1) "3 or 7" - does it mean byte's ordinal number in packet or length of 
session id in bytes?

2) What you mean by "hack"? Do you mean new packet format or something else?

3) I am trying to comprehend protocol format reading 
http://openvpn.net/index.php/open-source/documentation/security-
overview.html and looking at wireshark capture results. Where exactly 
session id field should be placed?

-Lev




[Openvpn-devel] New frame format with session ID

2014-03-10 Thread Lev Stipakov
Hi guys,

I've read January's IRC meeting minutes and there was a discussion
about new frame format with session id.

Is there any progress in this field so far? If James or someone happen
to have time to document a new format, would be nice to see it.

-- 
-Lev



[Openvpn-devel] session-id implementation

2014-03-26 Thread Lev Stipakov
Hello,

Despite that implementation of session-id has already been discussed,
I would like to propose an alternative approach.

I suggest to use an array of multi_instance objects and session-id as
an item's index in that array. Why I think it is a good idea?

1) We could utilize less bytes for session-id, since array's max
length would be equal to max_clients. 3 bytes for a max of 2**24
clients, no need to swap one byte to the end of packet.

[op][s1][s2][s3][data]

2) Lookup in array is faster than lookup by 8-byte session-id in
hashtable and happens with constant speed.

3) Proof of concept is attached!

I have tested it with openvpn master branch (server) and ics-openvpn
(android) - merged without any conflicts and works nicely. Of course
it supports also peers without session-id support.

This patch solves 2 issues for mobile clients:

1) UDP NAT timeout. After, say, 30, seconds router might close UDP
socket and new packet from client to VPN server originates from
different port. Lookup by peer address fails and packet got dropped.
Currently this is solved by small keep-alive interval, which drains
battery. With new implementation it is not an issue anymore since
lookup is done by session-id, therefore keep-alive interval can be
increased.

2) Transition between networks (for example WiFi->3G). Without
session-id client got disconnected. With this patch and
http://code.google.com/p/ics-openvpn/source/detail?r=bc9f3f448b9a4d95c999d3e582987840ba1e0fbf
transition happens seamlessly.

I would love to hear any critics / comments!

-- 
-Lev
From 284e473548a49012baf6c954a637161eec11c2e8 Mon Sep 17 00:00:00 2001
From: Lev Stipakov <lev.stipa...@f-secure.com>
Date: Tue, 11 Mar 2014 17:58:31 +0200
Subject: [PATCH] Floating implementation. Use array lookup for new opcode
 P_DATA_V2 and check HMAC for floated peers.

---
 src/openvpn/crypto.c |  54 
 src/openvpn/crypto.h |   3 ++
 src/openvpn/mudp.c   | 106 ---
 src/openvpn/multi.c  |  14 ++-
 src/openvpn/multi.h  |   2 +
 src/openvpn/options.c|  15 ++-
 src/openvpn/options.h|   4 +-
 src/openvpn/push.c   |   8 +++-
 src/openvpn/ssl.c|  59 +++---
 src/openvpn/ssl.h|   9 +++-
 src/openvpn/ssl_common.h |   4 ++
 11 files changed, 259 insertions(+), 19 deletions(-)

diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index c4c356d..8c0d33f 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -389,6 +389,60 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }
 
 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  struct gc_arena gc;
+  gc_init ();
+  int offset = 4; /* 1 byte opcode + 3 bytes session-id */
+
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+	{
+	  int hmac_len;
+	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
+
+	  hmac_ctx_reset(ctx->hmac);
+
+	  /* Assume the length of the input HMAC */
+	  hmac_len = hmac_ctx_size (ctx->hmac);
+
+	  /* Authentication fails if insufficient data in packet for HMAC */
+	  if ((buf->len - offset) < hmac_len)
+	{
+	  gc_free ();
+	  return false;
+	}
+
+	  hmac_ctx_update (ctx->hmac, BPTR (buf) + offset + hmac_len,
+			   BLEN (buf) - offset - hmac_len);
+	  hmac_ctx_final (ctx->hmac, local_hmac);
+
+	  /* Compare locally computed HMAC with packet HMAC */
+	  if (memcmp (local_hmac, BPTR (buf) + offset, hmac_len))
+	{
+	  gc_free ();
+	  return false;
+	}
+
+	  gc_free ();
+	  return true;
+	}
+}
+
+  gc_free ();
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index 3b4b88e..68cdf16 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -279,6 +279,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work,
 		  const struct crypto_options *opt,
 		  const struct frame* frame);
 
+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
 /** @} name Functions for performing security operations on data channel packets */
 
 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3468dab..f7ab625 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -38,6 +38,55 @@
 #include "memdbg.h"
 
 /*
+ * Update instance with new peer address
+ */
+void
+update_floated(struct multi_context *m, struct multi_instance *mi,
+	   struct mroute_addr real, uint32_t hv)
+{
+  struct mroute_addr real_old;
+
+  real_old = mi->real;
+  generate_pr

Re: [Openvpn-devel] session-id implementation

2014-03-27 Thread Lev Stipakov
Hi,

Same patch with added NULL check in push.c:308. Turns out that
peer_info might be NULL.

-Lev

On Wed, Mar 26, 2014 at 10:52 AM, Lev Stipakov <lstipa...@gmail.com> wrote:
> Hello,
>
> Despite that implementation of session-id has already been discussed,
> I would like to propose an alternative approach.
>
> I suggest to use an array of multi_instance objects and session-id as
> an item's index in that array. Why I think it is a good idea?
>
> 1) We could utilize less bytes for session-id, since array's max
> length would be equal to max_clients. 3 bytes for a max of 2**24
> clients, no need to swap one byte to the end of packet.
>
> [op][s1][s2][s3][data]
>
> 2) Lookup in array is faster than lookup by 8-byte session-id in
> hashtable and happens with constant speed.
>
> 3) Proof of concept is attached!
>
> I have tested it with openvpn master branch (server) and ics-openvpn
> (android) - merged without any conflicts and works nicely. Of course
> it supports also peers without session-id support.
>
> This patch solves 2 issues for mobile clients:
>
> 1) UDP NAT timeout. After, say, 30, seconds router might close UDP
> socket and new packet from client to VPN server originates from
> different port. Lookup by peer address fails and packet got dropped.
> Currently this is solved by small keep-alive interval, which drains
> battery. With new implementation it is not an issue anymore since
> lookup is done by session-id, therefore keep-alive interval can be
> increased.
>
> 2) Transition between networks (for example WiFi->3G). Without
> session-id client got disconnected. With this patch and
> http://code.google.com/p/ics-openvpn/source/detail?r=bc9f3f448b9a4d95c999d3e582987840ba1e0fbf
> transition happens seamlessly.
>
> I would love to hear any critics / comments!
>
> --
> -Lev



-- 
-Lev
From 0f330408e4b013cd505ad9492888557daa47e905 Mon Sep 17 00:00:00 2001
From: Lev Stipakov <lev.stipa...@f-secure.com>
Date: Tue, 11 Mar 2014 17:58:31 +0200
Subject: [PATCH] Floating implementation. Use array lookup for new opcode
 P_DATA_V2 and check HMAC for floated peers.

---
 src/openvpn/crypto.c |  54 
 src/openvpn/crypto.h |   3 ++
 src/openvpn/mudp.c   | 106 ---
 src/openvpn/multi.c  |  14 ++-
 src/openvpn/multi.h  |   2 +
 src/openvpn/options.c|  15 ++-
 src/openvpn/options.h|   4 +-
 src/openvpn/push.c   |   8 +++-
 src/openvpn/ssl.c|  59 +++---
 src/openvpn/ssl.h|   9 +++-
 src/openvpn/ssl_common.h |   4 ++
 11 files changed, 259 insertions(+), 19 deletions(-)

diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index c4c356d..8c0d33f 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -389,6 +389,60 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }
 
 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  struct gc_arena gc;
+  gc_init ();
+  int offset = 4; /* 1 byte opcode + 3 bytes session-id */
+
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+	{
+	  int hmac_len;
+	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
+
+	  hmac_ctx_reset(ctx->hmac);
+
+	  /* Assume the length of the input HMAC */
+	  hmac_len = hmac_ctx_size (ctx->hmac);
+
+	  /* Authentication fails if insufficient data in packet for HMAC */
+	  if ((buf->len - offset) < hmac_len)
+	{
+	  gc_free ();
+	  return false;
+	}
+
+	  hmac_ctx_update (ctx->hmac, BPTR (buf) + offset + hmac_len,
+			   BLEN (buf) - offset - hmac_len);
+	  hmac_ctx_final (ctx->hmac, local_hmac);
+
+	  /* Compare locally computed HMAC with packet HMAC */
+	  if (memcmp (local_hmac, BPTR (buf) + offset, hmac_len))
+	{
+	  gc_free ();
+	  return false;
+	}
+
+	  gc_free ();
+	  return true;
+	}
+}
+
+  gc_free ();
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index 3b4b88e..68cdf16 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -279,6 +279,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work,
 		  const struct crypto_options *opt,
 		  const struct frame* frame);
 
+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
 /** @} name Functions for performing security operations on data channel packets */
 
 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/mudp.c b/src/openvpn/

[Openvpn-devel] ipv6 env vars to client scripts

2014-04-17 Thread Lev Stipakov
Hello,

Are there any plans to support ipv6 env vars in
client-connect/disconnect scripts?

There are at least 2 tickes on that feature:

https://community.openvpn.net/openvpn/ticket/230
https://community.openvpn.net/openvpn/ticket/369

Is there anything that prevents merging any of suggested patches to
the master branch?

-- 
-Lev



[Openvpn-devel] Rekey and Defer sample plugin

2014-06-10 Thread Lev Stipakov
Hello,

I'm facing a problem with "defer" sample plugin and rekeying.

I use plugin from
https://github.com/OpenVPN/openvpn/tree/master/sample/sample-plugins/defer.

Relevant part of openvpn config:

> auth-user-pass-optional
> setenv test_deferred_auth 2
> plugin /etc/openvpn/simple.so
> reneg-sec 20

Everything works fine, plugin writes into auth control file in 2 secs
and client got authenticated. When rekeying happends, plugin got
called and writes again to auth control file, however after that
connection breaks.

Part of OpenVPN log:

OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
DEFER u='' p='' acf='/tmp/openvpn_acf_8ec7b1fb155ede01c8bae22c6e4ad4ea.tmp'
( sleep 2 ; echo AUTH
/tmp/openvpn_acf_8ec7b1fb155ede01c8bae22c6e4ad4ea.tmp 2 ; echo 1
>/tmp/openvpn_acf_8ec7b1fb155ede01c8bae22c6e4ad4ea.tmp ) &
Tue Jun 10 13:25:50 2014 us=851659
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 PLUGIN_CALL:
POST /etc/openvpn/simple.so/PLUGIN_AUTH_USER_PASS_VERIFY status=2
Tue Jun 10 13:25:50 2014 us=851680
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 TLS:
Username/Password authentication deferred for username ''
OPENVPN_PLUGIN_TLS_FINAL
Tue Jun 10 13:25:50 2014 us=851695
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 PLUGIN_CALL:
POST /etc/openvpn/simple.so/PLUGIN_TLS_FINAL status=0
Tue Jun 10 13:25:50 2014 us=851842
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 Data Channel
Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
Tue Jun 10 13:25:50 2014 us=851850
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 Data Channel
Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Tue Jun 10 13:25:50 2014 us=851894
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 Data Channel
Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
Tue Jun 10 13:25:50 2014 us=851902
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 Data Channel
Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Tue Jun 10 13:25:50 2014 us=853273
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 Control Channel:
TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 2048 bit RSA
Tue Jun 10 13:25:51 2014 us=238477
588b4d7d-f8ec-4397-8156-43ed232c2dd8/10.64.1.101:1194 TLS Error:
local/remote TLS keys are out of sync: [AF_INET]10.64.1.101:1194 [1]

and after that lots of "TLS keys are out of sync".

Is it kind of a bug in OpenVPN/sample plugin or am I missing something
in configuration? Anything can be done (maybe in OpenVPN code) to make
it work?

-- 
-Lev



[Openvpn-devel] Async OPENVPN_PLUGIN_CLIENT_CONNECT plugin support

2014-07-29 Thread Lev Stipakov
Hello,

I am pondering about asynchronous OPENVPN_PLUGIN_CLIENT_CONNECT
callback. Basically, I want _not_ to establish connection until
response is received and ofcI  don't want to block rest of traffic.

My idea is to have some kind of connect_control_file (similar to
auth_conrol_file) and pass its path via env to
OPENVPN_PLUGIN_CLIENT_CONNECT. In case of plugin (or maybe script
too?) has returned OPENVPN_PLUGIN_FUNC_DEFERRED, I continue executing
"multi_connection_established" as usual except I don't set
"push_reply_deferred" to False (to prevent push response from being
sent) and I set some "connect-deferred" flag.

Next, when "process_incoming_push_msg" get called and flag
"connect-deferred" is set, I check the state of connect_control_file.
If there is, say, "1" - I send push reply and connection got
established.

What do you think about that? Does that approach sound reasonable?

-- 
-Lev



[Openvpn-devel] Possible memory leaks found by Coverity

2014-08-14 Thread Lev Stipakov
Hello,

I have analyzed OpenVPN code with Coverity and I could not explain
some resource leaks Coverity has found.

1) https://github.com/OpenVPN/openvpn/blob/master/src/openvpn/options.c#L4378

char * ipv6_local;
VERIFY_PERMISSION (OPT_P_UP);
if ( get_ipv6_addr( p[1], NULL, , _local, msglevel ) &&
ipv6_addr_safe( p[2] ) ) {
  if ( netbits < 64 || netbits > 124 ) {
msg( msglevel, "ifconfig-ipv6: /netbits must be between 64 and
124, not '/%d'", netbits );
goto err;
  }

Coverity claims that "err" branch leaks "ipv6_local". I looked into
"get_ipv6_addr" implementation and noticed that it does not pass any
"gc" to subsequent string_alloc call. To my understanding, in this
case caller is responsible for cleaning up, which is not the case for
"err" branch.


2) https://github.com/OpenVPN/openvpn/blob/master/src/openvpn/proxy.c#L863

char *pa = NULL;
const int method = get_proxy_authenticate(sd, p->options.timeout, ,
NULL, signal_received);
if (method != HTTP_AUTH_NONE) {
  if (pa)
msg (D_PROXY, "HTTP proxy authenticate '%s'", pa);
if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) {
  msg (D_PROXY, "HTTP proxy: support for basic auth and other
cleartext proxy auth methods is disabled");
  goto error;
}

Coverity claims that "error" branch leaks "pa". Same pattern as above,
"get_proxy_authenticate" passes NULL (4th parameter) as "gc" to
"string_alloc".

Do those issues look like problems? Does it make sense to submit a
patch fixing those?

-- 
-Lev



Re: [Openvpn-devel] session-id implementation

2014-10-02 Thread Lev Stipakov
Hello Arne, Heikki and everyone,

Apologize for the delay. Patch with review suggestions attached.


-Lev.


2014-08-12 11:26 GMT+03:00 Heikki Hannikainen <he...@hes.iki.fi>:
> On Wed, 9 Jul 2014, Arne Schwabe wrote:
>
>> Am 29.06.14 18:13, schrieb Arne Schwabe:
>>>
>>> Am 27.03.14 09:57, schrieb Lev Stipakov:
>>>>
>>>> Hi,
>>>>
>>>> Same patch with added NULL check in push.c:308. Turns out that
>>>> peer_info might be NULL.
>>>>
>>> I looked at the patched, a few minor nitpicks:
>
>
> One more little nitpick:
>
>   uint32_t sess;
>
>...
>
>   sess = ((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) |
> (multi->vpn_session_id << 8);
>   ASSERT (buf_write_prepend (buf, , 4));
>
> I think this will cause byte sex issues when talking between big and little
> endian machines.
>
> A strategically placed htonl() + ntohl() pair might help.  Have to make sure
> that the opcode really goes in as the first byte on the wire, and that the
> next 3 bytes are the 3 least significant bytes of the session ID.
>
>   uint32_t sess = htonl(
> (((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24)
> | (multi->vpn_session_id & 0xFF)
>   );
>   ASSERT (buf_write_prepend (buf, , 4));
>
> Right? Maybe? :)
>
> I suppose this patch will improve things quite a bit for mobile clients
> which switch from network to another.
>
>   - Hessu
>



-- 
-Lev
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index c4c356d..8c0d33f 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -389,6 +389,60 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }
 
 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  struct gc_arena gc;
+  gc_init ();
+  int offset = 4; /* 1 byte opcode + 3 bytes session-id */
+
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+	{
+	  int hmac_len;
+	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
+
+	  hmac_ctx_reset(ctx->hmac);
+
+	  /* Assume the length of the input HMAC */
+	  hmac_len = hmac_ctx_size (ctx->hmac);
+
+	  /* Authentication fails if insufficient data in packet for HMAC */
+	  if ((buf->len - offset) < hmac_len)
+	{
+	  gc_free ();
+	  return false;
+	}
+
+	  hmac_ctx_update (ctx->hmac, BPTR (buf) + offset + hmac_len,
+			   BLEN (buf) - offset - hmac_len);
+	  hmac_ctx_final (ctx->hmac, local_hmac);
+
+	  /* Compare locally computed HMAC with packet HMAC */
+	  if (memcmp (local_hmac, BPTR (buf) + offset, hmac_len))
+	{
+	  gc_free ();
+	  return false;
+	}
+
+	  gc_free ();
+	  return true;
+	}
+}
+
+  gc_free ();
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index 3b4b88e..68cdf16 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -279,6 +279,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work,
 		  const struct crypto_options *opt,
 		  const struct frame* frame);
 
+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
 /** @} name Functions for performing security operations on data channel packets */
 
 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 3b72b96..fef7c1d 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1748,7 +1748,8 @@ pull_permission_mask (const struct context *c)
 | OPT_P_MESSAGES
 | OPT_P_EXPLICIT_NOTIFY
 | OPT_P_ECHO
-| OPT_P_PULL_MODE;
+| OPT_P_PULL_MODE
+| OPT_P_SESSION_ID;
 
   if (!c->options.route_nopull)
 flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
@@ -1825,6 +1826,13 @@ do_deferred_options (struct context *c, const unsigned int found)
 msg (D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified");
   if (found & OPT_P_SETENV)
 msg (D_PUSH, "OPTIONS IMPORT: environment modified");
+
+  if (found & OPT_P_SESSION_ID)
+{
+  msg (D_PUSH, "OPTIONS IMPORT: session-id set");
+  c->c2.tls_multi->use_session_id = true;
+  c->c2.tls_multi->vpn_session_id = c->options.vpn_session_id;
+}
 }
 
 /*
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3468dab..7a6911c 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -38,6 +38,55 @@
 #include "memdbg.h"
 
 /*
+ * Update instance with new peer address
+ */
+void
+update_floated

Re: [Openvpn-devel] Async OPENVPN_PLUGIN_CLIENT_CONNECT plugin support

2014-10-07 Thread Lev Stipakov
Hi Fabian & all,

Patch works great, thanks! I have rebased it a bit and added support
for client-connect plugin call.

I would like to offer a related feature (and implementation) I call async-push.

Use case: authentication / authorization takes time. I have auth/az
code in auth-user-pass-verify and client-connect calls, and sometimes
it takes more that second to execute those. The problem is that after
auth-user-pass-verify is done, OpenVPN server won’t proceed with
client-connect unless some timeout/io event happens for that client.
Also, server will not notify client that client-connect returned
success unless client sends PULL_REQUEST. Client, in turn, sends
PULL_REQUEST one second after connection initiation and after that
once per 5 seconds. So, for example, if at the moment when first pull
request has arrived, client-connect has not finished yet, we will have
to wait another 5 seconds for the next PULL_REQUEST.

Solution: Inotify. Since OpenVPN creates itself files (auth-contro and
client-connect-deferred) which names it passes to the plugin, we
create one inotify descriptor for event loop and right after creating
those files, we add inotify watch on those. Before calling epoll (or
whatever we use) we add inotify descriptor to the list of watched
descriptors. We also keep watch descriptor and multi_instance in a
hashtable.

When epoll informs us that an event has happened on inotify
descriptor, we get multi_instance by watch descriptor (fetched from
poll event) from our new hashtable and call multi_process_post for
given multi_instance. This will check result from the file and
eventually call multi_connection_established, from where we call
send_push_reply.

Since implementation uses Inotify, it will work on Linux only. Code is
under #define, which is set at compile-time (--enable-async-push=yes).

I have attached an implementation. So far has been working nicely in
my test environment. I would love to hear a feedback from the
community. Is the whole thing done more or less right? Any bugs got
introduced that someone could spot?

-Lev

2014-08-01 0:21 GMT+03:00 Fabian Knittel <fabian.knit...@lettink.de>:
> Hi Lev,
>
> 2014-07-29 12:56 GMT+02:00 Lev Stipakov <lstipa...@gmail.com>:
>>
>> I am pondering about asynchronous OPENVPN_PLUGIN_CLIENT_CONNECT
>> callback. Basically, I want _not_ to establish connection until
>> response is received and ofcI  don't want to block rest of traffic.
>
>
> [ Details of approach snipped. ]
>
>> What do you think about that? Does that approach sound reasonable?
>
>
> Some time ago I implemented something quite similar, but never quite managed
> to officially submit it. You can find my old git branch here [0].
> Unfortunately, to be of any use it would need to be ported to a current
> OpenVPN release / master first.
>
> The code has been in use for several years now [1], so the approach and the
> code basically work quite well. (I think my use case involved calling a
> Python script, but I might have implemented the plugin part too.)
>
> If the OpenVPN commiters see a certain chance, that such a change could be
> included upstream, I might even try to rebase the branch to master myself...
>
> Cheers
> Fabian
>
> 0:
> http://opensource.fsmi.uni-karlsruhe.de/gitweb/?p=openvpn.git;a=shortlog;h=refs/heads/feat_deferred_client-connect
> 1: ... in a production environment with several hundred users (together with
> the equally unofficial VLAN-tagging feature [2]). The feature is needed by a
> daemon that does asynchronous IP-configuration via a central DHCP server
> [3].
> 2:
> http://opensource.fsmi.uni-karlsruhe.de/gitweb/?p=openvpn.git;a=shortlog;h=refs/heads/feat_vlan
> 3: https://gitorious.org/odr



-- 
-Lev
diff --git a/configure.ac b/configure.ac
index ffba374..2c5c65d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,6 +264,13 @@ AC_ARG_ENABLE(
 	[enable_systemd="no"]
 )
 
+AC_ARG_ENABLE(
+	[async-push],
+	[AS_HELP_STRING([--enable-async-push], [enable async-push support @<:@default=no@:>@])],
+	[enable_async_push="yes"],
+	[enable_async_push="no"]
+)
+
 AC_ARG_WITH(
 	[special-build],
 	[AS_HELP_STRING([--with-special-build=STRING], [specify special build string])],
@@ -1144,6 +1151,14 @@ if test "${enable_plugin_auth_pam}" = "yes"; then
 	fi
 fi
 
+if test "${enable_async_push}" = "yes"; then
+	AC_CHECK_HEADERS(
+		[sys/inotify.h],
+		AC_DEFINE([ENABLE_ASYNC_PUSH], [1], [Enable async push]),
+		AC_MSG_ERROR([inotify.h not found.])
+	)
+fi
+
 CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`"
 AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], [Configuration settings])
 
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 39f66e3..940d426 100644
--- a/src/openvpn/for

Re: [Openvpn-devel] Async OPENVPN_PLUGIN_CLIENT_CONNECT plugin support

2014-10-13 Thread Lev Stipakov
Hi Fabian,

> You say that you've added support for the client-connect plugin call. May I
> ask what was missing?

Nothing dramatic, I just added deferred support for client-connect v2.

> So this is basically about replacing a 5s poll-interval with something that
> should proceed near instantaneously, correct?

Well, 5 seconds interval is still there, it is client-side thing. I
made server send
push_reply immediately after result is ready (written to ccr file)
without waiting
for incoming push_request.

I noticed that if authentication / authorization happens fast enough, server may
send push_reply before push_request is arrived. Sometimes client anyway sends
push_request and server sends second push_reply. To avoid that and to follow
the protocol (I haven't noticed any issues, though), in latest version
I made server wait
for the first push_request. So, if authorization takes less than
second, client will get response
in a second (with first push_request), otherwise immediately when auth is done.

I can probably modify client part and make it not send push_request if
push_reply
has already arrived. Would it be the correct way?

> Thanks for sharing! I'll have a look at it, when time permits. Though my
> focus is currently on getting some or all of the patches from the basic
> patch-set upstream.

Indeed it would be great to have your patch in upstream master.

-Lev



Re: [Openvpn-devel] session-id implementation

2014-10-21 Thread Lev Stipakov
Hi Steffan,

Thanks for your comments. I have fixed (1) and (2) - well, reusing
existing code in (2) has fixed also (1).

Regarding (3) - I don't have much experience in crypto thing, so it
would be nice if someone suggests if we should use another alignment.

I'd be happy to join IRC meeting (nickname lev__) to discuss how we
should process with this feature.

-Lev

2014-10-09 22:49 GMT+03:00 Steffan Karger <stef...@karger.me>:
> Hi Lev,
>
> On 02-10-14 13:47, Lev Stipakov wrote:
>> Apologize for the delay. Patch with review suggestions attached.
>
> Thanks for providing the patch, and following up on comments on the
> list. I've been deferring a reply to your first version, because I
> wanted to take a thorough look at the code before replying, but somehow
> did not get to it. Sorry. So, instead of deferring further, I'll just
> mail what's in my head at this point.
>
> I think your approach is a good alternative to the original proposal. I
> like that it requires less bytes in the message. However, I think we
> should arrange maybe a community meeting to discuss your alternative and
> choose our way forward.
>
> For now, some things I noticed while taking a quick peek at your patch.
> Since I mostly focus on the crypto bits of openvpn, my remarks focus on
> the crypto part of your patch too. I haven't looked at the other parts.
>
> 1) Your patch introduced a memcmp() call to verify an HMAC. That would
> introduce a timing side channel we just got rid of in commit 11d2134.
> Please *always* use use constant time comparisons when checking HMACs.
> OpenVPN provides a memcmp_constant_time().
>
> 2) The crypto_test_hmac() function your patch introduces duplicates a
> lot of code from openvpn_decrypt(). I don't like to maintain more code
> than absolutely necessary ;) So, please add some functions to reuse the
> code. Also, I think the hard-coded offset in that function is a bit ugly.
>
> 3) The three-byte offset helps to align the data on 32-bit blocks, but I
> am trying to remember what the specific reason for this was. If it was
> to speed up the crypto, we should make sure its 128-bits aligned,
> because SSE/AES-NI instructions require 128-bits aligned data. (Though
> that would probably only be useful for CBC mode, since in CFB/OFB/GCM,
> the AES-operations are not actually performed the packet data buffer.)
>
> -Steffan
>
> --
> Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
> Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
> Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
> Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
> http://pubads.g.doubleclick.net/gampad/clk?id=154622311=/4140/ostg.clktrk
> ___
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel



-- 
-Lev



Re: [Openvpn-devel] session-id implementation

2014-10-23 Thread Lev Stipakov
Hi Steffan,

Patch attached.

-Lev

2014-10-23 10:52 GMT+03:00 Steffan Karger <steffan.kar...@fox-it.com>:
> Hi Lev,
>
> On 10/21/2014 09:33 AM, Lev Stipakov wrote:
>>
>> Thanks for your comments. I have fixed (1) and (2) - well, reusing
>> existing code in (2) has fixed also (1).
>
> Thanks! Do you have the patch somewhere for us to look at?
>
>> Regarding (3) - I don't have much experience in crypto thing, so it
>> would be nice if someone suggests if we should use another alignment.
>
> >From later discussions I get the feeling the alignment was not crypto
> related.
>
> Also, alignment for crypto is very platform-specific. e.g. AES-NI
> instructions require 128-bit alignment for maximum speed. Though it
> depends on the crypto mode and implementation whether the data we supply
> it is directly used or not.
>
> The main accelerated crypto mode currently is AES-GCM, and that does not
> run the data through the crypto (but rather encrypts counters, and then
> XORs the result with the data). So I wouldn't worry too much about that
> for now.
>
> -Steffan
>
> --
> ___
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel



-- 
-Lev
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index c4c356d..2c827e2 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -220,6 +220,30 @@ err:
   return;
 }
 
+int verify_hmac(struct buffer *buf, struct key_ctx *ctx, int offset)
+{
+  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
+  int hmac_len = 0;
+
+  hmac_ctx_reset(ctx->hmac);
+  /* Assume the length of the input HMAC */
+  hmac_len = hmac_ctx_size (ctx->hmac);
+
+  /* Authentication fails if insufficient data in packet for HMAC */
+  if (buf->len - offset < hmac_len)
+return 0;
+
+  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len + offset,
+  	BLEN (buf) - hmac_len - offset);
+  hmac_ctx_final (ctx->hmac, local_hmac);
+
+  /* Compare locally computed HMAC with packet HMAC */
+  if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len) == 0)
+return hmac_len;
+
+  return 0;
+}
+
 /*
  * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
  *
@@ -246,30 +270,13 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
   /* Verify the HMAC */
   if (ctx->hmac)
 	{
-	  int hmac_len;
-	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
-
-	  hmac_ctx_reset(ctx->hmac);
-
-	  /* Assume the length of the input HMAC */
-	  hmac_len = hmac_ctx_size (ctx->hmac);
-
-	  /* Authentication fails if insufficient data in packet for HMAC */
-	  if (buf->len < hmac_len)
-	CRYPT_ERROR ("missing authentication info");
-
-	  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - hmac_len);
-	  hmac_ctx_final (ctx->hmac, local_hmac);
-
-	  /* Compare locally computed HMAC with packet HMAC */
-	  if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
+	  int hmac_len = verify_hmac(buf, ctx, 0);
+	  if (hmac_len == 0)
 	CRYPT_ERROR ("packet HMAC authentication failed");
-
 	  ASSERT (buf_advance (buf, hmac_len));
 	}
 
   /* Decrypt packet ID + payload */
-
   if (ctx->cipher)
 	{
 	  const unsigned int mode = cipher_ctx_mode (ctx->cipher);
@@ -389,6 +396,28 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }
 
 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+	{
+	  /* sizeof(uint32_t) comes from session_id (3 bytes) and opcode (1 byte) */
+	  return verify_hmac(buf, ctx, sizeof(uint32_t)) != 0;
+	}
+}
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index 3b4b88e..68cdf16 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -279,6 +279,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work,
 		  const struct crypto_options *opt,
 		  const struct frame* frame);
 
+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
 /** @} name Functions for performing security operations on data channel packets */
 
 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 3b72b96..fef7c1d 100644
--- a/src/openvp

Re: [Openvpn-devel] session-id implementation

2014-10-24 Thread Lev Stipakov
Hello,

As discussed on IRC meeting, we replace session-id with peer-id.

So, waiting for review and code-ACK :)

-Lev

2014-10-23 17:07 GMT+03:00 Lev Stipakov <lstipa...@gmail.com>:
> Hi Steffan,
>
> Patch attached.
>
> -Lev
>
> 2014-10-23 10:52 GMT+03:00 Steffan Karger <steffan.kar...@fox-it.com>:
>> Hi Lev,
>>
>> On 10/21/2014 09:33 AM, Lev Stipakov wrote:
>>>
>>> Thanks for your comments. I have fixed (1) and (2) - well, reusing
>>> existing code in (2) has fixed also (1).
>>
>> Thanks! Do you have the patch somewhere for us to look at?
>>
>>> Regarding (3) - I don't have much experience in crypto thing, so it
>>> would be nice if someone suggests if we should use another alignment.
>>
>> >From later discussions I get the feeling the alignment was not crypto
>> related.
>>
>> Also, alignment for crypto is very platform-specific. e.g. AES-NI
>> instructions require 128-bit alignment for maximum speed. Though it
>> depends on the crypto mode and implementation whether the data we supply
>> it is directly used or not.
>>
>> The main accelerated crypto mode currently is AES-GCM, and that does not
>> run the data through the crypto (but rather encrypts counters, and then
>> XORs the result with the data). So I wouldn't worry too much about that
>> for now.
>>
>> -Steffan
>>
>> --
>> ___
>> Openvpn-devel mailing list
>> Openvpn-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/openvpn-devel
>
>
>
> --
> -Lev



-- 
-Lev
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index c4c356d..c26e02d 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -220,6 +220,30 @@ err:
   return;
 }
 
+int verify_hmac(struct buffer *buf, struct key_ctx *ctx, int offset)
+{
+  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
+  int hmac_len = 0;
+
+  hmac_ctx_reset(ctx->hmac);
+  /* Assume the length of the input HMAC */
+  hmac_len = hmac_ctx_size (ctx->hmac);
+
+  /* Authentication fails if insufficient data in packet for HMAC */
+  if (buf->len - offset < hmac_len)
+return 0;
+
+  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len + offset,
+  	BLEN (buf) - hmac_len - offset);
+  hmac_ctx_final (ctx->hmac, local_hmac);
+
+  /* Compare locally computed HMAC with packet HMAC */
+  if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len) == 0)
+return hmac_len;
+
+  return 0;
+}
+
 /*
  * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
  *
@@ -246,30 +270,13 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
   /* Verify the HMAC */
   if (ctx->hmac)
 	{
-	  int hmac_len;
-	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */
-
-	  hmac_ctx_reset(ctx->hmac);
-
-	  /* Assume the length of the input HMAC */
-	  hmac_len = hmac_ctx_size (ctx->hmac);
-
-	  /* Authentication fails if insufficient data in packet for HMAC */
-	  if (buf->len < hmac_len)
-	CRYPT_ERROR ("missing authentication info");
-
-	  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - hmac_len);
-	  hmac_ctx_final (ctx->hmac, local_hmac);
-
-	  /* Compare locally computed HMAC with packet HMAC */
-	  if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
+	  int hmac_len = verify_hmac(buf, ctx, 0);
+	  if (hmac_len == 0)
 	CRYPT_ERROR ("packet HMAC authentication failed");
-
 	  ASSERT (buf_advance (buf, hmac_len));
 	}
 
   /* Decrypt packet ID + payload */
-
   if (ctx->cipher)
 	{
 	  const unsigned int mode = cipher_ctx_mode (ctx->cipher);
@@ -389,6 +396,28 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }
 
 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+	{
+	  /* sizeof(uint32_t) comes from peer_id (3 bytes) and opcode (1 byte) */
+	  return verify_hmac(buf, ctx, sizeof(uint32_t)) != 0;
+	}
+}
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index 3b4b88e..68cdf16 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -279,6 +279,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work,
 		  const struct crypto_options *opt,
 		

[Openvpn-devel] [PATCH] Peer-id patch

2014-10-28 Thread Lev Stipakov
Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.
---
 src/openvpn/crypto.c |  66 
 src/openvpn/crypto.h |   3 ++
 src/openvpn/init.c   |  10 -
 src/openvpn/mudp.c   | 111 +--
 src/openvpn/multi.c  |   6 +++
 src/openvpn/multi.h  |   2 +
 src/openvpn/options.c|   9 +++-
 src/openvpn/options.h|   8 +++-
 src/openvpn/push.c   |  16 ++-
 src/openvpn/ssl.c|  58 ++---
 src/openvpn/ssl.h|   9 +++-
 src/openvpn/ssl_common.h |   4 ++
 12 files changed, 260 insertions(+), 42 deletions(-)

diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index ef2bde1..0f1a36f 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -223,6 +223,30 @@ err:
   return;
 }

+int verify_hmac(struct buffer *buf, struct key_ctx *ctx, int offset)
+{
+  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed 
locally */
+  int hmac_len = 0;
+
+  hmac_ctx_reset(ctx->hmac);
+  /* Assume the length of the input HMAC */
+  hmac_len = hmac_ctx_size (ctx->hmac);
+
+  /* Authentication fails if insufficient data in packet for HMAC */
+  if (buf->len - offset < hmac_len)
+return 0;
+
+  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len + offset,
+   BLEN (buf) - hmac_len - offset);
+  hmac_ctx_final (ctx->hmac, local_hmac);
+
+  /* Compare locally computed HMAC with packet HMAC */
+  if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len) == 0)
+return hmac_len;
+
+  return 0;
+}
+
 /*
  * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
  *
@@ -249,25 +273,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
   /* Verify the HMAC */
   if (ctx->hmac)
{
- int hmac_len;
- uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext 
computed locally */
-
- hmac_ctx_reset(ctx->hmac);
-
- /* Assume the length of the input HMAC */
- hmac_len = hmac_ctx_size (ctx->hmac);
-
- /* Authentication fails if insufficient data in packet for HMAC */
- if (buf->len < hmac_len)
-   CRYPT_ERROR ("missing authentication info");
-
- hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - 
hmac_len);
- hmac_ctx_final (ctx->hmac, local_hmac);
-
- /* Compare locally computed HMAC with packet HMAC */
- if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
+ int hmac_len = verify_hmac(buf, ctx, 0);
+ if (hmac_len == 0)
CRYPT_ERROR ("packet HMAC authentication failed");
-
  ASSERT (buf_advance (buf, hmac_len));
}

@@ -392,6 +400,28 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }

 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+   {
+ /* sizeof(uint32_t) comes from peer_id (3 bytes) and opcode (1 byte) 
*/
+ return verify_hmac(buf, ctx, sizeof(uint32_t)) != 0;
+   }
+}
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index bf2f802..3c4e59d 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -275,6 +275,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer 
work,
  const struct crypto_options *opt,
  const struct frame* frame);

+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
 /** @} name Functions for performing security operations on data channel 
packets */

 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index a673be5..3811e09 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1718,7 +1718,8 @@ pull_permission_mask (const struct context *c)
 | OPT_P_MESSAGES
 | OPT_P_EXPLICIT_NOTIFY
 | OPT_P_ECHO
-| OPT_P_PULL_MODE;
+| OPT_P_PULL_MODE
+| OPT_P_PEER_ID;

   if (!c->options.route_nopull)
 flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
@@ -1795,6 +1796,13 @@ do_deferred_options (struct context *c, const unsigned 
int found)
 msg (D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options 
modified");
   if (found & OPT_P_SETENV)
 msg (D_PUSH, "OPTIONS IMPORT: environment modified");
+
+  if (found & OPT_P_PEER_ID)
+{
+  msg (D_PUSH, 

[Openvpn-devel] [PATCH] Peer-id patch v2

2014-10-29 Thread Lev Stipakov
Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.
---
 src/openvpn/crypto.c |  66 
 src/openvpn/crypto.h |   3 ++
 src/openvpn/init.c   |  10 -
 src/openvpn/mudp.c   | 111 +--
 src/openvpn/multi.c  |   6 +++
 src/openvpn/multi.h  |   2 +
 src/openvpn/options.c|   9 +++-
 src/openvpn/options.h|   8 +++-
 src/openvpn/push.c   |  16 ++-
 src/openvpn/ssl.c|  66 +---
 src/openvpn/ssl.h|   9 +++-
 src/openvpn/ssl_common.h |   4 ++
 12 files changed, 269 insertions(+), 41 deletions(-)

diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index ef2bde1..0f1a36f 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -223,6 +223,30 @@ err:
   return;
 }

+int verify_hmac(struct buffer *buf, struct key_ctx *ctx, int offset)
+{
+  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed 
locally */
+  int hmac_len = 0;
+
+  hmac_ctx_reset(ctx->hmac);
+  /* Assume the length of the input HMAC */
+  hmac_len = hmac_ctx_size (ctx->hmac);
+
+  /* Authentication fails if insufficient data in packet for HMAC */
+  if (buf->len - offset < hmac_len)
+return 0;
+
+  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len + offset,
+   BLEN (buf) - hmac_len - offset);
+  hmac_ctx_final (ctx->hmac, local_hmac);
+
+  /* Compare locally computed HMAC with packet HMAC */
+  if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len) == 0)
+return hmac_len;
+
+  return 0;
+}
+
 /*
  * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
  *
@@ -249,25 +273,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
   /* Verify the HMAC */
   if (ctx->hmac)
{
- int hmac_len;
- uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext 
computed locally */
-
- hmac_ctx_reset(ctx->hmac);
-
- /* Assume the length of the input HMAC */
- hmac_len = hmac_ctx_size (ctx->hmac);
-
- /* Authentication fails if insufficient data in packet for HMAC */
- if (buf->len < hmac_len)
-   CRYPT_ERROR ("missing authentication info");
-
- hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - 
hmac_len);
- hmac_ctx_final (ctx->hmac, local_hmac);
-
- /* Compare locally computed HMAC with packet HMAC */
- if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
+ int hmac_len = verify_hmac(buf, ctx, 0);
+ if (hmac_len == 0)
CRYPT_ERROR ("packet HMAC authentication failed");
-
  ASSERT (buf_advance (buf, hmac_len));
}

@@ -392,6 +400,28 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }

 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt)
+{
+  if (buf->len > 0 && opt->key_ctx_bi)
+{
+  struct key_ctx *ctx = >key_ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+   {
+ /* sizeof(uint32_t) comes from peer_id (3 bytes) and opcode (1 byte) 
*/
+ return verify_hmac(buf, ctx, sizeof(uint32_t)) != 0;
+   }
+}
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index bf2f802..3c4e59d 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -275,6 +275,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer 
work,
  const struct crypto_options *opt,
  const struct frame* frame);

+
+bool crypto_test_hmac (struct buffer *buf, const struct crypto_options *opt);
+
 /** @} name Functions for performing security operations on data channel 
packets */

 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index a673be5..3811e09 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1718,7 +1718,8 @@ pull_permission_mask (const struct context *c)
 | OPT_P_MESSAGES
 | OPT_P_EXPLICIT_NOTIFY
 | OPT_P_ECHO
-| OPT_P_PULL_MODE;
+| OPT_P_PULL_MODE
+| OPT_P_PEER_ID;

   if (!c->options.route_nopull)
 flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
@@ -1795,6 +1796,13 @@ do_deferred_options (struct context *c, const unsigned 
int found)
 msg (D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options 
modified");
   if (found & OPT_P_SETENV)
 msg (D_PUSH, "OPTIONS IMPORT: environment modified");
+
+  if (found & OPT_P_PEER_ID)
+{
+  msg (D_PUSH, 

[Openvpn-devel] [PATCH] Peer-id patch v4

2014-11-13 Thread Lev Stipakov
Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.

New in v4:
Handles correctly float to an address which is used by another peer.
This also has fixed crash on assert in multi_client_disconnect.

New in v3:
Bugfix: If float happens after TLS renegotiation and there are no data packets 
between reneg and float, server will not recognize floated client.
---
 src/openvpn/crypto.c |  66 +++--
 src/openvpn/crypto.h |   3 +
 src/openvpn/init.c   |  10 +++-
 src/openvpn/mudp.c   | 150 ++-
 src/openvpn/multi.c  |   6 ++
 src/openvpn/multi.h  |   2 +
 src/openvpn/options.c|   9 ++-
 src/openvpn/options.h|   8 ++-
 src/openvpn/push.c   |  16 -
 src/openvpn/ssl.c|  67 +++--
 src/openvpn/ssl.h|   9 ++-
 src/openvpn/ssl_common.h |   4 ++
 12 files changed, 308 insertions(+), 42 deletions(-)

diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index ef2bde1..ccea1b8 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -223,6 +223,30 @@ err:
   return;
 }

+int verify_hmac(struct buffer *buf, struct key_ctx *ctx, int offset)
+{
+  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed 
locally */
+  int hmac_len = 0;
+
+  hmac_ctx_reset(ctx->hmac);
+  /* Assume the length of the input HMAC */
+  hmac_len = hmac_ctx_size (ctx->hmac);
+
+  /* Authentication fails if insufficient data in packet for HMAC */
+  if (buf->len - offset < hmac_len)
+return 0;
+
+  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len + offset,
+   BLEN (buf) - hmac_len - offset);
+  hmac_ctx_final (ctx->hmac, local_hmac);
+
+  /* Compare locally computed HMAC with packet HMAC */
+  if (memcmp_constant_time (local_hmac, BPTR (buf) + offset, hmac_len) == 0)
+return hmac_len;
+
+  return 0;
+}
+
 /*
  * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
  *
@@ -249,25 +273,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
   /* Verify the HMAC */
   if (ctx->hmac)
{
- int hmac_len;
- uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext 
computed locally */
-
- hmac_ctx_reset(ctx->hmac);
-
- /* Assume the length of the input HMAC */
- hmac_len = hmac_ctx_size (ctx->hmac);
-
- /* Authentication fails if insufficient data in packet for HMAC */
- if (buf->len < hmac_len)
-   CRYPT_ERROR ("missing authentication info");
-
- hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - 
hmac_len);
- hmac_ctx_final (ctx->hmac, local_hmac);
-
- /* Compare locally computed HMAC with packet HMAC */
- if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
+ int hmac_len = verify_hmac(buf, ctx, 0);
+ if (hmac_len == 0)
CRYPT_ERROR ("packet HMAC authentication failed");
-
  ASSERT (buf_advance (buf, hmac_len));
}

@@ -392,6 +400,28 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 }

 /*
+ * This verifies if a packet and its HMAC fit to a crypto context.
+ *
+ * On success true is returned.
+ */
+bool
+crypto_test_hmac (struct buffer *buf, struct key_ctx_bi *key_ctx_bi)
+{
+  if (buf->len > 0 && key_ctx_bi)
+{
+  struct key_ctx *ctx = _ctx_bi->decrypt;
+
+  /* Verify the HMAC */
+  if (ctx->hmac)
+   {
+ /* sizeof(uint32_t) comes from peer_id (3 bytes) and opcode (1 byte) 
*/
+ return verify_hmac(buf, ctx, sizeof(uint32_t)) != 0;
+   }
+}
+  return false;
+}
+
+/*
  * How many bytes will we add to frame buffer for a given
  * set of crypto options?
  */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index bf2f802..b8db85c 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -275,6 +275,9 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer 
work,
  const struct crypto_options *opt,
  const struct frame* frame);

+
+bool crypto_test_hmac (struct buffer *buf, struct key_ctx_bi *key_ctx_bi);
+
 /** @} name Functions for performing security operations on data channel 
packets */

 void crypto_adjust_frame_parameters(struct frame *frame,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index a673be5..3811e09 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1718,7 +1718,8 @@ pull_permission_mask (const struct context *c)
 | OPT_P_MESSAGES
 | OPT_P_EXPLICIT_NOTIFY
 | OPT_P_ECHO
-| OPT_P_PULL_MODE;
+| OPT_P_PULL_MODE
+| OPT_P_PEER_ID;

   if (!c->options.route_nopull)
 flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
@@ -1795,6 +1796,13 @@ do_deferred_options (struct context 

[Openvpn-devel] [PATCH] Peer-id patch v5

2014-11-15 Thread Lev Stipakov
Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.

Changes in v5:
Protection agains replay attack by commiting float changes only after
existing packet processing flow has completed.

If peer floats to an address which is already taken by another active
session, drop float packet, otherwise disconnect existing session.

Changes in v4:
Handles correctly float to an address which is used by another peer.
This also has fixed crash on assert in multi_client_disconnect.

Changes in v3:
Bugfix: If float happens after TLS renegotiation and there are no
data packets between reneg and float, server will not recognize floated client.
---
 src/openvpn/forward.c| 57 
 src/openvpn/forward.h|  2 +
 src/openvpn/init.c   | 10 -
 src/openvpn/mudp.c   | 54 +++
 src/openvpn/mudp.h   |  2 +-
 src/openvpn/multi.c  | 97 ++--
 src/openvpn/multi.h  |  2 +
 src/openvpn/options.c|  9 -
 src/openvpn/options.h|  8 +++-
 src/openvpn/push.c   | 16 +++-
 src/openvpn/ssl.c| 75 +
 src/openvpn/ssl.h| 12 +-
 src/openvpn/ssl_common.h |  4 ++
 13 files changed, 300 insertions(+), 48 deletions(-)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 27b775f..d373231 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -722,20 +722,12 @@ read_incoming_link (struct context *c)
   perf_pop ();
 }

-/*
- * Input:  c->c2.buf
- * Output: c->c2.to_tun
- */
-
-void
-process_incoming_link (struct context *c)
+bool
+process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, 
bool floated)
 {
   struct gc_arena gc = gc_new ();
   bool decrypt_status;
-  struct link_socket_info *lsi = get_link_socket_info (c);
-  const uint8_t *orig_buf = c->c2.buf.data;
-
-  perf_push (PERF_PROC_IN_LINK);
+  bool res = false;

   if (c->c2.buf.len > 0)
 {
@@ -805,7 +797,7 @@ process_incoming_link (struct context *c)
   * will load crypto_options with the correct encryption key
   * and return false.
   */
- if (tls_pre_decrypt (c->c2.tls_multi, >c2.from, >c2.buf, 
>c2.crypto_options))
+ if (tls_pre_decrypt (c->c2.tls_multi, >c2.from, >c2.buf, 
>c2.crypto_options, floated))
{
  interval_action (>c2.tmp_int);

@@ -824,6 +816,14 @@ process_incoming_link (struct context *c)
 #endif
 #endif /* ENABLE_SSL */

+  /*
+   * Good, non-zero length packet received.
+   * Commence multi-stage processing of packet,
+   * such as authenticate, decrypt, decompress.
+   * If any stage fails, it sets buf.len to 0 or -1,
+   * telling downstream stages to ignore the packet.
+   */
+   
   /* authenticate and decrypt the incoming packet */
   decrypt_status = openvpn_decrypt (>c2.buf, 
c->c2.buffers->decrypt_buf, >c2.crypto_options, >c2.frame);

@@ -832,11 +832,25 @@ process_incoming_link (struct context *c)
  /* decryption errors are fatal in TCP mode */
  register_signal (c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- 
decryption error in TCP mode */
  msg (D_STREAM_ERRORS, "Fatal decryption error 
(process_incoming_link), restarting");
- goto done;
}
-
+  else
+   res = true;
 #endif /* ENABLE_CRYPTO */
+}
+  else
+{
+  buf_reset (>c2.to_tun);
+}
+  gc_free ();
+
+  return res;
+}

+void
+process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, 
const uint8_t *orig_buf)
+{
+  if (c->c2.buf.len > 0)
+{
 #ifdef ENABLE_FRAGMENT
   if (c->c2.fragment)
fragment_incoming (c->c2.fragment, >c2.buf, >c2.frame_fragment);
@@ -903,9 +917,20 @@ process_incoming_link (struct context *c)
 {
   buf_reset (>c2.to_tun);
 }
- done:
+}
+
+void
+process_incoming_link (struct context *c)
+{
+  perf_push (PERF_PROC_IN_LINK);
+
+  struct link_socket_info *lsi = get_link_socket_info (c);
+  const uint8_t *orig_buf = c->c2.buf.data;
+
+  process_incoming_link_part1(c, lsi, false);   
+  process_incoming_link_part2(c, lsi, orig_buf);
+
   perf_pop ();
-  gc_free ();
 }

 /*
diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h
index 1830a00..b9dfeea 100644
--- a/src/openvpn/forward.h
+++ b/src/openvpn/forward.h
@@ -161,6 +161,8 @@ void read_incoming_link (struct context *c);
  */
 void process_incoming_link (struct context *c);

+bool process_incoming_link_part1 (struct context *c, struct link_socket_info 
*lsi, bool floated);
+void process_incoming_link_part2 (struct context *c, struct link_socket_info 
*lsi, const uint8_t *orig_buf);

 /**
  * Write a packet to the external 

[Openvpn-devel] [PATCH] Peer-id patch v6

2014-11-21 Thread Lev Stipakov
Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.

Changes in v6:
Fixed: Make sure float won't happen if hmac check failed (regression).
Fixed: Access outside of bounds of array, which has caused memory corruption 
and crash.
Various review fixes.

Changes in v5:
Protection agains replay attack by commiting float changes only after
existing packet processing flow has completed.

If peer floats to an address which is already taken by another active
session, drop float packet, otherwise disconnect existing session.

Changes in v4:
Handles correctly float to an address which is used by another peer.
This also has fixed crash on assert in multi_client_disconnect.

Changes in v3:
Bugfix: If float happens after TLS renegotiation and there are no
data packets between reneg and float, server will not recognize floated client.
---
 src/openvpn/forward.c| 50 -
 src/openvpn/forward.h|  2 +
 src/openvpn/init.c   | 12 +-
 src/openvpn/mudp.c   | 57 +---
 src/openvpn/mudp.h   |  2 +-
 src/openvpn/multi.c  | 97 ++--
 src/openvpn/multi.h  | 13 +++
 src/openvpn/options.c|  6 +++
 src/openvpn/options.h|  5 +++
 src/openvpn/push.c   | 13 +++
 src/openvpn/ssl.c| 74 
 src/openvpn/ssl.h| 15 +++-
 src/openvpn/ssl_common.h |  4 ++
 13 files changed, 304 insertions(+), 46 deletions(-)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 27b775f..b772d9a 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -722,20 +722,11 @@ read_incoming_link (struct context *c)
   perf_pop ();
 }

-/*
- * Input:  c->c2.buf
- * Output: c->c2.to_tun
- */
-
-void
-process_incoming_link (struct context *c)
+bool
+process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, 
bool floated)
 {
   struct gc_arena gc = gc_new ();
-  bool decrypt_status;
-  struct link_socket_info *lsi = get_link_socket_info (c);
-  const uint8_t *orig_buf = c->c2.buf.data;
-
-  perf_push (PERF_PROC_IN_LINK);
+  bool decrypt_status = false;

   if (c->c2.buf.len > 0)
 {
@@ -805,7 +796,7 @@ process_incoming_link (struct context *c)
   * will load crypto_options with the correct encryption key
   * and return false.
   */
- if (tls_pre_decrypt (c->c2.tls_multi, >c2.from, >c2.buf, 
>c2.crypto_options))
+ if (tls_pre_decrypt (c->c2.tls_multi, >c2.from, >c2.buf, 
>c2.crypto_options, floated))
{
  interval_action (>c2.tmp_int);

@@ -832,11 +823,25 @@ process_incoming_link (struct context *c)
  /* decryption errors are fatal in TCP mode */
  register_signal (c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- 
decryption error in TCP mode */
  msg (D_STREAM_ERRORS, "Fatal decryption error 
(process_incoming_link), restarting");
- goto done;
}
-
+#else /* ENABLE_CRYPTO */
+  decrypt_status = true;
 #endif /* ENABLE_CRYPTO */
+}
+  else
+{
+  buf_reset (>c2.to_tun);
+}
+  gc_free ();

+  return decrypt_status;
+}
+
+void
+process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, 
const uint8_t *orig_buf)
+{
+  if (c->c2.buf.len > 0)
+{
 #ifdef ENABLE_FRAGMENT
   if (c->c2.fragment)
fragment_incoming (c->c2.fragment, >c2.buf, >c2.frame_fragment);
@@ -903,9 +908,20 @@ process_incoming_link (struct context *c)
 {
   buf_reset (>c2.to_tun);
 }
- done:
+}
+
+void
+process_incoming_link (struct context *c)
+{
+  perf_push (PERF_PROC_IN_LINK);
+
+  struct link_socket_info *lsi = get_link_socket_info (c);
+  const uint8_t *orig_buf = c->c2.buf.data;
+
+  process_incoming_link_part1(c, lsi, false);   
+  process_incoming_link_part2(c, lsi, orig_buf);
+
   perf_pop ();
-  gc_free ();
 }

 /*
diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h
index 1830a00..b9dfeea 100644
--- a/src/openvpn/forward.h
+++ b/src/openvpn/forward.h
@@ -161,6 +161,8 @@ void read_incoming_link (struct context *c);
  */
 void process_incoming_link (struct context *c);

+bool process_incoming_link_part1 (struct context *c, struct link_socket_info 
*lsi, bool floated);
+void process_incoming_link_part2 (struct context *c, struct link_socket_info 
*lsi, const uint8_t *orig_buf);

 /**
  * Write a packet to the external network interface.
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index a673be5..a135aa5 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1718,7 +1718,8 @@ pull_permission_mask (const struct context *c)
 | OPT_P_MESSAGES
 | OPT_P_EXPLICIT_NOTIFY
 | OPT_P_ECHO
-| OPT_P_PULL_MODE;
+| 

[Openvpn-devel] [PATCH] Peer-id patch v7

2014-11-23 Thread Lev Stipakov
Added new packet format P_DATA_V2, which includes peer-id. If server
supports, client sends all data packets in the new format. When data
packet arrives, server identifies peer by peer-id. If peer's ip/port has
changed, server assumes that client has floated, verifies HMAC and
updates ip/port in internal structs.

Changes in v7:
A few nitpicks.

Changes in v6:
Fixed: Make sure float won't happen if hmac check failed (regression).
Fixed: Access outside of bounds of array, which has caused memory corruption 
and crash.
Various review fixes.

Changes in v5:
Protection agains replay attack by commiting float changes only after
existing packet processing flow has completed.

If peer floats to an address which is already taken by another active
session, drop float packet, otherwise disconnect existing session.

Changes in v4:
Handles correctly float to an address which is used by another peer.
This also has fixed crash on assert in multi_client_disconnect.

Changes in v3:
Bugfix: If float happens after TLS renegotiation and there are no
data packets between reneg and float, server will not recognize floated client.
---
 src/openvpn/forward.c| 50 -
 src/openvpn/forward.h| 30 ---
 src/openvpn/init.c   | 12 +-
 src/openvpn/mudp.c   | 57 +---
 src/openvpn/mudp.h   |  2 +-
 src/openvpn/multi.c  | 97 ++--
 src/openvpn/multi.h  | 19 ++
 src/openvpn/options.c|  6 +++
 src/openvpn/options.h|  4 ++
 src/openvpn/push.c   | 13 +++
 src/openvpn/ssl.c| 74 
 src/openvpn/ssl.h| 15 +++-
 src/openvpn/ssl_common.h |  4 ++
 13 files changed, 332 insertions(+), 51 deletions(-)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 27b775f..b772d9a 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -722,20 +722,11 @@ read_incoming_link (struct context *c)
   perf_pop ();
 }

-/*
- * Input:  c->c2.buf
- * Output: c->c2.to_tun
- */
-
-void
-process_incoming_link (struct context *c)
+bool
+process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, 
bool floated)
 {
   struct gc_arena gc = gc_new ();
-  bool decrypt_status;
-  struct link_socket_info *lsi = get_link_socket_info (c);
-  const uint8_t *orig_buf = c->c2.buf.data;
-
-  perf_push (PERF_PROC_IN_LINK);
+  bool decrypt_status = false;

   if (c->c2.buf.len > 0)
 {
@@ -805,7 +796,7 @@ process_incoming_link (struct context *c)
   * will load crypto_options with the correct encryption key
   * and return false.
   */
- if (tls_pre_decrypt (c->c2.tls_multi, >c2.from, >c2.buf, 
>c2.crypto_options))
+ if (tls_pre_decrypt (c->c2.tls_multi, >c2.from, >c2.buf, 
>c2.crypto_options, floated))
{
  interval_action (>c2.tmp_int);

@@ -832,11 +823,25 @@ process_incoming_link (struct context *c)
  /* decryption errors are fatal in TCP mode */
  register_signal (c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- 
decryption error in TCP mode */
  msg (D_STREAM_ERRORS, "Fatal decryption error 
(process_incoming_link), restarting");
- goto done;
}
-
+#else /* ENABLE_CRYPTO */
+  decrypt_status = true;
 #endif /* ENABLE_CRYPTO */
+}
+  else
+{
+  buf_reset (>c2.to_tun);
+}
+  gc_free ();

+  return decrypt_status;
+}
+
+void
+process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, 
const uint8_t *orig_buf)
+{
+  if (c->c2.buf.len > 0)
+{
 #ifdef ENABLE_FRAGMENT
   if (c->c2.fragment)
fragment_incoming (c->c2.fragment, >c2.buf, >c2.frame_fragment);
@@ -903,9 +908,20 @@ process_incoming_link (struct context *c)
 {
   buf_reset (>c2.to_tun);
 }
- done:
+}
+
+void
+process_incoming_link (struct context *c)
+{
+  perf_push (PERF_PROC_IN_LINK);
+
+  struct link_socket_info *lsi = get_link_socket_info (c);
+  const uint8_t *orig_buf = c->c2.buf.data;
+
+  process_incoming_link_part1(c, lsi, false);   
+  process_incoming_link_part2(c, lsi, orig_buf);
+
   perf_pop ();
-  gc_free ();
 }

 /*
diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h
index 1830a00..eccbf36 100644
--- a/src/openvpn/forward.h
+++ b/src/openvpn/forward.h
@@ -127,12 +127,11 @@ void encrypt_sign (struct context *c, bool comp_frag);
  */
 void read_incoming_link (struct context *c);

-
 /**
- * Process a packet read from the external network interface.
+ * Starts processing a packet read from the external network interface.
  * @ingroup external_multiplexer
  *
- * This function controls the processing of a data channel packet which
+ * This function starts the processing of a data channel packet which
  * has come out of a VPN tunnel.  It's high-level structure is as follows:
  * - Verify that a nonzero length packet has been received from a valid
  *   source address for the given context \a 

Re: [Openvpn-devel] [PATCH] Peer-id patch v7

2014-11-27 Thread Lev Stipakov
Hello,

Currently it should be safe, since multi_create_instance returns NULL
if amount of clients >= max_clients. In this case we won't reach that
"for" loop thanks to "if (mi)" check.

But it probably won't harm to assert if we've reached "for" loop and
could not find available "instance" item. I can implement that.

As for the second question - hard to say. If we make it opt-in, we
probably will need to announce this feature loudly to make users aware
of that. From the other side, it is not inconceivable to assume that
someone might not want this. Maybe we could make it opt-out and have
"-no-peer-id" config option?

-Lev

2014-11-27 16:22 GMT+02:00 Gert Doering <g...@greenie.muc.de>:
> Hi,
>
> On Sun, Nov 23, 2014 at 05:17:11PM +0200, Lev Stipakov wrote:
>> Changes in v7:
>> A few nitpicks.
>
> Went in, and has just been pushed.  Time for your dance now :-)
>
> Question to you:
>
>> @@ -75,6 +101,16 @@ multi_get_create_instance_udp (struct multi_context *m)
>>   {
>> hash_add_fast (hash, bucket, >real, hv, mi);
>> mi->did_real_hash = true;
>> +
>> +   for (i = 0; i < m->max_clients; ++i)
>> + {
>> +   if (!m->instances[i])
>> + {
>> +   mi->context.c2.tls_multi->peer_id = i;
>> +   m->instances[i] = mi;
>> +   break;
>> + }
>> + }
>
> Is this code "safe"?  That is, if max_clients is set too low, and you have
> more than this number of clients trying to connect, what will happen?
>
> Will the server check this case before this loop, or will it just "not
> find a free instance" and leave peer_id as "0"?
>
> Maybe we should add an ASSERT() here, to be sure that whatever other pieces
> of the code do, this will always end up in a defined state  (as a separate
> patch).
>
>
>
> Second, question to the group.  Right now, this code is active unconditionally
> on the server side - what if someone does not want this behaviour, for
> whatever reason?  Shall we make it depend on --float (which right now
> doesn't do anything for a --server OpenVPN server)?
>
> This should be a fairly small change, I think, just never send the client
> a "peer-id " push-reply (so it won't use T_PACKET_V2), and check
> "if (options.float)" before checking whether it's a floated client...
> so the question is more along the line "is this a useful thing to do,
> nor not?".
>
> gert
> --
> USENET is *not* the non-clickable part of WWW!
>//www.muc.de/~gert/
> Gert Doering - Munich, Germany g...@greenie.muc.de
> fax: +49-89-35655025g...@net.informatik.tu-muenchen.de



-- 
-Lev



[Openvpn-devel] [PATCH] Send push reply right after async auth complete

2014-11-28 Thread Lev Stipakov
This feature speeds up connection establishment in cases when async
authentication result is not ready when first push request arrives. At
the moment server sends push reply only when it receives next push
request, which comes 5 seconds later.

Implementation overview.

Add new configure option ENABLE_ASYNC_PUSH, which can be enabled if
system supports inotify.

Add inotify descriptor to an event loop. Add inotify watch for a
authentication control file. Store mapping between watch descriptor and
multi_instance in a dictionary. When file is closed, inotify fires an
event and we continue with connection establishment - call client-
connect etc and send push reply.

Inotify watch descriptor got automatically deleted after file is closed
or when file is removed. We catch that event and remove it from the
dictionary.

Feature is easily tested with sample "defer" plugin and following settings:

auth-user-pass-optional
setenv test_deferred_auth 3
plugin simple.so

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 configure.ac  |  15 ++
 src/openvpn/forward.c |   8 +++
 src/openvpn/mtcp.c|  28 +++
 src/openvpn/mudp.c|  27 ++
 src/openvpn/multi.c   | 135 --
 src/openvpn/multi.h   |  10 
 src/openvpn/openvpn.h |   9 
 src/openvpn/push.c|  67 ++---
 src/openvpn/push.h|   2 +
 9 files changed, 270 insertions(+), 31 deletions(-)

diff --git a/configure.ac b/configure.ac
index 608ab6d..fc28779 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,6 +264,13 @@ AC_ARG_ENABLE(
[enable_systemd="no"]
 )

+AC_ARG_ENABLE(
+   [async-push],
+   [AS_HELP_STRING([--enable-async-push], [enable async-push support 
@<:@default=no@:>@])],
+   [enable_async_push="yes"],
+   [enable_async_push="no"]
+)
+
 AC_ARG_WITH(
[special-build],
[AS_HELP_STRING([--with-special-build=STRING], [specify special build 
string])],
@@ -1168,6 +1175,14 @@ if test "${enable_plugin_auth_pam}" = "yes"; then
fi
 fi

+if test "${enable_async_push}" = "yes"; then
+   AC_CHECK_HEADERS(
+   [sys/inotify.h],
+   AC_DEFINE([ENABLE_ASYNC_PUSH], [1], [Enable async push]),
+   AC_MSG_ERROR([inotify.h not found.])
+   )
+fi
+
 CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`"
 AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], 
[Configuration settings])

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 91c4711..417e7cb 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -1378,6 +1378,9 @@ io_wait_dowork (struct context *c, const unsigned int 
flags)
 #ifdef ENABLE_MANAGEMENT
   static int management_shift = 6; /* depends on MANAGEMENT_READ and 
MANAGEMENT_WRITE */
 #endif
+#ifdef ENABLE_ASYNC_PUSH
+  static int file_shift = 8;
+#endif

   /*
* Decide what kind of events we want to wait for.
@@ -1472,6 +1475,11 @@ io_wait_dowork (struct context *c, const unsigned int 
flags)
 management_socket_set (management, c->c2.event_set, 
(void*)_shift, NULL);
 #endif

+#ifdef ENABLE_ASYNC_PUSH
+  /* arm inotify watcher */
+  event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, 
(void*)_shift);
+#endif
+
   /*
* Possible scenarios:
*  (1) tcp/udp port has data available to read
diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c
index dc15f09..b27c5eb 100644
--- a/src/openvpn/mtcp.c
+++ b/src/openvpn/mtcp.c
@@ -62,6 +62,10 @@
 # define MTCP_MANAGEMENT ((void*)4)
 #endif

+#ifdef ENABLE_ASYNC_PUSH
+#define MTCP_FILE_CLOSE_WRITE ((void*)5)
+#endif
+
 #define MTCP_N   ((void*)16) /* upper bound on MTCP_x */

 struct ta_iow_flags
@@ -245,6 +249,12 @@ multi_tcp_wait (const struct context *c,
   if (management)
 management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, 
>management_persist_flags);
 #endif
+
+#ifdef ENABLE_ASYNC_PUSH
+  /* arm inotify watcher */
+  event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE);
+#endif
+
   status = event_wait (mtcp->es, >c2.timeval, mtcp->esr, mtcp->maxevents);
   update_time ();
   mtcp->n_esr = 0;
@@ -636,6 +646,12 @@ multi_tcp_process_io (struct multi_context *m)
{
  get_signal (>top.sig->signal_received);
}
+#ifdef ENABLE_ASYNC_PUSH
+ else if (e->arg == MTCP_FILE_CLOSE_WRITE)
+   {
+ multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH);
+   }
+#endif
}
   if (IS_SIG (>top))
break;
@@ -684,6 +700,14 @@ tunnel_server_tcp (struct context *top)
   /* finished with initialization */
   initialization_sequence_completed (top, ISC_SERVER); /* --mode server 
--proto tcp-server */

+#ifdef ENABLE_ASYNC_PUSH
+  multi.top.c2.inotify_fd = inot

[Openvpn-devel] [PATCH] Prevent memory drain for long lasting floating sessions

2014-12-08 Thread Lev Stipakov
For every float event we generate prefix, which allocates 256 + 64
bytes. That memory is reclaimed when client disconnects, so long lasting
and constantly floating sessions drain memory.

As a fix use preallocated buffer inside multi_instance for storing
multi_prefix.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/mudp.c  |  4 
 src/openvpn/multi.c | 14 ++
 src/openvpn/multi.h |  8 +---
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 853c08c..3e3f750 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -111,6 +111,10 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
  break;
}
}
+
+ /* should not really end up here, since 
multi_create_instance returns null
+  * if amount of clients exceeds max_clients */
+ ASSERT(i < m->max_clients);
}
}
  else
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 538f4f1..fd0d0fe 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -403,7 +403,7 @@ multi_instance_string (const struct multi_instance *mi, 
bool null, struct gc_are
 {
   if (mi)
 {
-  struct buffer out = alloc_buf_gc (256, gc);
+  struct buffer out = alloc_buf_gc (MULTI_PREFIX_MAX_LENGTH, gc);
   const char *cn = tls_common_name (mi->context.c2.tls_multi, true);

   if (cn)
@@ -420,21 +420,27 @@ multi_instance_string (const struct multi_instance *mi, 
bool null, struct gc_are
 void
 generate_prefix (struct multi_instance *mi)
 {
-  mi->msg_prefix = multi_instance_string (mi, true, >gc);
+  struct gc_arena gc = gc_new();
+  const char *prefix = multi_instance_string (mi, true, );
+  if (prefix)
+strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix));
+  else
+mi->msg_prefix[0] = '\0';
   set_prefix (mi);
+  gc_free();
 }

 void
 ungenerate_prefix (struct multi_instance *mi)
 {
-  mi->msg_prefix = NULL;
+  mi->msg_prefix[0] = '\0';
   set_prefix (mi);
 }

 static const char *
 mi_prefix (const struct multi_instance *mi)
 {
-  if (mi && mi->msg_prefix)
+  if (mi && mi->msg_prefix[0])
 return mi->msg_prefix;
   else
 return "UNDEF_I";
diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index ad7f700..32b89d2 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -42,6 +42,8 @@
 #include "mtcp.h"
 #include "perf.h"

+#define MULTI_PREFIX_MAX_LENGTH 256
+
 /*
  * Walk (don't run) through the routing table,
  * deleting old entries, and possibly multi_instance
@@ -80,7 +82,7 @@ struct multi_instance {
   struct mroute_addr real;  /**< External network address of the
  *   remote peer. */
   ifconfig_pool_handle vaddr_handle;
-  const char *msg_prefix;
+  char msg_prefix[MULTI_PREFIX_MAX_LENGTH];

   /* queued outgoing data in Server/TCP mode */
   unsigned int tcp_rwflags;
@@ -445,10 +447,10 @@ static inline void
 set_prefix (struct multi_instance *mi)
 {
 #ifdef MULTI_DEBUG_EVENT_LOOP
-  if (mi->msg_prefix)
+  if (mi->msg_prefix[0])
 printf ("[%s]\n", mi->msg_prefix);
 #endif
-  msg_set_prefix (mi->msg_prefix);
+  msg_set_prefix (mi->msg_prefix[0] ? mi->msg_prefix : NULL);
 }

 static inline void
-- 
1.9.1




[Openvpn-devel] [PATCH] Add the peer-id to the output of the status command

2014-12-08 Thread Lev Stipakov
This adds peer-id to the status output which might help analyze floating
logs. This will change the output of status in the same way commit
662ce6acc065bddf6490b3494725b8b3987b7def did.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/multi.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 538f4f1..b7785c1 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -815,8 +815,8 @@ multi_print_status (struct multi_context *m, struct 
status_output *so, const int
   */
  status_printf (so, "TITLE%c%s", sep, title_string);
  status_printf (so, "TIME%c%s%c%u", sep, time_string (now, 0, false, 
_top), sep, (unsigned int)now);
- status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal 
Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes 
Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID",
-sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep);
+ status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal 
Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes 
Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID",
+sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, 
sep);
  hash_iterator_init (m->hash, );
  while ((he = hash_iterator_next ()))
{
@@ -827,10 +827,11 @@ multi_print_status (struct multi_context *m, struct 
status_output *so, const int
{
  status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" 
counter_format "%c" counter_format "%c%s%c%u%c%s%c"
 #ifdef MANAGEMENT_DEF_AUTH
-"%lu",
+"%lu"
 #else
-"",
+""
 #endif
+"%c%"PRIu32,
 sep, tls_common_name 
(mi->context.c2.tls_multi, false),
 sep, mroute_addr_print (>real, ),
 sep, print_in_addr_t (mi->reporting_addr, 
IA_EMPTY_IF_UNDEF, ),
@@ -841,10 +842,11 @@ multi_print_status (struct multi_context *m, struct 
status_output *so, const int
 sep, (unsigned int)mi->created,
 sep, tls_username (mi->context.c2.tls_multi, 
false),
 #ifdef MANAGEMENT_DEF_AUTH
-sep, mi->context.c2.mda_context.cid);
+sep, mi->context.c2.mda_context.cid,
 #else
-sep);
+sep,
 #endif
+sep, mi->context.c2.tls_multi ? 
mi->context.c2.tls_multi->peer_id : UINT32_MAX);
}
  gc_free ();
}
-- 
1.9.1




Re: [Openvpn-devel] OpenVPN protocol extensions update

2015-01-09 Thread Lev Stipakov
Hi James,

A few comments on peer-id part:

  * A disabled peer ID is denoted by 0xFF.
  * Server tells the client to use DATA_V2/peer_id by pushing
 the directive "peer-id ID" where ID is a decimal integer
 in the range [-1, 16777215].  Setting the peer ID to -1
 transmits DATA_V2 packets with the peer ID field set to
 0xFF.  Setting the peer_id to -1 is the same as
 setting it to 16777215 (i.e. 0xFF).

There is no such thing as "disabled peer-id" in current
implementation, server does not send "-1" and client does not send
0xFF. I can surely do it, if needed. Could you maybe explain its
meaning? And just to make sure - if server gets DATA_V2 with peer-id
-1, it should skip peer-id bytes and treat it as data_v1, correct?

There is no specific check for the max value of peer-id at the place
where peer-id is issued. Logic relies on max_clients option. So in
case if max_clients is set to 2^24 or above, peer-id will wrap. There
is a check, however, that peer-id is between 0 and max_clients in the
code which handles incoming data packets.

  * Server never pushes a "peer-id" directive unless the client has
indicated its support for DATA_V2 by including "IV_PROTO=2" in the
peer info data.

Server pushes peer-id if IV_PROTO>=2. Is it ok or should it be changed to =2 ?

  * ensure that the float doesn't clobber a pre-existing client (i.e.
if the address floated to is already owned by another client) unless
it can be verified that the pre-existing client is a previous instance
of the floating client.

Thanks to this mail, I've checked code again and found a bug - a lame
duck client may float to an address taken by another client. I have
submitted a fix:

http://thread.gmane.org/gmane.network.openvpn.devel/9386

which is waiting for an ACK.

Otherwise implementation is pretty much in line with your spec.

-Lev

2015-01-07 2:08 GMT+02:00 James Yonan :
> I've updated the OpenVPN protocol extension doc with additional details, now
> that more of these features have been implemented in OpenVPN 3.
>
> If you are implementing any of these features in OpenVPN 2.x, please review
> so we can ensure that OpenVPN 2.x and 3 are on the same page with respect to
> protocol extensions.
>
> Changes:
>
> 1. Added specific details on DATA_V2/peer-id/float support.
>
> 2. For AEAD mode, emphasized that the leading 8 bytes (4 bytes for
> DATA_V2/peer-id and 4 for packet ID) is all included in the AD.
>
> 3. Added specific details on protocol negotiation where the client indicates
> protocol extension availability with IV_x parameters in the peer info
> string, and the server responds by pushing directives to the client to
> enable the feature.
>
> 4. Added "TCP nonlinear mode" section, a new protocol extension that is
> needed by multithreaded TCP servers.
>
> James
>
> --
> Dive into the World of Parallel Programming! The Go Parallel Website,
> sponsored by Intel and developed in partnership with Slashdot Media, is your
> hub for all things parallel software development, from weekly thought
> leadership blogs to news, videos, case studies, tutorials and more. Take a
> look and join the conversation now. http://goparallel.sourceforge.net
> ___
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel
>



-- 
-Lev



Re: [Openvpn-devel] [PATCH] Account for peer-id in frame size calculation

2015-01-23 Thread Lev Stipakov
ACK

Reproduced the problem with ping -s 1500 (also no compression) and
patch on both sides have fixed it.

2015-01-23 21:52 GMT+02:00 Steffan Karger :
> Data channel packet using P_DATA_V2 will use three bytes extra for the
> peer-id. This needs to be accounted for, otherwise OpenVPN will throw
>
>   TCP/UDP packet too large on write to [AF_INET]10.1.1.1:1194
>
> warnings.
>
> Signed-off-by: Steffan Karger 
> ---
>  src/openvpn/ssl.c | 10 --
>  1 file changed, 4 insertions(+), 6 deletions(-)
>
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index 0bca28d..80293ef 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -264,16 +264,14 @@ tls_get_cipher_name_pair (const char * cipher_name, 
> size_t len) {
>return NULL;
>  }
>
> -/*
> - * Max number of bytes we will add
> - * for data structures common to both
> - * data and control channel packets.
> - * (opcode only).
> +/**
> + * Max number of bytes we will add for data structures common to both data 
> and
> + * control channel packets (1 byte opcode + 3 bytes peer-id).
>   */
>  void
>  tls_adjust_frame_parameters(struct frame *frame)
>  {
> -  frame_add_to_extra_frame (frame, 1); /* space for opcode */
> +  frame_add_to_extra_frame (frame, 1 + 3); /* space for opcode + peer-id */
>  }
>
>  /*
> --
> 1.9.1
>
>
> --
> New Year. New Location. New Benefits. New Data Center in Ashburn, VA.
> GigeNET is offering a free month of service with a new server in Ashburn.
> Choose from 2 high performing configs, both with 100TB of bandwidth.
> Higher redundancy.Lower latency.Increased capacity.Completely compliant.
> http://p.sf.net/sfu/gigenet
> ___
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel



-- 
-Lev



[Openvpn-devel] [PATCH] Fix NULL dereferencing

2015-02-06 Thread Lev Stipakov
In certain cases buf.len can be -1, which causes BPTR to return NULL and
NULL pointer dereferencing on the next line.

As a fix, process only packets with non-zero length.
---
 src/openvpn/mudp.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3e3f750..57118f8 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -52,20 +52,19 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
   struct multi_instance *mi = NULL;
   struct hash *hash = m->hash;

-  if (mroute_extract_openvpn_sockaddr (, >top.c2.from.dest, true))
+  if (mroute_extract_openvpn_sockaddr (, >top.c2.from.dest, true) &&
+  m->top.c2.buf.len > 0)
 {
   struct hash_element *he;
   const uint32_t hv = hash_value (hash, );
   struct hash_bucket *bucket = hash_bucket (hash, hv);
   uint8_t* ptr = BPTR(>top.c2.buf);
   uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
-  uint32_t peer_id;
-  int i;

   /* make sure buffer has enough length to read opcode (1 byte) and 
peer-id (3 bytes) */
   if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
{
- peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
+ uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
  if ((peer_id < m->max_clients) && (m->instances[peer_id]))
{
  mi = m->instances[peer_id];
@@ -99,6 +98,8 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  mi = multi_create_instance (m, );
  if (mi)
{
+ int i;
+
  hash_add_fast (hash, bucket, >real, hv, mi);
  mi->did_real_hash = true;

-- 
1.9.1




[Openvpn-devel] [PATCH] Notify clients about server's restart/shutdown

2015-02-27 Thread Lev Stipakov
When server gets shutdown signal (SIGUSR1, SIGTERM, SIGHUP, SIGINT), it
broadcasts new OCC_SHUTTING_DOWN command to all clients and reschedules
received signal in 2 secs.

When client receives OCC_SHUTTING_DOWN, it fires SIGUSR1 and switches to
the next remote.
---
 src/openvpn/multi.c | 63 +
 src/openvpn/multi.h | 14 +++-
 src/openvpn/occ.c   |  8 +++
 src/openvpn/occ.h   |  6 +
 4 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 4412491..b5f2dd2 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -396,6 +396,8 @@ multi_init (struct multi_context *m, struct context *t, 
bool tcp_mode, int threa
 t->options.stale_routes_check_interval, 
t->options.stale_routes_ageing_time);
   event_timeout_init (>stale_routes_check_et, 
t->options.stale_routes_check_interval, 0);
 }
+
+  m->deferred_signal.signal_received = 0;
 }

 const char *
@@ -603,6 +605,25 @@ multi_close_instance (struct multi_context *m,
   perf_pop ();
 }

+void
+multi_broadcast_shutdown (struct multi_context *m)
+{
+  msg (D_LOW, "multi_broadcast_shutdown");
+
+  struct gc_arena gc = gc_new ();
+  struct buffer buf = alloc_buf_gc (BUF_SIZE (>top.c2.frame), );
+
+  buf_init (, FRAME_HEADROOM (>top.c2.frame));
+  buf_safe (, MAX_RW_SIZE_TUN (>top.c2.frame));
+  buf_write (, occ_magic, OCC_STRING_SIZE);
+
+  buf_write_u8 (, OCC_SHUTTING_DOWN);
+
+  multi_bcast (m, , NULL, NULL);
+
+  gc_free ();
+}
+
 /*
  * Called on shutdown or restart.
  */
@@ -1952,7 +1973,7 @@ multi_unicast (struct multi_context *m,
 /*
  * Broadcast a packet to all clients.
  */
-static void
+void
 multi_bcast (struct multi_context *m,
 const struct buffer *buf,
 const struct multi_instance *sender_instance,
@@ -2571,10 +2592,18 @@ multi_process_timeout (struct multi_context *m, const 
unsigned int mpp_flags)
   /* instance marked for wakeup? */
   if (m->earliest_wakeup)
 {
-  set_prefix (m->earliest_wakeup);
-  ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+  if (m->earliest_wakeup == (struct multi_instance*)>deferred_signal)
+   {
+ schedule_remove_entry(m->schedule, (struct schedule_entry*) 
>deferred_signal);
+ throw_signal(m->deferred_signal.signal_received);
+}
+  else
+   {
+ set_prefix (m->earliest_wakeup);
+ ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+ clear_prefix ();
+   }
   m->earliest_wakeup = NULL;
-  clear_prefix ();
 }
   return ret;
 }
@@ -2699,6 +2728,10 @@ multi_top_free (struct multi_context *m)
   free_context_buffers (m->top.c2.buffers);
 }

+bool is_shutdown_signal(int sig) {
+return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == 
SIGINT);
+}
+
 /*
  * Return true if event loop should break,
  * false if it should continue.
@@ -2714,6 +2747,28 @@ multi_process_signal (struct multi_context *m)
   m->top.sig->signal_received = 0;
   return false;
 }
+  else if (proto_is_dgram(m->top.options.ce.proto) &&
+  is_shutdown_signal(m->top.sig->signal_received) &&
+  (m->deferred_signal.signal_received == 0))
+{
+  // broadcast OCC_SHUTTING_DOWN to all connected clients
+  multi_broadcast_shutdown(m);
+
+  // schedule signal
+  openvpn_gettimeofday (>deferred_signal.wakeup, NULL);
+  struct timeval tv;
+  tv.tv_sec = 2;
+  tv.tv_usec = 0;
+  tv_add (>deferred_signal.wakeup, );
+
+  m->deferred_signal.signal_received = m->top.sig->signal_received;
+
+  schedule_add_entry (m->schedule, (struct schedule_entry *) 
>deferred_signal,
+ >deferred_signal.wakeup, compute_wakeup_sigma 
(>deferred_signal.wakeup));
+
+  m->top.sig->signal_received = 0;
+  return false;
+  }
   return true;
 }

diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index 32b89d2..c9c1940 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -57,6 +57,13 @@ struct multi_reap
 };


+struct deferred_signal_schedule_entry
+{
+  struct schedule_entry se;
+  int signal_received;
+  struct timeval wakeup;
+};
+
 /**
  * Server-mode state structure for one single VPN tunnel.
  *
@@ -172,6 +179,8 @@ struct multi_context {
* Timer object for stale route check
*/
   struct event_timeout stale_routes_check_et;
+
+  struct deferred_signal_schedule_entry deferred_signal;
 };

 /*
@@ -190,7 +199,6 @@ struct multi_route
   time_t last_reference;
 };

-
 /**/
 /**
  * Main event loop for OpenVPN in server mode.
@@ -290,6 +298,10 @@ bool multi_process_post (struct multi_context *m, struct 
multi_instance *mi, con
 bool multi_process_incoming_link (struct multi_context *m, struct 
multi_instance *instance, const unsigned int mpp_flags);


+void multi_bcast (struct multi_context *m, const struct buffer *buf,
+ 

[Openvpn-devel] [PATCH v2] Notify clients about server's exit/restart

2015-03-02 Thread Lev Stipakov
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and
explicit-exit-notify is set, server broadcasts new OCC_SERVER_EXIT command
to all clients and reschedules received signal in 2 secs.

When client receives OCC_SERVER_EXIT, it fires SIGUSR1 and switches to
the next server. Next server is defined as same remote with different IP address
if remote resolves into multiple addresses or next remote otherwise.

v2:
 - take into use explicit-exit-notify on the server side
 - OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT
 - minor code prettifying

---
 src/openvpn/multi.c   | 66 +++
 src/openvpn/multi.h   | 14 ++-
 src/openvpn/occ.c |  8 +++
 src/openvpn/occ.h |  6 +
 src/openvpn/options.c |  7 ++
 src/openvpn/options.h |  3 ++-
 6 files changed, 93 insertions(+), 11 deletions(-)

diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 4412491..b0d0e08 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -396,6 +396,8 @@ multi_init (struct multi_context *m, struct context *t, 
bool tcp_mode, int threa
 t->options.stale_routes_check_interval, 
t->options.stale_routes_ageing_time);
   event_timeout_init (>stale_routes_check_et, 
t->options.stale_routes_check_interval, 0);
 }
+
+  m->deferred_shutdown_signal.signal_received = 0;
 }

 const char *
@@ -603,6 +605,25 @@ multi_close_instance (struct multi_context *m,
   perf_pop ();
 }

+void
+multi_broadcast_server_exit (struct multi_context *m)
+{
+  msg (D_LOW, "multi_broadcast_server_exit");
+
+  struct gc_arena gc = gc_new ();
+  struct buffer buf = alloc_buf_gc (BUF_SIZE (>top.c2.frame), );
+
+  buf_init (, FRAME_HEADROOM (>top.c2.frame));
+  buf_safe (, MAX_RW_SIZE_TUN (>top.c2.frame));
+  buf_write (, occ_magic, OCC_STRING_SIZE);
+
+  buf_write_u8 (, OCC_SERVER_EXIT);
+
+  multi_bcast (m, , NULL, NULL);
+
+  gc_free ();
+}
+
 /*
  * Called on shutdown or restart.
  */
@@ -1952,7 +1973,7 @@ multi_unicast (struct multi_context *m,
 /*
  * Broadcast a packet to all clients.
  */
-static void
+void
 multi_bcast (struct multi_context *m,
 const struct buffer *buf,
 const struct multi_instance *sender_instance,
@@ -2571,10 +2592,18 @@ multi_process_timeout (struct multi_context *m, const 
unsigned int mpp_flags)
   /* instance marked for wakeup? */
   if (m->earliest_wakeup)
 {
-  set_prefix (m->earliest_wakeup);
-  ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+  if (m->earliest_wakeup == (struct 
multi_instance*)>deferred_shutdown_signal)
+   {
+ schedule_remove_entry(m->schedule, (struct schedule_entry*) 
>deferred_shutdown_signal);
+ throw_signal(m->deferred_shutdown_signal.signal_received);
+   }
+  else
+   {
+ set_prefix (m->earliest_wakeup);
+ ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+ clear_prefix ();
+   }
   m->earliest_wakeup = NULL;
-  clear_prefix ();
 }
   return ret;
 }
@@ -2699,6 +2728,12 @@ multi_top_free (struct multi_context *m)
   free_context_buffers (m->top.c2.buffers);
 }

+bool
+is_exit_restart(int sig)
+{
+  return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT);
+}
+
 /*
  * Return true if event loop should break,
  * false if it should continue.
@@ -2714,6 +2749,29 @@ multi_process_signal (struct multi_context *m)
   m->top.sig->signal_received = 0;
   return false;
 }
+  else if (proto_is_dgram(m->top.options.ce.proto) &&
+  is_exit_restart(m->top.sig->signal_received) &&
+  (m->deferred_shutdown_signal.signal_received == 0) &&
+  m->top.options.ce.explicit_exit_notification)
+{
+  /* broadcast OCC_SERVER_EXIT to clients */
+  multi_broadcast_server_exit(m);
+
+  /* schedule signal */
+  openvpn_gettimeofday (>deferred_shutdown_signal.wakeup, NULL);
+  struct timeval tv;
+  tv.tv_sec = 2;
+  tv.tv_usec = 0;
+  tv_add (>deferred_shutdown_signal.wakeup, );
+
+  m->deferred_shutdown_signal.signal_received = 
m->top.sig->signal_received;
+
+  schedule_add_entry (m->schedule, (struct schedule_entry *) 
>deferred_shutdown_signal,
+ >deferred_shutdown_signal.wakeup, 
compute_wakeup_sigma (>deferred_shutdown_signal.wakeup));
+
+  m->top.sig->signal_received = 0;
+  return false;
+  }
   return true;
 }

diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index 32b89d2..d968626 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -57,6 +57,13 @@ struct multi_reap
 };


+struct deferred_signal_schedule_entry
+{
+  struct schedule_entry se;
+  int signal_received;
+  struct timeval wakeup;
+};
+
 /**
  * Server-mode state structure for one single VPN tunnel.
  *
@@ -172,6 +179,8 @@ struct multi_context {
* Timer object for stale route check
*/
   struct event_timeout stale_routes_check_et;
+
+  struct deferred_signal_schedule_entry 

[Openvpn-devel] [PATCH] Client-side handling of OCC_SERVER_EXIT

2015-03-02 Thread Lev Stipakov
When client receives OCC_SERVER_EXIT, it fires SIGUSR1 and switches to
the next server. Next server is defined as same remote with different IP
address if remote resolves into multiple addresses or next remote
otherwise.

This is a client-side only verion of "Notify clients about server's
exit/restart" patch.
---
 src/openvpn/occ.c | 7 +++
 src/openvpn/occ.h | 5 +
 2 files changed, 12 insertions(+)

diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c
index ff48706..e8652de 100644
--- a/src/openvpn/occ.c
+++ b/src/openvpn/occ.c
@@ -390,6 +390,13 @@ process_received_occ_msg (struct context *c)
   c->sig->signal_received = SIGTERM;
   c->sig->signal_text = "remote-exit";
   break;
+
+case OCC_SERVER_EXIT:
+  msg (D_LOW, "RECEIVED OCC_SERVER_EXIT");
+  c->sig->signal_received = SIGUSR1;
+  c->sig->signal_text = "remote-server-exit";
+  c->options.no_advance = false;
+  break;
 }
   c->c2.buf.len = 0; /* don't pass packet on */
 }
diff --git a/src/openvpn/occ.h b/src/openvpn/occ.h
index 5d88cc9..8856c55 100644
--- a/src/openvpn/occ.h
+++ b/src/openvpn/occ.h
@@ -70,6 +70,11 @@
 #define OCC_EXIT   6

 /*
+ * Notifies clients that server is exiting/restarting
+ */
+#define OCC_SERVER_EXIT7
+
+/*
  * Used to conduct a load test command sequence
  * of UDP connection for empirical MTU measurement.
  */
-- 
1.9.1




[Openvpn-devel] [PATCH] Fast recovery when host is in unreachable network

2015-03-02 Thread Lev Stipakov
When client connects to the server which is in unreachable network (for
example hostname got resolved into ipv6 address and client has no ipv6),
throw SIGUSR1 and connect to the next server without waiting 60 seconds
for "TLS key negotiation failed".
---
 src/openvpn/forward.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index a3323e9..8eb8434 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -1090,6 +1090,7 @@ void
 process_outgoing_link (struct context *c)
 {
   struct gc_arena gc = gc_new ();
+  int error_code = 0;

   perf_push (PERF_PROC_OUT_LINK);

@@ -1177,6 +1178,7 @@ process_outgoing_link (struct context *c)
}

   /* Check return status */
+  error_code = openvpn_errno();
   check_status (size, "write", c->c2.link_socket, NULL);

   if (size > 0)
@@ -1193,6 +1195,14 @@ process_outgoing_link (struct context *c)
   /* if not a ping/control message, indicate activity regarding --inactive 
parameter */
   if (c->c2.buf.len > 0 )
 register_activity (c, size);
+
+  /* for unreachable network and "connecting" state switch to the next 
host */
+  if (size < 0 && ENETUNREACH == error_code && 
!tls_initial_packet_received (c->c2.tls_multi)
+ && c->options.mode == MODE_POINT_TO_POINT)
+   {
+ msg (M_INFO, "Network unreachable, restarting");
+ register_signal (c, SIGUSR1, "network-unreachable");
+   }
 }
   else
 {
-- 
1.9.1




[Openvpn-devel] [PATCH] Fix mssfix default value

2015-03-05 Thread Lev Stipakov
Due to this bug, mssfix hasn't been assigned to fragment value
and used default value (1450) instead. As a consequence, TCP packets
get fragmented, which causes performance penalty.

Since dual stack patch
https://github.com/OpenVPN/openvpn/commit/23d61c56b9fd218c39ad151b01b7e2d6690e6093
OpenVPN uses options->connection_list, even for single remote.

This fix assigns mssfix value to fragment value for connection_entry
inside connection_list instead of connection_entry inside options struct
(which does not work for connection_list case).
---
 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 4ea03d1..20b37db 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -2352,7 +2352,7 @@ options_postprocess_mutate_ce (struct options *o, struct 
connection_entry *ce)
 {
 #ifdef ENABLE_FRAGMENT
   if (ce->fragment)
-   o->ce.mssfix = ce->fragment;
+   ce->mssfix = ce->fragment;
 #else
   msg (M_USAGE, "--mssfix must specify a parameter");
 #endif  
-- 
1.9.1




Re: [Openvpn-devel] [PATCH] Change float log message to include common name, if available.

2015-03-08 Thread Lev Stipakov
ACK

2015-03-07 18:23 GMT+02:00 Steffan Karger :
> Makes it a lot easier to see which client is floating.
>
> Signed-off-by: Steffan Karger 
> ---
>  src/openvpn/multi.c | 7 +--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
> index 4412491..b0f66ca 100644
> --- a/src/openvpn/multi.c
> +++ b/src/openvpn/multi.c
> @@ -2151,8 +2151,11 @@ void multi_process_float (struct multi_context* m, 
> struct multi_instance* mi)
>multi_close_instance(m, ex_mi, false);
>  }
>
> -msg (D_MULTI_MEDIUM, "peer %" PRIu32 " floated from %s to %s", 
> mi->context.c2.tls_multi->peer_id,
> -mroute_addr_print (>real, ), print_link_socket_actual 
> (>top.c2.from, ));
> +msg (D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s",
> +   mi->context.c2.tls_multi->peer_id,
> +   tls_common_name (mi->context.c2.tls_multi, false),
> +   mroute_addr_print (>real, ),
> +   print_link_socket_actual (>top.c2.from, ));
>
>  ASSERT (hash_remove(m->hash, >real));
>  ASSERT (hash_remove(m->iter, >real));
> --
> 2.1.0
>
>
> --
> Dive into the World of Parallel Programming The Go Parallel Website, sponsored
> by Intel and developed in partnership with Slashdot Media, is your hub for all
> things parallel software development, from weekly thought leadership blogs to
> news, videos, case studies, tutorials and more. Take a look and join the
> conversation now. http://goparallel.sourceforge.net/
> ___
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel



-- 
-Lev



Re: [Openvpn-devel] Packet loss due to radius issues

2015-07-31 Thread Lev Stipakov
Hello Samuel,

Do you use radius plugin from http://www.nongnu.org/radiusplugin/ ? I
think the way OpenVPN delegates authentication to a plugin
(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY hook) is asynchronous, as well
as plugin implementation, i. e. OpenVPN does not wait for a response.
Instead it periodically checks a tmp file to where plugin is supposed
to write authentication result (1 or 0).

However, plugin may also hook on OPENVPN_PLUGIN_CLIENT_CONNECT_V2,
which is called after authentication has been done. OpenVPN calls that
hook synchronously, which may cause traffic to stall. There is a patch
that makes OpenVPN behave asynchronously, however it is not (yet)
merger to the master branch.

http://sourceforge.net/p/openvpn/mailman/message/33244190/

We used to have a packet loss issue due to synchronous nature of
client-connect and that patch has solved it.

-Lev

2015-07-31 2:37 GMT+03:00 Samuel Thibault :
> Hello,
>
> We've been having issues on our VPN server due to the way authentication
> is done in openvpn.  Basically, when a user would connect to the VPN
> server, no trafic would pass for a couple of seconds, thus making
> the VPN way less effective...  This was an unfortunate combination
> of several issues described below.  Our current setup is openvpn in
> multiple client mode, with the openvpn-auth-radius plugin to get
> authentication from a couple of radius servers on two other machines
> next to our VPN server.
>
> Here is what happens:
>
> - AIUI, when openvpn receives an authentication request, it gives hand
> to the authentication plugin, and thus while the authentication plugin
> is working on it, no trafic can be handled by openvpn.  That is, I
> believe, an important issue, and will turn that into a bug report.  The
> issue is that authentication might take time for whatever reason (see
> below for an example).
>
> - The radius authentication plugin interrogates our two radius servers,
> gets a response, and gives back hand to openvpn.
>
> - The issue we were having is that the first of the two radius servers
> is being replaced, and is thus currently turned off.  Since the radius
> plugin tries the first server first and waits for a couple of seconds
> before trying the second one, the authentication currently always takes
> a couple of seconds. Unfortunately, that thus makes openvpn not process
> traffic for that couple of seconds...  Of course I have now disabled the
> first radius server to avoid the issue, but a radius server downtime
> (e.g. reboot or whatever) should *not* make trafic stall, so it's not
> acceptable.
>
> One could argue that the radius plugin should perhaps try both servers
> at the same time and take the first answer it gets.  That however drops
> the idea of load balancing, and in case both radius servers are down,
> the openvpn trafic will get interrupted everytime somebody tries to
> connect (and retry shortly after again and again since it'll fail),
> that's really not acceptable either.
>
> Samuel
>
> --
> ___
> Openvpn-devel mailing list
> Openvpn-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/openvpn-devel



-- 
-Lev



[Openvpn-devel] [PATCH] This fixes MSVS 2013 compilation.

2015-10-02 Thread Lev Stipakov
 * Tools version changed to 12
 * Added comp.c/h and compat.c/h to project files
 * Workaround for missing __attribute__ support

Also, as a preparation for MSVS2015, ensured that snprintf is not defined for 
that VS version.
---
 config-msvc.h   |  3 +++
 src/compat/compat.vcxproj   |  6 --
 src/openvpn/openvpn.vcxproj | 10 --
 src/openvpn/syshead.h   |  1 +
 src/openvpnserv/openvpnserv.vcxproj |  6 --
 5 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/config-msvc.h b/config-msvc.h
index 8294c2c..ffd35f4 100644
--- a/config-msvc.h
+++ b/config-msvc.h
@@ -90,7 +90,10 @@

 #define strncasecmp strnicmp
 #define strcasecmp _stricmp
+
+#if _MSC_VER<1900
 #define snprintf _snprintf
+#endif

 #if _MSC_VER < 1800
 #define strtoull strtoul
diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj
index 42979c1..7fca62f 100644
--- a/src/compat/compat.vcxproj
+++ b/src/compat/compat.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 StaticLibrary
 MultiByte
 true
+v120
   
   
 StaticLibrary
 MultiByte
+v120
   
   
   
@@ -84,4 +86,4 @@
   
   
   
-
\ No newline at end of file
+
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
index 3b2340e..b117b0b 100755
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 Application
 true
 Unicode
+v120
   
   
 Application
 Unicode
+v120
   
   
   
@@ -100,6 +102,8 @@
 
 
 
+
+
 
 
 
@@ -168,6 +172,8 @@
 
 
 
+
+
 
 
 
@@ -260,4 +266,4 @@
   
   
   
-
\ No newline at end of file
+
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index 4bebb25..92f5834 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -47,6 +47,7 @@

 #ifdef _MSC_VER // Visual Studio
 #define __func__ __FUNCTION__
+#define __attribute__(x)
 #endif

 #if defined(__APPLE__)
diff --git a/src/openvpnserv/openvpnserv.vcxproj 
b/src/openvpnserv/openvpnserv.vcxproj
index 0b75ed0..c6760da 100644
--- a/src/openvpnserv/openvpnserv.vcxproj
+++ b/src/openvpnserv/openvpnserv.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 Application
 MultiByte
 true
+v120
   
   
 Application
 MultiByte
+v120
   
   
   
@@ -109,4 +111,4 @@
   
   
   
-
\ No newline at end of file
+
-- 
1.9.1




[Openvpn-devel] [PATCH v2] Fix MSVS 2013 compilation

2015-10-06 Thread Lev Stipakov
v2:
* Bump API level to Vista to for get_default_gateway_ipv6() implementation
* Define HAVE_INET_NTOP/PTON for Vista since it has own implementation of 
inet_ntop/pton

v1:
* Add comp/compstub to project files
* Bump tools version to 12
* define __attribute__

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 config-msvc.h   |  9 +
 msvc-env.bat|  2 +-
 src/compat/compat.vcxproj   |  6 --
 src/openvpn/openvpn.vcxproj | 10 --
 src/openvpn/syshead.h   |  1 +
 src/openvpnserv/openvpnserv.vcxproj |  6 --
 6 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/config-msvc.h b/config-msvc.h
index 8294c2c..07032ce 100644
--- a/config-msvc.h
+++ b/config-msvc.h
@@ -90,7 +90,10 @@

 #define strncasecmp strnicmp
 #define strcasecmp _stricmp
+
+#if _MSC_VER<1900
 #define snprintf _snprintf
+#endif

 #if _MSC_VER < 1800
 #define strtoull strtoul
@@ -125,3 +128,9 @@ typedef __int8  int8_t;
 #include 
 #endif

+// Vista and above has implementation of inet_ntop / inet_pton
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#define HAVE_INET_NTOP
+#define HAVE_INET_PTON
+#endif
+
diff --git a/msvc-env.bat b/msvc-env.bat
index 2dd0f00..aabed75 100644
--- a/msvc-env.bat
+++ b/msvc-env.bat
@@ -12,7 +12,7 @@ if "%VCHOME%"=="" SET VCHOME=%VSHOME%\VC
 set SOURCEBASE=%cd%
 set SOLUTION=openvpn.sln
 set 
CPPFLAGS=%CPPFLAGS%;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS
-set 
CPPFLAGS=%CPPFLAGS%;NTDDI_VERSION=NTDDI_WINXP;_WIN32_WINNT=_WIN32_WINNT_WINXP
+set 
CPPFLAGS=%CPPFLAGS%;NTDDI_VERSION=NTDDI_VISTA;_WIN32_WINNT=_WIN32_WINNT_VISTA
 set CPPFLAGS=%CPPFLAGS%;_USE_32BIT_TIME_T
 set CPPFLAGS=%CPPFLAGS%;%EXTRA_CPPFLAGS%

diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj
index 42979c1..7fca62f 100644
--- a/src/compat/compat.vcxproj
+++ b/src/compat/compat.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 StaticLibrary
 MultiByte
 true
+v120
   
   
 StaticLibrary
 MultiByte
+v120
   
   
   
@@ -84,4 +86,4 @@
   
   
   
-
\ No newline at end of file
+
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
index e349401..ad07a05 100755
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 Application
 true
 Unicode
+v120
   
   
 Application
 Unicode
+v120
   
   
   
@@ -100,6 +102,8 @@
 
 
 
+
+
 
 
 
@@ -170,6 +174,8 @@
 
 
 
+
+
 
 
 
@@ -264,4 +270,4 @@
   
   
   
-
\ No newline at end of file
+
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index ba3b7e4..3aa5c5f 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -47,6 +47,7 @@

 #ifdef _MSC_VER // Visual Studio
 #define __func__ __FUNCTION__
+#define __attribute__(x)
 #endif

 #if defined(__APPLE__)
diff --git a/src/openvpnserv/openvpnserv.vcxproj 
b/src/openvpnserv/openvpnserv.vcxproj
index 0b75ed0..c6760da 100644
--- a/src/openvpnserv/openvpnserv.vcxproj
+++ b/src/openvpnserv/openvpnserv.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 Application
 MultiByte
 true
+v120
   
   
 Application
 MultiByte
+v120
   
   
   
@@ -109,4 +111,4 @@
   
   
   
-
\ No newline at end of file
+
-- 
1.9.1




[Openvpn-devel] [PATCH] Continuation of MSVS fixes

2015-10-06 Thread Lev Stipakov
 * Upgrade API level to Vista to implement get_default_gateway_ipv6
 * Define HAVE_INET_NTOP/PTON since Vista has its own implementation of those

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 config-msvc.h | 6 ++
 msvc-env.bat  | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/config-msvc.h b/config-msvc.h
index ffd35f4..07032ce 100644
--- a/config-msvc.h
+++ b/config-msvc.h
@@ -128,3 +128,9 @@ typedef __int8  int8_t;
 #include 
 #endif

+// Vista and above has implementation of inet_ntop / inet_pton
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#define HAVE_INET_NTOP
+#define HAVE_INET_PTON
+#endif
+
diff --git a/msvc-env.bat b/msvc-env.bat
index 2dd0f00..aabed75 100644
--- a/msvc-env.bat
+++ b/msvc-env.bat
@@ -12,7 +12,7 @@ if "%VCHOME%"=="" SET VCHOME=%VSHOME%\VC
 set SOURCEBASE=%cd%
 set SOLUTION=openvpn.sln
 set 
CPPFLAGS=%CPPFLAGS%;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS
-set 
CPPFLAGS=%CPPFLAGS%;NTDDI_VERSION=NTDDI_WINXP;_WIN32_WINNT=_WIN32_WINNT_WINXP
+set 
CPPFLAGS=%CPPFLAGS%;NTDDI_VERSION=NTDDI_VISTA;_WIN32_WINNT=_WIN32_WINNT_VISTA
 set CPPFLAGS=%CPPFLAGS%;_USE_32BIT_TIME_T
 set CPPFLAGS=%CPPFLAGS%;%EXTRA_CPPFLAGS%

-- 
1.9.1




[Openvpn-devel] [PATCH v2] Send push reply right after async auth complete

2015-10-07 Thread Lev Stipakov
v2:
More careful inotify_watchers handling
* Ensure that same multi_instance is added only once
* Ensure that multi_instance is always removed

v1:
This feature speeds up connection establishment in cases when async
authentication result is not ready when first push request arrives. At
the moment server sends push reply only when it receives next push
request, which comes 5 seconds later.

Implementation overview.

Add new configure option ENABLE_ASYNC_PUSH, which can be enabled if
system supports inotify.

Add inotify descriptor to an event loop. Add inotify watch for a
authentication control file. Store mapping between watch descriptor and
multi_instance in a dictionary. When file is closed, inotify fires an
event and we continue with connection establishment - call client-
connect etc and send push reply.

Inotify watch descriptor got automatically deleted after file is closed
or when file is removed. We catch that event and remove it from the
dictionary.

Feature is easily tested with sample "defer" plugin and following settings:

auth-user-pass-optional
setenv test_deferred_auth 3
plugin simple.so

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 configure.ac  |  15 +
 src/openvpn/forward.c |   8 +++
 src/openvpn/mtcp.c|  28 ++
 src/openvpn/mudp.c|  27 +
 src/openvpn/multi.c   | 152 +-
 src/openvpn/multi.h   |  14 +
 src/openvpn/openvpn.h |  11 
 src/openvpn/push.c|  69 +--
 src/openvpn/push.h|   2 +
 9 files changed, 295 insertions(+), 31 deletions(-)

diff --git a/configure.ac b/configure.ac
index 2e651d8..32620c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -277,6 +277,13 @@ AC_ARG_ENABLE(
[enable_systemd="no"]
 )

+AC_ARG_ENABLE(
+   [async-push],
+   [AS_HELP_STRING([--enable-async-push], [enable async-push support 
@<:@default=no@:>@])],
+   [enable_async_push="yes"],
+   [enable_async_push="no"]
+)
+
 AC_ARG_WITH(
[special-build],
[AS_HELP_STRING([--with-special-build=STRING], [specify special build 
string])],
@@ -1201,6 +1208,14 @@ if test "${enable_plugin_auth_pam}" = "yes"; then
fi
 fi

+if test "${enable_async_push}" = "yes"; then
+   AC_CHECK_HEADERS(
+   [sys/inotify.h],
+   AC_DEFINE([ENABLE_ASYNC_PUSH], [1], [Enable async push]),
+   AC_MSG_ERROR([inotify.h not found.])
+   )
+fi
+
 CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`"
 AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], 
[Configuration settings])

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 7a5d383..134905c 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -1371,6 +1371,9 @@ io_wait_dowork (struct context *c, const unsigned int 
flags)
 #ifdef ENABLE_MANAGEMENT
   static int management_shift = 6; /* depends on MANAGEMENT_READ and 
MANAGEMENT_WRITE */
 #endif
+#ifdef ENABLE_ASYNC_PUSH
+  static int file_shift = 8;
+#endif

   /*
* Decide what kind of events we want to wait for.
@@ -1465,6 +1468,11 @@ io_wait_dowork (struct context *c, const unsigned int 
flags)
 management_socket_set (management, c->c2.event_set, 
(void*)_shift, NULL);
 #endif

+#ifdef ENABLE_ASYNC_PUSH
+  /* arm inotify watcher */
+  event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, 
(void*)_shift);
+#endif
+
   /*
* Possible scenarios:
*  (1) tcp/udp port has data available to read
diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c
index dc15f09..b27c5eb 100644
--- a/src/openvpn/mtcp.c
+++ b/src/openvpn/mtcp.c
@@ -62,6 +62,10 @@
 # define MTCP_MANAGEMENT ((void*)4)
 #endif

+#ifdef ENABLE_ASYNC_PUSH
+#define MTCP_FILE_CLOSE_WRITE ((void*)5)
+#endif
+
 #define MTCP_N   ((void*)16) /* upper bound on MTCP_x */

 struct ta_iow_flags
@@ -245,6 +249,12 @@ multi_tcp_wait (const struct context *c,
   if (management)
 management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, 
>management_persist_flags);
 #endif
+
+#ifdef ENABLE_ASYNC_PUSH
+  /* arm inotify watcher */
+  event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE);
+#endif
+
   status = event_wait (mtcp->es, >c2.timeval, mtcp->esr, mtcp->maxevents);
   update_time ();
   mtcp->n_esr = 0;
@@ -636,6 +646,12 @@ multi_tcp_process_io (struct multi_context *m)
{
  get_signal (>top.sig->signal_received);
}
+#ifdef ENABLE_ASYNC_PUSH
+ else if (e->arg == MTCP_FILE_CLOSE_WRITE)
+   {
+ multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH);
+   }
+#endif
}
   if (IS_SIG (>top))
break;
@@ -684,6 +700,14 @@ tunnel_server_tcp (struct context *top)
   /* finished with initialization */
   i

[Openvpn-devel] [PATCH] Support for disabled peer-id

2015-10-09 Thread Lev Stipakov
When peer-id value is 0xFF, server should ignore it and treat packet
in a same way as P_DATA_V1.

Make sure that issued peer-id does not exceed 0xFF.
---
 src/openvpn/mudp.c  | 15 ---
 src/openvpn/multi.c |  3 ++-
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 57118f8..43b4f06 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -60,12 +60,16 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
   struct hash_bucket *bucket = hash_bucket (hash, hv);
   uint8_t* ptr = BPTR(>top.c2.buf);
   uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+  bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
+  bool peer_id_disabled = false;

   /* make sure buffer has enough length to read opcode (1 byte) and 
peer-id (3 bytes) */
-  if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
+  if (v2)
{
  uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
- if ((peer_id < m->max_clients) && (m->instances[peer_id]))
+ peer_id_disabled = peer_id == 0xFF;
+
+ if (!peer_id_disabled && (peer_id < m->max_clients) && 
(m->instances[peer_id]))
{
  mi = m->instances[peer_id];

@@ -80,7 +84,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  }
}
}
-  else
+  if (!v2 || peer_id_disabled)
{
  he = hash_lookup_fast (hash, bucket, , hv);
  if (he)
@@ -103,11 +107,16 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
  hash_add_fast (hash, bucket, >real, hv, mi);
  mi->did_real_hash = true;

+ /* TODO: support for disabled peer-id */
  for (i = 0; i < m->max_clients; ++i)
{
  if (!m->instances[i])
{
+ /* issued peer-id should fit into 3 bytes to 
avoid wrap and cannot have reserved value 0xFF */
+ ASSERT(i < 0xFF);
+
  mi->context.c2.tls_multi->peer_id = i;
+
  m->instances[i] = mi;
  break;
}
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 902c4dc..76f5a44 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -562,7 +562,8 @@ multi_close_instance (struct multi_context *m,
}
 #endif

-  m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
+  if (mi->context.c2.tls_multi->peer_id != 0xFF)
+m->instances[mi->context.c2.tls_multi->peer_id] = NULL;

   schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);

-- 
1.9.1




[Openvpn-devel] [PATCH v2] Support for disabled peer-id

2015-10-09 Thread Lev Stipakov
v2:
 * Add round brackets for clarity.
 * Rephrase comment.

v1:
 * When peer-id value is 0xFF, server should ignore it and treat packet
in a same way as P_DATA_V1.
 * Make sure that issued peer-id does not exceed 0xFF.
---
 src/openvpn/mudp.c  | 14 +++---
 src/openvpn/multi.c |  3 ++-
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 57118f8..fcbb47d 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -60,12 +60,16 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
   struct hash_bucket *bucket = hash_bucket (hash, hv);
   uint8_t* ptr = BPTR(>top.c2.buf);
   uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+  bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
+  bool peer_id_disabled = false;

   /* make sure buffer has enough length to read opcode (1 byte) and 
peer-id (3 bytes) */
-  if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
+  if (v2)
{
  uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFF;
- if ((peer_id < m->max_clients) && (m->instances[peer_id]))
+ peer_id_disabled = (peer_id == 0xFF);
+
+ if (!peer_id_disabled && (peer_id < m->max_clients) && 
(m->instances[peer_id]))
{
  mi = m->instances[peer_id];

@@ -80,7 +84,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  }
}
}
-  else
+  if (!v2 || peer_id_disabled)
{
  he = hash_lookup_fast (hash, bucket, , hv);
  if (he)
@@ -103,10 +107,14 @@ multi_get_create_instance_udp (struct multi_context *m, 
bool *floated)
  hash_add_fast (hash, bucket, >real, hv, mi);
  mi->did_real_hash = true;

+ /* In future we might want to use P_DATA_V2 but not need 
peer-id/float functionality */
  for (i = 0; i < m->max_clients; ++i)
{
  if (!m->instances[i])
{
+ /* issued peer-id should fit into 3 bytes to 
avoid wrap and cannot have reserved value 0xFF */
+ ASSERT(i < 0xFF);
+
  mi->context.c2.tls_multi->peer_id = i;
  m->instances[i] = mi;
  break;
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 902c4dc..76f5a44 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -562,7 +562,8 @@ multi_close_instance (struct multi_context *m,
}
 #endif

-  m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
+  if (mi->context.c2.tls_multi->peer_id != 0xFF)
+m->instances[mi->context.c2.tls_multi->peer_id] = NULL;

   schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);

-- 
1.9.1




[Openvpn-devel] [PATCH] Fix compilcation error with --disable-crypto

2015-10-10 Thread Lev Stipakov
Also disable behavior for static key setup.
---
 src/openvpn/forward.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 513fbae..c17be35 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -1199,13 +1199,16 @@ process_outgoing_link (struct context *c)
   if (c->c2.buf.len > 0 )
 register_activity (c, size);

+
+#ifdef ENABLE_CRYPTO
   /* for unreachable network and "connecting" state switch to the next 
host */
-  if (size < 0 && ENETUNREACH == error_code && 
!tls_initial_packet_received (c->c2.tls_multi)
- && c->options.mode == MODE_POINT_TO_POINT)
+  if (size < 0 && ENETUNREACH == error_code && c->c2.tls_multi &&
+  !tls_initial_packet_received (c->c2.tls_multi) && c->options.mode == 
MODE_POINT_TO_POINT)
{
  msg (M_INFO, "Network unreachable, restarting");
  register_signal (c, SIGUSR1, "network-unreachable");
}
+#endif
 }
   else
 {
-- 
1.9.1




Re: [Openvpn-devel] ipv6 env vars to client scripts

2015-10-10 Thread Lev Stipakov

Hi Samuel,

I like the idea of patch 
https://community.openvpn.net/openvpn/attachment/ticket/230/patch, I 
think ifconfig_ipv6_pool_remote_ip is indeed useful - we use it in our 
production, too.


Here:

void
+setenv_in6_addr_t (struct env_set *es, const char *name_prefix, struct 
in6_addr *addr, const bool flags)

+{

"flags" should have type "const unsigned int" instead of "const bool".


Could you also rebase it on top of master - at the moment the first part 
of socket.c fails to apply.


-Lev


02.05.2014, 01:50, Samuel Thibault kirjoitti:

David Sommerseth, le Fri 02 May 2014 01:39:05 +0200, a écrit :

On 17/04/14 14:07, Lev Stipakov wrote:

Hello,

Are there any plans to support ipv6 env vars in
client-connect/disconnect scripts?

There are at least 2 tickes on that feature:

https://community.openvpn.net/openvpn/ticket/230
https://community.openvpn.net/openvpn/ticket/369

Is there anything that prevents merging any of suggested patches to
the master branch?


I don't think I've seen these patches on the mailing list (I'm going through
the list now).


My patches were sent on 2013 May 24th on openvpn-devel.

Samuel

--
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs







Re: [Openvpn-devel] ipv6 env vars to client scripts

2015-10-10 Thread Lev Stipakov
Hi Samuel,

I like the idea of patch
https://community.openvpn.net/openvpn/attachment/ticket/230/patch, I
think ifconfig_ipv6_pool_remote_ip is indeed useful - we use it in our
production, too.

Here:

void
+setenv_in6_addr_t (struct env_set *es, const char *name_prefix,
struct in6_addr *addr, const bool flags)
+{

"flags" should have type "const unsigned int" instead of "const bool".

Could you also rebase it on top of master - at the moment the first
part of socket.c fails to apply.

-Lev

2014-05-02 1:50 GMT+02:00 Samuel Thibault <samuel.thiba...@ens-lyon.org>:
> David Sommerseth, le Fri 02 May 2014 01:39:05 +0200, a écrit :
>> On 17/04/14 14:07, Lev Stipakov wrote:
>> > Hello,
>> >
>> > Are there any plans to support ipv6 env vars in
>> > client-connect/disconnect scripts?
>> >
>> > There are at least 2 tickes on that feature:
>> >
>> > https://community.openvpn.net/openvpn/ticket/230
>> > https://community.openvpn.net/openvpn/ticket/369
>> >
>> > Is there anything that prevents merging any of suggested patches to
>> > the master branch?
>>
>> I don't think I've seen these patches on the mailing list (I'm going through
>> the list now).
>
> My patches were sent on 2013 May 24th on openvpn-devel.
>
> Samuel



-- 
-Lev



Re: [Openvpn-devel] ipv6 env vars to client scripts

2015-10-10 Thread Lev Stipakov

Hi Samuel,

I like the idea of patch 
https://community.openvpn.net/openvpn/attachment/ticket/230/patch, I 
think ifconfig_ipv6_pool_remote_ip is indeed useful - we use it in our 
production, too.


Here:

void
+setenv_in6_addr_t (struct env_set *es, const char *name_prefix, struct 
in6_addr *addr, const bool flags)

+{

"flags" should have type "const unsigned int" instead of "const bool".


Could you also rebase it on top of master - at the moment the first part 
of socket.c fails to apply.


-Lev


02.05.2014, 01:50, Samuel Thibault kirjoitti:

David Sommerseth, le Fri 02 May 2014 01:39:05 +0200, a écrit :

On 17/04/14 14:07, Lev Stipakov wrote:

Hello,

Are there any plans to support ipv6 env vars in
client-connect/disconnect scripts?

There are at least 2 tickes on that feature:

https://community.openvpn.net/openvpn/ticket/230
https://community.openvpn.net/openvpn/ticket/369

Is there anything that prevents merging any of suggested patches to
the master branch?


I don't think I've seen these patches on the mailing list (I'm going through
the list now).


My patches were sent on 2013 May 24th on openvpn-devel.

Samuel

--
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs







Re: [Openvpn-devel] ipv6 env vars to client scripts

2015-10-10 Thread Lev Stipakov

Hi Samuel,

I like the idea of patch 
https://community.openvpn.net/openvpn/attachment/ticket/230/patch, I 
think ifconfig_ipv6_pool_remote_ip is indeed useful - we use it in our 
production, too.


Here:

void
+setenv_in6_addr_t (struct env_set *es, const char *name_prefix, struct 
in6_addr *addr, const bool flags)

+{

"flags" should have type "const unsigned int" instead of "const bool".


Could you also rebase it on top of master - at the moment the first part 
of socket.c fails to apply.


-Lev


02.05.2014, 01:50, Samuel Thibault kirjoitti:

David Sommerseth, le Fri 02 May 2014 01:39:05 +0200, a écrit :

On 17/04/14 14:07, Lev Stipakov wrote:

Hello,

Are there any plans to support ipv6 env vars in
client-connect/disconnect scripts?

There are at least 2 tickes on that feature:

https://community.openvpn.net/openvpn/ticket/230
https://community.openvpn.net/openvpn/ticket/369

Is there anything that prevents merging any of suggested patches to
the master branch?


I don't think I've seen these patches on the mailing list (I'm going through
the list now).


My patches were sent on 2013 May 24th on openvpn-devel.

Samuel

--
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs







[Openvpn-devel] [PATCH v3] Send push reply right after async auth complete

2015-10-10 Thread Lev Stipakov
v3:
* better comments
* better variable naming
* include sys/inotify.h if HAVE_SYS_INOTIFY_H is defined

v2:
More careful inotify_watchers handling
* Ensure that same multi_instance is added only once
* Ensure that multi_instance is always removed

v1:
This feature speeds up connection establishment in cases when async
authentication result is not ready when first push request arrives. At
the moment server sends push reply only when it receives next push
request, which comes 5 seconds later.

Implementation overview.

Add new configure option ENABLE_ASYNC_PUSH, which can be enabled if
system supports inotify.

Add inotify descriptor to an event loop. Add inotify watch for a
authentication control file. Store mapping between watch descriptor and
multi_instance in a dictionary. When file is closed, inotify fires an
event and we continue with connection establishment - call client-
connect etc and send push reply.

Inotify watch descriptor got automatically deleted after file is closed
or when file is removed. We catch that event and remove it from the
dictionary.

Feature is easily tested with sample "defer" plugin and following settings:

auth-user-pass-optional
setenv test_deferred_auth 3
plugin simple.so

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>

Add doxygen comment
---
 configure.ac  |  15 +
 src/openvpn/forward.c |   8 +++
 src/openvpn/mtcp.c|  28 +
 src/openvpn/mudp.c|  27 +
 src/openvpn/multi.c   | 155 +-
 src/openvpn/multi.h   |  21 +++
 src/openvpn/openvpn.h |  10 
 src/openvpn/push.c|  69 +-
 src/openvpn/push.h|   2 +
 9 files changed, 304 insertions(+), 31 deletions(-)

diff --git a/configure.ac b/configure.ac
index 2e651d8..32620c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -277,6 +277,13 @@ AC_ARG_ENABLE(
[enable_systemd="no"]
 )

+AC_ARG_ENABLE(
+   [async-push],
+   [AS_HELP_STRING([--enable-async-push], [enable async-push support 
@<:@default=no@:>@])],
+   [enable_async_push="yes"],
+   [enable_async_push="no"]
+)
+
 AC_ARG_WITH(
[special-build],
[AS_HELP_STRING([--with-special-build=STRING], [specify special build 
string])],
@@ -1201,6 +1208,14 @@ if test "${enable_plugin_auth_pam}" = "yes"; then
fi
 fi

+if test "${enable_async_push}" = "yes"; then
+   AC_CHECK_HEADERS(
+   [sys/inotify.h],
+   AC_DEFINE([ENABLE_ASYNC_PUSH], [1], [Enable async push]),
+   AC_MSG_ERROR([inotify.h not found.])
+   )
+fi
+
 CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`"
 AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], 
[Configuration settings])

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 7a5d383..f89c5bc 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -1371,6 +1371,9 @@ io_wait_dowork (struct context *c, const unsigned int 
flags)
 #ifdef ENABLE_MANAGEMENT
   static int management_shift = 6; /* depends on MANAGEMENT_READ and 
MANAGEMENT_WRITE */
 #endif
+#ifdef ENABLE_ASYNC_PUSH
+  static int file_shift = 8;   /* listening inotify events */
+#endif

   /*
* Decide what kind of events we want to wait for.
@@ -1465,6 +1468,11 @@ io_wait_dowork (struct context *c, const unsigned int 
flags)
 management_socket_set (management, c->c2.event_set, 
(void*)_shift, NULL);
 #endif

+#ifdef ENABLE_ASYNC_PUSH
+  /* arm inotify watcher */
+  event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, 
(void*)_shift);
+#endif
+
   /*
* Possible scenarios:
*  (1) tcp/udp port has data available to read
diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c
index dc15f09..b27c5eb 100644
--- a/src/openvpn/mtcp.c
+++ b/src/openvpn/mtcp.c
@@ -62,6 +62,10 @@
 # define MTCP_MANAGEMENT ((void*)4)
 #endif

+#ifdef ENABLE_ASYNC_PUSH
+#define MTCP_FILE_CLOSE_WRITE ((void*)5)
+#endif
+
 #define MTCP_N   ((void*)16) /* upper bound on MTCP_x */

 struct ta_iow_flags
@@ -245,6 +249,12 @@ multi_tcp_wait (const struct context *c,
   if (management)
 management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, 
>management_persist_flags);
 #endif
+
+#ifdef ENABLE_ASYNC_PUSH
+  /* arm inotify watcher */
+  event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE);
+#endif
+
   status = event_wait (mtcp->es, >c2.timeval, mtcp->esr, mtcp->maxevents);
   update_time ();
   mtcp->n_esr = 0;
@@ -636,6 +646,12 @@ multi_tcp_process_io (struct multi_context *m)
{
  get_signal (>top.sig->signal_received);
}
+#ifdef ENABLE_ASYNC_PUSH
+ else if (e->arg == MTCP_FILE_CLOSE_WRITE)
+   {
+ multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH);
+  

[Openvpn-devel] [PATCH] Fix compilation with --disable-server

2015-10-11 Thread Lev Stipakov
Add missing #if P2MP_SERVER
---
 src/openvpn/push.c | 2 ++
 src/openvpn/push.h | 5 ++---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 704818d..a4cb726 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -410,6 +410,7 @@ push_reset (struct options *o)
 }
 #endif

+#if P2MP_SERVER
 int
 process_incoming_push_request (struct context *c)
 {
@@ -449,6 +450,7 @@ process_incoming_push_request (struct context *c)

   return ret;
 }
+#endif

 int
 process_incoming_push_msg (struct context *c,
diff --git a/src/openvpn/push.h b/src/openvpn/push.h
index 5eca45f..fa06e08 100644
--- a/src/openvpn/push.h
+++ b/src/openvpn/push.h
@@ -37,9 +37,6 @@
 #define PUSH_MSG_CONTINUATION 5
 #define PUSH_MSG_ALREADY_REPLIED  6

-void incoming_push_message (struct context *c,
-   const struct buffer *buffer);
-
 int process_incoming_push_request (struct context *c);

 int process_incoming_push_msg (struct context *c,
@@ -56,6 +53,8 @@ void server_pushed_signal (struct context *c, const struct 
buffer *buffer, const

 #if P2MP_SERVER

+void incoming_push_message (struct context *c, const struct buffer *buffer);
+
 void clone_push_list (struct options *o);

 void push_option (struct options *o, const char *opt, int msglevel);
-- 
1.9.1




[Openvpn-devel] [PATCH v3] Notify clients about server's exit/restart

2015-10-13 Thread Lev Stipakov
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and
explicit-exit-notify is set, server sends RESTART control channel command to
all clients and reschedules received signal in 2 secs.

When client receives RESTART command, it either reconnects to the same server or
advances to the new one, depends on parameter comes with RESTART
command - behavior is controlled by explicit-exit-notify in the server config.

v3:
 - Use control channel "RESTART" command instead of new OCC code to
notify clients
 - Configure on the server side (by value of explicit-exit-notify) if
client should reconnect to the same server or advance to the next one
 - Fix compilation when OCC is disabled (--enable-small)
 - Update man page

v2:
 - Take into use explicit-exit-notify on the server side
 - OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT
 - Code prettifying

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 doc/openvpn.8 | 15 ++--
 src/openvpn/multi.c   | 68 ---
 src/openvpn/multi.h   |  9 +++
 src/openvpn/options.c |  9 +++
 src/openvpn/push.c|  6 +
 5 files changed, 96 insertions(+), 11 deletions(-)

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index e213f5a..0a00dec 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -3829,8 +3829,19 @@ option will tell the server to immediately close its 
client instance object
 rather than waiting for a timeout.  The
 .B n
 parameter (default=1) controls the maximum number of attempts that the client
-will try to resend the exit notification message.  OpenVPN will not send any 
exit
-notifications unless this option is enabled.
+will try to resend the exit notification message. 
+
+In UDP server mode, send RESTART control channel command to connected clients. 
The
+.B n
+parameter (default=1) controls client behavior. With
+.B n
+= 1 client will attempt to reconnect
+to the same server, with
+.B n
+= 2 client will advance to the next server.
+
+OpenVPN will not send any exit
+notifications unless this option is enabled. 
 .\"*
 .SS Data Channel Encryption Options:
 These options are meaningful for both Static & TLS-negotiated key modes
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 902c4dc..d16b145 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -396,6 +396,8 @@ multi_init (struct multi_context *m, struct context *t, 
bool tcp_mode, int threa
 t->options.stale_routes_check_interval, 
t->options.stale_routes_ageing_time);
   event_timeout_init (>stale_routes_check_et, 
t->options.stale_routes_check_interval, 0);
 }
+
+  m->deferred_shutdown_signal.signal_received = 0;
 }

 const char *
@@ -2572,10 +2574,18 @@ multi_process_timeout (struct multi_context *m, const 
unsigned int mpp_flags)
   /* instance marked for wakeup? */
   if (m->earliest_wakeup)
 {
-  set_prefix (m->earliest_wakeup);
-  ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+  if (m->earliest_wakeup == (struct 
multi_instance*)>deferred_shutdown_signal)
+   {
+ schedule_remove_entry(m->schedule, (struct schedule_entry*) 
>deferred_shutdown_signal);
+ throw_signal(m->deferred_shutdown_signal.signal_received);
+   }
+  else
+   {
+ set_prefix (m->earliest_wakeup);
+ ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+ clear_prefix ();
+   }
   m->earliest_wakeup = NULL;
-  clear_prefix ();
 }
   return ret;
 }
@@ -2700,6 +2710,48 @@ multi_top_free (struct multi_context *m)
   free_context_buffers (m->top.c2.buffers);
 }

+static bool
+is_exit_restart(int sig)
+{
+  return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT);
+}
+
+static void
+multi_push_restart_schedule_exit(struct multi_context *m, bool next_server)
+{
+  struct hash_iterator hi;
+  struct hash_element *he;
+  struct timeval tv;
+
+  /* tell all clients to restart */
+  hash_iterator_init (m->iter, );
+  while ((he = hash_iterator_next ()))
+{
+  struct multi_instance *mi = (struct multi_instance *) he->value;
+  if (!mi->halt)
+{
+ send_control_channel_string (>context, next_server ? 
"RESTART,[N]" : "RESTART", D_PUSH);
+ multi_schedule_context_wakeup(m, mi);
+}
+}
+  hash_iterator_free ();
+
+  /* reschedule signal */
+  ASSERT (!openvpn_gettimeofday (>deferred_shutdown_signal.wakeup, NULL));
+  tv.tv_sec = 2;
+  tv.tv_usec = 0;
+  tv_add (>deferred_shutdown_signal.wakeup, );
+
+  m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received;
+
+  schedule_add_entry (m->schedule,
+ (struct schedule_entry *) >deferred_shutdown_signal,
+ >deferred_shutdown_signal.wakeup,
+ compute_wakeup_s

Re: [Openvpn-devel] [PATCH V2] Fix commit c67acea173dc9ee37220f5b9ff14ede081181992

2015-10-14 Thread Lev Stipakov

ACK from me. Tested on ics-openvpn, problem with endtag now fixed.

A nitpick. git am says:

/home/stiple/Projects/ics-openvpn/.git/modules/main/openvpn/rebase-apply/patch:20: 
trailing whitespace.

  char *line_ptr = line;
warning: 1 line adds whitespace errors.


On 14.10.2015 16:05, Arne Schwabe wrote:

Move things to the proper place, ensure that line_ptr is actually properly
initialized for *every* line read, not just for the first one

---
  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 086dcea..c2b956d 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -3672,13 +3672,13 @@ static char *
  read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena 
*gc)
  {
char line[OPTION_LINE_SIZE];
-  char *line_ptr = line;
struct buffer buf = alloc_buf (8*OPTION_LINE_SIZE);
char *ret;
bool endtagfound = false;

while (in_src_get (is, line, sizeof (line)))
  {
+  char *line_ptr = line;
/* Remove leading spaces */
while (isspace(*line_ptr)) line_ptr++;
if (!strncmp (line_ptr, close_tag, strlen (close_tag)))







[Openvpn-devel] [PATCH] Decrease log level for peer float message

2015-10-15 Thread Lev Stipakov
Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/mudp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3aed3a0..9fa9f9e 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -79,7 +79,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  {
/* reset prefix, since here we are not sure peer is the one it 
claims to be */
ungenerate_prefix(mi);
-   msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float 
to %s", peer_id,
+   msg (D_MULTI_MEDIUM, "Untrusted peer %" PRIu32 " wants to float 
to %s", peer_id,
mroute_addr_print (, ));
  }
}
-- 
1.9.1




[Openvpn-devel] [PATCH] Refine float logging

2015-10-15 Thread Lev Stipakov
v2:
 * Bump log level for attack attempt message
 * More clear message for float event

v1:
 * Decrease log level for peer float message

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/mudp.c  | 2 +-
 src/openvpn/multi.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3aed3a0..ce67206 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -79,7 +79,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool 
*floated)
  {
/* reset prefix, since here we are not sure peer is the one it 
claims to be */
ungenerate_prefix(mi);
-   msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float 
to %s", peer_id,
+   msg (D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to 
%s", peer_id,
mroute_addr_print (, ));
  }
}
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 05c36db..7c3aaac 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -2286,7 +2286,7 @@ void multi_process_float (struct multi_context* m, struct 
multi_instance* mi)
   /* do not float if target address is taken by client with another cert */
   if (!cert_hash_compare(m1->locked_cert_hash_set, 
m2->locked_cert_hash_set))
{
- msg (D_MULTI_MEDIUM, "Disallow float to an address taken by another 
client %s",
+ msg (D_MULTI_LOW, "Disallow float to an address taken by another 
client %s",
   multi_instance_string (ex_mi, false, ));

  mi->context.c2.buf.len = 0;
-- 
1.9.1




[Openvpn-devel] [PATCH] Replace variable length array with malloc

2015-10-20 Thread Lev Stipakov
Commit 
https://github.com/OpenVPN/openvpn/commit/685e486e8b8f70c25f09590c24762ff734f94a51
introduced a variable length array. Although C99 supports that, MSVS 2013 still 
requires
size of array to be compiler time constant. As a fix, use OPENSSL_malloc/free.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/ssl_openssl.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index c08d4fe..1b4b1da 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -141,7 +141,10 @@ key_state_export_keying_material(struct key_state_ssl *ssl,
 {
 #if (OPENSSL_VERSION_NUMBER >= 0x10001000)
   unsigned int size = session->opt->ekm_size;
-  unsigned char ekm[size];
+  unsigned char* ekm = OPENSSL_malloc(size);
+
+  if (ekm == NULL)
+   crypto_msg (M_FATAL, "Failed to allocate memory for export key 
material.");

   if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm),
   session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0))
@@ -162,6 +165,8 @@ key_state_export_keying_material(struct key_state_ssl *ssl,
  msg (M_WARN, "WARNING: Export keying material failed!");
  setenv_del (session->opt->es, "exported_keying_material");
}
+
+  OPENSSL_free(ekm);
 #endif
 }
 }
-- 
1.9.1




Re: [Openvpn-devel] [PATCH] Replace variable length array with malloc

2015-10-20 Thread Lev Stipakov

> Why OPENSSL_malloc() in particular?

I looked for other malloc calls in that file and only example I've found 
was OPENSSL_malloc in show_available_curves().


On the other side Dr. Stephen Henson says (quote unedited):

http://permalink.gmane.org/gmane.comp.encryption.openssl.user/11291

> You don't have to use OPENSSL_malloc() in an application but you do 
you can make use of OpenSSLs memory leak checking routines if you do.


-Lev

On 20.10.2015 16:52, Gert Doering wrote:

Hi,

On Tue, Oct 20, 2015 at 04:22:59PM +0300, Lev Stipakov wrote:

Commit 
https://github.com/OpenVPN/openvpn/commit/685e486e8b8f70c25f09590c24762ff734f94a51
introduced a variable length array. Although C99 supports that, MSVS 2013 still 
requires
size of array to be compiler time constant. As a fix, use OPENSSL_malloc/free.


Why OPENSSL_malloc() in particular?

(As I have no clue about the intricacies of openssl-interfacing code, this
might be a stupid question, but it looks like "normal gc_malloc() should
be perfectly fine")

gert



--



___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel







Re: [Openvpn-devel] [PATCH] Replace variable length array with malloc

2015-10-20 Thread Lev Stipakov

Why OPENSSL_malloc() in particular?


I looked for other malloc calls in that file and only example I've found 
was OPENSSL_malloc in show_available_curves().


On the other side Dr. Stephen Henson says (quote unedited):

http://permalink.gmane.org/gmane.comp.encryption.openssl.user/11291


You don't have to use OPENSSL_malloc() in an application but you do

you can make use of OpenSSLs memory leak checking routines if you do.

-Lev

On 20.10.2015 16:52, Gert Doering wrote:

Hi,

On Tue, Oct 20, 2015 at 04:22:59PM +0300, Lev Stipakov wrote:

Commit 
https://github.com/OpenVPN/openvpn/commit/685e486e8b8f70c25f09590c24762ff734f94a51
introduced a variable length array. Although C99 supports that, MSVS 2013 still 
requires
size of array to be compiler time constant. As a fix, use OPENSSL_malloc/free.


Why OPENSSL_malloc() in particular?

(As I have no clue about the intricacies of openssl-interfacing code, this
might be a stupid question, but it looks like "normal gc_malloc() should
be perfectly fine")

gert



--



___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel







[Openvpn-devel] [PATCH v2] Replace variable length array with malloc

2015-10-21 Thread Lev Stipakov
Commit 
https://github.com/OpenVPN/openvpn/commit/685e486e8b8f70c25f09590c24762ff734f94a51
introduced a variable length array. Although C99 supports that, MSVS 2013 still 
requires
size of array to be compiler time constant. As a fix, use malloc/free.

v2:
 Replace OPENSSL_malloc with gc_malloc

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/ssl_openssl.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index c08d4fe..3c8d41f 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -141,12 +141,12 @@ key_state_export_keying_material(struct key_state_ssl 
*ssl,
 {
 #if (OPENSSL_VERSION_NUMBER >= 0x10001000)
   unsigned int size = session->opt->ekm_size;
-  unsigned char ekm[size];
+  struct gc_arena gc = gc_new();
+  unsigned char* ekm = (unsigned char*) gc_malloc(size, true, );

   if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm),
   session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0))
{
- struct gc_arena gc = gc_new();
  unsigned int len = (size * 2) + 2;

  const char *key = format_hex_ex (ekm, size, len, 0, NULL, );
@@ -154,14 +154,13 @@ key_state_export_keying_material(struct key_state_ssl 
*ssl,

  dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s",
   __func__, key);
-
- gc_free();
}
   else
{
  msg (M_WARN, "WARNING: Export keying material failed!");
  setenv_del (session->opt->es, "exported_keying_material");
}
+  gc_free();
 #endif
 }
 }
-- 
1.9.1




Re: [Openvpn-devel] [PATCH] openssl: remove usage of OPENSSL_malloc() from show_available_curves

2015-10-21 Thread Lev Stipakov

ACK from me. Less code is better.

On 21.10.2015 01:39, Steffan Karger wrote:

There is no need to use OPENSSL_malloc(), so use our own functions that
automatically check for NULL and remove the now redundant NULL check.

Signed-off-by: Steffan Karger 
---
  src/openvpn/ssl_openssl.c | 33 +
  1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index c08d4fe..c5543fe 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -1447,31 +1447,24 @@ show_available_curves()
size_t n = 0;

crv_len = EC_get_builtin_curves(NULL, 0);
-
-  curves = OPENSSL_malloc((int)(sizeof(EC_builtin_curve) * crv_len));
-
-  if (curves == NULL)
-crypto_msg (M_FATAL, "Cannot create EC_builtin_curve object");
-  else
+  ALLOC_ARRAY(curves, EC_builtin_curve, crv_len);
+  if (EC_get_builtin_curves(curves, crv_len))
{
-if (EC_get_builtin_curves(curves, crv_len))
+printf ("Available Elliptic curves:\n");
+for (n = 0; n < crv_len; n++)
  {
-  printf ("Available Elliptic curves:\n");
-  for (n = 0; n < crv_len; n++)
-  {
-const char *sname;
-sname   = OBJ_nid2sn(curves[n].nid);
-if (sname == NULL) sname = "";
+  const char *sname;
+  sname   = OBJ_nid2sn(curves[n].nid);
+  if (sname == NULL) sname = "";

-printf("%s\n", sname);
-  }
+  printf("%s\n", sname);
  }
-else
-{
-  crypto_msg (M_FATAL, "Cannot get list of builtin curves");
-}
-OPENSSL_free(curves);
}
+  else
+  {
+crypto_msg (M_FATAL, "Cannot get list of builtin curves");
+  }
+  free(curves);
  #else
msg (M_WARN, "Your OpenSSL library was built without elliptic curve support. 
"
   "No curves available.");







Re: [Openvpn-devel] [PATCH] Fix memory leak in auth-pam plugin

2015-10-21 Thread Lev Stipakov

ACK from me. My Clang static analyzer concurs.

On 21.10.2015 01:38, Steffan Karger wrote:

As it says on the tin.  aresp would not be free'd nor returned by
my_conv() on errors.  Note that we never reach this code if allocation
of aresp failed.

Found with the Clang static analyzer.

Signed-off-by: Steffan Karger 
---
  src/plugins/auth-pam/auth-pam.c | 3 +++
  1 file changed, 3 insertions(+)

diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c
index bd71792..95692ab 100644
--- a/src/plugins/auth-pam/auth-pam.c
+++ b/src/plugins/auth-pam/auth-pam.c
@@ -642,6 +642,9 @@ my_conv (int n, const struct pam_message **msg_array,

if (ret == PAM_SUCCESS)
  *response_array = aresp;
+  else
+free(aresp);
+
return ret;
  }








[Openvpn-devel] [PATCH] Generate openvpn-plugin.h for MSVC build

2015-10-22 Thread Lev Stipakov
openvpn-plugin.h was not generated for MSVC build since it has been
removed from sources and made generated by configure script.

This fix generates it for MSVC build and substitutes macroses like
@OPENVPN_VERSION_MAJOR@ with actual values.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 build/msvc/msvc-generate/Makefile.mak  | 27 +--
 build/msvc/msvc-generate/version.m4.in |  3 +++
 2 files changed, 24 insertions(+), 6 deletions(-)
 mode change 100755 => 100644 build/msvc/msvc-generate/Makefile.mak
 create mode 100644 build/msvc/msvc-generate/version.m4.in

diff --git a/build/msvc/msvc-generate/Makefile.mak 
b/build/msvc/msvc-generate/Makefile.mak
old mode 100755
new mode 100644
index 72415f1..be72643
--- a/build/msvc/msvc-generate/Makefile.mak
+++ b/build/msvc/msvc-generate/Makefile.mak
@@ -1,13 +1,28 @@
 # Copyright (C) 2008-2012 Alon Bar-Lev <alon.bar...@gmail.com>

 CONFIG=$(SOURCEBASE)/version.m4
-INPUT=$(SOURCEBASE)/config-msvc-version.h.in
-OUTPUT=$(SOURCEBASE)/config-msvc-version.h

-all:   $(OUTPUT)
+INPUT_MSVC_VER=$(SOURCEBASE)/config-msvc-version.h.in
+OUTPUT_MSVC_VER=$(SOURCEBASE)/config-msvc-version.h

-$(OUTPUT): $(INPUT) $(CONFIG)
-   cscript //nologo msvc-generate.js --config="$(CONFIG)" 
--input="$(INPUT)" --output="$(OUTPUT)"
+INPUT_PLUGIN=$(SOURCEBASE)/include/openvpn-plugin.h.in
+OUTPUT_PLUGIN=$(SOURCEBASE)/include/openvpn-plugin.h
+
+INPUT_PLUGIN_CONFIG=version.m4.in
+OUTPUT_PLUGIN_CONFIG=version.m4
+
+all:   $(OUTPUT_MSVC_VER) $(OUTPUT_PLUGIN)
+
+$(OUTPUT_MSVC_VER): $(INPUT_MSVC_VER) $(CONFIG) 
+   cscript //nologo msvc-generate.js --config="$(CONFIG)" 
--input="$(INPUT_MSVC_VER)" --output="$(OUTPUT_MSVC_VER)"
+
+$(OUTPUT_PLUGIN_CONFIG): $(INPUT_PLUGIN_CONFIG)
+   cscript //nologo msvc-generate.js --config="$(CONFIG)" 
--input="$(INPUT_PLUGIN_CONFIG)" --output="$(OUTPUT_PLUGIN_CONFIG)"  
+
+$(OUTPUT_PLUGIN): $(INPUT_PLUGIN) $(OUTPUT_PLUGIN_CONFIG)
+   cscript //nologo msvc-generate.js --config="$(OUTPUT_PLUGIN_CONFIG)" 
--input="$(INPUT_PLUGIN)" --output="$(OUTPUT_PLUGIN)"

 clean:
-   -del "$(OUTPUT)"
+   -del "$(OUTPUT_MSVC_VER)"
+   -del "$(OUTPUT_PLUGIN)"
+   -del "$(OUTPUT_PLUGIN_CONFIG)"
diff --git a/build/msvc/msvc-generate/version.m4.in 
b/build/msvc/msvc-generate/version.m4.in
new file mode 100644
index 000..cbb4fef
--- /dev/null
+++ b/build/msvc/msvc-generate/version.m4.in
@@ -0,0 +1,3 @@
+define([OPENVPN_VERSION_MAJOR], [@PRODUCT_VERSION_MAJOR@])
+define([OPENVPN_VERSION_MINOR], [@PRODUCT_VERSION_MINOR@])
+define([OPENVPN_VERSION_PATCH], [@PRODUCT_VERSION_PATCH@])
-- 
1.9.1




[Openvpn-devel] [PATCH] Use adapter index instead of name

2015-10-22 Thread Lev Stipakov
From: Olli Mannisto <olmanni...@gmail.com>

Some windows machines get weird issues with netsh when using
adapter name on "netsh.exe interface ipv6 set address" command.

Changed logic to get adapter index and use it instead of adapter
name for netsh set address command. if unable to get adapter index,
try with adapter name.

Signed-off-by: Olli Mannisto <olmanni...@gmail.com>
Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/tun.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 24a61ec..aa0278d 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1301,18 +1301,30 @@ do_ifconfig (struct tuntap *tt,
 if ( do_ipv6 )
   {
char * saved_actual;
+   const DWORD idx = get_adapter_index_flexible(actual);

if (!strcmp (actual, "NULL"))
  msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than 
one TAP-Windows adapter, you must also specify --dev-node");

/* example: netsh interface ipv6 set address MyTap 2001:608:8003::d 
store=active */
-   argv_printf (,
-   "%s%sc interface ipv6 set address %s %s store=active",
-get_win_sys_path(),
-NETSH_PATH_SUFFIX,
-actual,
-ifconfig_ipv6_local );
-
+if (idx != TUN_ADAPTER_INDEX_INVALID)
+{
+argv_printf (,
+"%s%sc interface ipv6 set address %u %s store=active",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ idx,
+ ifconfig_ipv6_local);
+}
+else
+{
+argv_printf (,
+"%s%sc interface ipv6 set address %s %s store=active",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ actual,
+ ifconfig_ipv6_local);
+}
netsh_command (, 4);

/* explicit route needed */
-- 
1.9.1




Re: [Openvpn-devel] [PATCH] Use adapter index instead of name

2015-10-22 Thread Lev Stipakov

Hello,

> And with interface indexes, it works all the time?

We have tested it on a few machines which previously have had this 
problem and this patch has fixed that. We will test it for larger 
audience in near future and report results.


-Lev


On 22.10.2015 16.59, Gert Doering wrote:

hi,

On Thu, Oct 22, 2015 at 02:55:44PM +0100, David Woodhouse wrote:

So what is the underlying issue here?  Non-ASCII characters in the
device name ("this *should* have been fixed a few releases ago")?


No, and not spaces (despite the vpn.ccrypto.org link above suggesting
that it is).


Spaces are known to not cause issues ("I do test things" :-) ).


The issue is not known. Seriously, "because Windows".

Renaming the interface, and then renaming it back to precisely what it
was before, and doing registry dumps and checking that things really
*are* just the same as they were before, is sufficient to fix it.


Urgh.

And with interface indexes, it works all the time?  In that case, we'll
just change over... (the new rgi6 stuff uses interface indexes for routing
anyway)  ((meh, git master really is different from 2.3 code here...))

gert



--



___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel







[Openvpn-devel] [PATCH v2] Use adapter index instead of name

2015-11-09 Thread Lev Stipakov
v2:
 * Remove netsh call which uses adapter name. After thoughtful testing
turns out that "adapter name" code branch is never used.

Some windows machines get weird issues with netsh when using
adapter name on "netsh.exe interface ipv6 set address" command.

Changed logic to get adapter index and use it instead of adapter
name for netsh set address command. if unable to get adapter index,
try with adapter name.

Signed-off-by: Olli Mannisto <olmanni...@gmail.com>
Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/tun.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 24a61ec..0347a52 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1301,18 +1301,18 @@ do_ifconfig (struct tuntap *tt,
 if ( do_ipv6 )
   {
char * saved_actual;
+   const DWORD idx = get_adapter_index_flexible(actual);

if (!strcmp (actual, "NULL"))
  msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than 
one TAP-Windows adapter, you must also specify --dev-node");

-   /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d 
store=active */
+   /* example: netsh interface ipv6 set address 42 2001:608:8003::d 
store=active */
argv_printf (,
-   "%s%sc interface ipv6 set address %s %s store=active",
+"%s%sc interface ipv6 set address %u %s store=active",
 get_win_sys_path(),
 NETSH_PATH_SUFFIX,
-actual,
-ifconfig_ipv6_local );
-
+idx,
+ifconfig_ipv6_local);
netsh_command (, 4);

/* explicit route needed */
-- 
1.9.1




Re: [Openvpn-devel] [PATCH v2] Use adapter index instead of name

2015-11-11 Thread Lev Stipakov

Hi,



It should actually be not very hard - we should be able to set "tt->actual"
to read "interface=nnn", and then it should work automagically without even
touching route.c at all


Setting "interface=" to "tt->actual_name" will affect all code 
branches which use that value, for example "netsh_enable_dhcp". In this 
particular case we cannot use index and must use interface name, 
according to MS 
(https://technet.microsoft.com/en-us/library/cc731521(v=ws.10).aspx#BKMK_setaddress)


Same documentation claims that "set/delete address" accepts interface 
index only for ipv6. That said, "add/delete route" accepts index for 
both ipv4/ipv6. Besides, ipv4 syntax for "set address" is "[ name =] 
InterfaceName" and ipv6 is "[[ interface=] String]".


So, if we want to use index also for "add/del route", I'd gently modify 
add/del_route_ipv6 and make it use "interface=" (without breaking 
"vpn server special route" case).



What does surprise me, though, is that it works for you with just specifying
the interface index, without "IF" or "interface=" before it.



MS says "[[ interface=] String] Specifies an interface name or index" 
for "set address" and "add route". If I read it right, "interface" 
prefix can be omitted. But let's use it for consistency with existing code.


-Lev








[Openvpn-devel] [PATCH v3] Use adapter index instead of name

2015-11-11 Thread Lev Stipakov
v3:
 * Use interface= syntax.
 * Add forward declaration of get_adapter_index_flexible to get rid of warning.

v2:
 * Remove netsh call which uses adapter name. After thoughtful testing
turns out that "adapter name" code branch is never used.

Some windows machines get weird issues with netsh when using
adapter name on "netsh.exe interface ipv6 set address" command.

Changed logic to get adapter index and use it instead of adapter
name for netsh set address command. if unable to get adapter index,
try with adapter name.

Signed-off-by: Olli Mannisto <olmanni...@gmail.com>
Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/tun.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 24a61ec..070fd18 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -67,6 +67,8 @@ static void netsh_command (const struct argv *a, int n);

 static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);

+static DWORD get_adapter_index_flexible (const char *name);
+
 #endif

 #ifdef TARGET_SOLARIS
@@ -1301,18 +1303,20 @@ do_ifconfig (struct tuntap *tt,
 if ( do_ipv6 )
   {
char * saved_actual;
+   char iface[64];

if (!strcmp (actual, "NULL"))
  msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than 
one TAP-Windows adapter, you must also specify --dev-node");

-   /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d 
store=active */
+   openvpn_snprintf(iface, sizeof(iface), "interface=%lu", 
get_adapter_index_flexible(actual));
+
+   /* example: netsh interface ipv6 set address interface=42 
2001:608:8003::d store=active */
argv_printf (,
-   "%s%sc interface ipv6 set address %s %s store=active",
+"%s%sc interface ipv6 set address %s %s store=active",
 get_win_sys_path(),
 NETSH_PATH_SUFFIX,
-actual,
-ifconfig_ipv6_local );
-
+iface,
+ifconfig_ipv6_local);
netsh_command (, 4);

/* explicit route needed */
-- 
1.9.1




[Openvpn-devel] [PATCH] Fix "implicit declaration" compiler warning

2015-11-11 Thread Lev Stipakov
Add missing "include" directive.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/mtcp.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c
index b27c5eb..9926d47 100644
--- a/src/openvpn/mtcp.c
+++ b/src/openvpn/mtcp.c
@@ -37,6 +37,10 @@

 #include "memdbg.h"

+#ifdef HAVE_SYS_INOTIFY_H
+#include 
+#endif
+
 /*
  * TCP States
  */
-- 
1.9.1




Re: [Openvpn-devel] [PATCH v3] Notify clients about server's exit/restart

2015-11-16 Thread Lev Stipakov

Hi,


Since the new server side code does not actually *do* OCC any more we
are just #ifdef'ing it to access options->ce.explicit_exit_notify
because that one is only compiled in #ifdef ENABLE_OCC ... so we're
coupling this new functionality to an #ifdef which is not really
relevant.

No good suggestion yet, just expressing thoughts...



Since connection_entry->explicit_exit_notification is now used also 
outside of OCC context, I suggest to:


1) Remove #ifdef ENABLE_OCC around it's definition.

2) Fix comment there:

/* Explicitly tell peer when we are exiting via OCC_EXIT or control 
channel [RESTART] message */


3) Remove (unneeded anymore) #ifdef in multi_process_signal around 
accessing explicit_exit_notification.


What do you think?

-Lev







[Openvpn-devel] [PATCH v4] Notify clients about server's exit/restart

2015-11-17 Thread Lev Stipakov
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and
explicit-exit-notify is set, server sends RESTART control channel
command to all clients and reschedules received signal in 2 secs.

When client receives RESTART command, it either reconnects to the same
server or advances to the new one, depends on parameter comes with
RESTART command - behavior is controlled by explicit-exit-notify in the
server config.

v4:
- Rebase on top of master
- Remove #ifdef ENABLE_OCC around connection_entry->explicit_exit_notification
since it is also used outside of OCC context
- Update usage message

v3:
- Use control channel "RESTART" command instead of new OCC code to
notify clients
- Configure on the server side (by value of explicit-exit-notify) if
client should reconnect to the same server or advance to the next one
- Fix compilation when OCC is disabled (--enable-small)
- Update man page

v2:
- Take into use explicit-exit-notify on the server side
- OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT
- Code prettifying

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 doc/openvpn.8 | 15 ++--
 src/openvpn/multi.c   | 66 ---
 src/openvpn/multi.h   |  9 +++
 src/openvpn/options.c |  7 +++---
 src/openvpn/options.h |  4 +---
 src/openvpn/push.c|  6 +
 6 files changed, 95 insertions(+), 12 deletions(-)

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 2978b7f..dfb63fc 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -3886,8 +3886,19 @@ option will tell the server to immediately close its 
client instance object
 rather than waiting for a timeout.  The
 .B n
 parameter (default=1) controls the maximum number of attempts that the client
-will try to resend the exit notification message.  OpenVPN will not send any 
exit
-notifications unless this option is enabled.
+will try to resend the exit notification message. 
+
+In UDP server mode, send RESTART control channel command to connected clients. 
The
+.B n
+parameter (default=1) controls client behavior. With
+.B n
+= 1 client will attempt to reconnect
+to the same server, with
+.B n
+= 2 client will advance to the next server.
+
+OpenVPN will not send any exit
+notifications unless this option is enabled. 
 .\"*
 .SS Data Channel Encryption Options:
 These options are meaningful for both Static & TLS-negotiated key modes
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 7c3aaac..e153be7 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -429,6 +429,8 @@ multi_init (struct multi_context *m, struct context *t, 
bool tcp_mode, int threa
 t->options.stale_routes_check_interval, 
t->options.stale_routes_ageing_time);
   event_timeout_init (>stale_routes_check_et, 
t->options.stale_routes_check_interval, 0);
 }
+
+  m->deferred_shutdown_signal.signal_received = 0;
 }

 const char *
@@ -2721,10 +2723,18 @@ multi_process_timeout (struct multi_context *m, const 
unsigned int mpp_flags)
   /* instance marked for wakeup? */
   if (m->earliest_wakeup)
 {
-  set_prefix (m->earliest_wakeup);
-  ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+  if (m->earliest_wakeup == (struct 
multi_instance*)>deferred_shutdown_signal)
+   {
+ schedule_remove_entry(m->schedule, (struct schedule_entry*) 
>deferred_shutdown_signal);
+ throw_signal(m->deferred_shutdown_signal.signal_received);
+   }
+  else
+   {
+ set_prefix (m->earliest_wakeup);
+ ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+ clear_prefix ();
+   }
   m->earliest_wakeup = NULL;
-  clear_prefix ();
 }
   return ret;
 }
@@ -2849,6 +2859,48 @@ multi_top_free (struct multi_context *m)
   free_context_buffers (m->top.c2.buffers);
 }

+static bool
+is_exit_restart(int sig)
+{
+  return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT);
+}
+
+static void
+multi_push_restart_schedule_exit(struct multi_context *m, bool next_server)
+{
+  struct hash_iterator hi;
+  struct hash_element *he;
+  struct timeval tv;
+
+  /* tell all clients to restart */
+  hash_iterator_init (m->iter, );
+  while ((he = hash_iterator_next ()))
+{
+  struct multi_instance *mi = (struct multi_instance *) he->value;
+  if (!mi->halt)
+{
+ send_control_channel_string (>context, next_server ? 
"RESTART,[N]" : "RESTART", D_PUSH);
+ multi_schedule_context_wakeup(m, mi);
+}
+}
+  hash_iterator_free ();
+
+  /* reschedule signal */
+  ASSERT (!openvpn_gettimeofday (>deferred_shutdown_signal.wakeup, NULL));
+  tv.tv_sec = 2;
+  tv.tv_usec = 0;
+  tv_add (>deferred_shutdown_signal.wakeup, );
+
+  m->deferred_shutdown_signal.signal_received = m->top.sig->si

Re: [Openvpn-devel] [PATCH v8-master] Add Windows DNS Leak fix using WFP ('block-outside-dns')

2015-12-10 Thread Lev Stipakov

Hi,

Sorry for the late response.

+bool
+win_wfp_uninit()
+{
+dmsg (D_LOW, "Uninitializing WFP");
+if (m_hEngineHandle) {
+FwpmSubLayerDeleteByKey0(m_hEngineHandle, _subLayerGUID);
+CLEAR(m_subLayerGUID);
+FwpmEngineClose0(m_hEngineHandle);
+m_hEngineHandle = NULL;


FwpmSubLayerDeleteByKey0 will likely fail if there is a filter 
associated with sublayer. On the other side, FwpmEngineClose0 seems to 
be enough to remove blocking.


I think the correct way would be to create GUID for filter same way as 
you did for sublayer and copy it to filter.filterKey. In uninit method, 
before deleting sublayer you call FwpmFilterDeleteByKey0 with that guid.


-Lev




Re: [Openvpn-devel] [PATCH v8-master] Add Windows DNS Leak fix using WFP ('block-outside-dns')

2015-12-11 Thread Lev Stipakov

On 10.12.2015 18:49, ValdikSS wrote:


I'd better go with just
closing the engine without deleting everything. I don't see any
drawbacks, that should be perfectly OK for a dynamic session.

Is this correct, Lev? If yes, I'll push v9 today or tomorrow morning.


Removing non-working FwpmSubLayerDeleteByKey0 call is indeed step into 
right direction, rest is up to you :) I already mentioned above what I 
would do.


Just for the record - this patch does not work on my only win10 box with 
DNS leak - it blocks leaks but each DNS request takes 10 seconds, so I 
cannot give an ACK. On the other hand, it works for others in this 
discussion and is optional in any case (should not break things). So I 
won't say NACK either.


-Lev






Re: [Openvpn-devel] [PATCH v2] Use adapter index instead of name

2015-12-11 Thread Lev Stipakov

Hi,


So, if we want to use index also for "add/del route", I'd gently modify
add/del_route_ipv6 and make it use "interface=" (without breaking
"vpn server special route" case).


For consistency, I think we should do that.  What I'd avoid is to do
the adapter_index lookup for every single route - which would imply adding
the index to struct tuntap_options or something like that which is
available in add/del_route[_ipv6]() already.  But this is less elegant
than I hoped for, and might have to look different for 2.3 and master.


Adding the index - you probably meant to "struct tuntap"?

Master has member "adapter_index", which seems to be used for "special 
case", release/2.3 does not have that.


Do you think it is safe to store adapter index there (would have to add 
it to 2.3) without breaking "special case"? I personally not so sure, 
since that "adapter_index" is obtained via "adapter_index_of_ip" in 
tun.c, which looks quite different from "get_adapter_index_flexible".


We might have a semantic problem here.

-Lev







Re: [Openvpn-devel] [PATCH v2] Use adapter index instead of name

2015-12-11 Thread Lev Stipakov

Thanks, I think (I think!) I got it now.

1) Since we have tt->adapter_index (which temporarily disappeared from 
my perception of reality), no need to add new member to tuntap or 
tuntap_options.


2) tt->adapter_index has nothing to do with rgi->adapter_index, first 
one is windows adapter index (which we pass to netsh), last one is for 
routing (which we pass to netsh too in special case).


3) In add/del_route* we (try to) use tt->adapter_index.

Regarding master's "special case" code. Should it be something like this:

  if ( r6->adapter_index )   /* vpn server special route */
{
  struct buffer out = alloc_buf_gc (64, );
  buf_printf (, "interface=%d", r6->adapter_index );
  device = buf_bptr();
  gateway_needed = true;
}
  else
{
  /* device = interface=tt->adapter_index */
}

-Lev




[Openvpn-devel] [PATCH master] Use adapter index for add/delete_route_ipv6

2015-12-11 Thread Lev Stipakov
Trac #637

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/route.c | 16 
 src/openvpn/tun.c   |  2 ++
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 4a60345..2012b5c 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -1770,13 +1770,17 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct 
tuntap *tt, unsigned int fla

 #elif defined (WIN32)

+  struct buffer out = alloc_buf_gc (64, );
   if ( r6->adapter_index ) /* vpn server special route */
 {
-  struct buffer out = alloc_buf_gc (64, );
   buf_printf (, "interface=%d", r6->adapter_index );
-  device = buf_bptr();
   gateway_needed = true;
 }
+  else
+{
+  buf_printf (, "interface=%d", tt->adapter_index );
+}
+  device = buf_bptr();

   /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
   argv_printf (, "%s%sc interface ipv6 add route %s/%d %s",
@@ -2168,13 +2172,17 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const 
struct tuntap *tt, unsigne

 #elif defined (WIN32)

+  struct buffer out = alloc_buf_gc (64, );
   if ( r6->adapter_index ) /* vpn server special route */
 {
-  struct buffer out = alloc_buf_gc (64, );
   buf_printf (, "interface=%d", r6->adapter_index );
-  device = buf_bptr();
   gateway_needed = true;
 }
+  else
+{
+  buf_printf (, "interface=%d", tt->adapter_index );
+}
+  device = buf_bptr();

   /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
   argv_printf (, "%s%sc interface ipv6 delete route %s/%d %s",
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 014d988..aed5e75 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1328,6 +1328,8 @@ do_ifconfig (struct tuntap *tt,
 */
saved_actual = tt->actual_name;
tt->actual_name = (char*) actual;
+   /* we use adapter_index in add_route_ipv6 */
+   tt->adapter_index = idx;
add_route_connected_v6_net(tt, es);
tt->actual_name = saved_actual;
   }
-- 
1.9.1




[Openvpn-devel] [PATCH v2 master] Use adapter index for add/delete_route_ipv6

2015-12-11 Thread Lev Stipakov
Trac #637

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/route.c | 16 
 src/openvpn/tun.c   |  6 +-
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 4a60345..2012b5c 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -1770,13 +1770,17 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct 
tuntap *tt, unsigned int fla

 #elif defined (WIN32)

+  struct buffer out = alloc_buf_gc (64, );
   if ( r6->adapter_index ) /* vpn server special route */
 {
-  struct buffer out = alloc_buf_gc (64, );
   buf_printf (, "interface=%d", r6->adapter_index );
-  device = buf_bptr();
   gateway_needed = true;
 }
+  else
+{
+  buf_printf (, "interface=%d", tt->adapter_index );
+}
+  device = buf_bptr();

   /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
   argv_printf (, "%s%sc interface ipv6 add route %s/%d %s",
@@ -2168,13 +2172,17 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const 
struct tuntap *tt, unsigne

 #elif defined (WIN32)

+  struct buffer out = alloc_buf_gc (64, );
   if ( r6->adapter_index ) /* vpn server special route */
 {
-  struct buffer out = alloc_buf_gc (64, );
   buf_printf (, "interface=%d", r6->adapter_index );
-  device = buf_bptr();
   gateway_needed = true;
 }
+  else
+{
+  buf_printf (, "interface=%d", tt->adapter_index );
+}
+  device = buf_bptr();

   /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
   argv_printf (, "%s%sc interface ipv6 delete route %s/%d %s",
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 014d988..efcd225 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1306,11 +1306,13 @@ do_ifconfig (struct tuntap *tt,
   {
char * saved_actual;
char iface[64];
+   DWORD idx;

if (!strcmp (actual, "NULL"))
  msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than 
one TAP-Windows adapter, you must also specify --dev-node");

-   openvpn_snprintf(iface, sizeof(iface), "interface=%lu", 
get_adapter_index_flexible(actual));
+   idx = get_adapter_index_flexible(actual);
+   openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx);

/* example: netsh interface ipv6 set address interface=42 
2001:608:8003::d store=active */
argv_printf (,
@@ -1328,6 +1330,8 @@ do_ifconfig (struct tuntap *tt,
 */
saved_actual = tt->actual_name;
tt->actual_name = (char*) actual;
+   /* we use adapter_index in add_route_ipv6 */
+   tt->adapter_index = idx;
add_route_connected_v6_net(tt, es);
tt->actual_name = saved_actual;
   }
-- 
1.9.1




[Openvpn-devel] [PATCH 2.3] Use adapter index for add/delete_route_ipv6

2015-12-11 Thread Lev Stipakov
Trac #637
---
 src/openvpn/route.c | 8 
 src/openvpn/tun.c   | 6 +-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 1775a9c..cf5a067 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -1623,6 +1623,10 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct 
tuntap *tt, unsigned int fla

 #elif defined (WIN32)

+  struct buffer out = alloc_buf_gc (64, );
+  buf_printf (, "interface=%d", tt->adapter_index );
+  device = buf_bptr();
+
   /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
   argv_printf (, "%s%sc interface ipv6 add route %s/%d %s",
   get_win_sys_path(),
@@ -1954,6 +1958,10 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const 
struct tuntap *tt, unsigne

 #elif defined (WIN32)

+  struct buffer out = alloc_buf_gc (64, );
+  buf_printf (, "interface=%d", tt->adapter_index );
+  device = buf_bptr();
+
   /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
   argv_printf (, "%s%sc interface ipv6 delete route %s/%d %s",
   get_win_sys_path(),
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index b4223b1..b08c827 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1231,11 +1231,13 @@ do_ifconfig (struct tuntap *tt,
   {
char * saved_actual;
char iface[64];
+   DWORD idx;

if (!strcmp (actual, "NULL"))
  msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than 
one TAP-Windows adapter, you must also specify --dev-node");

-   openvpn_snprintf(iface, sizeof(iface), "interface=%lu", 
get_adapter_index_flexible(actual));
+   idx = get_adapter_index_flexible(actual);
+   openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx);

/* example: netsh interface ipv6 set address interface=42 
2001:608:8003::d store=active */
argv_printf (,
@@ -1253,6 +1255,8 @@ do_ifconfig (struct tuntap *tt,
 */
saved_actual = tt->actual_name;
tt->actual_name = (char*) actual;
+   /* we use adapter_index in add_route_ipv6 */
+   tt->adapter_index = idx;
add_route_connected_v6_net(tt, es);
tt->actual_name = saved_actual;
   }
-- 
1.9.1




[Openvpn-devel] [PATCH] Pass adapter index to up/down scripts

2015-12-12 Thread Lev Stipakov
Trac #637

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/init.c | 18 ++
 src/openvpn/misc.c |  6 ++
 src/openvpn/misc.h |  3 +++
 3 files changed, 27 insertions(+)

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 179c7ef..b0c0e26 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1485,6 +1485,9 @@ do_open_tun (struct context *c)
   c->plugins,
   OPENVPN_PLUGIN_UP,
   c->c1.tuntap->actual_name,
+#ifdef WIN32
+  c->c1.tuntap->adapter_index,
+#endif
   dev_type_string (c->options.dev, c->options.dev_type),
   TUN_MTU_SIZE (>c2.frame),
   EXPANDED_SIZE (>c2.frame),
@@ -1526,6 +1529,9 @@ do_open_tun (struct context *c)
 c->plugins,
 OPENVPN_PLUGIN_UP,
 c->c1.tuntap->actual_name,
+#ifdef WIN32
+c->c1.tuntap->adapter_index,
+#endif
 dev_type_string (c->options.dev, c->options.dev_type),
 TUN_MTU_SIZE (>c2.frame),
 EXPANDED_SIZE (>c2.frame),
@@ -1564,6 +1570,9 @@ do_close_tun (struct context *c, bool force)
   if (c->c1.tuntap && c->c1.tuntap_owned)
 {
   const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, 
);
+#ifdef WIN32
+  DWORD adapter_index = c->c1.tuntap->adapter_index;
+#endif
   const in_addr_t local = c->c1.tuntap->local;
   const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask;

@@ -1587,6 +1596,9 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_ROUTE_PREDOWN,
tuntap_actual,
+#ifdef WIN32
+   adapter_index,
+#endif
NULL,
TUN_MTU_SIZE (>c2.frame),
EXPANDED_SIZE (>c2.frame),
@@ -1612,6 +1624,9 @@ do_close_tun (struct context *c, bool force)
   c->plugins,
   OPENVPN_PLUGIN_DOWN,
   tuntap_actual,
+#ifdef WIN32
+  adapter_index,
+#endif
   NULL,
   TUN_MTU_SIZE (>c2.frame),
   EXPANDED_SIZE (>c2.frame),
@@ -1635,6 +1650,9 @@ do_close_tun (struct context *c, bool force)
 c->plugins,
 OPENVPN_PLUGIN_DOWN,
 tuntap_actual,
+#ifdef WIN32
+adapter_index,
+#endif
 NULL,
 TUN_MTU_SIZE (>c2.frame),
 EXPANDED_SIZE (>c2.frame),
diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
index bc411bf..05ed073 100644
--- a/src/openvpn/misc.c
+++ b/src/openvpn/misc.c
@@ -62,6 +62,9 @@ run_up_down (const char *command,
 const struct plugin_list *plugins,
 int plugin_type,
 const char *arg,
+#ifdef WIN32
+DWORD adapter_index,
+#endif
 const char *dev_type,
 int tun_mtu,
 int link_mtu,
@@ -82,6 +85,9 @@ run_up_down (const char *command,
   setenv_str (es, "dev", arg);
   if (dev_type)
 setenv_str (es, "dev_type", dev_type);
+#ifdef WIN32
+  setenv_int (es, "dev_idx", adapter_index);
+#endif

   if (!ifconfig_local)
 ifconfig_local = "";
diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h
index dbe899e..65a6e55 100644
--- a/src/openvpn/misc.h
+++ b/src/openvpn/misc.h
@@ -63,6 +63,9 @@ void run_up_down (const char *command,
  const struct plugin_list *plugins,
  int plugin_type,
  const char *arg,
+#ifdef WIN32
+ DWORD adapter_index,
+#endif
  const char *dev_type,
  int tun_mtu,
  int link_mtu,
-- 
1.9.1




Re: [Openvpn-devel] [PATCH] Make MSVC happy about route.c

2015-12-14 Thread Lev Stipakov

ACK.

I don't have VC2010, but at least on 2013 it compiles nicely.



[Openvpn-devel] [PATCH 2.3] Fix VS2013 compilation

2015-12-15 Thread Lev Stipakov
Update toolset, define __attribute__.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/compat/compat.vcxproj   | 4 +++-
 src/openvpn/openvpn.vcxproj | 6 --
 src/openvpn/syshead.h   | 1 +
 src/openvpnserv/openvpnserv.vcxproj | 4 +++-
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj
index 42979c1..1dedb33 100644
--- a/src/compat/compat.vcxproj
+++ b/src/compat/compat.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 StaticLibrary
 MultiByte
 true
+v120
   
   
 StaticLibrary
 MultiByte
+v120
   
   
   
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
index 0b1b3fd..d691500 100644
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 Application
 true
 Unicode
+v120
   
   
 Application
 Unicode
+v120
   
   
   
@@ -260,4 +262,4 @@
   
   
   
-
+
\ No newline at end of file
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index ffba4e8..24926ae 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -47,6 +47,7 @@

 #ifdef _MSC_VER // Visual Studio
 #define __func__ __FUNCTION__
+#define __attribute__(x)
 #endif

 #if defined(__APPLE__)
diff --git a/src/openvpnserv/openvpnserv.vcxproj 
b/src/openvpnserv/openvpnserv.vcxproj
index 0b75ed0..2a8943d 100644
--- a/src/openvpnserv/openvpnserv.vcxproj
+++ b/src/openvpnserv/openvpnserv.vcxproj
@@ -1,5 +1,5 @@
 
-http://schemas.microsoft.com/developer/msbuild/2003;>
+http://schemas.microsoft.com/developer/msbuild/2003;>
   
 
   Debug
@@ -20,10 +20,12 @@
 Application
 MultiByte
 true
+v120
   
   
 Application
 MultiByte
+v120
   
   
   
-- 
1.9.1




Re: [Openvpn-devel] XP broken

2015-12-20 Thread Lev Stipakov
Hi,

Screenshot seems to be lost in transmission.

Moving to openvpn-devel.

We could probably detect XP only (or technically "less then Vista") by
checking that IsWindowsVistaOrGreater() == false which seems to be
simpler. It should fix the problem.

However I like the idea that server will be able to know client's win
version, which might help with troubleshooting. I wouldn't not change
"IV_PLAT" value, so shall we add something like "IV_PLAT_WINVER=6.1"?

-Lev

2015-12-20 15:46 GMT+02:00 Gert Doering :

> Unfortunately, this is a bit complicated.
>
> First, XP really doesn't *do* interface indexes in netsh (*rant*) - I
> have attached a screen shot.  German, unfortunately, but "Zeichenkette"
> is "string", and the example clearly has an interface name there...
>
> We *could* introduce yet another option ("--ip-win32 netsh-names"),
> but the usefulness of that would depend on "whoever writes the .conf file
> knows what client OS it is for" (plus, we add an option that 2.4 won't
> have because it has no XP support anyway).  This does not sound like
> the way forward.
>
> So, I think we need to do this in two steps:
>
>  - add (in win32.c) a "win32_version_info()" function that will do the
>necessary things to figure out what Windows version we're running on.
>Stackoverflow suggests that this is complicated, as Windows will lie
>to programs most of the time, so "Win10" is reported as "Win8" unless
>there is something in the manifest (whatever that is) that tells windows
>"this program is prepared to deal with THE TRUTH"
>
>  - while at it, add "win32_version_string()" which would produce a printed
>version of this - so we can log it at startup, to help people diagnose
>why something isn't working for a user - and we could send it to the
>server as well if --push-peer-info is enabled (ssl.c, push_peer_info())
>
>  - and then, make the interface index bit conditional...
>
> if ( win32_version_info() == WIN_XP )
> device = tt->actual;
> else
>   {
> buf_printf (, "interface=%d", tt->adapter_index );
> device = buf_bptr();
>   }
>
>(for add/delete_route_ipv6(), but ifconfig would look the same)
>
>
> the win32_version_* stuff would go into 2.3 and master, because having
> that information is generally useful - the conditional setting only into
> 2.3.10
>
> what do you think?

-- 
-Lev



[Openvpn-devel] [PATCH] Detecting Windows version

2015-12-29 Thread Lev Stipakov
* Use adapter name instead of index on WinXP - sadly XP does not support indexes
* Write Windows version to log
* Send it with peer-info as IV_PLAT_VER

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 config-msvc.h  |  1 +
 configure.ac   |  1 +
 src/compat/compat-versionhelpers.h | 81 ++
 src/openvpn/openvpn.c  |  3 ++
 src/openvpn/options.c  | 12 ++
 src/openvpn/options.h  |  4 ++
 src/openvpn/route.c| 19 ++---
 src/openvpn/ssl.c  |  2 +
 src/openvpn/tun.c  |  2 +-
 src/openvpn/win32.c| 63 +
 src/openvpn/win32.h| 13 ++
 11 files changed, 194 insertions(+), 7 deletions(-)
 create mode 100644 src/compat/compat-versionhelpers.h

diff --git a/config-msvc.h b/config-msvc.h
index fa99384..ae43a5f 100644
--- a/config-msvc.h
+++ b/config-msvc.h
@@ -45,6 +45,7 @@
 #define HAVE_SYS_STAT_H 1
 #define HAVE_LZO_LZO1X_H 1
 #define HAVE_LZO_LZOUTIL_H 1
+#define HAVE_VERSIONHELPERS_H 1

 #define HAVE_ACCESS 1
 #define HAVE_CHDIR 1
diff --git a/configure.ac b/configure.ac
index 87d9116..773cded 100644
--- a/configure.ac
+++ b/configure.ac
@@ -423,6 +423,7 @@ AC_CHECK_HEADERS([ \
netinet/in.h netinet/in_systm.h \
netinet/tcp.h arpa/inet.h netdb.h \
windows.h winsock2.h ws2tcpip.h \
+   versionhelpers.h \
 ])
 AC_CHECK_HEADERS([ \
sys/time.h sys/ioctl.h sys/stat.h \
diff --git a/src/compat/compat-versionhelpers.h 
b/src/compat/compat-versionhelpers.h
new file mode 100644
index 000..f634091
--- /dev/null
+++ b/src/compat/compat-versionhelpers.h
@@ -0,0 +1,81 @@
+/**
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#ifndef _INC_VERSIONHELPERS
+#define _INC_VERSIONHELPERS
+
+#include 
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIDL__)
+
+#ifdef __cplusplus
+#define VERSIONHELPERAPI inline bool
+#else
+#define VERSIONHELPERAPI FORCEINLINE BOOL
+#endif
+
+#define _WIN32_WINNT_WINBLUE0x0603
+
+VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD major, WORD minor, WORD 
servpack)
+{
+OSVERSIONINFOEXW vi = {sizeof(vi),major,minor,0,0,{0},servpack};
+return VerifyVersionInfoW(, 
VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR,
+VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0,
+VER_MAJORVERSION,VER_GREATER_EQUAL),
+VER_MINORVERSION,VER_GREATER_EQUAL),
+VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL));
+}
+
+VERSIONHELPERAPI IsWindowsXPOrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 0);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 1);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP2OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 2);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP3OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 3);
+}
+
+VERSIONHELPERAPI IsWindowsVistaOrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), 
LOBYTE(_WIN32_WINNT_VISTA), 0);
+}
+
+VERSIONHELPERAPI IsWindowsVistaSP1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), 
LOBYTE(_WIN32_WINNT_VISTA), 1);
+}
+
+VERSIONHELPERAPI IsWindowsVistaSP2OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), 
LOBYTE(_WIN32_WINNT_VISTA), 2);
+}
+
+VERSIONHELPERAPI IsWindows7OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), 
LOBYTE(_WIN32_WINNT_WIN7), 0);
+}
+
+VERSIONHELPERAPI IsWindows7SP1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), 
LOBYTE(_WIN32_WINNT_WIN7), 1);
+}
+
+VERSIONHELPERAPI IsWindows8OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), 
LOBYTE(_WIN32_WINNT_WIN8), 0);
+}
+
+VERSIONHELPERAPI IsWindows8Point1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), 
LOBYTE(_WIN32_WINNT_WINBLUE), 0);
+}
+
+VERSIONHELPERAPI IsWindowsServer(void) {
+OSVERSIONINFOEXW vi = {sizeof(vi),0,0,0,0,{0},0,0,0,VER_NT_WORKSTATION};
+return !VerifyVersionInfoW(, VER_PRODUCT_TYPE, VerSetConditionMask(0, 
VER_PRODUCT_TYPE, VER_EQUAL));
+}
+
+#endif
+#endif
diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
index 32e326e..823c3dd 100644
--- a/src/openvpn/openvpn.c
+++ b/src/openvpn/openvpn.c
@@ -220,6 +220,9 @@ openvpn_main (int argc, char *argv[])

  /* print version number */
  msg (M_INFO, "%s", title_string);
+#ifdef WIN32
+ show_windows_version(M_INFO);
+#endif
   

[Openvpn-devel] [PATCH v2 2.3] Repair IPv6 netsh calls if Win XP is detected

2015-12-29 Thread Lev Stipakov
v2:
* Add compat-versionhelpers.h to compat/Makefile.am so that "make dist" will 
include it into tarball.
* Indentation

v1:
* Use adapter name instead of index on WinXP - sadly XP does not support indexes
* Write Windows version to log
* Send it with peer-info as IV_PLAT_VER

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 config-msvc.h  |  1 +
 configure.ac   |  1 +
 src/compat/Makefile.am |  3 +-
 src/compat/compat-versionhelpers.h | 81 ++
 src/openvpn/openvpn.c  |  3 ++
 src/openvpn/options.c  | 12 ++
 src/openvpn/options.h  |  4 ++
 src/openvpn/route.c| 19 ++---
 src/openvpn/ssl.c  |  3 ++
 src/openvpn/tun.c  |  2 +-
 src/openvpn/win32.c| 63 +
 src/openvpn/win32.h| 13 ++
 12 files changed, 197 insertions(+), 8 deletions(-)
 create mode 100644 src/compat/compat-versionhelpers.h

diff --git a/config-msvc.h b/config-msvc.h
index fa99384..ae43a5f 100644
--- a/config-msvc.h
+++ b/config-msvc.h
@@ -45,6 +45,7 @@
 #define HAVE_SYS_STAT_H 1
 #define HAVE_LZO_LZO1X_H 1
 #define HAVE_LZO_LZOUTIL_H 1
+#define HAVE_VERSIONHELPERS_H 1

 #define HAVE_ACCESS 1
 #define HAVE_CHDIR 1
diff --git a/configure.ac b/configure.ac
index 87d9116..773cded 100644
--- a/configure.ac
+++ b/configure.ac
@@ -423,6 +423,7 @@ AC_CHECK_HEADERS([ \
netinet/in.h netinet/in_systm.h \
netinet/tcp.h arpa/inet.h netdb.h \
windows.h winsock2.h ws2tcpip.h \
+   versionhelpers.h \
 ])
 AC_CHECK_HEADERS([ \
sys/time.h sys/ioctl.h sys/stat.h \
diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am
index 7ad4452..273389e 100644
--- a/src/compat/Makefile.am
+++ b/src/compat/Makefile.am
@@ -26,4 +26,5 @@ libcompat_la_SOURCES = \
compat-gettimeofday.c \
compat-daemon.c \
compat-inet_ntop.c \
-   compat-inet_pton.c
+   compat-inet_pton.c \
+   compat-versionhelpers.h
diff --git a/src/compat/compat-versionhelpers.h 
b/src/compat/compat-versionhelpers.h
new file mode 100644
index 000..f634091
--- /dev/null
+++ b/src/compat/compat-versionhelpers.h
@@ -0,0 +1,81 @@
+/**
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#ifndef _INC_VERSIONHELPERS
+#define _INC_VERSIONHELPERS
+
+#include 
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIDL__)
+
+#ifdef __cplusplus
+#define VERSIONHELPERAPI inline bool
+#else
+#define VERSIONHELPERAPI FORCEINLINE BOOL
+#endif
+
+#define _WIN32_WINNT_WINBLUE0x0603
+
+VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD major, WORD minor, WORD 
servpack)
+{
+OSVERSIONINFOEXW vi = {sizeof(vi),major,minor,0,0,{0},servpack};
+return VerifyVersionInfoW(, 
VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR,
+VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0,
+VER_MAJORVERSION,VER_GREATER_EQUAL),
+VER_MINORVERSION,VER_GREATER_EQUAL),
+VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL));
+}
+
+VERSIONHELPERAPI IsWindowsXPOrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 0);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 1);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP2OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 2);
+}
+
+VERSIONHELPERAPI IsWindowsXPSP3OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), 
LOBYTE(_WIN32_WINNT_WINXP), 3);
+}
+
+VERSIONHELPERAPI IsWindowsVistaOrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), 
LOBYTE(_WIN32_WINNT_VISTA), 0);
+}
+
+VERSIONHELPERAPI IsWindowsVistaSP1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), 
LOBYTE(_WIN32_WINNT_VISTA), 1);
+}
+
+VERSIONHELPERAPI IsWindowsVistaSP2OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), 
LOBYTE(_WIN32_WINNT_VISTA), 2);
+}
+
+VERSIONHELPERAPI IsWindows7OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), 
LOBYTE(_WIN32_WINNT_WIN7), 0);
+}
+
+VERSIONHELPERAPI IsWindows7SP1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), 
LOBYTE(_WIN32_WINNT_WIN7), 1);
+}
+
+VERSIONHELPERAPI IsWindows8OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), 
LOBYTE(_WIN32_WINNT_WIN8), 0);
+}
+
+VERSIONHELPERAPI IsWindows8Point1OrGreater(void) {
+return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), 
LOBYTE(_WIN32_WINNT_WINBLUE), 0);
+}
+
+VERSIONHELPERAPI IsWindowsServer(void) {
+OSVERSIONINFOEXW 

[Openvpn-devel] [PATCH] Drop recursively routed packets

2016-01-04 Thread Lev Stipakov
On certain OSes (Windows, OS X) when network adapter is
disabled (ethernet cable pulled off, Wi-Fi hardware switch disabled),
operating system starts to use tun as an external interface.
Outgoing packets are routed to tun, UDP encapsulated, given to
routing table and sent to.. tun.

As a consequence, system starts talking to itself on full power,
traffic counters skyrocket and user is not happy.

To prevent that, drop packets which have gateway IP as
destination address.

Tested on Win7/10, OS X.

Trac #642

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/forward.c | 63 +++
 1 file changed, 63 insertions(+)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 36a99e6..05445a1 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -973,6 +973,68 @@ read_incoming_tun (struct context *c)
   perf_pop ();
 }

+/**
+ * Drops UDP packets which OS decided to route via tun. 
+ * 
+ * On Windows and OS X when netwotk adapter is disabled or
+ * disconnected, platform starts to use tun as external interface. 
+ * When packet is sent to tun, it comes to openvpn, encapsulated
+ * and sent to routing table, which sends it again to tun.
+ */
+static void
+drop_recursive (struct context *c, struct buffer *buf)
+{
+  bool drop = false;
+  struct openvpn_sockaddr tun_sa = c->c2.to_link_addr->dest;
+
+  if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), buf))
+{
+  const struct openvpn_iphdr *pip;
+
+  /* make sure we got whole IP header */
+  if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr))
+   return;
+
+  /* skip ipv4 packets for ipv6 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET)
+   return;
+
+  pip = (struct openvpn_iphdr *) BPTR (buf);
+
+  /* drop packets with same dest addr as gateway */
+  if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr)
+   drop = true;
+}
+  else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), buf))
+{
+  const struct openvpn_ipv6hdr *pip6;
+
+  /* make sure we got whole IPv6 header */
+  if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr))
+   return;
+
+  /* skip ipv6 packets for ipv4 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET6)
+   return;
+
+  /* drop packets with same dest addr as gateway */
+  pip6 = (struct openvpn_ipv6hdr *) BPTR(buf);
+  if (IN6_ARE_ADDR_EQUAL(_sa.addr.in6.sin6_addr, >daddr))
+   drop = true;
+}
+
+  if (drop)
+{
+  struct gc_arena gc = gc_new ();
+
+  c->c2.buf.len = 0;
+
+  msg(D_LOW, "Recursive routing detected, drop tun packet to %s",
+   print_link_socket_actual(c->c2.to_link_addr, ));
+  gc_free ();
+}
+}
+
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_link
@@ -998,6 +1060,7 @@ process_incoming_tun (struct context *c)

   if (c->c2.buf.len > 0)
 {
+  drop_recursive (c, >c2.buf);
   /*
* The --passtos and --mssfix options require
* us to examine the IP header (IPv4 or IPv6).
-- 
1.9.1




[Openvpn-devel] [PATCH v2] Drop recursively routed packets

2016-01-04 Thread Lev Stipakov
v2: better method naming

On certain OSes (Windows, OS X) when network adapter is
disabled (ethernet cable pulled off, Wi-Fi hardware switch disabled),
operating system starts to use tun as an external interface.
Outgoing packets are routed to tun, UDP encapsulated, given to
routing table and sent to.. tun.

As a consequence, system starts talking to itself on full power,
traffic counters skyrocket and user is not happy.

To prevent that, drop packets which have gateway IP as
destination address.

Tested on Win7/10, OS X.

Trac #642

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/forward.c | 63 +++
 1 file changed, 63 insertions(+)

diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 36a99e6..af05bd0 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -973,6 +973,68 @@ read_incoming_tun (struct context *c)
   perf_pop ();
 }

+/**
+ * Drops UDP packets which OS decided to route via tun. 
+ * 
+ * On Windows and OS X when netwotk adapter is disabled or
+ * disconnected, platform starts to use tun as external interface. 
+ * When packet is sent to tun, it comes to openvpn, encapsulated
+ * and sent to routing table, which sends it again to tun.
+ */
+static void
+drop_if_recursive_routing (struct context *c, struct buffer *buf)
+{
+  bool drop = false;
+  struct openvpn_sockaddr tun_sa = c->c2.to_link_addr->dest;
+
+  if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), buf))
+{
+  const struct openvpn_iphdr *pip;
+
+  /* make sure we got whole IP header */
+  if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr))
+   return;
+
+  /* skip ipv4 packets for ipv6 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET)
+   return;
+
+  pip = (struct openvpn_iphdr *) BPTR (buf);
+
+  /* drop packets with same dest addr as gateway */
+  if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr)
+   drop = true;
+}
+  else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), buf))
+{
+  const struct openvpn_ipv6hdr *pip6;
+
+  /* make sure we got whole IPv6 header */
+  if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr))
+   return;
+
+  /* skip ipv6 packets for ipv4 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET6)
+   return;
+
+  /* drop packets with same dest addr as gateway */
+  pip6 = (struct openvpn_ipv6hdr *) BPTR(buf);
+  if (IN6_ARE_ADDR_EQUAL(_sa.addr.in6.sin6_addr, >daddr))
+   drop = true;
+}
+
+  if (drop)
+{
+  struct gc_arena gc = gc_new ();
+
+  c->c2.buf.len = 0;
+
+  msg(D_LOW, "Recursive routing detected, drop tun packet to %s",
+   print_link_socket_actual(c->c2.to_link_addr, ));
+  gc_free ();
+}
+}
+
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_link
@@ -998,6 +1060,7 @@ process_incoming_tun (struct context *c)

   if (c->c2.buf.len > 0)
 {
+  drop_if_recursive_routing (c, >c2.buf);
   /*
* The --passtos and --mssfix options require
* us to examine the IP header (IPv4 or IPv6).
-- 
1.9.1




[Openvpn-devel] [PATCH] Report Windows bitness

2016-02-07 Thread Lev Stipakov
Trac #599

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/win32.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
index 6c6ac4c..5702304 100644
--- a/src/openvpn/win32.c
+++ b/src/openvpn/win32.c
@@ -1323,6 +1323,20 @@ win32_version_info()
 }
 }

+bool
+win32_is_64bit()
+{
+#if defined(_WIN64)
+return true;  // 64-bit programs run only on Win64
+#elif defined(_WIN32)
+// 32-bit programs run on both 32-bit and 64-bit Windows
+BOOL f64 = FALSE;
+return IsWow64Process(GetCurrentProcess(), ) && f64;
+#else
+return false; // Win64 does not support Win16
+#endif
+}
+
 const char *
 win32_version_string(struct gc_arena *gc, bool add_name)
 {
@@ -1349,6 +1363,8 @@ win32_version_string(struct gc_arena *gc, bool add_name)
 break;
 }

+buf_printf (, win32_is_64bit() ? " 64bit" : " 32bit");
+
 return (const char *)out.data;
 }

-- 
1.9.1




Re: [Openvpn-devel] --block-outside-dns speed

2016-02-16 Thread Lev Stipakov

Hi James,


Has anyone seen issues with --block-outside-dns speed?  Because this
approach drops certain DNS packets, I'm wondering if apps will
experience lag time while waiting for dropped DNS requests to time out.


Yes, I have experienced issues with that patch.

On only machine I was able to reproduce DNS leak, this patch causes 
_all_ DNS requests to take 10 seconds to execute. According to 
Wireshark, Windows sends DNS requests to all adapters, got fast response 
from "right one", but nevertheless waits for about 10 seconds before 
giving up.



-Lev





Re: [Openvpn-devel] [PATCH] Support for disabled peer-id

2016-04-27 Thread Lev Stipakov

Yep, was a bit busy with other stuff last weeks.

On 27.04.2016 11:16, Arne Schwabe wrote:


I am just going through the patches. Lev, do you plan a follow up for this?

Arne






Re: [Openvpn-devel] [PATCH v2] Drop recursively routed packets

2016-08-30 Thread Lev Stipakov
So, following changes are required for V3:

1) No drop_if_recursive() call for P2P
2) Same for TAP
3) Add an option to disable it

Sounds reasonable?


2016-08-24 16:13 GMT+03:00 Gert Doering :

> Hi,
>
> On Wed, Aug 24, 2016 at 10:12:54AM +0200, Jan Just Keijser wrote:
> > may I suggest to make this configurable,
>
> Well...
>
> > i.e. the user can specify
> > whether rec routed packets should be dropped?  I'm afraid that we might
> > end up with code that drops packets that really should not be dropped -
> > people do weird things with routing: in 99% of the cases in error, but
> > in 1% of the cases because they want to do something funky.
>
> There is no way that this might ever work(*).
>
> If your tunnel gateway is 1.2.3.4, and you send packets to 1.2.3.4 into
> the tunnel, how are these going to arrive?
>
> Packet goes to TUN, is ecapsulated, and sent to 1.2.3.4.
>
> 1.2.3.4 route points to TUN, so packet goes to TUN, gets another layer
> of openvpn, and is sent to 1.2.3.4.
>
> 1.2.3.4 route points to TUN, so packet goes to TUN, gets a *third* layer
> of openvpn, and is sent to 1.2.3.4.
>
> repeat, until the packet hits 1500 byte MTU, and gets fragmented into
> *two* packets that loop forever...
>
> gert
>
>
> (*) it will work if and only if there are multiple routing tables involved,
> that is, packets sent by openvpn itself are not subject to the routing
> tables that would move packets *into* the tunnel - so the Android client
> wouldn't need it (VPN API takes care of this), and with the work on
> Github #13 to suport network name spaces on linux and multiple routing
> tables on *BSD, there are indeed scenarios where this makes sense...
>
> ... so you're right, v3 needs to have an option...
>
> (This started out really small and simple :-) )
> --
> USENET is *not* the non-clickable part of WWW!
>//
> www.muc.de/~gert/
> Gert Doering - Munich, Germany
> g...@greenie.muc.de
> fax: +49-89-35655025g...@net.informatik.tu-
> muenchen.de
>



-- 
-Lev
--
___
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel


[Openvpn-devel] [PATCH] Use separate list for per-client push options

2016-10-07 Thread Lev Stipakov
Move client-specific push options (currently peer-id and cipher) to
separate list, which is deallocated after push_reply
has been send. This makes sure that options are fit into buf,
not duplicated nor leak memory on renegotiation.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/push.c | 142 +++--
 1 file changed, 83 insertions(+), 59 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index a1b999e..a968c29 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -40,26 +40,29 @@
 
 #if P2MP
 
+static char push_reply_cmd[] = "PUSH_REPLY";
+
 /**
- * Add an option to the push list by providing a format string.
+ * Add an option to the given push list by providing a format string.
  *
  * The string added to the push options is allocated in o->gc, so the caller
  * does not have to preserve anything.
  *
- * @param oThe current connection's options
- * @param msglevel The message level to use when printing errors
+ * @param gc   GC arena where options are allocated
+ * @param push_list Push list containing options
+ * @param msglevel  The message level to use when printing errors
  * @param fmt  Format string for the option
  * @param ...  Format string arguments
  *
  * @return true on success, false on failure.
  */
-static bool push_option_fmt(struct options *o, int msglevel,
+static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, 
int msglevel,
 const char *fmt, ...)
 #ifdef __GNUC__
 #if __USE_MINGW_ANSI_STDIO
-__attribute__ ((format (gnu_printf, 3, 4)))
+__attribute__ ((format (gnu_printf, 4, 5)))
 #else
-__attribute__ ((format (__printf__, 3, 4)))
+__attribute__ ((format (__printf__, 4, 5)))
 #endif
 #endif
 ;
@@ -296,12 +299,14 @@ send_push_request (struct context *c)
  * Prepare push options, based on local options and available peer info.
  *
  * @param options  Connection options
+ * @param gc   gc arena for allocating push options
+ * @param push_list push list to where options are added
  * @param tls_multiTLS state structure for the current tunnel
  *
  * @return true on success, false on failure.
  */
 static bool
-prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
+prepare_push_reply (struct options *o, struct gc_arena *gc, struct push_list 
*push_list, struct tls_multi *tls_multi)
 {
   const char *optstr = NULL;
   const char * const peer_info = tls_multi->peer_info;
@@ -314,7 +319,7 @@ prepare_push_reply (struct options *o, struct tls_multi 
*tls_multi)
   int r = sscanf(optstr, "IV_PROTO=%d", );
   if ((r == 1) && (proto >= 2))
{
- push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id);
+ push_option_fmt(gc, push_list, M_USAGE, "peer-id %d", 
tls_multi->peer_id);
}
 }
 
@@ -335,29 +340,63 @@ prepare_push_reply (struct options *o, struct tls_multi 
*tls_multi)
{
  /* Push the first cipher from --ncp-ciphers to the client.
   * TODO: actual negotiation, instead of server dictatorship. */
- char *push_cipher = string_alloc(o->ncp_ciphers, >gc);
+ char *push_cipher = string_alloc(o->ncp_ciphers, gc);
  o->ciphername = strtok (push_cipher, ":");
- push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername);
+ push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername);
}
 }
   return true;
 }
 
 static bool
-send_push_reply (struct context *c)
+send_push_options (struct context *c, struct buffer *buf, struct push_list 
*push_list,
+int safe_cap, bool *push_sent, bool *multi_push)
+{
+  struct push_entry *e = push_list->head;
+
+  while (e)
+{
+  if (e->enable)
+   {
+ const int l = strlen (e->option);
+ if (BLEN (buf) + l >= safe_cap)
+   {
+ buf_printf (buf, ",push-continuation 2");
+   {
+ const bool status = send_control_channel_string (c, BSTR 
(buf), D_PUSH);
+ if (!status)
+   return false;
+ *push_sent = true;
+ *multi_push = true;
+ buf_reset_len (buf);
+ buf_printf (buf, "%s", push_reply_cmd);
+   }
+   }
+ if (BLEN (buf) + l >= safe_cap)
+   {
+ msg (M_WARN, "--push option is too long");
+ return false;
+   }
+ buf_printf (buf, ",%s", e->option);
+   }
+  e = e->next;
+}
+  return true;
+}
+
+static bool
+send_push_reply (struct context *c, struct push_list *per_client_push_list)
 {
   struct gc_arena gc = gc_new ();
   struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, );
-  struct push_entry *e = c->o

[Openvpn-devel] [PATCH v4] Drop recursively routed packets

2016-11-03 Thread Lev Stipakov
From: Lev Stipakov <lev.stipa...@f-secure.com>

v4:
 - Account for IP header offset in TAP mode
 - Correct handle of non-IP protocols in TAP mode

v3: Use better way of figuring out IP proto version which
does not break TAP mode. Add an option to allow recursive
routing, could be useful when packets sent by openvpn itself
are not subject to the routing tables that would move packets
into the tunnel.

v2: better method naming

On certain OSes (Windows, OS X) when network adapter is
disabled (ethernet cable pulled off, Wi-Fi hardware switch disabled),
operating system starts to use tun as an external interface.
Outgoing packets are routed to tun, UDP encapsulated, given to
routing table and sent to.. tun.

As a consequence, system starts talking to itself on full power,
traffic counters skyrocket and user is not happy.

To prevent that, drop packets which have gateway IP as
destination address.

Tested on Win7/10, OS X.
---
 Changes.rst   |  2 ++
 doc/openvpn.8 |  4 +++
 src/openvpn/forward.c | 72 +++
 src/openvpn/options.c | 10 +++
 src/openvpn/options.h |  4 +++
 src/openvpn/proto.h   | 39 
 6 files changed, 131 insertions(+)

diff --git a/Changes.rst b/Changes.rst
index 8fd5859..d7aae00 100644
--- a/Changes.rst
+++ b/Changes.rst
@@ -188,6 +188,8 @@ User-visible Changes
   capable. The ``--tun-ipv6`` option is ignored (behaves like it is always
   on).
 
+- On the client side recursively routed packets, which have same destination 
as host,
+  are dropped. This could be disabled with --allow-recursive-routing option.
 
 Maintainer-visible changes
 --
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 3a4ab21..863dcf9 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -4004,6 +4004,10 @@ to the same server, with
 
 OpenVPN will not send any exit
 notifications unless this option is enabled.
+.TP
+.B \-\-allow\-recursive\-routing
+When this option is set, OpenVPN will not drop incoming tun packets
+with same destination as host.
 .\"*
 .SS Data Channel Encryption Options:
 These options are meaningful for both Static & TLS-negotiated key modes
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index b3077ed..3a4c26a 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -993,6 +993,76 @@ read_incoming_tun (struct context *c)
   perf_pop ();
 }
 
+/**
+ * Drops UDP packets which OS decided to route via tun.
+ *
+ * On Windows and OS X when netwotk adapter is disabled or
+ * disconnected, platform starts to use tun as external interface.
+ * When packet is sent to tun, it comes to openvpn, encapsulated
+ * and sent to routing table, which sends it again to tun.
+ */
+static void
+drop_if_recursive_routing (struct context *c, struct buffer *buf)
+{
+  bool drop = false;
+  struct openvpn_sockaddr tun_sa;
+  int ip_hdr_offset = 0;
+
+  if (c->c2.to_link_addr == NULL) /* no remote addr known */
+return;
+
+  tun_sa = c->c2.to_link_addr->dest;
+
+  int proto_ver = get_tun_ip_ver (TUNNEL_TYPE (c->c1.tuntap), >c2.buf, 
_hdr_offset);
+
+  if (proto_ver == 4)
+{
+  const struct openvpn_iphdr *pip;
+
+  /* make sure we got whole IP header */
+  if (BLEN (buf) < ((int) sizeof (struct openvpn_iphdr) + ip_hdr_offset))
+   return;
+
+  /* skip ipv4 packets for ipv6 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET)
+   return;
+
+  pip = (struct openvpn_iphdr *) (BPTR (buf) + ip_hdr_offset);
+
+  /* drop packets with same dest addr as gateway */
+  if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr)
+   drop = true;
+}
+  else if (proto_ver == 6)
+{
+  const struct openvpn_ipv6hdr *pip6;
+
+  /* make sure we got whole IPv6 header */
+  if (BLEN (buf) < ((int) sizeof (struct openvpn_ipv6hdr) + ip_hdr_offset))
+   return;
+
+  /* skip ipv6 packets for ipv4 tun */
+  if (tun_sa.addr.sa.sa_family != AF_INET6)
+   return;
+
+  /* drop packets with same dest addr as gateway */
+  pip6 = (struct openvpn_ipv6hdr *) (BPTR (buf) + ip_hdr_offset);
+  if (IN6_ARE_ADDR_EQUAL(_sa.addr.in6.sin6_addr, >daddr))
+   drop = true;
+}
+
+  if (drop)
+{
+  struct gc_arena gc = gc_new ();
+
+  c->c2.buf.len = 0;
+
+  msg(D_LOW, "Recursive routing detected, drop tun packet to %s",
+   print_link_socket_actual(c->c2.to_link_addr, ));
+  gc_free ();
+}
+}
+
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_link
@@ -1018,6 +1088,8 @@ process_incoming_tun (struct context *c)
 
   if (c->c2.buf.len > 0)
 {
+  if ((c->options.mode == MODE_POINT_TO_POINT) && 
(!c->options.allow_recursive_routing))
+   drop_if_recursive_routing (c, >c2.buf);
   /*
* The --passtos and --mssfix options require
* us to examine t

[Openvpn-devel] [PATCH v2] Use separate list for per-client push options

2016-10-09 Thread Lev Stipakov
v2:
 - Also move ifconfig and ipv6-ifconfig to separate options list

Move client-specific push options (currently peer-id and cipher) to
separate list, which is deallocated after push_reply
has been send. This makes sure that options fit into buf,
not duplicated nor leak memory on renegotiation.

Signed-off-by: Lev Stipakov <lstipa...@gmail.com>
---
 src/openvpn/push.c | 186 ++---
 1 file changed, 104 insertions(+), 82 deletions(-)

diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index a1b999e..f7bcad1 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -40,26 +40,29 @@
 
 #if P2MP
 
+static char push_reply_cmd[] = "PUSH_REPLY";
+
 /**
- * Add an option to the push list by providing a format string.
+ * Add an option to the given push list by providing a format string.
  *
  * The string added to the push options is allocated in o->gc, so the caller
  * does not have to preserve anything.
  *
- * @param oThe current connection's options
- * @param msglevel The message level to use when printing errors
+ * @param gc   GC arena where options are allocated
+ * @param push_list Push list containing options
+ * @param msglevel  The message level to use when printing errors
  * @param fmt  Format string for the option
  * @param ...  Format string arguments
  *
  * @return true on success, false on failure.
  */
-static bool push_option_fmt(struct options *o, int msglevel,
+static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, 
int msglevel,
 const char *fmt, ...)
 #ifdef __GNUC__
 #if __USE_MINGW_ANSI_STDIO
-__attribute__ ((format (gnu_printf, 3, 4)))
+__attribute__ ((format (gnu_printf, 4, 5)))
 #else
-__attribute__ ((format (__printf__, 3, 4)))
+__attribute__ ((format (__printf__, 4, 5)))
 #endif
 #endif
 ;
@@ -295,16 +298,39 @@ send_push_request (struct context *c)
 /**
  * Prepare push options, based on local options and available peer info.
  *
- * @param options  Connection options
- * @param tls_multiTLS state structure for the current tunnel
+ * @param context  context structure storing data for VPN tunnel
+ * @param gc   gc arena for allocating push options
+ * @param push_listpush list to where options are added
  *
  * @return true on success, false on failure.
  */
 static bool
-prepare_push_reply (struct options *o, struct tls_multi *tls_multi)
+prepare_push_reply (struct context *c, struct gc_arena *gc, struct push_list 
*push_list)
 {
   const char *optstr = NULL;
+  const struct tls_multi *tls_multi = c->c2.tls_multi;
   const char * const peer_info = tls_multi->peer_info;
+  struct options *o = >options;
+
+  /* ipv6 */
+  if (c->c2.push_ifconfig_ipv6_defined && !o->push_ifconfig_ipv6_blocked)
+{
+  push_option_fmt (gc, push_list, M_USAGE, "ifconfig-ipv6 %s/%d %s",
+  print_in6_addr (c->c2.push_ifconfig_ipv6_local, 0, gc),
+  c->c2.push_ifconfig_ipv6_netbits,
+  print_in6_addr (c->c2.push_ifconfig_ipv6_remote, 0, gc));
+}
+
+  /* ipv4 */
+  if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && 
c->c2.push_ifconfig_remote_netmask)
+{
+  in_addr_t ifconfig_local = c->c2.push_ifconfig_local;
+  if (c->c2.push_ifconfig_local_alias)
+   ifconfig_local = c->c2.push_ifconfig_local_alias;
+  push_option_fmt (gc, push_list, M_USAGE, "ifconfig %s %s",
+  print_in_addr_t (ifconfig_local, 0, gc),
+  print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, 
gc));
+}
 
   /* Send peer-id if client supports it */
   optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
@@ -314,7 +340,7 @@ prepare_push_reply (struct options *o, struct tls_multi 
*tls_multi)
   int r = sscanf(optstr, "IV_PROTO=%d", );
   if ((r == 1) && (proto >= 2))
{
- push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id);
+ push_option_fmt(gc, push_list, M_USAGE, "peer-id %d", 
tls_multi->peer_id);
}
 }
 
@@ -324,7 +350,7 @@ prepare_push_reply (struct options *o, struct tls_multi 
*tls_multi)
   /* if we have already created our key, we cannot change our own
* cipher, so disable NCP and warn = explain why
*/
-  struct tls_session *session = _multi->session[TM_ACTIVE];
+  const struct tls_session *session = _multi->session[TM_ACTIVE];
   if ( session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized )
{
   msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but "
@@ -335,86 +361,76 @@ prepare_push_reply (struct options *o, struct tls_multi 
*tls_multi)
{
  /* Push the first cipher from --ncp-ciphers to the client.

  1   2   3   4   5   6   7   8   >