Attention is currently required from: plaisthos, ralf_lici, stipa.

Hello plaisthos, ralf_lici,

I'd like you to reexamine a change. Please visit

    http://gerrit.openvpn.net/c/openvpn/+/1752?usp=email

to look at the new patch set (#26).


Change subject: oob: Add --server-probe-reply to advertise probe reply values
......................................................................

oob: Add --server-probe-reply to advertise probe reply values

Add a server option, --server-probe-reply max-latency-diff [weight]
[prio], setting the values the server returns in its OOB PROBE_REPLY. An
unconfigured server advertises weight 50, priority 100 and a 10 ms
max-latency-diff.

max-latency-diff is how much slower than the fastest server a server may
be and still count as equally good; 0 asks clients to pick strictly by
latency, so only servers whose measured RTT ties the fastest stay
candidates, with weight still splitting exact ties. All three values are
range-checked to 0..65535.

--server-probe-reply off stops the server answering probes at all, for
an admin who would rather not serve them. The probe is dropped on its
opcode before it is unwrapped, so it costs neither the tls-crypt-v2
client-key unwrap nor any of the reply budget. A probing client then
treats the server as one without probe support, which puts it behind
every server that did answer.

The server puts the values into the probe_reply it builds once a probe
is accepted; the client already reads and ranks remotes by them. The
option takes at least the margin and is a server-mode option.

Also add the 2.8 changelog entry for the out-of-band probing feature.

Change-Id: Id74cfae7e9d69029d2ddbf635ee85a2a6cedc3d8
Signed-off-by: Lev Stipakov <[email protected]>
---
M Changes.md
M doc/man-sections/server-options.rst
M src/openvpn/mudp.c
M src/openvpn/options.c
M src/openvpn/options.h
5 files changed, 115 insertions(+), 5 deletions(-)


  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/52/1752/26

diff --git a/Changes.md b/Changes.md
index 2684251..cb85456 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,15 @@
 # Overview of changes in 2.8

+## New features
+
+* **Out-of-band server probing and server-controlled selection**
+
+  With `--server-probe`, a client probes all configured UDP remotes before
+  connecting and reorders them based on the replies: reachable servers are 
tried
+  first, ordered by server-advertised priority, measured latency and advertised
+  weight with DNS-SRV-like semantics. Servers advertise these values with
+  `--server-probe-reply`.
+
 ## User-visible Changes

 * **Parsing Distinguished Names in certificates**
diff --git a/doc/man-sections/server-options.rst 
b/doc/man-sections/server-options.rst
index 9dfa6bd..e77e85c 100644
--- a/doc/man-sections/server-options.rst
+++ b/doc/man-sections/server-options.rst
@@ -662,6 +662,44 @@
   Pushing of the ``--tun-ipv6`` directive is done for older clients which
   require an explicit ``--tun-ipv6`` in their configuration.

+--server-probe-reply args
+  Set the values a server advertises in its replies to out-of-band
+  probes from clients using ``--server-probe``.
+
+  Valid syntaxes::
+
+     server-probe-reply off
+     server-probe-reply max-latency-diff
+     server-probe-reply max-latency-diff weight
+     server-probe-reply max-latency-diff weight priority
+
+  ``max-latency-diff`` is the candidate-band margin in milliseconds that
+  *this* server asks for: a probing client keeps it among the candidates
+  while its round-trip time is within that margin of the fastest server
+  of the same priority. Each server advertises its own margin, so this
+  value does not constrain the others. The default is :code:`10`;
+  :code:`0` asks to stay a candidate only while tying the fastest, and
+  ``weight`` still distributes load between servers that tie exactly. A
+  client that sets its own margin with ``--server-probe`` overrides
+  every advertised value.
+
+  ``weight`` (default :code:`50`) and ``priority`` (default :code:`100`)
+  have DNS SRV (RFC 2782) semantics: clients try servers with a lower
+  priority value first, and distribute load between equally-good
+  servers of the same priority proportionally to their weights.
+
+  All values are in the range :code:`0` to :code:`65535`. A UDP server
+  answers probes by default, whether or not this option is given, and
+  the values above only change what it advertises.
+  :code:`server-probe-reply off` stops it answering probes at all. A
+  probing client then treats it like a server without probe support,
+  which means it is tried only after every server that did answer,
+  whatever its position in the client's remote list. Replies are
+  stateless and rate-limited. A probe whose timestamp is more than
+  ``--hand-window`` away from the server's clock is answered only within
+  a small budget, a twentieth of ``--connect-freq-initial``, so a client
+  with a wrong clock can still probe while a replayed probe gets little.
+
 --stale-routes-check args
   Remove routes which haven't had activity for ``n`` seconds (i.e. the ageing
   time).  This check is run every ``t`` seconds (i.e. check interval).
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index d592d40..e78db23 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -244,6 +244,10 @@
         {
             return false; /* malformed: silently drop */
         }
+        if (m->top.options.server_probe_reply_disabled)
+        {
+            return false; /* --server-probe-reply off: exactly the probe 
reply, nothing else */
+        }
         /* A client whose clock is off by more than --hand-window still gets a
          * few probes per period answered, which is also all a replayed probe
          * can get. */
@@ -252,8 +256,13 @@
             return false;
         }

