Eliminate memcpy() for incoming packets from DTLS
[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                         queue_new_packet(&vpninfo->incoming_queue, buf+1, len-1);
466                         work_done = 1;
467                         break;
468
469                 case AC_PKT_DPD_OUT:
470                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
471
472                         /* FIXME: What if the packet doesn't get through? */
473                         magic_pkt = AC_PKT_DPD_RESP;
474                         if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
475                                 vpn_progress(vpninfo, PRG_ERR,
476                                              _("Failed to send DPD response. Expect disconnect\n"));
477                         continue;
478
479                 case AC_PKT_DPD_RESP:
480                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
481                         break;
482
483                 case AC_PKT_KEEPALIVE:
484                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
485                         break;
486
487                 default:
488                         vpn_progress(vpninfo, PRG_ERR,
489                                      _("Unknown DTLS packet type %02x, len %d\n"),
490                                      buf[0], len);
491                         if (1) {
492                                 /* Some versions of OpenSSL have bugs with receiving out-of-order
493                                  * packets. Not only do they wrongly decide to drop packets if
494                                  * two packets get swapped in transit, but they also _fail_ to
495                                  * drop the packet in non-blocking mode; instead they return
496                                  * the appropriate length of garbage. So don't abort... for now. */
497                                 break;
498                         } else {
499                                 vpninfo->quit_reason = "Unknown packet received";
500                                 return 1;
501                         }
502
503                 }
504         }
505
506         switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
507         case KA_REKEY:
508                 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
509
510                 /* There ought to be a method of rekeying DTLS without tearing down
511                    the CSTP session and restarting, but we don't (yet) know it */
512                 if (cstp_reconnect(vpninfo)) {
513                         vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
514                         vpninfo->quit_reason = "CSTP reconnect failed";
515                         return 1;
516                 }
517
518                 if (dtls_restart(vpninfo)) {
519                         vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
520                         return 1;
521                 }
522                 work_done = 1;
523                 break;
524
525
526         case KA_DPD_DEAD:
527                 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
528                 /* Fall back to SSL, and start a new DTLS connection */
529                 dtls_restart(vpninfo);
530                 return 1;
531
532         case KA_DPD:
533                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
534
535                 magic_pkt = AC_PKT_DPD_OUT;
536                 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
537                 /* last_dpd will just have been set */
538                 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
539                 work_done = 1;
540                 break;
541
542         case KA_KEEPALIVE:
543                 /* No need to send an explicit keepalive
544                    if we have real data to send */
545                 if (vpninfo->outgoing_queue)
546                         break;
547
548                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
549
550                 magic_pkt = AC_PKT_KEEPALIVE;
551                 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
552                 time(&vpninfo->dtls_times.last_tx);
553                 work_done = 1;
554                 break;
555
556         case KA_NONE:
557                 ;
558         }
559
560         /* Service outgoing packet queue */
561         while (vpninfo->outgoing_queue) {
562                 struct pkt *this = vpninfo->outgoing_queue;
563                 int ret;
564
565                 vpninfo->outgoing_queue = this->next;
566                 vpninfo->outgoing_qlen--;
567
568                 /* One byte of header */
569                 this->hdr[7] = AC_PKT_DATA;
570
571                 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
572                 if (ret <= 0) {
573                         ret = SSL_get_error(vpninfo->dtls_ssl, ret);
574
575                         /* If it's a real error, kill the DTLS connection and
576                            requeue the packet to be sent over SSL */
577                         if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
578                                 vpn_progress(vpninfo, PRG_ERR,
579                                              _("DTLS got write error %d. Falling back to SSL\n"),
580                                              ret);
581                                 report_ssl_errors(vpninfo);
582                                 dtls_restart(vpninfo);
583                                 vpninfo->outgoing_queue = this;
584                                 vpninfo->outgoing_qlen++;
585                         }
586                         return 1;
587                 }
588                 time(&vpninfo->dtls_times.last_tx);
589                 vpn_progress(vpninfo, PRG_TRACE,
590                              _("Sent DTLS packet of %d bytes; SSL_write() returned %d\n"),
591                              this->len, ret);
592                 free(this);
593         }
594
595         return work_done;
596 }
597 #else /* No DTLS support in OpenSSL */
598 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
599  int setup_dtls(struct openconnect_info *vpninfo)
600 {
601         vpn_progress(vpninfo, PRG_ERR,
602                      _("Built against OpenSSL with no Cisco DTLS support\n"));
603         return -EINVAL;
604 }
605 #endif
606