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