Clean up BIO_set_nbio() calls for DTLS
[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 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         fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
234
235         dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
236         /* Set non-blocking */
237         BIO_set_nbio(dtls_bio, 1);
238         SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
239
240         SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
241
242         vpninfo->new_dtls_fd = dtls_fd;
243         vpninfo->new_dtls_ssl = dtls_ssl;
244
245         if (vpninfo->select_nfds <= dtls_fd)
246                 vpninfo->select_nfds = dtls_fd + 1;
247
248         FD_SET(dtls_fd, &vpninfo->select_rfds);
249         FD_SET(dtls_fd, &vpninfo->select_efds);
250
251         time(&vpninfo->new_dtls_started);
252         return dtls_try_handshake(vpninfo);
253 }
254
255 int dtls_try_handshake(struct openconnect_info *vpninfo)
256 {
257         int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
258
259         if (ret == 1) {
260                 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
261
262                 if (vpninfo->dtls_ssl) {
263                         /* We are replacing an old connection */
264                         SSL_free(vpninfo->dtls_ssl);
265                         close(vpninfo->dtls_fd);
266                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
267                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
268                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
269                 }
270                 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
271                 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
272
273                 vpninfo->new_dtls_ssl = NULL;
274                 vpninfo->new_dtls_fd = -1;
275
276                 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
277
278                 /* From about 8.4.1(11) onwards, the ASA seems to get
279                    very unhappy if we resend ChangeCipherSpec messages
280                    after the initial setup. This was "fixed" in OpenSSL
281                    1.0.0e for RT#2505, but it's not clear if that was
282                    the right fix. What happens if the original packet
283                    *does* get lost? Surely we *wanted* the retransmits,
284                    because without them the server will never be able
285                    to decrypt anything we send?
286                    Oh well, our retransmitted packets upset the server
287                    because we don't get the Cisco-compatibility right
288                    (this is one of the areas in which Cisco's DTLS differs
289                    from the RFC4347 spec), and DPD should help us notice
290                    if *nothing* is getting through. */
291 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
292                 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
293                    However, if we were *built* against 1.0.0e or newer, but at
294                    runtime we find that we are being run against an older 
295                    version, warn about it. */
296                 if (SSLeay() < 0x1000005fL) {
297                         vpn_progress(vpninfo, PRG_ERR,
298                                      _("Your OpenSSL is older than the one you built against, so DTLS may fail!"));
299                 }
300 #elif defined (HAVE_DTLS1_STOP_TIMER)
301                 /*
302                  * This works for any normal OpenSSL that supports
303                  * Cisco DTLS compatibility (0.9.8m to 1.0.0d inclusive,
304                  * and even later versions although it isn't needed there.
305                  */
306                 dtls1_stop_timer(vpninfo->dtls_ssl);
307 #elif defined (BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT)
308                 /*
309                  * Debian restricts visibility of dtls1_stop_timer()
310                  * so do it manually. This version also works on all
311                  * sane versions of OpenSSL:
312                  */
313                 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
314                         sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
315                 vpninfo->dtls_ssl->d1->timeout_duration = 1;
316                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
317                          BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
318                          &(vpninfo->dtls_ssl->d1->next_timeout));
319 #elif defined (BIO_CTRL_DGRAM_SET_TIMEOUT)
320                 /*
321                  * OK, here it gets more fun... this shoul handle the case
322                  * of older OpenSSL which has the Cisco DTLS compatibility
323                  * backported, but *not* the fix for RT#1922.
324                  */
325                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
326                          BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
327 #else
328                 /*
329                  * And if they don't have any of the above, they probably
330                  * don't have RT#1829 fixed either, but that's OK because
331                  * that's the "fix" that *introduces* the timeout we're
332                  * trying to disable. So do nothing...
333                  */
334 #endif
335                 return 0;
336         }
337
338         ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
339         if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
340                 if (time(NULL) < vpninfo->new_dtls_started + 5)
341                         return 0;
342                 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
343         }
344
345         vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
346         openconnect_report_ssl_errors(vpninfo);
347
348         /* Kill the new (failed) connection... */
349         SSL_free(vpninfo->new_dtls_ssl);
350         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
351         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
352         close(vpninfo->new_dtls_fd);
353         vpninfo->new_dtls_ssl = NULL;
354         vpninfo->new_dtls_fd = -1;
355
356         /* ... and kill the old one too. The only time there'll be a valid
357            existing session is when it was a rekey, and in that case it's
358            time for the old one to die. */
359         if (vpninfo->dtls_ssl) {
360                 SSL_free(vpninfo->dtls_ssl);
361                 close(vpninfo->dtls_fd);
362                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
363                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
364                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
365                 vpninfo->dtls_ssl = NULL;
366                 vpninfo->dtls_fd = -1;
367         }
368
369         time(&vpninfo->new_dtls_started);
370         return -EINVAL;
371 }
372
373 static int dtls_restart(struct openconnect_info *vpninfo)
374 {
375         if (vpninfo->dtls_ssl) {
376                 SSL_free(vpninfo->dtls_ssl);
377                 close(vpninfo->dtls_fd);
378                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
379                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
380                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
381                 vpninfo->dtls_ssl = NULL;
382                 vpninfo->dtls_fd = -1;
383         }
384
385         return connect_dtls_socket(vpninfo);
386 }
387
388
389 int setup_dtls(struct openconnect_info *vpninfo)
390 {
391         struct vpn_option *dtls_opt = vpninfo->dtls_options;
392         int dtls_port = 0;
393
394         while (dtls_opt) {
395                 vpn_progress(vpninfo, PRG_TRACE,
396                              _("DTLS option %s : %s\n"),
397                              dtls_opt->option, dtls_opt->value);
398
399                 if (!strcmp(dtls_opt->option + 7, "Port")) {
400                         dtls_port = atol(dtls_opt->value);
401                 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
402                         vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
403                 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
404                         int j = atol(dtls_opt->value);
405                         if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
406                                 vpninfo->dtls_times.dpd = j;
407                 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
408                         vpninfo->dtls_times.rekey = atol(dtls_opt->value);
409                 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
410                         vpninfo->dtls_cipher = strdup(dtls_opt->value);
411                 }
412
413                 dtls_opt = dtls_opt->next;
414         }
415         if (!dtls_port) {
416                 vpninfo->dtls_attempt_period = 0;
417                 return -EINVAL;
418         }
419
420         vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
421         if (!vpninfo->dtls_addr) {
422                 vpninfo->dtls_attempt_period = 0;
423                 return -ENOMEM;
424         }
425         memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
426
427         if (vpninfo->peer_addr->sa_family == AF_INET) {
428                 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
429                 sin->sin_port = htons(dtls_port);
430         } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
431                 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
432                 sin->sin6_port = htons(dtls_port);
433         } else {
434                 vpn_progress(vpninfo, PRG_ERR,
435                              _("Unknown protocol family %d. Cannot do DTLS\n"),
436                              vpninfo->peer_addr->sa_family);
437                 vpninfo->dtls_attempt_period = 0;
438                 return -EINVAL;
439         }
440
441         if (connect_dtls_socket(vpninfo))
442                 return -EINVAL;
443
444         vpn_progress(vpninfo, PRG_TRACE,
445                      _("DTLS connected. DPD %d, Keepalive %d\n"),
446                      vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
447
448         return 0;
449 }
450
451 static struct pkt *dtls_pkt;
452
453 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
454 {
455         int work_done = 0;
456         char magic_pkt;
457
458         while (1) {
459                 int len = vpninfo->mtu;
460                 unsigned char *buf;
461
462                 if (!dtls_pkt) {
463                         dtls_pkt = malloc(sizeof(struct pkt) + len);
464                         if (!dtls_pkt) {
465                                 vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
466                                 break;
467                         }
468                 }
469
470                 buf = dtls_pkt->data - 1;
471                 len = SSL_read(vpninfo->dtls_ssl, buf, len + 1);
472                 if (len <= 0)
473                         break;
474
475                 vpn_progress(vpninfo, PRG_TRACE,
476                              _("Received DTLS packet 0x%02x of %d bytes\n"),
477                              buf[0], len);
478
479                 vpninfo->dtls_times.last_rx = time(NULL);
480
481                 switch(buf[0]) {
482                 case AC_PKT_DATA:
483                         dtls_pkt->len = len - 1;
484                         queue_packet(&vpninfo->incoming_queue, dtls_pkt);
485                         dtls_pkt = NULL;
486                         work_done = 1;
487                         break;
488
489                 case AC_PKT_DPD_OUT:
490                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
491
492                         /* FIXME: What if the packet doesn't get through? */
493                         magic_pkt = AC_PKT_DPD_RESP;
494                         if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
495                                 vpn_progress(vpninfo, PRG_ERR,
496                                              _("Failed to send DPD response. Expect disconnect\n"));
497                         continue;
498
499                 case AC_PKT_DPD_RESP:
500                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
501                         break;
502
503                 case AC_PKT_KEEPALIVE:
504                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
505                         break;
506
507                 default:
508                         vpn_progress(vpninfo, PRG_ERR,
509                                      _("Unknown DTLS packet type %02x, len %d\n"),
510                                      buf[0], len);
511                         if (1) {
512                                 /* Some versions of OpenSSL have bugs with receiving out-of-order
513                                  * packets. Not only do they wrongly decide to drop packets if
514                                  * two packets get swapped in transit, but they also _fail_ to
515                                  * drop the packet in non-blocking mode; instead they return
516                                  * the appropriate length of garbage. So don't abort... for now. */
517                                 break;
518                         } else {
519                                 vpninfo->quit_reason = "Unknown packet received";
520                                 return 1;
521                         }
522
523                 }
524         }
525
526         switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
527         case KA_REKEY:
528                 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
529
530                 /* There ought to be a method of rekeying DTLS without tearing down
531                    the CSTP session and restarting, but we don't (yet) know it */
532                 if (cstp_reconnect(vpninfo)) {
533                         vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
534                         vpninfo->quit_reason = "CSTP reconnect failed";
535                         return 1;
536                 }
537
538                 if (dtls_restart(vpninfo)) {
539                         vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
540                         return 1;
541                 }
542                 work_done = 1;
543                 break;
544
545
546         case KA_DPD_DEAD:
547                 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
548                 /* Fall back to SSL, and start a new DTLS connection */
549                 dtls_restart(vpninfo);
550                 return 1;
551
552         case KA_DPD:
553                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
554
555                 magic_pkt = AC_PKT_DPD_OUT;
556                 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
557                 /* last_dpd will just have been set */
558                 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
559                 work_done = 1;
560                 break;
561
562         case KA_KEEPALIVE:
563                 /* No need to send an explicit keepalive
564                    if we have real data to send */
565                 if (vpninfo->outgoing_queue)
566                         break;
567
568                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
569
570                 magic_pkt = AC_PKT_KEEPALIVE;
571                 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
572                 time(&vpninfo->dtls_times.last_tx);
573                 work_done = 1;
574                 break;
575
576         case KA_NONE:
577                 ;
578         }
579
580         /* Service outgoing packet queue */
581         while (vpninfo->outgoing_queue) {
582                 struct pkt *this = vpninfo->outgoing_queue;
583                 int ret;
584
585                 vpninfo->outgoing_queue = this->next;
586                 vpninfo->outgoing_qlen--;
587
588                 /* One byte of header */
589                 this->hdr[7] = AC_PKT_DATA;
590
591                 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
592                 if (ret <= 0) {
593                         ret = SSL_get_error(vpninfo->dtls_ssl, ret);
594
595                         /* If it's a real error, kill the DTLS connection and
596                            requeue the packet to be sent over SSL */
597                         if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
598                                 vpn_progress(vpninfo, PRG_ERR,
599                                              _("DTLS got write error %d. Falling back to SSL\n"),
600                                              ret);
601                                 openconnect_report_ssl_errors(vpninfo);
602                                 dtls_restart(vpninfo);
603                                 vpninfo->outgoing_queue = this;
604                                 vpninfo->outgoing_qlen++;
605                         }
606                         return 1;
607                 }
608                 time(&vpninfo->dtls_times.last_tx);
609                 vpn_progress(vpninfo, PRG_TRACE,
610                              _("Sent DTLS packet of %d bytes; SSL_write() returned %d\n"),
611                              this->len, ret);
612                 free(this);
613         }
614
615         return work_done;
616 }
617 #else /* No DTLS support in OpenSSL */
618 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
619  int setup_dtls(struct openconnect_info *vpninfo)
620 {
621         vpn_progress(vpninfo, PRG_ERR,
622                      _("Built against OpenSSL with no Cisco DTLS support\n"));
623         return -EINVAL;
624 }
625 #endif
626