Browse code

Added "management-query-remote" directive (client) to allow 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

James Yonan authored on 2011/07/05 09:33:55
Showing 9 changed files
... ...
@@ -199,6 +199,90 @@ management_callback_http_proxy_fallback_cmd (void *arg, const char *server, cons
199 199
 
200 200
 #endif
201 201
 
202
+#if MANAGEMENT_QUERY_REMOTE
203
+
204
+static bool
205
+management_callback_remote_cmd (void *arg, const char **p)
206
+{
207
+  struct context *c = (struct context *) arg;
208
+  struct connection_entry *ce = &c->options.ce;
209
+  int ret = false;
210
+  if (p[1] && ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT)&CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY)
211
+    {
212
+      int flags = 0;
213
+      if (!strcmp(p[1], "ACCEPT"))
214
+	{
215
+	  flags = CE_MAN_QUERY_REMOTE_ACCEPT;
216
+	  ret = true;
217
+	}
218
+      else if (!strcmp(p[1], "SKIP"))
219
+	{
220
+	  flags = CE_MAN_QUERY_REMOTE_SKIP;
221
+	  ret = true;
222
+	}
223
+      else if (!strcmp(p[1], "MOD") && p[2] && p[3])
224
+	{
225
+	  const int port = atoi(p[3]);
226
+	  if (strlen(p[2]) < RH_HOST_LEN && legal_ipv4_port(port))
227
+	    {
228
+	      struct remote_host_store *rhs = c->options.rh_store;
229
+	      if (!rhs)
230
+		{
231
+		  ALLOC_OBJ_CLEAR_GC (rhs, struct remote_host_store, &c->options.gc);
232
+		  c->options.rh_store = rhs;
233
+		}
234
+	      strncpynt(rhs->host, p[2], RH_HOST_LEN);
235
+	      ce->remote = rhs->host;
236
+	      ce->remote_port = port;
237
+	      flags = CE_MAN_QUERY_REMOTE_MOD;
238
+	      ret = true;
239
+	    }
240
+	}
241
+      if (ret)
242
+	{
243
+	  ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT);
244
+	  ce->flags |= ((flags&CE_MAN_QUERY_REMOTE_MASK)<<CE_MAN_QUERY_REMOTE_SHIFT);
245
+	}
246
+    }
247
+  return ret;
248
+}
249
+
250
+static bool
251
+ce_management_query_remote (struct context *c, const char *remote_ip_hint)
252
+{
253
+  struct gc_arena gc = gc_new ();
254
+  volatile struct connection_entry *ce = &c->options.ce;
255
+  int ret = true;
256
+  update_time();
257
+  if (management)
258
+    {
259
+      struct buffer out = alloc_buf_gc (256, &gc);
260
+      buf_printf (&out, ">REMOTE:%s,%d,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, false));
261
+      management_notify_generic(management, BSTR (&out));
262
+      ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT);
263
+      ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY<<CE_MAN_QUERY_REMOTE_SHIFT);
264
+      while (((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY)
265
+	{
266
+	  management_event_loop_n_seconds (management, 1);
267
+	  if (IS_SIG (c))
268
+	    {
269
+	      ret = false;
270
+	      break;
271
+	    }
272
+	}
273
+    }
274
+  {
275
+    const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK);
276
+    if (flags == CE_MAN_QUERY_REMOTE_ACCEPT && remote_ip_hint)
277
+      ce->remote = remote_ip_hint;
278
+    ret = (flags != CE_MAN_QUERY_REMOTE_SKIP);
279
+  }
280
+  gc_free (&gc);
281
+  return ret;
282
+}
283
+
284
+#endif
285
+
202 286
 /*
203 287
  * Initialize and possibly randomize connection list.
204 288
  */
... ...
@@ -313,6 +397,15 @@ next_connection_entry (struct context *c)
313 313
 
314 314
 	c->options.ce = *ce;
315 315
 
316
+#if MANAGEMENT_QUERY_REMOTE
317
+	if (ce_defined && management && management_query_remote_enabled(management))
318
+	  {
319
+	    /* allow management interface to override connection entry details */
320
+	    ce_defined = ce_management_query_remote(c, remote_ip_hint);
321
+	    if (IS_SIG (c))
322
+	      break;
323
+	  } else
324
+#endif
316 325
 	if (remote_ip_hint)
