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
... | ... |
@@ -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 |
*/ |