Fix memcpy-less DTLS RX so it really doesn't use memcpy().
[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                 dtls1_stop_timer(vpninfo->dtls_ssl);
304 #else
305                 /* Debian restricts visibility of dtls1_stop_timer()
306                    so do it manually. Thankfully this *should* work,
307                    from 0.9.8m to 1.0.0d inclusive, and we don't have
308                    to worry about future changes because we don't do
309                    this for 1.0.0e and above anyway */
310                 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
311                         sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
312                 vpninfo->dtls_ssl->d1->timeout_duration = 1;
313                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
314                          BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
315                          &(vpninfo->dtls_ssl->d1->next_timeout));
316 #endif
317                 return 0;
318         }
319
320         ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
321         if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
322                 if (time(NULL) < vpninfo->new_dtls_started + 5)
323                         return 0;
324                 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
325         }
326
327         vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
328         report_ssl_errors(vpninfo);
329
330         /* Kill the new (failed) connection... */
331         SSL_free(vpninfo->new_dtls_ssl);
332         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
333         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
334         close(vpninfo->new_dtls_fd);
335         vpninfo->new_dtls_ssl = NULL;
336         vpninfo->new_dtls_fd = -1;
337
338         /* ... and kill the old one too. The only time there'll be a valid
339            existing session is when it was a rekey, and in that case it's
340            time for the old one to die. */
341         if (vpninfo->dtls_ssl) {
342                 SSL_free(vpninfo->dtls_ssl);
343                 close(vpninfo->dtls_fd);
344                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
345                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
346                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
347                 vpninfo->dtls_ssl = NULL;
348                 vpninfo->dtls_fd = -1;
349         }
350
351         time(&vpninfo->new_dtls_started);
352         return -EINVAL;
353 }
354
355 static int dtls_restart(struct openconnect_info *vpninfo)
356 {
357         if (vpninfo->dtls_ssl) {
358                 SSL_free(vpninfo->dtls_ssl);
359                 close(vpninfo->dtls_fd);
360                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
361                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
362                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
363                 vpninfo->dtls_ssl = NULL;
364                 vpninfo->dtls_fd = -1;
365         }
366
367         return connect_dtls_socket(vpninfo);
368 }
369
370
371 int setup_dtls(struct openconnect_info *vpninfo)
372 {
373         struct vpn_option *dtls_opt = vpninfo->dtls_options;
374         int dtls_port = 0;
375
376         while (dtls_opt) {
377                 vpn_progress(vpninfo, PRG_TRACE,
378                              _("DTLS option %s : %s\n"),
379                              dtls_opt->option, dtls_opt->value);
380
381                 if (!strcmp(dtls_opt->option + 7, "Port")) {
382                         dtls_port = atol(dtls_opt->value);
383                 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
384                         vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
385                 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
386                         int j = atol(dtls_opt->value);
387                         if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
388                                 vpninfo->dtls_times.dpd = j;
389                 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
390                         vpninfo->dtls_times.rekey = atol(dtls_opt->value);
391                 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
392                         vpninfo->dtls_cipher = strdup(dtls_opt->value);
393                 }
394
395                 dtls_opt = dtls_opt->next;
396         }
397         if (!dtls_port) {
398                 vpninfo->dtls_attempt_period = 0;
399                 return -EINVAL;
400         }
401
402         vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
403         if (!vpninfo->dtls_addr) {
404                 vpninfo->dtls_attempt_period = 0;
405                 return -ENOMEM;
406         }
407         memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
408
409         if (vpninfo->peer_addr->sa_family == AF_INET) {
410                 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
411                 sin->sin_port = htons(dtls_port);
412         } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
413                 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
414                 sin->sin6_port = htons(dtls_port);
415         } else {
416                 vpn_progress(vpninfo, PRG_ERR,
417                              _("Unknown protocol family %d. Cannot do DTLS\n"),
418                              vpninfo->peer_addr->sa_family);
419                 vpninfo->dtls_attempt_period = 0;
420                 return -EINVAL;
421         }
422
423         if (connect_dtls_socket(vpninfo))
424                 return -EINVAL;
425
426         vpn_progress(vpninfo, PRG_TRACE,
427                      _("DTLS connected. DPD %d, Keepalive %d\n"),
428                      vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
429
430         return 0;
431 }
432
433 static struct pkt *dtls_pkt;
434
435 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
436 {
437         int work_done = 0;
438         char magic_pkt;
439
440         while (1) {
441                 int len = vpninfo->mtu;
442                 unsigned char *buf;
443
444                 if (!dtls_pkt) {
445                         dtls_pkt = malloc(sizeof(struct pkt) + len);
446                         if (!dtls_pkt) {
447                                 vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
448                                 break;
449                         }
450                 }
451
452                 buf = dtls_pkt->data - 1;
453                 len = SSL_read(vpninfo->dtls_ssl, buf, len + 1);
454                 if (len <= 0)
455                         break;
456
457                 vpn_progress(vpninfo, PRG_TRACE,
458                              _("Received DTLS packet 0x%02x of %d bytes\n"),
459                              buf[0], len);
460
461                 vpninfo->dtls_times.last_rx = time(NULL);
462
463                 switch(buf[0]) {
464                 case AC_PKT_DATA:
465                         dtls_pkt->len = len - 1;
466                         queue_packet(&vpninfo->incoming_queue, dtls_pkt);
467                         dtls_pkt = NULL;
468                         work_done = 1;
469                         break;
470
471                 case AC_PKT_DPD_OUT:
472                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
473
474                         /* FIXME: What if the packet doesn't get through? */
475                         magic_pkt = AC_PKT_DPD_RESP;
476                         if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
477                                 vpn_progress(vpninfo, PRG_ERR,
478                                              _("Failed to send DPD response. Expect disconnect\n"));
479                         continue;
480
481                 case AC_PKT_DPD_RESP:
482                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
483                         break;
484
485                 case AC_PKT_KEEPALIVE:
486                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
487                         break;
488
489                 default:
490                         vpn_progress(vpninfo, PRG_ERR,
491                                      _("Unknown DTLS packet type %02x, len %d\n"),
492                                      buf[0], len);
493                         if (1) {
494                                 /* Some versions of OpenSSL have bugs with receiving out-of-order
495                                  * packets. Not only do they wrongly decide to drop packets if
496                                  * two packets get swapped in transit, but they also _fail_ to
497                                  * drop the packet in non-blocking mode; instead they return
498                                  * the appropriate length of garbage. So don't abort... for now. */
499                                 break;
500                         } else {
501                                 vpninfo->quit_reason = "Unknown packet received";
502                                 return 1;
503                         }
504
505                 }
506         }
507
508         switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
509         case KA_REKEY:
510                 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
511
512                 /* There ought to be a method of rekeying DTLS without tearing down
513                    the CSTP session and restarting, but we don't (yet) know it */
514                 if (cstp_reconnect(vpninfo)) {
515                         vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
516                         vpninfo->quit_reason = "CSTP reconnect failed";
517                         return 1;
518                 }
519
520                 if (dtls_restart(vpninfo)) {
521                         vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
522                         return 1;
523                 }
524                 work_done = 1;
525                 break;
526
527
528         case KA_DPD_DEAD:
529                 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
530                 /* Fall back to SSL, and start a new DTLS connection */
531                 dtls_restart(vpninfo);
532                 return 1;
533
534         case KA_DPD:
535                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
536
537                 magic_pkt = AC_PKT_DPD_OUT;
538                 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
539                 /* last_dpd will just have been set */
540                 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
541                 work_done = 1;
542                 break;
543
544         case KA_KEEPALIVE:
545                 /* No need to send an explicit keepalive
546                    if we have real data to send */
547                 if (vpninfo->outgoing_queue)
548                         break;
549
550                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
551
552                 magic_pkt = AC_PKT_KEEPALIVE;
553                 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
554                 time(&vpninfo->dtls_times.last_tx);
555                 work_done = 1;
556                 break;
557
558         case KA_NONE:
559                 ;
560         }
561
562         /* Service outgoing packet queue */
563         while (vpninfo->outgoing_queue) {
564                 struct pkt *this = vpninfo->outgoing_queue;
565                 int ret;
566
567                 vpninfo->outgoing_queue = this->next;
568                 vpninfo->outgoing_qlen--;
569
570                 /* One byte of header */
571                 this->hdr[7] = AC_PKT_DATA;
572
573                 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
574                 if (ret <= 0) {
575                         ret = SSL_get_error(vpninfo->dtls_ssl, ret);
576
577                         /* If it's a real error, kill the DTLS connection and
578                            requeue the packet to be sent over SSL */
579                         if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
580                                 vpn_progress(vpninfo, PRG_ERR,
581                                              _("DTLS got write error %d. Falling back to SSL\n"),
582                                              ret);
583                                 report_ssl_errors(vpninfo);
584                                 dtls_restart(vpninfo);
585                                 vpninfo->outgoing_queue = this;
586                                 vpninfo->outgoing_qlen++;
587                         }
588                         return 1;
589                 }
590                 time(&vpninfo->dtls_times.last_tx);
591                 vpn_progress(vpninfo, PRG_TRACE,
592                              _("Sent DTLS packet of %d bytes; SSL_write() returned %d\n"),
593                              this->len, ret);
594                 free(this);
595         }
596
597         return work_done;
598 }
599 #else /* No DTLS support in OpenSSL */
600 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
601  int setup_dtls(struct openconnect_info *vpninfo)
602 {
603         vpn_progress(vpninfo, PRG_ERR,
604                      _("Built against OpenSSL with no Cisco DTLS support\n"));
605         return -EINVAL;
606 }
607 #endif
608