317 326
 	  c->options.ce.remote = remote_ip_hint;
318 327
 
... ...
@@ -2975,6 +3068,9 @@ init_management_callback_p2p (struct context *c)
2975 2975
 #if HTTP_PROXY_FALLBACK
2976 2976
       cb.http_proxy_fallback_cmd = management_callback_http_proxy_fallback_cmd;
2977 2977
 #endif
2978
+#if MANAGEMENT_QUERY_REMOTE
2979
+      cb.remote_cmd = management_callback_remote_cmd;
2980
+#endif
2978 2981
       management_set_callback (management, &cb);
2979 2982
     }
2980 2983
 #endif
... ...
@@ -3110,6 +3206,16 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
3110 3110
 	goto sig;
3111 3111
     }
3112 3112
 
3113
+  /* should we disable paging? */
3114
+  if (c->first_time && options->mlock)
3115
+    do_mlockall (true);
3116
+
3117
+#if P2MP
3118
+  /* get passwords if undefined */
3119
+  if (auth_retry_get () == AR_INTERACT)
3120
+    init_query_passwords (c);
3121
+#endif
3122
+
3113 3123
   /* map in current connection entry */
3114 3124
   next_connection_entry (c);
3115 3125
 
... ...
@@ -3124,16 +3230,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
3124 3124
 	link_socket_mode = LS_MODE_TCP_ACCEPT_FROM;
3125 3125
     }
3126 3126
 
3127
-  /* should we disable paging? */
3128
-  if (c->first_time && options->mlock)
3129
-    do_mlockall (true);
3130
-
3131
-#if P2MP
3132
-  /* get passwords if undefined */
3133
-  if (auth_retry_get () == AR_INTERACT)
3134
-    init_query_passwords (c);
3135
-#endif
3136
-
3137 3127
   /* initialize context level 2 --verb/--mute parms */
3138 3128
   init_verb_mute (c, IVM_LEVEL_2);
3139 3129
 
... ...
@@ -86,6 +86,9 @@ man_help ()
86 86
   msg (M_CLIENT, "                         where action is reply string.");
87 87
   msg (M_CLIENT, "net                    : (Windows only) Show network info and routing table.");
88 88
   msg (M_CLIENT, "password type p        : Enter password p for a queried OpenVPN password.");
89
+#if MANAGEMENT_QUERY_REMOTE
90
+  msg (M_CLIENT, "remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP.");
91
+#endif
89 92
   msg (M_CLIENT, "pid                    : Show process ID of the current OpenVPN process.");
90 93
 #ifdef ENABLE_PKCS11
91 94
   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
1085 1085
 
1086 1086
 #endif
1087 1087
 
1088
+#if MANAGEMENT_QUERY_REMOTE
1089
+
1090
+static void
1091
+man_remote (struct management *man, const char **p)
1092
+{
1093
+  if (man->persist.callback.remote_cmd)
1094
+    {
1095
+      const bool status = (*man->persist.callback.remote_cmd)(man->persist.callback.arg, p);
1096
+      if (status)
1097
+	{
1098
+	  msg (M_CLIENT, "SUCCESS: remote command succeeded");
1099
+	}
1100
+      else
1101
+	{
1102
+	  msg (M_CLIENT, "ERROR: remote command failed");
1103
+	}
1104
+    }
1105
+  else
1106
+    {
1107
+      msg (M_CLIENT, "ERROR: The remote command is not supported by the current daemon mode");
1108
+    }
1109
+}
1110
+
1111
+#endif
1112
+
1088 1113
 static void
1089 1114
 man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms)
1090 1115
 {
... ...
@@ -1314,6 +1342,13 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
1314 1314
       man_http_proxy_fallback (man, NULL, NULL, NULL);
1315 1315
     }
1316 1316
 #endif
1317
+#if MANAGEMENT_QUERY_REMOTE
1318
+  else if (streq (p[0], "remote"))
1319
+    {
1320
+      if (man_need (man, p, 1, MN_AT_LEAST))
1321
+	man_remote (man, p);
1322
+    }
1323
+#endif
1317 1324
 #if 1
1318 1325
   else if (streq (p[0], "test"))
