2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2012 Intel Corporation.
6 * Author: David Woodhouse <dwmw2@infradead.org>
8 * 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.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
26 #include <sys/types.h>
27 #include <sys/socket.h>
30 #include <netinet/in.h>
34 #include "openconnect-internal.h"
36 #ifdef HAVE_DTLS1_STOP_TIMER
37 /* OpenSSL doesn't deliberately export this, but we need it to
38 workaround a DTLS bug in versions < 1.0.0e */
39 extern void dtls1_stop_timer (SSL *);
42 static unsigned char nybble(unsigned char n)
44 if (n >= '0' && n <= '9') return n - '0';
45 else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
46 else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
50 unsigned char unhex(const char *data)
52 return (nybble(data[0]) << 4) | nybble(data[1]);
59 * Useful for catching test cases, where we want everything to be
60 * reproducible. *NEVER* do this in the wild.
62 time_t time(time_t *t)
64 time_t x = 0x3ab2d948;
69 int RAND_pseudo_bytes(char *buf, int len)
71 memset(buf, 0x5a, len);
72 printf("FAKE PSEUDO RANDOM!\n");
76 int RAND_bytes(char *buf, int len)
78 static int foo = 0x5b;
79 printf("FAKE RANDOM!\n");
80 memset(buf, foo, len);
86 * The master-secret is generated randomly by the client. The server
87 * responds with a DTLS Session-ID. These, done over the HTTPS
88 * connection, are enough to 'resume' a DTLS session, bypassing all
89 * the normal setup of a normal DTLS connection.
91 * Cisco use a version of the protocol which predates RFC4347, but
92 * isn't quite the same as the pre-RFC version of the protocol which
93 * was in OpenSSL 0.9.8e -- it includes backports of some later
96 * The openssl/ directory of this source tree should contain both a
97 * small patch against OpenSSL 0.9.8e to make it support Cisco's
98 * snapshot of the protocol, and a larger patch against newer OpenSSL
99 * which gives us an option to use the old protocol again.
101 * Cisco's server also seems to respond to the official version of the
102 * protocol, with a change in the ChangeCipherSpec packet which implies
103 * that it does know the difference and isn't just repeating the version
104 * number seen in the ClientHello. But although I can make the handshake
105 * complete by hacking tls1_mac() to use the _old_ protocol version
106 * number when calculating the MAC, the server still seems to be ignoring
107 * my subsequent data packets. So we use the old protocol, which is what
108 * their clients use anyway.
111 #if defined (OPENCONNECT_OPENSSL)
112 #define DTLS_SEND SSL_write
113 #define DTLS_RECV SSL_read
114 static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
116 STACK_OF(SSL_CIPHER) *ciphers;
117 method_const SSL_METHOD *dtls_method;
118 SSL_CIPHER *dtls_cipher;
122 if (!vpninfo->dtls_ctx) {
123 dtls_method = DTLSv1_client_method();
124 vpninfo->dtls_ctx = SSL_CTX_new(dtls_method);
125 if (!vpninfo->dtls_ctx) {
126 vpn_progress(vpninfo, PRG_ERR,
127 _("Initialise DTLSv1 CTX failed\n"));
128 vpninfo->dtls_attempt_period = 0;
132 /* If we don't readahead, then we do short reads and throw
133 away the tail of data packets. */
134 SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1);
136 if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) {
137 vpn_progress(vpninfo, PRG_ERR,
138 _("Set DTLS cipher list failed\n"));
139 SSL_CTX_free(vpninfo->dtls_ctx);
140 vpninfo->dtls_ctx = NULL;
141 vpninfo->dtls_attempt_period = 0;
146 if (!vpninfo->dtls_session) {
147 /* We're going to "resume" a session which never existed. Fake it... */
148 vpninfo->dtls_session = SSL_SESSION_new();
149 if (!vpninfo->dtls_session) {
150 vpn_progress(vpninfo, PRG_ERR,
151 _("Initialise DTLSv1 session failed\n"));
152 vpninfo->dtls_attempt_period = 0;
155 vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */
158 /* Do this every time; it may have changed due to a rekey */
159 vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
160 memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
161 sizeof(vpninfo->dtls_secret));
163 vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
164 memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
165 sizeof(vpninfo->dtls_session_id));
167 dtls_ssl = SSL_new(vpninfo->dtls_ctx);
168 SSL_set_connect_state(dtls_ssl);
170 ciphers = SSL_get_ciphers(dtls_ssl);
171 if (sk_SSL_CIPHER_num(ciphers) != 1) {
172 vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n"));
173 SSL_CTX_free(vpninfo->dtls_ctx);
175 SSL_SESSION_free(vpninfo->dtls_session);
176 vpninfo->dtls_ctx = NULL;
177 vpninfo->dtls_session = NULL;
178 vpninfo->dtls_attempt_period = 0;
181 dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0);
183 /* Set the appropriate cipher on our session to be resumed */
184 vpninfo->dtls_session->cipher = dtls_cipher;
185 vpninfo->dtls_session->cipher_id = dtls_cipher->id;
187 /* Add the generated session to the SSL */
188 if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
189 vpn_progress(vpninfo, PRG_ERR,
190 _("SSL_set_session() failed with old protocol version 0x%x\n"
191 "Are you using a version of OpenSSL older than 0.9.8m?\n"
192 "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
193 "Use the --no-dtls command line option to avoid this message\n"),
194 vpninfo->dtls_session->ssl_version);
195 vpninfo->dtls_attempt_period = 0;
199 dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
200 /* Set non-blocking */
201 BIO_set_nbio(dtls_bio, 1);
202 SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
204 SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
206 vpninfo->new_dtls_ssl = dtls_ssl;
211 int dtls_try_handshake(struct openconnect_info *vpninfo)
213 int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
216 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
218 if (vpninfo->dtls_ssl) {
219 /* We are replacing an old connection */
220 SSL_free(vpninfo->dtls_ssl);
221 close(vpninfo->dtls_fd);
222 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
223 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
224 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
226 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
227 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
229 vpninfo->new_dtls_ssl = NULL;
230 vpninfo->new_dtls_fd = -1;
232 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
234 /* From about 8.4.1(11) onwards, the ASA seems to get
235 very unhappy if we resend ChangeCipherSpec messages
236 after the initial setup. This was "fixed" in OpenSSL
237 1.0.0e for RT#2505, but it's not clear if that was
238 the right fix. What happens if the original packet
239 *does* get lost? Surely we *wanted* the retransmits,
240 because without them the server will never be able
241 to decrypt anything we send?
242 Oh well, our retransmitted packets upset the server
243 because we don't get the Cisco-compatibility right
244 (this is one of the areas in which Cisco's DTLS differs
245 from the RFC4347 spec), and DPD should help us notice
246 if *nothing* is getting through. */
247 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
248 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
249 However, if we were *built* against 1.0.0e or newer, but at
250 runtime we find that we are being run against an older
251 version, warn about it. */
252 if (SSLeay() < 0x1000005fL) {
253 vpn_progress(vpninfo, PRG_ERR,
254 _("Your OpenSSL is older than the one you built against, so DTLS may fail!"));
256 #elif defined (HAVE_DTLS1_STOP_TIMER)
258 * This works for any normal OpenSSL that supports
259 * Cisco DTLS compatibility (0.9.8m to 1.0.0d inclusive,
260 * and even later versions although it isn't needed there.
262 dtls1_stop_timer(vpninfo->dtls_ssl);
263 #elif defined (BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT)
265 * Debian restricts visibility of dtls1_stop_timer()
266 * so do it manually. This version also works on all
267 * sane versions of OpenSSL:
269 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
270 sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
271 vpninfo->dtls_ssl->d1->timeout_duration = 1;
272 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
273 BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
274 &(vpninfo->dtls_ssl->d1->next_timeout));
275 #elif defined (BIO_CTRL_DGRAM_SET_TIMEOUT)
277 * OK, here it gets more fun... this shoul handle the case
278 * of older OpenSSL which has the Cisco DTLS compatibility
279 * backported, but *not* the fix for RT#1922.
281 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
282 BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
285 * And if they don't have any of the above, they probably
286 * don't have RT#1829 fixed either, but that's OK because
287 * that's the "fix" that *introduces* the timeout we're
288 * trying to disable. So do nothing...
294 ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
295 if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
296 if (time(NULL) < vpninfo->new_dtls_started + 5)
298 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
301 vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
302 openconnect_report_ssl_errors(vpninfo);
304 /* Kill the new (failed) connection... */
305 SSL_free(vpninfo->new_dtls_ssl);
306 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
307 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
308 close(vpninfo->new_dtls_fd);
309 vpninfo->new_dtls_ssl = NULL;
310 vpninfo->new_dtls_fd = -1;
312 /* ... and kill the old one too. The only time there'll be a valid
313 existing session is when it was a rekey, and in that case it's
314 time for the old one to die. */
315 if (vpninfo->dtls_ssl) {
316 SSL_free(vpninfo->dtls_ssl);
317 close(vpninfo->dtls_fd);
318 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
319 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
320 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
321 vpninfo->dtls_ssl = NULL;
322 vpninfo->dtls_fd = -1;
325 time(&vpninfo->new_dtls_started);
329 #elif defined (OPENCONNECT_GNUTLS)
332 gnutls_cipher_algorithm_t cipher;
333 gnutls_mac_algorithm_t mac;
335 } gnutls_dtls_ciphers[] = {
336 { "AES128-SHA", GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA1,
337 "NONE:+VERS-DTLS0.9:+COMP-NULL:+AES-128-CBC:+SHA1:+RSA:%COMPAT:%DISABLE_SAFE_RENEGOTIATION" },
338 { "DES-CBC3-SHA", GNUTLS_CIPHER_3DES_CBC, GNUTLS_MAC_SHA1,
339 "NONE:+VERS-DTLS0.9:+COMP-NULL:+3DES-CBC:+SHA1:+RSA:%COMPAT:%DISABLE_SAFE_RENEGOTIATION" },
342 #define DTLS_SEND gnutls_record_send
343 #define DTLS_RECV gnutls_record_recv
344 static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
346 gnutls_session_t dtls_ssl;
347 gnutls_datum_t master_secret, session_id;
351 for (cipher = 0; cipher < sizeof(gnutls_dtls_ciphers)/sizeof(gnutls_dtls_ciphers[0]); cipher++) {
352 if (!strcmp(vpninfo->dtls_cipher, gnutls_dtls_ciphers[cipher].name))
355 vpn_progress(vpninfo, PRG_ERR, _("Unknown DTLS parameters for requested CipherSuite '%s'\n"),
356 vpninfo->dtls_cipher);
357 vpninfo->dtls_attempt_period = 0;
362 gnutls_init(&dtls_ssl, GNUTLS_CLIENT|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK);
363 err = gnutls_priority_set_direct(dtls_ssl,
364 gnutls_dtls_ciphers[cipher].prio,
367 vpn_progress(vpninfo, PRG_ERR,
368 _("Failed to set DTLS priority: %s\n"),
369 gnutls_strerror(err));
370 gnutls_deinit(dtls_ssl);
371 vpninfo->dtls_attempt_period = 0;
374 gnutls_transport_set_ptr(dtls_ssl,
375 (gnutls_transport_ptr_t)(long) dtls_fd);
376 gnutls_record_disable_padding(dtls_ssl);
377 master_secret.data = vpninfo->dtls_secret;
378 master_secret.size = sizeof(vpninfo->dtls_secret);
379 session_id.data = vpninfo->dtls_session_id;
380 session_id.size = sizeof(vpninfo->dtls_session_id);
381 err = gnutls_session_set_premaster(dtls_ssl, GNUTLS_CLIENT, GNUTLS_DTLS0_9,
382 GNUTLS_KX_RSA, gnutls_dtls_ciphers[cipher].cipher,
383 gnutls_dtls_ciphers[cipher].mac, GNUTLS_COMP_NULL,
384 &master_secret, &session_id);
386 vpn_progress(vpninfo, PRG_ERR,
387 _("Failed to set DTLS session parameters: %s\n"),
388 gnutls_strerror(err));
389 gnutls_deinit(dtls_ssl);
390 vpninfo->dtls_attempt_period = 0;
394 vpninfo->new_dtls_ssl = dtls_ssl;
398 int dtls_try_handshake(struct openconnect_info *vpninfo)
400 int err = gnutls_handshake(vpninfo->new_dtls_ssl);
403 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
405 if (vpninfo->dtls_ssl) {
406 /* We are replacing an old connection */
407 gnutls_deinit(vpninfo->dtls_ssl);
408 close(vpninfo->dtls_fd);
409 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
410 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
411 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
413 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
414 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
416 vpninfo->new_dtls_ssl = NULL;
417 vpninfo->new_dtls_fd = -1;
419 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
421 /* XXX: For OpenSSL we explicitly prevent retransmits here. */
425 if (err == GNUTLS_E_AGAIN) {
426 if (time(NULL) < vpninfo->new_dtls_started + 5)
428 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
431 vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %s\n"),
432 gnutls_strerror(err));
434 /* Kill the new (failed) connection... */
435 gnutls_deinit(vpninfo->new_dtls_ssl);
436 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
437 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
438 close(vpninfo->new_dtls_fd);
439 vpninfo->new_dtls_ssl = NULL;
440 vpninfo->new_dtls_fd = -1;
442 /* ... and kill the old one too. The only time there'll be a valid
443 existing session is when it was a rekey, and in that case it's
444 time for the old one to die. */
445 if (vpninfo->dtls_ssl) {
446 gnutls_deinit(vpninfo->dtls_ssl);
447 close(vpninfo->dtls_fd);
448 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
449 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
450 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
451 vpninfo->dtls_ssl = NULL;
452 vpninfo->dtls_fd = -1;
455 time(&vpninfo->new_dtls_started);
460 int connect_dtls_socket(struct openconnect_info *vpninfo)
464 if (!vpninfo->dtls_addr) {
465 vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
466 vpninfo->dtls_attempt_period = 0;
470 if (!vpninfo->dtls_cipher) {
471 /* We probably didn't offer it any ciphers it liked */
472 vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
473 vpninfo->dtls_attempt_period = 0;
477 if (vpninfo->proxy) {
478 /* XXX: Theoretically, SOCKS5 proxies can do UDP too */
479 vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
480 vpninfo->dtls_attempt_period = 0;
484 dtls_fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
486 perror(_("Open UDP socket for DTLS:"));
490 if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
491 perror(_("UDP (DTLS) connect:\n"));
496 fcntl(dtls_fd, F_SETFD, FD_CLOEXEC);
497 fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
499 ret = start_dtls_handshake(vpninfo, dtls_fd);
505 vpninfo->new_dtls_fd = dtls_fd;
506 if (vpninfo->select_nfds <= dtls_fd)
507 vpninfo->select_nfds = dtls_fd + 1;
509 FD_SET(dtls_fd, &vpninfo->select_rfds);
510 FD_SET(dtls_fd, &vpninfo->select_efds);
512 time(&vpninfo->new_dtls_started);
514 return dtls_try_handshake(vpninfo);
517 static int dtls_restart(struct openconnect_info *vpninfo)
519 if (vpninfo->dtls_ssl) {
520 #if defined (OPENCONNECT_OPENSSL)
521 SSL_free(vpninfo->dtls_ssl);
522 #elif defined (OPENCONNECT_GNUTLS)
523 gnutls_deinit(vpninfo->dtls_ssl);
525 close(vpninfo->dtls_fd);
526 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
527 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
528 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
529 vpninfo->dtls_ssl = NULL;
530 vpninfo->dtls_fd = -1;
533 return connect_dtls_socket(vpninfo);
537 int setup_dtls(struct openconnect_info *vpninfo)
539 struct vpn_option *dtls_opt = vpninfo->dtls_options;
543 vpn_progress(vpninfo, PRG_TRACE,
544 _("DTLS option %s : %s\n"),
545 dtls_opt->option, dtls_opt->value);
547 if (!strcmp(dtls_opt->option + 7, "Port")) {
548 dtls_port = atol(dtls_opt->value);
549 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
550 vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
551 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
552 int j = atol(dtls_opt->value);
553 if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
554 vpninfo->dtls_times.dpd = j;
555 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
556 vpninfo->dtls_times.rekey = atol(dtls_opt->value);
557 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
558 vpninfo->dtls_cipher = strdup(dtls_opt->value);
561 dtls_opt = dtls_opt->next;
564 vpninfo->dtls_attempt_period = 0;
568 vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
569 if (!vpninfo->dtls_addr) {
570 vpninfo->dtls_attempt_period = 0;
573 memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
575 if (vpninfo->peer_addr->sa_family == AF_INET) {
576 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
577 sin->sin_port = htons(dtls_port);
578 } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
579 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
580 sin->sin6_port = htons(dtls_port);
582 vpn_progress(vpninfo, PRG_ERR,
583 _("Unknown protocol family %d. Cannot do DTLS\n"),
584 vpninfo->peer_addr->sa_family);
585 vpninfo->dtls_attempt_period = 0;
589 if (connect_dtls_socket(vpninfo))
592 vpn_progress(vpninfo, PRG_TRACE,
593 _("DTLS connected. DPD %d, Keepalive %d\n"),
594 vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
599 static struct pkt *dtls_pkt;
601 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
607 int len = vpninfo->mtu;
611 dtls_pkt = malloc(sizeof(struct pkt) + len);
613 vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
618 buf = dtls_pkt->data - 1;
619 len = DTLS_RECV(vpninfo->dtls_ssl, buf, len + 1);
623 vpn_progress(vpninfo, PRG_TRACE,
624 _("Received DTLS packet 0x%02x of %d bytes\n"),
627 vpninfo->dtls_times.last_rx = time(NULL);
631 dtls_pkt->len = len - 1;
632 queue_packet(&vpninfo->incoming_queue, dtls_pkt);
638 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
640 /* FIXME: What if the packet doesn't get through? */
641 magic_pkt = AC_PKT_DPD_RESP;
642 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
643 vpn_progress(vpninfo, PRG_ERR,
644 _("Failed to send DPD response. Expect disconnect\n"));
647 case AC_PKT_DPD_RESP:
648 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
651 case AC_PKT_KEEPALIVE:
652 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
656 vpn_progress(vpninfo, PRG_ERR,
657 _("Unknown DTLS packet type %02x, len %d\n"),
660 /* Some versions of OpenSSL have bugs with receiving out-of-order
661 * packets. Not only do they wrongly decide to drop packets if
662 * two packets get swapped in transit, but they also _fail_ to
663 * drop the packet in non-blocking mode; instead they return
664 * the appropriate length of garbage. So don't abort... for now. */
667 vpninfo->quit_reason = "Unknown packet received";
674 switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
676 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
678 /* There ought to be a method of rekeying DTLS without tearing down
679 the CSTP session and restarting, but we don't (yet) know it */
680 if (cstp_reconnect(vpninfo)) {
681 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
682 vpninfo->quit_reason = "CSTP reconnect failed";
686 if (dtls_restart(vpninfo)) {
687 vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
695 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
696 /* Fall back to SSL, and start a new DTLS connection */
697 dtls_restart(vpninfo);
701 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
703 magic_pkt = AC_PKT_DPD_OUT;
704 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
705 vpn_progress(vpninfo, PRG_ERR,
706 _("Failed to send DPD request. Expect disconnect\n"));
708 /* last_dpd will just have been set */
709 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
714 /* No need to send an explicit keepalive
715 if we have real data to send */
716 if (vpninfo->outgoing_queue)
719 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
721 magic_pkt = AC_PKT_KEEPALIVE;
722 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
723 vpn_progress(vpninfo, PRG_ERR,
724 _("Failed to send keepalive request. Expect disconnect\n"));
725 time(&vpninfo->dtls_times.last_tx);
733 /* Service outgoing packet queue */
734 while (vpninfo->outgoing_queue) {
735 struct pkt *this = vpninfo->outgoing_queue;
738 vpninfo->outgoing_queue = this->next;
739 vpninfo->outgoing_qlen--;
741 /* One byte of header */
742 this->hdr[7] = AC_PKT_DATA;
744 #if defined(OPENCONNECT_OPENSSL)
745 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
747 ret = SSL_get_error(vpninfo->dtls_ssl, ret);
749 /* If it's a real error, kill the DTLS connection and
750 requeue the packet to be sent over SSL */
751 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
752 vpn_progress(vpninfo, PRG_ERR,
753 _("DTLS got write error %d. Falling back to SSL\n"),
755 openconnect_report_ssl_errors(vpninfo);
756 dtls_restart(vpninfo);
757 vpninfo->outgoing_queue = this;
758 vpninfo->outgoing_qlen++;
762 #elif defined (OPENCONNECT_GNUTLS)
763 ret = gnutls_record_send(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
765 if (ret != GNUTLS_E_AGAIN) {
766 vpn_progress(vpninfo, PRG_ERR,
767 _("DTLS got write error: %s. Falling back to SSL\n"),
768 gnutls_strerror(ret));
769 dtls_restart(vpninfo);
770 vpninfo->outgoing_queue = this;
771 vpninfo->outgoing_qlen++;
776 time(&vpninfo->dtls_times.last_tx);
777 vpn_progress(vpninfo, PRG_TRACE,
778 _("Sent DTLS packet of %d bytes; DTLS send returned %d\n"),
785 #else /* !HAVE_DTLS */
786 #warning Your SSL library does not seem to support Cisco DTLS compatibility
787 int setup_dtls(struct openconnect_info *vpninfo)
789 vpn_progress(vpninfo, PRG_ERR,
790 _("Built against SSL library with no Cisco DTLS support\n"));