-        /* the reply echoes the peer's session id */
-        struct oob_probe_reply reply = { .peer_session_id = 
state->peer_session_id };
+        /* the echo of the peer's session id, plus what we advertise */
+        struct oob_probe_reply reply = {
+            .peer_session_id = state->peer_session_id,
+            .priority = (uint16_t)m->top.options.server_probe_reply_priority,
+            .weight = (uint16_t)m->top.options.server_probe_reply_weight,
+            .max_latency_diff = 
(uint16_t)m->top.options.server_probe_reply_max_latency_diff,
+        };

         /* Our session id is a stateless SYN cookie (the same HMAC the 
three-way
          * handshake uses): we keep no per-probe state, and the reply can later
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 35ef2af..60918cd 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -44,6 +44,7 @@
 #include "ssl.h"
 #include "ssl_ncp.h"
 #include "options.h"
+#include "oob.h"
 #include "misc.h"
 #include "socket_util.h"
 #include "packet_id.h"
@@ -480,6 +481,9 @@
     "--auth-user-pass-optional : Allow connections by clients that don't\n"
     "                  specify a username/password.\n"
     "--client-to-client : Internally route client-to-client traffic.\n"
+    "--server-probe-reply m [w [p]] : Advertise latency margin m (ms), weight 
w\n"
+    "                  and priority p in replies to --server-probe clients.\n"
+    "                  'off' stops answering probes altogether.\n"
     "--duplicate-cn  : Allow multiple clients with the same common name to\n"
     "                  concurrently connect.\n"
     "--client-connect cmd : Run command cmd on client connection.\n"
@@ -813,10 +817,15 @@
     o->ce.proto = PROTO_UDP;
     o->ce.af = AF_UNSPEC;

-    /* The client latency margin is -1 = "not set": the client's value is
-     * authoritative when given, otherwise each server's advertised margin (or
-     * the built-in default) applies. */
+    /* server-probe defaults. The client latency margin is -1 = "not set": the
+     * client's value is authoritative when given, otherwise each server's
+     * advertised margin applies. An (unconfigured) server advertises weight 
50 /
+     * priority 100 and a margin of OOB_DEFAULT_LATENCY_MARGIN_MS -- 
announcing 0
+     * would ask clients to pick strictly by latency and never by weight. */
     o->server_probe_latency_margin = -1;
+    o->server_probe_reply_weight = 50;
+    o->server_probe_reply_priority = 100;
+    o->server_probe_reply_max_latency_diff = OOB_DEFAULT_LATENCY_MARGIN_MS;
     o->ce.bind_ipv6_only = false;
     o->ce.connect_retry_seconds = 1;
     o->ce.connect_retry_seconds_max = 300;
@@ -2005,6 +2014,7 @@
         MUST_BE_UNDEF(duplicate_cn, "duplicate-cn");
         MUST_BE_UNDEF(cf_max, "connect-freq");
         MUST_BE_UNDEF(cf_per, "connect-freq");
+        MUST_BE_UNDEF(server_probe_reply_defined, "server-probe-reply");
         MUST_BE_FALSE(options->ssl_flags
                           & (SSLF_CLIENT_CERT_NOT_REQUIRED | 
SSLF_CLIENT_CERT_OPTIONAL),
                       "verify-client-cert");
@@ -5105,6 +5115,40 @@
             options->server_probe_latency_margin = margin;
         }
     }
+    else if (streq(p[0], "server-probe-reply") && p[1] && !p[4])
+    {
+        VERIFY_PERMISSION(OPT_P_GENERAL);
+        /* --server-probe-reply off | max-latency-diff [weight] [prio] */
+        options->server_probe_reply_defined = true;
+        if (streq(p[1], "off"))
+        {
+            if (p[2])
+            {
+                msg(msglevel, "--server-probe-reply: 'off' takes no further 
arguments");
+                goto err;
+            }
+            options->server_probe_reply_disabled = true;
+        }
+        else
+        {
+            options->server_probe_reply_disabled = false;
+            int vals[3] = { options->server_probe_reply_max_latency_diff,
+                            options->server_probe_reply_weight,
+                            options->server_probe_reply_priority };
+            for (int i = 0; i < 3 && p[i + 1]; i++)
+            {
+                vals[i] = positive_atoi(p[i + 1], msglevel);
+                if (vals[i] > 0xffff)
+                {
+                    msg(msglevel, "--server-probe-reply: values must be 0 to 
65535");
+                    goto err;
+                }
+            }
+            options->server_probe_reply_max_latency_diff = vals[0];
+            options->server_probe_reply_weight = vals[1];
+            options->server_probe_reply_priority = vals[2];
+        }
+    }
     else if (streq(p[0], "nice") && p[1] && !p[2])
     {
         VERIFY_PERMISSION(OPT_P_NICE);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index c2cde60..9cb8e3fc 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -341,6 +341,15 @@
     /* client: default candidate-band margin in ms (--server-probe 
[max-latency-diff]):
      * servers within this RTT of the fastest are treated as equally fast */
     int server_probe_latency_margin;
+    /* server: values advertised in the OOB PROBE_REPLY (--server-probe-reply).
+     * priority/weight follow DNS-SRV semantics; max_latency_diff is the
+     * candidate band this server asks clients to use (0 = only the fastest
+     * server of the group is a candidate). */
+    int server_probe_reply_priority;
+    int server_probe_reply_weight;
+    int server_probe_reply_max_latency_diff;
+    bool server_probe_reply_defined;
+    bool server_probe_reply_disabled;

     bool mlock;


--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1752?usp=email
To unsubscribe, or for help writing mail filters, visit 
http://gerrit.openvpn.net/settings?usp=email

Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: Id74cfae7e9d69029d2ddbf635ee85a2a6cedc3d8
Gerrit-Change-Number: 1752
Gerrit-PatchSet: 26
Gerrit-Owner: stipa <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-Reviewer: ralf_lici <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>
Gerrit-Attention: ralf_lici <[email protected]>
Gerrit-Attention: stipa <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to