]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added "management-query-remote" directive (client) to allow
authorJames Yonan <james@openvpn.net>
Tue, 5 Jul 2011 00:33:55 +0000 (00:33 +0000)
committerJames Yonan <james@openvpn.net>
Tue, 5 Jul 2011 00:33:55 +0000 (00:33 +0000)
the management interface to override the "remote" directive.

See "remote" command in management/management-notes.txt for
documentation.

Version 2.1.4.

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

init.c
manage.c
manage.h
management/management-notes.txt
openvpn.8
options.c
options.h
syshead.h
version.m4

diff --git a/init.c b/init.c
index b3613b745992bcfa9ce3d16a06c15d97bfaad5c0..0e567e6e38e3870a45daf3a9d8d70f5c81864379 100644 (file)
--- a/init.c
+++ b/init.c
@@ -199,6 +199,90 @@ management_callback_http_proxy_fallback_cmd (void *arg, const char *server, cons
 
 #endif
 
+#if MANAGEMENT_QUERY_REMOTE
+
+static bool
+management_callback_remote_cmd (void *arg, const char **p)
+{
+  struct context *c = (struct context *) arg;
+  struct connection_entry *ce = &c->options.ce;
+  int ret = false;
+  if (p[1] && ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT)&CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY)
+    {
+      int flags = 0;
+      if (!strcmp(p[1], "ACCEPT"))
+       {
+         flags = CE_MAN_QUERY_REMOTE_ACCEPT;
+         ret = true;
+       }
+      else if (!strcmp(p[1], "SKIP"))
+       {
+         flags = CE_MAN_QUERY_REMOTE_SKIP;
+         ret = true;
+       }
+      else if (!strcmp(p[1], "MOD") && p[2] && p[3])
+       {
+         const int port = atoi(p[3]);
+         if (strlen(p[2]) < RH_HOST_LEN && legal_ipv4_port(port))
+           {
+             struct remote_host_store *rhs = c->options.rh_store;
+             if (!rhs)
+               {
+                 ALLOC_OBJ_CLEAR_GC (rhs, struct remote_host_store, &c->options.gc);
+                 c->options.rh_store = rhs;
+               }
+             strncpynt(rhs->host, p[2], RH_HOST_LEN);
+             ce->remote = rhs->host;
+             ce->remote_port = port;
+             flags = CE_MAN_QUERY_REMOTE_MOD;
+             ret = true;
+           }
+       }
+      if (ret)
+       {
+         ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT);
+         ce->flags |= ((flags&CE_MAN_QUERY_REMOTE_MASK)<<CE_MAN_QUERY_REMOTE_SHIFT);
+       }
+    }
+  return ret;
+}
+
+static bool
+ce_management_query_remote (struct context *c, const char *remote_ip_hint)
+{
+  struct gc_arena gc = gc_new ();
+  volatile struct connection_entry *ce = &c->options.ce;
+  int ret = true;
+  update_time();
+  if (management)
+    {
+      struct buffer out = alloc_buf_gc (256, &gc);
+      buf_printf (&out, ">REMOTE:%s,%d,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, false));
+      management_notify_generic(management, BSTR (&out));
+      ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT);
+      ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY<<CE_MAN_QUERY_REMOTE_SHIFT);
+      while (((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY)
+       {
+         management_event_loop_n_seconds (management, 1);
+         if (IS_SIG (c))
+           {
+             ret = false;
+             break;
+           }
+       }
+    }
+  {
+    const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK);
+    if (flags == CE_MAN_QUERY_REMOTE_ACCEPT && remote_ip_hint)
+      ce->remote = remote_ip_hint;
+    ret = (flags != CE_MAN_QUERY_REMOTE_SKIP);
+  }
+  gc_free (&gc);
+  return ret;
+}
+
+#endif
+
 /*
  * Initialize and possibly randomize connection list.
  */
@@ -313,6 +397,15 @@ next_connection_entry (struct context *c)
 
        c->options.ce = *ce;
 
