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