1319 1326
     {
... ...
@@ -2334,6 +2369,12 @@ management_notify(struct management *man, const char *severity, const char *type
2334 2334
   msg (M_CLIENT, ">NOTIFY:%s,%s,%s", severity, type, text);
2335 2335
 }
2336 2336
 
2337
+void
2338
+management_notify_generic (struct management *man, const char *str)
2339
+{
2340
+  msg (M_CLIENT, "%s", str);
2341
+}
2342
+
2337 2343
 #ifdef MANAGEMENT_DEF_AUTH
2338 2344
 
2339 2345
 static bool
... ...
@@ -174,6 +174,9 @@ struct management_callback
174 174
 #if HTTP_PROXY_FALLBACK
175 175
   bool (*http_proxy_fallback_cmd) (void *arg, const char *server, const char *port, const char *flags);
176 176
 #endif
177
+#if MANAGEMENT_QUERY_REMOTE
178
+  bool (*remote_cmd) (void *arg, const char **p);
179
+#endif
177 180
 };
178 181
 
179 182
 /*
... ...
@@ -333,6 +336,9 @@ struct management *management_init (void);
333 333
 # define MF_EXTERNAL_KEY    (1<<9)
334 334
 #endif
335 335
 #define MF_UP_DOWN          (1<<10)
336
+#if MANAGEMENT_QUERY_REMOTE
337
+#define MF_QUERY_REMOTE     (1<<11)
338
+#endif
336 339
 
337 340
 bool management_open (struct management *man,
338 341
 		      const char *addr,
... ...
@@ -381,6 +387,8 @@ void management_up_down(struct management *man, const char *updown, const struct
381 381
 
382 382
 void management_notify(struct management *man, const char *severity, const char *type, const char *text);
383 383
 
384
+void management_notify_generic (struct management *man, const char *str);
385
+
384 386
 #ifdef MANAGEMENT_DEF_AUTH
385 387
 void management_notify_client_needing_auth (struct management *management,
386 388
 					    const unsigned int auth_id,
... ...
@@ -419,6 +427,14 @@ management_query_user_pass_enabled (const struct management *man)
419 419
   return BOOL_CAST(man->settings.flags & MF_QUERY_PASSWORDS);
420 420
 }
421 421
 
422
+#if MANAGEMENT_QUERY_REMOTE
423
+static inline bool
424
+management_query_remote_enabled (const struct management *man)
425
+{
426
+  return BOOL_CAST(man->settings.flags & MF_QUERY_REMOTE);
427
+}
428
+#endif
429
+
422 430
 #ifdef MANAGEMENT_PF
423 431
 static inline bool
424 432
 management_enable_pf (const struct management *man)
... ...
@@ -687,6 +687,38 @@ the 10.0.0.0/8 netblock is allowed: 10.10.0.1.  Also, the client
687 687
 may not interact with external IP addresses using an "unknown"
688 688
 protocol (i.e. one that is not IPv4 or ARP).
689 689
 
690
+COMMAND -- remote  (OpenVPN 2.1.4 or higher)
691
+--------------------------------------------
692
+
693
+Provide remote host/port in response to a >REMOTE notification
694
+(client only).  Requires that the --management-query-remote
695
+directive is used.
696
+
697
+  remote ACTION [HOST PORT]
698
+
699
+The "remote" command should only be given in response to a >REMOTE
700
+notification.  For example, the following >REMOTE notification
701
+indicates that the client config file would ordinarily connect
702
+to vpn.example.com port 1194 (UDP):
703
+
704
+  >REMOTE:vpn.example.com,1194,udp
705
+
706
+Now, suppose we want to override the host and port, connecting
707
+instead to vpn.otherexample.com port 1234.  After receiving
708
+the above notification, use this command:
709
+
710
+  remote MOD vpn.otherexample.com 1234
711
+
712
+To accept the same host and port as the client would ordinarily
713
+have connected to, use this command:
714
+
715
+  remote ACCEPT
716
+
717
+To skip the current connection entry and advance to the next one,
718
+use this command:
719
+
720
+  remote SKIP
721
+
690 722
 OUTPUT FORMAT
691 723
 -------------
692 724
 
... ...
@@ -2370,6 +2370,12 @@ for inputs which ordinarily would have been queried from the
2370 2370
 console.
2371 2371
 .\"*********************************************************
2372 2372
 .TP
2373
+.B --management-query-remote
2374
+Allow management interface to override
2375
+.B --remote
2376
+directives (client-only).
2377
+.\"*********************************************************
2378
+.TP
2373 2379
 .B --management-forget-disconnect
2374 2380
 Make OpenVPN forget passwords when management session
2375 2381
 disconnects.
... ...
@@ -339,6 +339,9 @@ static const char usage_message[] =
339 339
   "                      ip/port rather than listen as a TCP server.\n"
340 340
   "--management-query-passwords : Query management channel for private key\n"
341 341
   "                  and auth-user-pass passwords.\n"
342
+#if MANAGEMENT_QUERY_REMOTE
343
+  "--management-query-remote : Query management channel for --remote directive.\n"
344
+#endif
342 345
   "--management-hold : Start " PACKAGE_NAME " in a hibernating state, until a client\n"
343 346
   "                    of the management interface explicitly starts it.\n"
344 347
   "--management-signal : Issue SIGUSR1 when management disconnect event occurs.\n"
... ...
@@ -3705,6 +3708,13 @@ add_option (struct options *options,
3705 3705
       VERIFY_PERMISSION (OPT_P_GENERAL);
3706 3706
       options->management_flags |= MF_QUERY_PASSWORDS;
3707 3707
     }
3708
+#if MANAGEMENT_QUERY_REMOTE
3709
+  else if (streq (p[0], "management-query-remote"))
3710
+    {
3711
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3712
+      options->management_flags |= MF_QUERY_REMOTE;
3713
+    }
3714
+#endif
3708 3715
   else if (streq (p[0], "management-hold"))
3709 3716
     {
3710 3717
       VERIFY_PERMISSION (OPT_P_GENERAL);
... ...
@@ -109,7 +109,15 @@ struct connection_entry
109 109
 # define CE_HTTP_PROXY_FALLBACK (1<<1)
110 110
   time_t ce_http_proxy_fallback_timestamp; /* time when fallback http_proxy_options was last updated */