+#if MANAGEMENT_QUERY_REMOTE
+       if (ce_defined && management && management_query_remote_enabled(management))
+         {
+           /* allow management interface to override connection entry details */
+           ce_defined = ce_management_query_remote(c, remote_ip_hint);
+           if (IS_SIG (c))
+             break;
+         } else
+#endif
        if (remote_ip_hint)
          c->options.ce.remote = remote_ip_hint;
 
@@ -2974,6 +3067,9 @@ init_management_callback_p2p (struct context *c)
       cb.show_net = management_show_net_callback;
 #if HTTP_PROXY_FALLBACK
       cb.http_proxy_fallback_cmd = management_callback_http_proxy_fallback_cmd;
+#endif
+#if MANAGEMENT_QUERY_REMOTE
+      cb.remote_cmd = management_callback_remote_cmd;
 #endif
       management_set_callback (management, &cb);
     }
@@ -3110,6 +3206,16 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
        goto sig;
     }
 
+  /* should we disable paging? */
+  if (c->first_time && options->mlock)
+    do_mlockall (true);
+
+#if P2MP
+  /* get passwords if undefined */
+  if (auth_retry_get () == AR_INTERACT)
+    init_query_passwords (c);
+#endif
+
   /* map in current connection entry */
   next_connection_entry (c);
 
@@ -3124,16 +3230,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
        link_socket_mode = LS_MODE_TCP_ACCEPT_FROM;
     }
 
-  /* should we disable paging? */
-  if (c->first_time && options->mlock)
-    do_mlockall (true);
-
-#if P2MP
-  /* get passwords if undefined */
-  if (auth_retry_get () == AR_INTERACT)
-    init_query_passwords (c);
-#endif
-
   /* initialize context level 2 --verb/--mute parms */
   init_verb_mute (c, IVM_LEVEL_2);
 
index 439bd76edcfb6e61806c4a6877d65554491e795c..df58ce460cc4492a42fb99e8bc8dee90da6131fd 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -86,6 +86,9 @@ man_help ()
   msg (M_CLIENT, "                         where action is reply string.");
   msg (M_CLIENT, "net                    : (Windows only) Show network info and routing table.");
   msg (M_CLIENT, "password type p        : Enter password p for a queried OpenVPN password.");
+#if MANAGEMENT_QUERY_REMOTE
+  msg (M_CLIENT, "remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP.");
+#endif
   msg (M_CLIENT, "pid                    : Show process ID of the current OpenVPN process.");
 #ifdef ENABLE_PKCS11
   msg (M_CLIENT, "pkcs11-id-count        : Get number of available PKCS#11 identities.");
@@ -1085,6 +1088,31 @@ man_http_proxy_fallback (struct management *man, const char *server, const char
 
 #endif
 
+#if MANAGEMENT_QUERY_REMOTE
+
+static void
+man_remote (struct management *man, const char **p)
+{
+  if (man->persist.callback.remote_cmd)
+    {
+      const bool status = (*man->persist.callback.remote_cmd)(man->persist.callback.arg, p);
+      if (status)
+       {
+         msg (M_CLIENT, "SUCCESS: remote command succeeded");
+       }
+      else
+       {
+         msg (M_CLIENT, "ERROR: remote command failed");
+       }
+    }
+  else
+    {
+      msg (M_CLIENT, "ERROR: The remote command is not supported by the current daemon mode");
+    }
+}
+
+#endif
+
 static void
 man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms)
 {
@@ -1314,6 +1342,13 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
       man_http_proxy_fallback (man, NULL, NULL, NULL);
     }
 #endif
