Add preliminary support for Negotiable Crypto Parameters 'level 2'
(IV_NCP=2), as proposed by James Yonan on the openvpn-devel mailinglist:
http://comments.gmane.org/gmane.network.openvpn.devel/9385
This patch makes a server push a 'cipher XXX' directive to the client,
if the client advertises "IV_NCP=2", where XXX is the cipher set in the
server config file.
This enables clients that have support for IV_NCP to connect to a
server, even when the client does not have the correct cipher specified
in it's config file.
Since pushing the cipher directive is quite similar to pushing peer-id,
I moved peer-id pushing to the same prepare_push_reply() function I
created for pushing cipher. Adding these directives as regular push
options allows us to use the existing 'push-continuation'
infrastructure. Note that we should not reduce safe_cap in
send_push_reply, because it was never increased to account for peer-id.
This is a preliminary patch, which will be followed by more patches to
add client support, and configurability.
v2:
* Reword doxygen of push_options_fmt()
* No longer push IV_NCP as a server
Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <CAA1Abx+gSgFH3=+xO6QN4NDAYwf8jctYhe8VyRxD8e1L=D6LWg@mail.gmail.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/11170
Signed-off-by: Gert Doering <gert@greenie.muc.de>
... | ... |
@@ -40,6 +40,30 @@ |
40 | 40 |
|
41 | 41 |
#if P2MP |
42 | 42 |
|
43 |
+/** |
|
44 |
+ * Add an option to the push list by providing a format string. |
|
45 |
+ * |
|
46 |
+ * The string added to the push options is allocated in o->gc, so the caller |
|
47 |
+ * does not have to preserve anything. |
|
48 |
+ * |
|
49 |
+ * @param o The current connection's options |
|
50 |
+ * @param msglevel The message level to use when printing errors |
|
51 |
+ * @param fmt Format string for the option |
|
52 |
+ * @param ... Format string arguments |
|
53 |
+ * |
|
54 |
+ * @return true on success, false on failure. |
|
55 |
+ */ |
|
56 |
+static bool push_option_fmt(struct options *o, int msglevel, |
|
57 |
+ const char *fmt, ...) |
|
58 |
+#ifdef __GNUC__ |
|
59 |
+#if __USE_MINGW_ANSI_STDIO |
|
60 |
+ __attribute__ ((format (gnu_printf, 3, 4))) |
|
61 |
+#else |
|
62 |
+ __attribute__ ((format (__printf__, 3, 4))) |
|
63 |
+#endif |
|
64 |
+#endif |
|
65 |
+ ; |
|
66 |
+ |
|
43 | 67 |
/* |
44 | 68 |
* Auth username/password |
45 | 69 |
* |
... | ... |
@@ -239,7 +263,47 @@ send_push_request (struct context *c) |
239 | 239 |
|
240 | 240 |
#if P2MP_SERVER |
241 | 241 |
|
242 |
-bool |
|
242 |
+/** |
|
243 |
+ * Prepare push options, based on local options and available peer info. |
|
244 |
+ * |
|
245 |
+ * @param options Connection options |
|
246 |
+ * @param tls_multi TLS state structure for the current tunnel |
|
247 |
+ * |
|
248 |
+ * @return true on success, false on failure. |
|
249 |
+ */ |
|
250 |
+static bool |
|
251 |
+prepare_push_reply (struct options *o, struct tls_multi *tls_multi) |
|
252 |
+{ |
|
253 |
+ const char *optstr = NULL; |
|
254 |
+ const char * const peer_info = tls_multi->peer_info; |
|
255 |
+ |
|
256 |
+ /* Send peer-id if client supports it */ |
|
257 |
+ optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; |
|
258 |
+ if (optstr) |
|
259 |
+ { |
|
260 |
+ int proto = 0; |
|
261 |
+ int r = sscanf(optstr, "IV_PROTO=%d", &proto); |
|
262 |
+ if ((r == 1) && (proto >= 2)) |
|
263 |
+ { |
|
264 |
+ push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id); |
|
265 |
+ } |
|
266 |
+ } |
|
267 |
+ |
|
268 |
+ /* Push cipher if client supports Negotiable Crypto Parameters */ |
|
269 |
+ optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL; |
|
270 |
+ if (optstr) |
|
271 |
+ { |
|
272 |
+ int ncp = 0; |
|
273 |
+ int r = sscanf(optstr, "IV_NCP=%d", &ncp); |
|
274 |
+ if ((r == 1) && (ncp == 2)) |
|
275 |
+ { |
|
276 |
+ push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); |
|
277 |
+ } |
|
278 |
+ } |
|
279 |
+ return true; |
|
280 |
+} |
|
281 |
+ |
|
282 |
+static bool |
|
243 | 283 |
send_push_reply (struct context *c) |
244 | 284 |
{ |
245 | 285 |
struct gc_arena gc = gc_new (); |
... | ... |
@@ -309,19 +373,6 @@ send_push_reply (struct context *c) |
309 | 309 |
if (multi_push) |
310 | 310 |
buf_printf (&buf, ",push-continuation 1"); |
311 | 311 |
|
312 |
- /* Send peer-id if client supports it */ |
|
313 |
- if (c->c2.tls_multi->peer_info) |
|
314 |
- { |
|
315 |
- const char* proto_str = strstr(c->c2.tls_multi->peer_info, "IV_PROTO="); |
|
316 |
- if (proto_str) |
|
317 |
- { |
|
318 |
- int proto = 0; |
|
319 |
- int r = sscanf(proto_str, "IV_PROTO=%d", &proto); |
|
320 |
- if ((r == 1) && (proto >= 2)) |
|
321 |
- buf_printf(&buf, ",peer-id %d", c->c2.tls_multi->peer_id); |
|
322 |
- } |
|
323 |
- } |
|
324 |
- |
|
325 | 312 |
if (BLEN (&buf) > sizeof(cmd)-1) |
326 | 313 |
{ |
327 | 314 |
const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); |
... | ... |
@@ -409,6 +460,21 @@ push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc) |
409 | 409 |
push_option (o, opt, msglevel); |
410 | 410 |
} |
411 | 411 |
|
412 |
+static bool push_option_fmt(struct options *o, int msglevel, |
|
413 |
+ const char *format, ...) |
|
414 |
+{ |
|
415 |
+ va_list arglist; |
|
416 |
+ char tmp[256] = {0}; |
|
417 |
+ int len = -1; |
|
418 |
+ va_start (arglist, format); |
|
419 |
+ len = vsnprintf (tmp, sizeof(tmp), format, arglist); |
|
420 |
+ va_end (arglist); |
|
421 |
+ if (len > sizeof(tmp)-1) |
|
422 |
+ return false; |
|
423 |
+ push_option (o, string_alloc (tmp, &o->gc), msglevel); |
|
424 |
+ return true; |
|
425 |
+} |
|
426 |
+ |
|
412 | 427 |
void |
413 | 428 |
push_reset (struct options *o) |
414 | 429 |
{ |
... | ... |
@@ -442,7 +508,8 @@ process_incoming_push_request (struct context *c) |
442 | 442 |
} |
443 | 443 |
else |
444 | 444 |
{ |
445 |
- if (send_push_reply (c)) |
|
445 |
+ if (prepare_push_reply(&c->options, c->c2.tls_multi) && |
|
446 |
+ send_push_reply (c)) |
|
446 | 447 |
{ |
447 | 448 |
ret = PUSH_MSG_REQUEST; |
448 | 449 |
c->c2.sent_push_reply_expiry = now + 30; |
... | ... |
@@ -62,8 +62,6 @@ void push_options (struct options *o, char **p, int msglevel, struct gc_arena *g |
62 | 62 |
|
63 | 63 |
void push_reset (struct options *o); |
64 | 64 |
|
65 |
-bool send_push_reply (struct context *c); |
|
66 |
- |
|
67 | 65 |
void remove_iroutes_from_push_route_list (struct options *o); |
68 | 66 |
|
69 | 67 |
void send_auth_failed (struct context *c, const char *client_reason); |