111 111
 #endif
112
-
112
+#if MANAGEMENT_QUERY_REMOTE
113
+# define CE_MAN_QUERY_REMOTE_UNDEF  0
114
+# define CE_MAN_QUERY_REMOTE_QUERY  1
115
+# define CE_MAN_QUERY_REMOTE_ACCEPT 2
116
+# define CE_MAN_QUERY_REMOTE_MOD    3
117
+# define CE_MAN_QUERY_REMOTE_SKIP   4
118
+# define CE_MAN_QUERY_REMOTE_MASK   (0x07)
119
+# define CE_MAN_QUERY_REMOTE_SHIFT  (2)
120
+#endif
113 121
   unsigned int flags;
114 122
 };
115 123
 
... ...
@@ -149,6 +157,14 @@ struct hpo_store
149 149
 };
150 150
 #endif
151 151
 
152
+#if MANAGEMENT_QUERY_REMOTE
153
+struct remote_host_store
154
+{
155
+# define RH_HOST_LEN 80
156
+  char host[RH_HOST_LEN];
157
+};
158
+#endif
159
+
152 160
 /* Command line options */
153 161
 struct options
154 162
 {
... ...
@@ -201,6 +217,10 @@ struct options
201 201
   struct hpo_store *hpo_store; /* used to store dynamic proxy info given by management interface */
202 202
 #endif
203 203
 
204
+#if MANAGEMENT_QUERY_REMOTE
205
+  struct remote_host_store *rh_store;
206
+#endif
207
+
204 208
   bool remote_random;
205 209
   const char *ipchange;
206 210
   const char *dev;
... ...
@@ -661,6 +661,15 @@ socket_defined (const socket_descriptor_t sd)
661 661
 #endif
662 662
 
663 663
 /*
664
+ * Should we include --management-query-remote functionality
665
+ */
666
+#if defined(ENABLE_CONNECTION) && defined(ENABLE_MANAGEMENT)
667
+#define MANAGEMENT_QUERY_REMOTE 1
668
+#else
669
+#define MANAGEMENT_QUERY_REMOTE 0
670
+#endif
671
+
672
+/*
664 673
  * Reduce sensitivity to system clock instability
665 674
  * and backtracks.
666 675
  */
... ...
@@ -1,5 +1,5 @@
1 1
 dnl define the OpenVPN version
2
-define(PRODUCT_VERSION,[2.1.3z])
2
+define(PRODUCT_VERSION,[2.1.4])
3 3
 dnl define the TAP version
4 4
 define(PRODUCT_TAP_ID,[tap0901])
5 5
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])