+#if MANAGEMENT_QUERY_REMOTE
+  else if (streq (p[0], "remote"))
+    {
+      if (man_need (man, p, 1, MN_AT_LEAST))
+       man_remote (man, p);
+    }
+#endif
 #if 1
   else if (streq (p[0], "test"))
     {
@@ -2334,6 +2369,12 @@ management_notify(struct management *man, const char *severity, const char *type
   msg (M_CLIENT, ">NOTIFY:%s,%s,%s", severity, type, text);
 }
 
+void
+management_notify_generic (struct management *man, const char *str)
+{
+  msg (M_CLIENT, "%s", str);
+}
+
 #ifdef MANAGEMENT_DEF_AUTH
 
 static bool
index 288e47b273c89ece7b26a1e9e019c6aaea306531..f681f8d46d07f3e1834a3b64c985a08c8bbe1dab 100644 (file)
--- a/manage.h
+++ b/manage.h
@@ -174,6 +174,9 @@ struct management_callback
 #if HTTP_PROXY_FALLBACK
   bool (*http_proxy_fallback_cmd) (void *arg, const char *server, const char *port, const char *flags);
 #endif
+#if MANAGEMENT_QUERY_REMOTE
+  bool (*remote_cmd) (void *arg, const char **p);
+#endif
 };
 
 /*
@@ -333,6 +336,9 @@ struct management *management_init (void);
 # define MF_EXTERNAL_KEY    (1<<9)
 #endif
 #define MF_UP_DOWN          (1<<10)
+#if MANAGEMENT_QUERY_REMOTE
+#define MF_QUERY_REMOTE     (1<<11)
+#endif
 
 bool management_open (struct management *man,
                      const char *addr,
@@ -381,6 +387,8 @@ void management_up_down(struct management *man, const char *updown, const struct
 
 void management_notify(struct management *man, const char *severity, const char *type, const char *text);
 
+void management_notify_generic (struct management *man, const char *str);
+
 #ifdef MANAGEMENT_DEF_AUTH
 void management_notify_client_needing_auth (struct management *management,
                                            const unsigned int auth_id,
@@ -419,6 +427,14 @@ management_query_user_pass_enabled (const struct management *man)
   return BOOL_CAST(man->settings.flags & MF_QUERY_PASSWORDS);
 }
 
+#if MANAGEMENT_QUERY_REMOTE
+static inline bool
+management_query_remote_enabled (const struct management *man)
+{
+  return BOOL_CAST(man->settings.flags & MF_QUERY_REMOTE);
+}
+#endif
+
 #ifdef MANAGEMENT_PF
 static inline bool
 management_enable_pf (const struct management *man)
index 6e1e7cdcebec1578723f5d5ff49e1ce733e18b79..c25c998f1be0a9862801c46e33624d8b32557309 100644 (file)
@@ -687,6 +687,38 @@ the 10.0.0.0/8 netblock is allowed: 10.10.0.1.  Also, the client
 may not interact with external IP addresses using an "unknown"
 protocol (i.e. one that is not IPv4 or ARP).
 
+COMMAND -- remote  (OpenVPN 2.1.4 or higher)
+--------------------------------------------
+
+Provide remote host/port in response to a >REMOTE notification
+(client only).  Requires that the --management-query-remote
+directive is used.
+
+  remote ACTION [HOST PORT]
+
+The "remote" command should only be given in response to a >REMOTE
+notification.  For example, the following >REMOTE notification
+indicates that the client config file would ordinarily connect
+to vpn.example.com port 1194 (UDP):
+
+  >REMOTE:vpn.example.com,1194,udp
+
+Now, suppose we want to override the host and port, connecting
+instead to vpn.otherexample.com port 1234.  After receiving
+the above notification, use this command:
+
+  remote MOD vpn.otherexample.com 1234
+
+To accept the same host and port as the client would ordinarily
+have connected to, use this command:
+
+  remote ACCEPT
+
+To skip the current connection entry and advance to the next one,
+use this command:
+
+  remote SKIP
+
 OUTPUT FORMAT
 -------------
 
index 1c5ca0d51559425533962c5098f4caf783723a25..87058699bc97eb0d1f683d0b208102eb31d77f7e 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -2370,6 +2370,12 @@ for inputs which ordinarily would have been queried from the
 console.
 .\"*********************************************************
 .TP
+.B --management-query-remote
+Allow management interface to override
+.B --remote
+directives (client-only).
+.\"*********************************************************
+.TP
 .B --management-forget-disconnect
 Make OpenVPN forget passwords when management session
 disconnects.
index bbd0be597053f4817cef33fd6f4ab040d37d9493..88ed45da0104ff34509083de850188504cb48ab6 100644 (file)
--- a/options.c
+++ b/options.c
@@ -339,6 +339,9 @@ static const char usage_message[] =
   "                      ip/port rather than listen as a TCP server.\n"
   "--management-query-passwords : Query management channel for private key\n"
   "                  and auth-user-pass passwords.\n"
+#if MANAGEMENT_QUERY_REMOTE
+  "--management-query-remote : Query management channel for --remote directive.\n"
+#endif
   "--management-hold : Start " PACKAGE_NAME " in a hibernating state, until a client\n"
   "                    of the management interface explicitly starts it.\n"
   "--management-signal : Issue SIGUSR1 when management disconnect event occurs.\n"
@@ -3705,6 +3708,13 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->management_flags |= MF_QUERY_PASSWORDS;
     }
+#if MANAGEMENT_QUERY_REMOTE
+  else if (streq (p[0], "management-query-remote"))
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->management_flags |= MF_QUERY_REMOTE;
+    }
+#endif
   else if (streq (p[0], "management-hold"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
index 34bacecfcded709d57e66250233d7e58bf7eed42..f426e2a1e3fb2394392751015d7558377e30732d 100644 (file)
--- a/options.h
+++ b/options.h
@@ -109,7 +109,15 @@ struct connection_entry
 # define CE_HTTP_PROXY_FALLBACK (1<<1)
   time_t ce_http_proxy_fallback_timestamp; /* time when fallback http_proxy_options was last updated */
 #endif
