Add DTLS support for GnuTLS
[platform/upstream/openconnect.git] / dtls.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 Intel Corporation.
5  *
6  * Author: David Woodhouse <dwmw2@infradead.org>
7  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <unistd.h>
30 #include <netinet/in.h>
31 #include <openssl/err.h>
32 #include <openssl/ssl.h>
33 #include <fcntl.h>
34 #include <string.h>
35
36 #include "openconnect-internal.h"
37
38 #ifdef HAVE_DTLS1_STOP_TIMER
39 /* OpenSSL doesn't deliberately export this, but we need it to
40    workaround a DTLS bug in versions < 1.0.0e */
41 extern void dtls1_stop_timer (SSL *);
42 #endif
43
44 static unsigned char nybble(unsigned char n)
45 {
46         if      (n >= '0' && n <= '9') return n - '0';
47         else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
48         else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
49         return 0;
50 }
51
52 unsigned char unhex(const char *data)
53 {
54         return (nybble(data[0]) << 4) | nybble(data[1]);
55 }
56
57 #ifdef HAVE_DTLS
58
59 #if 0
60 /*
61  * Useful for catching test cases, where we want everything to be
62  * reproducible.  *NEVER* do this in the wild.
63  */
64 time_t time(time_t *t)
65 {
66         time_t x = 0x3ab2d948;
67         if (t) *t = x;
68         return x;
69 }
70
71 int RAND_pseudo_bytes(char *buf, int len)
72 {
73         memset(buf, 0x5a, len);
74         printf("FAKE PSEUDO RANDOM!\n");
75         return 1;
76
77 }
78 int RAND_bytes(char *buf, int len)
79 {
80         static int foo = 0x5b;
81         printf("FAKE RANDOM!\n");
82         memset(buf, foo, len);
83         return 1;
84 }
85 #endif
86
87 /*
88  * The master-secret is generated randomly by the client. The server
89  * responds with a DTLS Session-ID. These, done over the HTTPS
90  * connection, are enough to 'resume' a DTLS session, bypassing all
91  * the normal setup of a normal DTLS connection.
92  *
93  * Cisco use a version of the protocol which predates RFC4347, but
94  * isn't quite the same as the pre-RFC version of the protocol which
95  * was in OpenSSL 0.9.8e -- it includes backports of some later
96  * OpenSSL patches.
97  *
98  * The openssl/ directory of this source tree should contain both a
99  * small patch against OpenSSL 0.9.8e to make it support Cisco's
100  * snapshot of the protocol, and a larger patch against newer OpenSSL
101  * which gives us an option to use the old protocol again.
102  *
103  * Cisco's server also seems to respond to the official version of the
104  * protocol, with a change in the ChangeCipherSpec packet which implies
105  * that it does know the difference and isn't just repeating the version
106  * number seen in the ClientHello. But although I can make the handshake
107  * complete by hacking tls1_mac() to use the _old_ protocol version
108  * number when calculating the MAC, the server still seems to be ignoring
109  * my subsequent data packets. So we use the old protocol, which is what
110  * their clients use anyway.
111  */
112
113 #if defined (OPENCONNECT_OPENSSL)
114 #define DTLS_SEND SSL_write
115 #define DTLS_RECV SSL_read
116 static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
117 {
118         STACK_OF(SSL_CIPHER) *ciphers;
119         method_const SSL_METHOD *dtls_method;
120         SSL_CIPHER *dtls_cipher;
121         SSL *dtls_ssl;
122         BIO *dtls_bio;
123
124         if (!vpninfo->dtls_ctx) {
125                 dtls_method = DTLSv1_client_method();
126                 vpninfo->dtls_ctx = SSL_CTX_new(dtls_method);
127                 if (!vpninfo->dtls_ctx) {
128                         vpn_progress(vpninfo, PRG_ERR,
129                                      _("Initialise DTLSv1 CTX failed\n"));
130                         vpninfo->dtls_attempt_period = 0;
131                         return -EINVAL;
132                 }
133
134                 /* If we don't readahead, then we do short reads and throw
135                    away the tail of data packets. */
136                 SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1);
137
138                 if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) {
139                         vpn_progress(vpninfo, PRG_ERR,
140                                      _("Set DTLS cipher list failed\n"));
141                         SSL_CTX_free(vpninfo->dtls_ctx);
142                         vpninfo->dtls_ctx = NULL;
143                         vpninfo->dtls_attempt_period = 0;
144                         return -EINVAL;
145                 }
146         }
147
148         if (!vpninfo->dtls_session) {
149                 /* We're going to "resume" a session which never existed. Fake it... */
150                 vpninfo->dtls_session = SSL_SESSION_new();
151                 if (!vpninfo->dtls_session) {
152                         vpn_progress(vpninfo, PRG_ERR,
153                                      _("Initialise DTLSv1 session failed\n"));
154                         vpninfo->dtls_attempt_period = 0;
155                         return -EINVAL;
156                 }
157                 vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */
158         }
159
160         /* Do this every time; it may have changed due to a rekey */
161         vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
162         memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
163                sizeof(vpninfo->dtls_secret));
164
165         vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
166         memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
167                sizeof(vpninfo->dtls_session_id));
168
169         dtls_ssl = SSL_new(vpninfo->dtls_ctx);
170         SSL_set_connect_state(dtls_ssl);
171
172         ciphers = SSL_get_ciphers(dtls_ssl);
173         if (sk_SSL_CIPHER_num(ciphers) != 1) {
174                 vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n"));
175                 SSL_CTX_free(vpninfo->dtls_ctx);
176                 SSL_free(dtls_ssl);
177                 SSL_SESSION_free(vpninfo->dtls_session);
178                 vpninfo->dtls_ctx = NULL;
179                 vpninfo->dtls_session = NULL;
180                 vpninfo->dtls_attempt_period = 0;
181                 return -EINVAL;
182         }
183         dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0);
184
185         /* Set the appropriate cipher on our session to be resumed */
186         vpninfo->dtls_session->cipher = dtls_cipher;
187         vpninfo->dtls_session->cipher_id = dtls_cipher->id;
188
189         /* Add the generated session to the SSL */
190         if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
191                 vpn_progress(vpninfo, PRG_ERR,
192                              _("SSL_set_session() failed with old protocol version 0x%x\n"
193                                "Are you using a version of OpenSSL older than 0.9.8m?\n"
194                                "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
195                                "Use the --no-dtls command line option to avoid this message\n"),
196                              vpninfo->dtls_session->ssl_version);
197                 vpninfo->dtls_attempt_period = 0;
198                 return -EINVAL;
199         }
200
201         dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
202         /* Set non-blocking */
203         BIO_set_nbio(dtls_bio, 1);
204         SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
205
206         SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
207
208         vpninfo->new_dtls_ssl = dtls_ssl;
209
210         return 0;
211 }
212
213 int dtls_try_handshake(struct openconnect_info *vpninfo)
214 {
215         int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
216
217         if (ret == 1) {
218                 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
219
220                 if (vpninfo->dtls_ssl) {
221                         /* We are replacing an old connection */
222                         SSL_free(vpninfo->dtls_ssl);
223                         close(vpninfo->dtls_fd);
224                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
225                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
226                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
227                 }
228                 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
229                 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
230
231                 vpninfo->new_dtls_ssl = NULL;
232                 vpninfo->new_dtls_fd = -1;
233
234                 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
235
236                 /* From about 8.4.1(11) onwards, the ASA seems to get
237                    very unhappy if we resend ChangeCipherSpec messages
238                    after the initial setup. This was "fixed" in OpenSSL
239                    1.0.0e for RT#2505, but it's not clear if that was
240                    the right fix. What happens if the original packet
241                    *does* get lost? Surely we *wanted* the retransmits,
242                    because without them the server will never be able
243                    to decrypt anything we send?
244                    Oh well, our retransmitted packets upset the server
245                    because we don't get the Cisco-compatibility right
246                    (this is one of the areas in which Cisco's DTLS differs
247                    from the RFC4347 spec), and DPD should help us notice
248                    if *nothing* is getting through. */
249 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
250                 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
251                    However, if we were *built* against 1.0.0e or newer, but at
252                    runtime we find that we are being run against an older 
253                    version, warn about it. */
254                 if (SSLeay() < 0x1000005fL) {
255                         vpn_progress(vpninfo, PRG_ERR,
256                                      _("Your OpenSSL is older than the one you built against, so DTLS may fail!"));
257                 }
258 #elif defined (HAVE_DTLS1_STOP_TIMER)
259                 /*
260                  * This works for any normal OpenSSL that supports
261                  * Cisco DTLS compatibility (0.9.8m to 1.0.0d inclusive,
262                  * and even later versions although it isn't needed there.
263                  */
264                 dtls1_stop_timer(vpninfo->dtls_ssl);
265 #elif defined (BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT)
266                 /*
267                  * Debian restricts visibility of dtls1_stop_timer()
268                  * so do it manually. This version also works on all
269                  * sane versions of OpenSSL:
270                  */
271                 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
272                         sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
273                 vpninfo->dtls_ssl->d1->timeout_duration = 1;
274                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
275                          BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
276                          &(vpninfo->dtls_ssl->d1->next_timeout));
277 #elif defined (BIO_CTRL_DGRAM_SET_TIMEOUT)
278                 /*
279                  * OK, here it gets more fun... this shoul handle the case
280                  * of older OpenSSL which has the Cisco DTLS compatibility
281                  * backported, but *not* the fix for RT#1922.
282                  */
283                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
284                          BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
285 #else
286                 /*
287                  * And if they don't have any of the above, they probably
288                  * don't have RT#1829 fixed either, but that's OK because
289                  * that's the "fix" that *introduces* the timeout we're
290                  * trying to disable. So do nothing...
291                  */
292 #endif
293                 return 0;
294         }
295
296         ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
297         if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
298                 if (time(NULL) < vpninfo->new_dtls_started + 5)
299                         return 0;
300                 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
301         }
302
303         vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
304         openconnect_report_ssl_errors(vpninfo);
305
306         /* Kill the new (failed) connection... */
307         SSL_free(vpninfo->new_dtls_ssl);
308         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
309         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
310         close(vpninfo->new_dtls_fd);
311         vpninfo->new_dtls_ssl = NULL;
312         vpninfo->new_dtls_fd = -1;
313
314         /* ... and kill the old one too. The only time there'll be a valid
315            existing session is when it was a rekey, and in that case it's
316            time for the old one to die. */
317         if (vpninfo->dtls_ssl) {
318                 SSL_free(vpninfo->dtls_ssl);
319                 close(vpninfo->dtls_fd);
320                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
321                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
322                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
323                 vpninfo->dtls_ssl = NULL;
324                 vpninfo->dtls_fd = -1;
325         }
326
327         time(&vpninfo->new_dtls_started);
328         return -EINVAL;
329 }
330
331 #elif defined (OPENCONNECT_GNUTLS)
332 #define DTLS_SEND gnutls_record_send
333 #define DTLS_RECV gnutls_record_recv
334 static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
335 {
336         gnutls_session_t dtls_ssl;
337         gnutls_datum_t master_secret, session_id;
338         int err;
339
340         gnutls_init(&dtls_ssl, GNUTLS_CLIENT|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK);
341         err = gnutls_priority_set_direct(dtls_ssl,
342                                          "NONE:+VERS-DTLS0.9:+COMP-NULL:+AES-128-CBC:+SHA1:+RSA:%COMPAT:%DISABLE_SAFE_RENEGOTIATION",
343                                          NULL);
344         if (err) {
345                 vpn_progress(vpninfo, PRG_ERR,
346                              _("Failed to set DTLS priority: %s\n"),
347                              gnutls_strerror(err));
348                 gnutls_deinit(dtls_ssl);
349                 vpninfo->dtls_attempt_period = 0;
350                 return -EINVAL;
351         }
352         gnutls_transport_set_ptr(dtls_ssl,
353                                  (gnutls_transport_ptr_t)(long) dtls_fd);
354         gnutls_record_disable_padding(dtls_ssl);
355         master_secret.data = vpninfo->dtls_secret;
356         master_secret.size = sizeof(vpninfo->dtls_secret);
357         session_id.data = vpninfo->dtls_session_id;
358         session_id.size = sizeof(vpninfo->dtls_session_id);
359         err = gnutls_session_set_master(dtls_ssl, GNUTLS_CLIENT, GNUTLS_DTLS0_9,
360                                         GNUTLS_KX_RSA, GNUTLS_CIPHER_AES_128_CBC,
361                                         GNUTLS_MAC_SHA1, GNUTLS_COMP_NULL,
362                                         &master_secret, &session_id);
363         if (err) {
364                 vpn_progress(vpninfo, PRG_ERR,
365                              _("Failed to set DTLS session parameters: %s\n"),
366                              gnutls_strerror(err));
367                 gnutls_deinit(dtls_ssl);
368                 vpninfo->dtls_attempt_period = 0;
369                 return -EINVAL;
370         }
371
372         vpninfo->new_dtls_ssl = dtls_ssl;
373         return 0;
374 }
375
376 int dtls_try_handshake(struct openconnect_info *vpninfo)
377 {
378         int err = gnutls_handshake(vpninfo->new_dtls_ssl);
379
380         if (!err) {
381                 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
382
383                 if (vpninfo->dtls_ssl) {
384                         /* We are replacing an old connection */
385                         gnutls_deinit(vpninfo->dtls_ssl);
386                         close(vpninfo->dtls_fd);
387                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
388                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
389                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
390                 }
391                 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
392                 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
393
394                 vpninfo->new_dtls_ssl = NULL;
395                 vpninfo->new_dtls_fd = -1;
396
397                 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
398
399                 /* XXX: For OpenSSL we explicitly prevent retransmits here. */
400                 return 0;
401         }
402
403         if (err == GNUTLS_E_AGAIN) {
404                 if (time(NULL) < vpninfo->new_dtls_started + 5)
405                         return 0;
406                 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
407         }
408
409         vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %s\n"),
410                      gnutls_strerror(err));
411
412         /* Kill the new (failed) connection... */
413         gnutls_deinit(vpninfo->new_dtls_ssl);
414         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
415         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
416         close(vpninfo->new_dtls_fd);
417         vpninfo->new_dtls_ssl = NULL;
418         vpninfo->new_dtls_fd = -1;
419
420         /* ... and kill the old one too. The only time there'll be a valid
421            existing session is when it was a rekey, and in that case it's
422            time for the old one to die. */
423         if (vpninfo->dtls_ssl) {
424                 gnutls_deinit(vpninfo->dtls_ssl);
425                 close(vpninfo->dtls_fd);
426                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
427                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
428                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
429                 vpninfo->dtls_ssl = NULL;
430                 vpninfo->dtls_fd = -1;
431         }
432
433         time(&vpninfo->new_dtls_started);
434         return -EINVAL;
435 }
436 #endif
437
438 int connect_dtls_socket(struct openconnect_info *vpninfo)
439 {
440         int dtls_fd, ret;
441
442         if (!vpninfo->dtls_addr) {
443                 vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
444                 vpninfo->dtls_attempt_period = 0;
445                 return -EINVAL;
446         }
447
448         if (!vpninfo->dtls_cipher) {
449                 /* We probably didn't offer it any ciphers it liked */
450                 vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
451                 vpninfo->dtls_attempt_period = 0;
452                 return -EINVAL;
453         }
454
455         if (vpninfo->proxy) {
456                 /* XXX: Theoretically, SOCKS5 proxies can do UDP too */
457                 vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
458                 vpninfo->dtls_attempt_period = 0;
459                 return -EINVAL;
460         }
461
462         dtls_fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
463         if (dtls_fd < 0) {
464                 perror(_("Open UDP socket for DTLS:"));
465                 return -EINVAL;
466         }
467
468         if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
469                 perror(_("UDP (DTLS) connect:\n"));
470                 close(dtls_fd);
471                 return -EINVAL;
472         }
473
474         fcntl(dtls_fd, F_SETFD, FD_CLOEXEC);
475         fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
476
477         ret = start_dtls_handshake(vpninfo, dtls_fd);
478         if (ret) {
479                 close(dtls_fd);
480                 return ret;
481         }
482
483         vpninfo->new_dtls_fd = dtls_fd;
484         if (vpninfo->select_nfds <= dtls_fd)
485                 vpninfo->select_nfds = dtls_fd + 1;
486
487         FD_SET(dtls_fd, &vpninfo->select_rfds);
488         FD_SET(dtls_fd, &vpninfo->select_efds);
489
490         time(&vpninfo->new_dtls_started);
491
492         return dtls_try_handshake(vpninfo);
493 }
494
495 static int dtls_restart(struct openconnect_info *vpninfo)
496 {
497         if (vpninfo->dtls_ssl) {
498 #if defined (OPENCONNECT_OPENSSL)
499                 SSL_free(vpninfo->dtls_ssl);
500 #elif defined (OPENCONNECT_GNUTLS)
501                 gnutls_deinit(vpninfo->dtls_ssl);
502 #endif
503                 close(vpninfo->dtls_fd);
504                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
505                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
506                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
507                 vpninfo->dtls_ssl = NULL;
508                 vpninfo->dtls_fd = -1;
509         }
510
511         return connect_dtls_socket(vpninfo);
512 }
513
514
515 int setup_dtls(struct openconnect_info *vpninfo)
516 {
517         struct vpn_option *dtls_opt = vpninfo->dtls_options;
518         int dtls_port = 0;
519
520         while (dtls_opt) {
521                 vpn_progress(vpninfo, PRG_TRACE,
522                              _("DTLS option %s : %s\n"),
523                              dtls_opt->option, dtls_opt->value);
524
525                 if (!strcmp(dtls_opt->option + 7, "Port")) {
526                         dtls_port = atol(dtls_opt->value);
527                 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
528                         vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
529                 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
530                         int j = atol(dtls_opt->value);
531                         if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
532                                 vpninfo->dtls_times.dpd = j;
533                 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
534                         vpninfo->dtls_times.rekey = atol(dtls_opt->value);
535                 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
536                         vpninfo->dtls_cipher = strdup(dtls_opt->value);
537                 }
538
539                 dtls_opt = dtls_opt->next;
540         }
541         if (!dtls_port) {
542                 vpninfo->dtls_attempt_period = 0;
543                 return -EINVAL;
544         }
545
546         vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
547         if (!vpninfo->dtls_addr) {
548                 vpninfo->dtls_attempt_period = 0;
549                 return -ENOMEM;
550         }
551         memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
552
553         if (vpninfo->peer_addr->sa_family == AF_INET) {
554                 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
555                 sin->sin_port = htons(dtls_port);
556         } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
557                 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
558                 sin->sin6_port = htons(dtls_port);
559         } else {
560                 vpn_progress(vpninfo, PRG_ERR,
561                              _("Unknown protocol family %d. Cannot do DTLS\n"),
562                              vpninfo->peer_addr->sa_family);
563                 vpninfo->dtls_attempt_period = 0;
564                 return -EINVAL;
565         }
566
567         if (connect_dtls_socket(vpninfo))
568                 return -EINVAL;
569
570         vpn_progress(vpninfo, PRG_TRACE,
571                      _("DTLS connected. DPD %d, Keepalive %d\n"),
572                      vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
573
574         return 0;
575 }
576
577 static struct pkt *dtls_pkt;
578
579 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
580 {
581         int work_done = 0;
582         char magic_pkt;
583
584         while (1) {
585                 int len = vpninfo->mtu;
586                 unsigned char *buf;
587
588                 if (!dtls_pkt) {
589                         dtls_pkt = malloc(sizeof(struct pkt) + len);
590                         if (!dtls_pkt) {
591                                 vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
592                                 break;
593                         }
594                 }
595
596                 buf = dtls_pkt->data - 1;
597                 len = DTLS_RECV(vpninfo->dtls_ssl, buf, len + 1);
598                 if (len <= 0)
599                         break;
600
601                 vpn_progress(vpninfo, PRG_TRACE,
602                              _("Received DTLS packet 0x%02x of %d bytes\n"),
603                              buf[0], len);
604
605                 vpninfo->dtls_times.last_rx = time(NULL);
606
607                 switch(buf[0]) {
608                 case AC_PKT_DATA:
609                         dtls_pkt->len = len - 1;
610                         queue_packet(&vpninfo->incoming_queue, dtls_pkt);
611                         dtls_pkt = NULL;
612                         work_done = 1;
613                         break;
614
615                 case AC_PKT_DPD_OUT:
616                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
617
618                         /* FIXME: What if the packet doesn't get through? */
619                         magic_pkt = AC_PKT_DPD_RESP;
620                         if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
621                                 vpn_progress(vpninfo, PRG_ERR,
622                                              _("Failed to send DPD response. Expect disconnect\n"));
623                         continue;
624
625                 case AC_PKT_DPD_RESP:
626                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
627                         break;
628
629                 case AC_PKT_KEEPALIVE:
630                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
631                         break;
632
633                 default:
634                         vpn_progress(vpninfo, PRG_ERR,
635                                      _("Unknown DTLS packet type %02x, len %d\n"),
636                                      buf[0], len);
637                         if (1) {
638                                 /* Some versions of OpenSSL have bugs with receiving out-of-order
639                                  * packets. Not only do they wrongly decide to drop packets if
640                                  * two packets get swapped in transit, but they also _fail_ to
641                                  * drop the packet in non-blocking mode; instead they return
642                                  * the appropriate length of garbage. So don't abort... for now. */
643                                 break;
644                         } else {
645                                 vpninfo->quit_reason = "Unknown packet received";
646                                 return 1;
647                         }
648
649                 }
650         }
651
652         switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
653         case KA_REKEY:
654                 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
655
656                 /* There ought to be a method of rekeying DTLS without tearing down
657                    the CSTP session and restarting, but we don't (yet) know it */
658                 if (cstp_reconnect(vpninfo)) {
659                         vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
660                         vpninfo->quit_reason = "CSTP reconnect failed";
661                         return 1;
662                 }
663
664                 if (dtls_restart(vpninfo)) {
665                         vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
666                         return 1;
667                 }
668                 work_done = 1;
669                 break;
670
671
672         case KA_DPD_DEAD:
673                 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
674                 /* Fall back to SSL, and start a new DTLS connection */
675                 dtls_restart(vpninfo);
676                 return 1;
677
678         case KA_DPD:
679                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
680
681                 magic_pkt = AC_PKT_DPD_OUT;
682                 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
683                         vpn_progress(vpninfo, PRG_ERR,
684                                      _("Failed to send DPD request. Expect disconnect\n"));
685
686                 /* last_dpd will just have been set */
687                 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
688                 work_done = 1;
689                 break;
690
691         case KA_KEEPALIVE:
692                 /* No need to send an explicit keepalive
693                    if we have real data to send */
694                 if (vpninfo->outgoing_queue)
695                         break;
696
697                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
698
699                 magic_pkt = AC_PKT_KEEPALIVE;
700                 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
701                         vpn_progress(vpninfo, PRG_ERR,
702                                      _("Failed to send keepalive request. Expect disconnect\n"));
703                 time(&vpninfo->dtls_times.last_tx);
704                 work_done = 1;
705                 break;
706
707         case KA_NONE:
708                 ;
709         }
710
711         /* Service outgoing packet queue */
712         while (vpninfo->outgoing_queue) {
713                 struct pkt *this = vpninfo->outgoing_queue;
714                 int ret;
715
716                 vpninfo->outgoing_queue = this->next;
717                 vpninfo->outgoing_qlen--;
718
719                 /* One byte of header */
720                 this->hdr[7] = AC_PKT_DATA;
721
722 #if defined(OPENCONNECT_OPENSSL)
723                 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
724                 if (ret <= 0) {
725                         ret = SSL_get_error(vpninfo->dtls_ssl, ret);
726
727                         /* If it's a real error, kill the DTLS connection and
728                            requeue the packet to be sent over SSL */
729                         if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
730                                 vpn_progress(vpninfo, PRG_ERR,
731                                              _("DTLS got write error %d. Falling back to SSL\n"),
732                                              ret);
733                                 openconnect_report_ssl_errors(vpninfo);
734                                 dtls_restart(vpninfo);
735                                 vpninfo->outgoing_queue = this;
736                                 vpninfo->outgoing_qlen++;
737                         }
738                         return 1;
739                 }
740 #elif defined (OPENCONNECT_GNUTLS)
741                 ret = gnutls_record_send(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
742                 if (ret <= 0) {
743                         if (ret != GNUTLS_E_AGAIN) {
744                                 vpn_progress(vpninfo, PRG_ERR,
745                                              _("DTLS got write error: %s. Falling back to SSL\n"),
746                                              gnutls_strerror(ret));
747                                 dtls_restart(vpninfo);
748                                 vpninfo->outgoing_queue = this;
749                                 vpninfo->outgoing_qlen++;
750                         }
751                         return 1;
752                 }
753 #endif
754                 time(&vpninfo->dtls_times.last_tx);
755                 vpn_progress(vpninfo, PRG_TRACE,
756                              _("Sent DTLS packet of %d bytes; DTLS send returned %d\n"),
757                              this->len, ret);
758                 free(this);
759         }
760
761         return work_done;
762 }
763 #else /* !HAVE_DTLS */
764 #warning Your SSL library does not seem to support Cisco DTLS compatibility
765  int setup_dtls(struct openconnect_info *vpninfo)
766 {
767         vpn_progress(vpninfo, PRG_ERR,
768                      _("Built against SSL library with no Cisco DTLS support\n"));
769         return -EINVAL;
770 }
771 #endif
772