/
dtls.c
661 lines (555 loc) · 17.5 KB
1
/*
2
* OpenConnect (SSL + DTLS) VPN client
3
*
4
* Copyright © 2008-2015 Intel Corporation.
5
*
6
7
8
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public License
10
* version 2.1, as published by the Free Software Foundation.
11
*
12
* This program is distributed in the hope that it will be useful, but
13
14
15
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
16
17
*/
18
19
#include <config.h>
20
21
#include "openconnect-internal.h"
22
#include <unistd.h>
23
#include <sys/types.h>
24
#include <fcntl.h>
25
26
27
28
#ifndef _WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#endif
29
30
31
32
33
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
34
35
36
37
38
39
40
/*
* The master-secret is generated randomly by the client. The server
* responds with a DTLS Session-ID. These, done over the HTTPS
* connection, are enough to 'resume' a DTLS session, bypassing all
* the normal setup of a normal DTLS connection.
*
41
42
43
44
* Cisco use a version of the protocol which predates RFC4347, but
* isn't quite the same as the pre-RFC version of the protocol which
* was in OpenSSL 0.9.8e -- it includes backports of some later
* OpenSSL patches.
45
*
46
47
* The openssl/ directory of this source tree should contain both a
* small patch against OpenSSL 0.9.8e to make it support Cisco's
48
49
* snapshot of the protocol, and a larger patch against newer OpenSSL
* which gives us an option to use the old protocol again.
50
*
51
52
53
54
55
56
* Cisco's server also seems to respond to the official version of the
* protocol, with a change in the ChangeCipherSpec packet which implies
* that it does know the difference and isn't just repeating the version
* number seen in the ClientHello. But although I can make the handshake
* complete by hacking tls1_mac() to use the _old_ protocol version
* number when calculating the MAC, the server still seems to be ignoring
57
58
* my subsequent data packets. So we use the old protocol, which is what
* their clients use anyway.
59
*/
60
61
62
char *openconnect_bin2hex(const char *prefix, const uint8_t *data, unsigned len)
{
63
64
struct oc_text_buf *buf;
char *p = NULL;
65
66
buf = buf_alloc();
67
68
if (prefix)
buf_append(buf, "%s", prefix);
69
70
71
72
73
buf_append_hex(buf, data, len);
if (!buf_error(buf)) {
p = buf->data;
buf->data = NULL;
74
}
75
76
77
buf_free(buf);
return p;
78
79
}
80
81
82
83
84
85
86
87
char *openconnect_bin2base64(const char *prefix, const uint8_t *data, unsigned len)
{
struct oc_text_buf *buf;
char *p = NULL;
buf = buf_alloc();
if (prefix)
buf_append(buf, "%s", prefix);
88
buf_append_base64(buf, data, len, 0);
89
90
91
92
93
94
95
96
97
98
if (!buf_error(buf)) {
p = buf->data;
buf->data = NULL;
}
buf_free(buf);
return p;
}
99
static int connect_dtls_socket(struct openconnect_info *vpninfo, int *timeout)
100
{
101
int dtls_fd, ret;
102
103
104
105
106
107
108
109
/* Sanity check for the removal of new_dtls_{fd,ssl} */
if (vpninfo->dtls_fd != -1) {
vpn_progress(vpninfo, PRG_ERR, _("DTLS connection attempted with an existing fd\n"));
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
110
111
112
113
114
115
if (!vpninfo->dtls_addr) {
vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
116
if (vpninfo->proto->proto == PROTO_ANYCONNECT && !vpninfo->dtls_cipher) {
117
118
119
120
121
122
123
124
125
126
127
128
129
/* We probably didn't offer it any ciphers it liked */
vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
if (vpninfo->proxy) {
/* XXX: Theoretically, SOCKS5 proxies can do UDP too */
vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
vpninfo->dtls_attempt_period = 0;
return -EINVAL;
}
130
131
dtls_fd = udp_connect(vpninfo);
if (dtls_fd < 0)
132
133
134
135
136
return -EINVAL;
ret = start_dtls_handshake(vpninfo, dtls_fd);
if (ret) {
137
closesocket(dtls_fd);
138
139
140
return ret;
}
141
142
vpninfo->dtls_state = DTLS_CONNECTING;
143
vpninfo->dtls_fd = dtls_fd;
144
145
146
monitor_fd_new(vpninfo, dtls);
monitor_read_fd(vpninfo, dtls);
monitor_except_fd(vpninfo, dtls);
147
148
149
time(&vpninfo->new_dtls_started);
150
return dtls_try_handshake(vpninfo, timeout);
151
152
}
153
void dtls_close(struct openconnect_info *vpninfo)
154
155
{
if (vpninfo->dtls_ssl) {
156
dtls_ssl_free(vpninfo);
157
unmonitor_fd(vpninfo, dtls);
158
closesocket(vpninfo->dtls_fd);
159
160
161
vpninfo->dtls_ssl = NULL;
vpninfo->dtls_fd = -1;
}
162
vpninfo->dtls_state = DTLS_SLEEPING;
163
}
164
165
int dtls_reconnect(struct openconnect_info *vpninfo, int *timeout)
166
{
167
dtls_close(vpninfo);
168
169
170
171
if (vpninfo->dtls_state == DTLS_DISABLED)
return -EINVAL;
172
vpninfo->dtls_state = DTLS_SLEEPING;
173
return connect_dtls_socket(vpninfo, timeout);
174
175
}
176
int dtls_setup(struct openconnect_info *vpninfo)
177
{
178
179
if (vpninfo->dtls_state == DTLS_DISABLED ||
vpninfo->dtls_state == DTLS_NOSECRET)
180
181
return -EINVAL;
182
if (!vpninfo->dtls_attempt_period)
183
184
return 0;
185
if (!vpninfo->dtls_addr) {
186
vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
187
vpninfo->dtls_attempt_period = 0;
188
return -EINVAL;
189
}
190
191
if (vpninfo->dtls_times.rekey <= 0)
vpninfo->dtls_times.rekey_method = REKEY_NONE;
192
193
if (connect_dtls_socket(vpninfo, NULL))
194
return -EINVAL;
195
196
vpn_progress(vpninfo, PRG_DEBUG,
197
_("DTLS initialised. DPD %d, Keepalive %d\n"),
198
vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
199
200
return 0;
201
202
}
203
204
205
206
207
208
int udp_tos_update(struct openconnect_info *vpninfo, struct pkt *pkt)
{
int tos;
/* Extract TOS field from IP header (IPv4 and IPv6 differ) */
switch(pkt->data[0] >> 4) {
209
210
211
212
213
214
215
216
217
218
219
case 4:
tos = pkt->data[1];
break;
case 6:
tos = (load_be16(pkt->data) >> 4) & 0xff;
break;
default:
vpn_progress(vpninfo, PRG_ERR,
_("Unknown packet (len %d) received: %02x %02x %02x %02x...\n"),
pkt->len, pkt->data[0], pkt->data[1], pkt->data[2], pkt->data[3]);
return -EINVAL;
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
}
/* set the actual value */
if (tos != vpninfo->dtls_tos_current) {
vpn_progress(vpninfo, PRG_DEBUG, _("TOS this: %d, TOS last: %d\n"),
tos, vpninfo->dtls_tos_current);
if (setsockopt(vpninfo->dtls_fd, vpninfo->dtls_tos_proto,
vpninfo->dtls_tos_optname, (void *)&tos, sizeof(tos)))
vpn_perror(vpninfo, _("UDP setsockopt"));
else
vpninfo->dtls_tos_current = tos;
}
return 0;
}
235
int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
236
{
237
int work_done = 0;
238
char magic_pkt;
239
240
241
if (vpninfo->dtls_need_reconnect) {
vpninfo->dtls_need_reconnect = 0;
242
dtls_reconnect(vpninfo, timeout);
243
244
245
return 1;
}
246
if (vpninfo->dtls_state == DTLS_CONNECTING) {
247
dtls_try_handshake(vpninfo, timeout);
248
249
250
251
252
if (vpninfo->dtls_state != DTLS_CONNECTED) {
vpninfo->delay_tunnel_reason = "DTLS MTU detection";
return 0;
}
return 1;
253
}
254
255
256
257
258
if (vpninfo->dtls_state == DTLS_SLEEPING) {
int when = vpninfo->new_dtls_started + vpninfo->dtls_attempt_period - time(NULL);
if (when <= 0) {
259
vpn_progress(vpninfo, PRG_DEBUG, _("Attempt new DTLS connection\n"));
260
if (connect_dtls_socket(vpninfo, timeout) < 0)
261
*timeout = 1000;
262
263
264
} else if ((when * 1000) < *timeout) {
*timeout = when * 1000;
}
265
return 0;
266
}
267
268
269
270
271
/* Nothing to do here for Cisco DTLS as it is preauthenticated */
if (vpninfo->dtls_state == DTLS_CONNECTED)
vpninfo->dtls_state = DTLS_ESTABLISHED;
272
while (readable) {
273
int len = MAX(16384, vpninfo->ip_info.mtu);
274
275
unsigned char *buf;
276
277
278
279
if (vpninfo->incoming_queue.count >= vpninfo->max_qlen) {
work_done = 1;
break;
}
280
if (!vpninfo->dtls_pkt) {
281
vpninfo->dtls_pkt = alloc_pkt(vpninfo, len);
282
if (!vpninfo->dtls_pkt) {
283
vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
284
285
286
287
break;
}
}
288
buf = vpninfo->dtls_pkt->data - 1;
289
len = ssl_nonblock_read(vpninfo, 1, buf, len + 1);
290
291
if (len <= 0)
break;
292
293
vpn_progress(vpninfo, PRG_TRACE,
294
295
_("Received DTLS packet 0x%02x of %d bytes\n"),
buf[0], len);
296
297
vpninfo->dtls_times.last_rx = time(NULL);
298
299
switch (buf[0]) {
300
case AC_PKT_DATA:
301
302
303
vpninfo->dtls_pkt->len = len - 1;
queue_packet(&vpninfo->incoming_queue, vpninfo->dtls_pkt);
vpninfo->dtls_pkt = NULL;
304
305
306
work_done = 1;
break;
307
case AC_PKT_DPD_OUT:
308
vpn_progress(vpninfo, PRG_DEBUG, _("Got DTLS DPD request\n"));
309
310
311
/* FIXME: What if the packet doesn't get through? */
magic_pkt = AC_PKT_DPD_RESP;
312
if (ssl_nonblock_write(vpninfo, 1, &magic_pkt, 1) != 1)
313
314
vpn_progress(vpninfo, PRG_ERR,
_("Failed to send DPD response. Expect disconnect\n"));
315
316
continue;
317
case AC_PKT_DPD_RESP:
318
vpn_progress(vpninfo, PRG_DEBUG, _("Got DTLS DPD response\n"));
319
320
break;
321
case AC_PKT_KEEPALIVE:
322
vpn_progress(vpninfo, PRG_DEBUG, _("Got DTLS Keepalive\n"));
323
324
break;
325
326
327
328
329
330
case AC_PKT_COMPRESSED:
if (!vpninfo->dtls_compr) {
vpn_progress(vpninfo, PRG_ERR,
_("Compressed DTLS packet received when compression not enabled\n"));
goto unknown_pkt;
}
331
332
decompress_and_queue_packet(vpninfo, vpninfo->dtls_compr,
vpninfo->dtls_pkt->data, len - 1);
333
break;
334
default:
335
vpn_progress(vpninfo, PRG_ERR,
336
337
_("Unknown DTLS packet type %02x, len %d\n"),
buf[0], len);
338
339
if (1) {
/* Some versions of OpenSSL have bugs with receiving out-of-order
340
* packets. Not only do they wrongly decide to drop packets if
341
342
343
344
345
* two packets get swapped in transit, but they also _fail_ to
* drop the packet in non-blocking mode; instead they return
* the appropriate length of garbage. So don't abort... for now. */
break;
} else {
346
unknown_pkt:
347
348
349
350
vpninfo->quit_reason = "Unknown packet received";
return 1;
}
351
}
352
}
353
354
switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
355
356
357
case KA_REKEY: {
int ret;
358
vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
359
360
361
362
if (vpninfo->dtls_times.rekey_method == REKEY_SSL) {
time(&vpninfo->new_dtls_started);
vpninfo->dtls_state = DTLS_CONNECTING;
363
ret = dtls_try_handshake(vpninfo, timeout);
364
if (ret) {
365
vpn_progress(vpninfo, PRG_ERR, _("DTLS Rehandshake failed; reconnecting.\n"));
366
return connect_dtls_socket(vpninfo, timeout);
367
}
368
369
}
370
return 1;
371
}
372
373
case KA_DPD_DEAD:
374
vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
375
/* Fall back to SSL, and start a new DTLS connection */
376
dtls_reconnect(vpninfo, timeout);
377
return 1;
378
379
case KA_DPD:
380
vpn_progress(vpninfo, PRG_DEBUG, _("Send DTLS DPD\n"));
381
382
magic_pkt = AC_PKT_DPD_OUT;
383
if (ssl_nonblock_write(vpninfo, 1, &magic_pkt, 1) != 1)
384
385
386
vpn_progress(vpninfo, PRG_ERR,
_("Failed to send DPD request. Expect disconnect\n"));
387
388
389
390
/* last_dpd will just have been set */
vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
work_done = 1;
break;
391
392
393
394
case KA_KEEPALIVE:
/* No need to send an explicit keepalive
if we have real data to send */
395
if (vpninfo->outgoing_queue.head)
396
break;
397
398
vpn_progress(vpninfo, PRG_DEBUG, _("Send DTLS Keepalive\n"));
399
400
magic_pkt = AC_PKT_KEEPALIVE;
401
if (ssl_nonblock_write(vpninfo, 1, &magic_pkt, 1) != 1)
402
403
vpn_progress(vpninfo, PRG_ERR,
_("Failed to send keepalive request. Expect disconnect\n"));
404
405
406
time(&vpninfo->dtls_times.last_tx);
work_done = 1;
break;
407
408
409
case KA_NONE:
;
410
411
}
412
/* Service outgoing packet queue */
413
unmonitor_write_fd(vpninfo, dtls);
414
415
while (vpninfo->outgoing_queue.head) {
struct pkt *this = dequeue_packet(&vpninfo->outgoing_queue);
416
struct pkt *send_pkt = this;
417
int ret;
418
419
420
/* If TOS optname is set, we want to copy the TOS/TCLASS header
to the outer UDP packet */
421
422
if (vpninfo->dtls_tos_optname)
udp_tos_update(vpninfo, this);
423
424
/* One byte of header */
425
this->cstp.hdr[7] = AC_PKT_DATA;
426
427
428
429
430
431
432
/* We can compress into vpninfo->deflate_pkt unless CSTP
* currently has a compressed packet pending — which it
* shouldn't if DTLS is active. */
if (vpninfo->dtls_compr &&
vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
!compress_packet(vpninfo, vpninfo->dtls_compr, this)) {
433
send_pkt = vpninfo->deflate_pkt;
434
send_pkt->cstp.hdr[7] = AC_PKT_COMPRESSED;
435
436
}
437
ret = ssl_nonblock_write(vpninfo, 1, &send_pkt->cstp.hdr[7], send_pkt->len + 1);
438
if (ret <= 0) {
439
440
441
442
443
444
/* Zero is -EAGAIN; just requeue. dtls_nonblock_write()
* will have added the socket to the poll wfd list. */
requeue_packet(&vpninfo->outgoing_queue, this);
if (ret < 0) {
/* If it's a real error, kill the DTLS connection so
the requeued packet will be sent over SSL */
445
dtls_reconnect(vpninfo, timeout);
446
work_done = 1;
447
}
448
return work_done;
449
}
450
time(&vpninfo->dtls_times.last_tx);
451
vpn_progress(vpninfo, PRG_TRACE,
452
_("Sent DTLS packet of %d bytes; DTLS send returned %d\n"),
453
this->len, ret);
454
free_pkt(vpninfo, this);
455
}
456
457
return work_done;
458
}
459
460
461
462
463
464
465
466
/* This symbol is missing in glibc < 2.22 (bug 18643). */
#if defined(__linux__) && !defined(HAVE_IPV6_PATHMTU)
# define HAVE_IPV6_PATHMTU 1
# define IPV6_PATHMTU 61
#endif
#define PKT_INTERVAL_MS 50
467
468
469
470
471
472
/* Performs a binary search to detect MTU.
* @buf: is preallocated with MTU size
*
* Returns: new MTU or 0
*/
473
static int probe_mtu(struct openconnect_info *vpninfo, unsigned char *buf)
474
{
475
int max, min, cur, ret, absolute_min, last;
476
int tries = 0; /* Number of loops in bin search - includes resends */
477
478
uint32_t id, id_len;
struct timeval start_tv, now_tv, last_tv;
479
480
481
482
absolute_min = 576;
if (vpninfo->ip_info.addr6)
absolute_min = 1280;
483
484
485
486
/* We'll assume that it is at least functional, and permits the bare
* minimum MTU for the protocol(s) it transports. All else is mad. */
min = absolute_min;
487
488
489
490
/* First send a probe at the configured maximum. Most of the time, this
one will probably work. */
last = cur = max = vpninfo->ip_info.mtu;
491
492
493
if (max <= min)
goto fail;
494
495
496
497
/* Generate unique ID */
if (openconnect_random(&id, sizeof(id)) < 0)
goto fail;
498
499
500
vpn_progress(vpninfo, PRG_DEBUG,
_("Initiating MTU detection (min=%d, max=%d)\n"), min, max);
501
502
503
gettimeofday(&start_tv, NULL);
last_tv = start_tv;
504
505
506
while (1) {
int wait_ms;
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
#ifdef HAVE_IPV6_PATHMTU
if (vpninfo->peer_addr->sa_family == AF_INET6) {
struct ip6_mtuinfo mtuinfo;
socklen_t len = sizeof(mtuinfo);
int newmax;
if (getsockopt(vpninfo->dtls_fd, IPPROTO_IPV6, IPV6_PATHMTU, &mtuinfo, &len) >= 0) {
newmax = mtuinfo.ip6m_mtu;
if (newmax > 0) {
newmax = dtls_set_mtu(vpninfo, newmax) - /*ipv6*/40 - /*udp*/20 - /*oc dtls*/1;
if (absolute_min > newmax)
goto fail;
if (max > newmax)
max = newmax;
if (cur > newmax)
cur = newmax;
}
525
}
526
}
527
528
#endif
529
buf[0] = AC_PKT_DPD_OUT;
530
531
id_len = id + cur;
memcpy(&buf[1], &id_len, sizeof(id_len));
532
533
vpn_progress(vpninfo, PRG_TRACE,
534
535
536
_("Sending MTU DPD probe (%u bytes)\n"), cur);
ret = openconnect_dtls_write(vpninfo, buf, cur + 1);
if (ret != cur + 1) {
537
vpn_progress(vpninfo, PRG_ERR,
538
539
540
541
542
543
544
545
546
547
548
549
550
_("Failed to send DPD request (%d %d)\n"), cur, ret);
if (cur == max) {
max = --cur;
if (cur >= absolute_min)
continue;
}
goto fail;
}
if (last == cur)
tries++;
else {
tries = 0;
last = cur;
551
552
553
}
memset(buf, 0, sizeof(id)+1);
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
keep_waiting:
gettimeofday(&now_tv, NULL);
if (now_tv.tv_sec > start_tv.tv_sec + 10) {
if (absolute_min == min) {
/* Hm, we never got *anything* back successfully? */
vpn_progress(vpninfo, PRG_ERR,
_("Too long time in MTU detect loop; assuming negotiated MTU.\n"));
goto fail;
} else {
vpn_progress(vpninfo, PRG_ERR,
_("Too long time in MTU detect loop; MTU set to %d.\n"), min);
ret = min;
goto out;
}
569
}
570
571
572
573
574
wait_ms = PKT_INTERVAL_MS -
((now_tv.tv_sec - last_tv.tv_sec) * 1000) -
((now_tv.tv_usec - last_tv.tv_usec) / 1000);
575
if (wait_ms <= 0 || wait_ms > PKT_INTERVAL_MS)
576
577
578
579
580
wait_ms = PKT_INTERVAL_MS;
ret = openconnect_dtls_read(vpninfo, buf, max+1, wait_ms);
if (ret > 0 && (buf[0] != AC_PKT_DPD_RESP || !memcpy(&id_len, &buf[1], sizeof(id_len)) ||
id_len != id + ret - 1)) {
581
vpn_progress(vpninfo, PRG_DEBUG,
582
583
_("Received unexpected packet (%.2x) in MTU detection; skipping.\n"), (unsigned)buf[0]);
goto keep_waiting;
584
585
}
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
if (ret == -ETIMEDOUT) {
if (tries >= 6) {
vpn_progress(vpninfo, PRG_DEBUG,
_("No response to size %u after %d tries; declare MTU is %u\n"),
last, tries, min);
ret = min;
goto out;
}
} else if (ret < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to recv DPD request (%d)\n"), ret);
goto fail;
} else if (ret > 0) {
vpn_progress(vpninfo, PRG_TRACE,
_("Received MTU DPD probe (%u bytes)\n"), ret - 1);
ret--;
tries = 0;
}
604
605
606
if (ret == max)
goto out;
607
608
609
610
611
612
613
if (ret > min) {
min = ret;
if (min >= last) {
cur = (min + max + 1) / 2;
} else {
cur = (min + last + 1) / 2;
614
}
615
616
} else {
cur = (min + last + 1) / 2;
617
618
619
}
}
fail:
620
621
622
ret = 0;
out:
return ret;
623
}
624
625
626
627
void dtls_detect_mtu(struct openconnect_info *vpninfo)
628
{
629
int mtu;
630
631
632
int prev_mtu = vpninfo->ip_info.mtu;
unsigned char *buf;
633
634
635
if (vpninfo->proto->proto != PROTO_ANYCONNECT)
return;
636
if (vpninfo->ip_info.mtu < 1 + sizeof(uint32_t))
637
638
639
640
641
642
643
644
645
return;
/* detect MTU */
buf = calloc(1, 1 + vpninfo->ip_info.mtu);
if (!buf) {
vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
return;
}
646
647
648
mtu = probe_mtu(vpninfo, buf);
if (mtu == 0)
goto skip_mtu;
649
650
651
652
653
654
655
656
657
658
659
660
661
vpninfo->ip_info.mtu = mtu;
if (prev_mtu != vpninfo->ip_info.mtu) {
vpn_progress(vpninfo, PRG_INFO,
_("Detected MTU of %d bytes (was %d)\n"), vpninfo->ip_info.mtu, prev_mtu);
} else {
vpn_progress(vpninfo, PRG_DEBUG,
_("No change in MTU after detection (was %d)\n"), prev_mtu);
}
skip_mtu:
free(buf);
}