-
+#if MANAGEMENT_QUERY_REMOTE
+# define CE_MAN_QUERY_REMOTE_UNDEF  0
+# define CE_MAN_QUERY_REMOTE_QUERY  1
+# define CE_MAN_QUERY_REMOTE_ACCEPT 2
+# define CE_MAN_QUERY_REMOTE_MOD    3
+# define CE_MAN_QUERY_REMOTE_SKIP   4
+# define CE_MAN_QUERY_REMOTE_MASK   (0x07)
+# define CE_MAN_QUERY_REMOTE_SHIFT  (2)
+#endif
   unsigned int flags;
 };
 
@@ -149,6 +157,14 @@ struct hpo_store
 };
 #endif
 
+#if MANAGEMENT_QUERY_REMOTE
+struct remote_host_store
+{
+# define RH_HOST_LEN 80
+  char host[RH_HOST_LEN];
+};
+#endif
+
 /* Command line options */
 struct options
 {
@@ -201,6 +217,10 @@ struct options
   struct hpo_store *hpo_store; /* used to store dynamic proxy info given by management interface */
 #endif
 
+#if MANAGEMENT_QUERY_REMOTE
+  struct remote_host_store *rh_store;
+#endif
+
   bool remote_random;
   const char *ipchange;
   const char *dev;
index 038b48416c4693f2fa5e044452651a2669259057..3cc6c3fa9100781f954561d990f1de33b8363e71 100644 (file)
--- a/syshead.h
+++ b/syshead.h
@@ -660,6 +660,15 @@ socket_defined (const socket_descriptor_t sd)
 #define HTTP_PROXY_FALLBACK 0
 #endif
 
+/*
+ * Should we include --management-query-remote functionality
+ */
+#if defined(ENABLE_CONNECTION) && defined(ENABLE_MANAGEMENT)
+#define MANAGEMENT_QUERY_REMOTE 1
+#else
+#define MANAGEMENT_QUERY_REMOTE 0
+#endif
+
 /*
  * Reduce sensitivity to system clock instability
  * and backtracks.
index 2b11a63447faecec37f2abf60c94c7e5cf0b5ced..c1122e5d4f3c25370ba9182c1db8abc5a1afcc56 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.3z])
+define(PRODUCT_VERSION,[2.1.4])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])