Add --force-dpd option
[platform/upstream/openconnect.git] / cstp.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2010 Intel Corporation.
5  * Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
6  *
7  * Author: David Woodhouse <dwmw2@infradead.org>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1, as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to:
20  *
21  *   Free Software Foundation, Inc.
22  *   51 Franklin Street, Fifth Floor,
23  *   Boston, MA 02110-1301 USA
24  */
25 #include <netdb.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <arpa/inet.h>
32
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35
36 #include "openconnect.h"
37
38 /*
39  * Data packets are encapsulated in the SSL stream as follows:
40  *
41  * 0000: Magic "STF\x1"
42  * 0004: Big-endian 16-bit length (not including 8-byte header)
43  * 0006: Byte packet type (see openconnect.h)
44  * 0008: data payload
45  */
46
47 static char data_hdr[8] = {
48         'S', 'T', 'F', 1,
49         0, 0,           /* Length */
50         AC_PKT_DATA,    /* Type */
51         0               /* Unknown */
52 };
53
54 static struct pkt keepalive_pkt = {
55         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
56 };
57
58 static struct pkt dpd_pkt = {
59         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
60 };
61
62 static struct pkt dpd_resp_pkt = {
63         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
64 };
65
66
67 static int start_cstp_connection(struct openconnect_info *vpninfo)
68 {
69         char buf[65536];
70         int i;
71         int retried = 0;
72         struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
73         struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
74         struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
75         struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
76         const char *old_addr = vpninfo->vpn_addr;
77         const char *old_netmask = vpninfo->vpn_netmask;
78         const char *old_addr6 = vpninfo->vpn_addr6;
79         const char *old_netmask6 = vpninfo->vpn_netmask6;
80         struct split_include *inc;
81
82         /* Clear old options which will be overwritten */
83         vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
84         vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
85         vpninfo->cstp_options = vpninfo->dtls_options = NULL;
86         vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
87         vpninfo->banner = NULL;
88
89         for (i=0; i<3; i++)
90                 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
91
92         for (inc = vpninfo->split_includes; inc; ) {
93                 struct split_include *next = inc->next;
94                 free(inc);
95                 inc = next;
96         }
97         for (inc = vpninfo->split_excludes; inc; ) {
98                 struct split_include *next = inc->next;
99                 free(inc);
100                 inc = next;
101         }
102         vpninfo->split_includes = vpninfo->split_excludes = NULL;
103  retry:
104         openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
105         openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
106         openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
107         openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
108         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
109         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
110         if (vpninfo->deflate)
111                 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
112         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
113         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
114                                vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
115         openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
116         for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
117                 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
118         openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
119                                vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
120
121         if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
122                 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
123                 if (!retried) {
124                         retried = 1;
125                         openconnect_close_https(vpninfo);
126
127                         if (openconnect_open_https(vpninfo)) {
128                                 vpninfo->progress(vpninfo, PRG_ERR,
129                                                   "Failed to open HTTPS connection to %s\n",
130                                                   vpninfo->hostname);
131                                 exit(1);
132                         }
133                         goto retry;
134                 }
135                 return -EINVAL;
136         }
137
138         if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
139                 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
140                         /* "Service Unavailable. Why? */
141                         char *reason = "<unknown>";
142                         while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
143                                 if (!strncmp(buf, "X-Reason: ", 10)) {
144                                         reason = buf + 10;
145                                         break;
146                                 }
147                         }
148                         vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
149                                           reason);
150                         return -EINVAL;
151                 }
152                 vpninfo->progress(vpninfo, PRG_ERR,
153                                   "Got inappropriate HTTP CONNECT response: %s\n",
154                                   buf);
155                 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
156                         exit(2);
157                 return -EINVAL;
158         }
159
160         vpninfo->progress(vpninfo, PRG_INFO,
161                           "Got CONNECT response: %s\n", buf);
162
163         /* We may have advertised it, but we only do it if the server agrees */
164         vpninfo->deflate = 0;
165
166         while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
167                 struct vpn_option *new_option;
168                 char *colon = strchr(buf, ':');
169                 if (!colon)
170                         continue;
171
172                 *colon = 0;
173                 colon++;
174                 if (*colon == ' ')
175                         colon++;
176
177                 if (strncmp(buf, "X-DTLS-", 7) &&
178                     strncmp(buf, "X-CSTP-", 7))
179                         continue;
180
181                 new_option = malloc(sizeof(*new_option));
182                 if (!new_option) {
183                         vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
184                         return -ENOMEM;
185                 }
186                 new_option->option = strdup(buf);
187                 new_option->value = strdup(colon);
188                 new_option->next = NULL;
189
190                 if (!new_option->option || !new_option->value) {
191                         vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
192                         return -ENOMEM;
193                 }
194
195                 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
196
197                 if (!strncmp(buf, "X-DTLS-", 7)) {
198                         *next_dtls_option = new_option;
199                         next_dtls_option = &new_option->next;
200                         continue;
201                 }
202                 /* CSTP options... */
203                 *next_cstp_option = new_option;
204                 next_cstp_option = &new_option->next;
205
206
207                 if (!strcmp(buf + 7, "Keepalive")) {
208                         vpninfo->ssl_times.keepalive = atol(colon);
209                 } else if (!strcmp(buf + 7, "DPD")) {
210                         int j = atol(colon);
211                         if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
212                                 vpninfo->ssl_times.dpd = j;
213                 } else if (!strcmp(buf + 7, "Content-Encoding")) {
214                         if (!strcmp(colon, "deflate"))
215                                 vpninfo->deflate = 1;
216                         else {
217                                 vpninfo->progress(vpninfo, PRG_ERR,
218                                         "Unknown CSTP-Content-Encoding %s\n",
219                                         colon);
220                                 return -EINVAL;
221                         }
222                 } else if (!strcmp(buf + 7, "MTU")) {
223                         vpninfo->mtu = atol(colon);
224                 } else if (!strcmp(buf + 7, "Address")) {
225                         if (strchr(new_option->value, ':'))
226                                 vpninfo->vpn_addr6 = new_option->value;
227                         else
228                                 vpninfo->vpn_addr = new_option->value;
229                 } else if (!strcmp(buf + 7, "Netmask")) {
230                         if (strchr(new_option->value, ':'))
231                                 vpninfo->vpn_netmask6 = new_option->value;
232                         else
233                                 vpninfo->vpn_netmask = new_option->value;
234                 } else if (!strcmp(buf + 7, "DNS")) {
235                         int j;
236                         for (j = 0; j < 3; j++) {
237                                 if (!vpninfo->vpn_dns[j]) {
238                                         vpninfo->vpn_dns[j] = new_option->value;
239                                         break;
240                                 }
241                         }
242                 } else if (!strcmp(buf + 7, "NBNS")) {
243                         int j;
244                         for (j = 0; j < 3; j++) {
245                                 if (!vpninfo->vpn_nbns[j]) {
246                                         vpninfo->vpn_nbns[j] = new_option->value;
247                                         break;
248                                 }
249                         }
250                 } else if (!strcmp(buf + 7, "Default-Domain")) {
251                         vpninfo->vpn_domain = new_option->value;
252                 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
253                         vpninfo->vpn_proxy_pac = new_option->value;
254                 } else if (!strcmp(buf + 7, "Banner")) {
255                         vpninfo->banner = new_option->value;
256                 } else if (!strcmp(buf + 7, "Split-Include")) {
257                         struct split_include *inc = malloc(sizeof(*inc));
258                         if (!inc)
259                                 continue;
260                         inc->route = new_option->value;
261                         inc->next = vpninfo->split_includes;
262                         vpninfo->split_includes = inc;
263                 } else if (!strcmp(buf + 7, "Split-Exclude")) {
264                         struct split_include *exc = malloc(sizeof(*exc));
265                         if (!exc)
266                                 continue;
267                         exc->route = new_option->value;
268                         exc->next = vpninfo->split_excludes;
269                         vpninfo->split_excludes = exc;
270                 }
271         }
272
273         if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
274                 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
275                 return -EINVAL;
276         }
277         if (old_addr) {
278                 if (strcmp(old_addr, vpninfo->vpn_addr)) {
279                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
280                                 vpninfo->vpn_addr, old_addr);
281                         return -EINVAL;
282                 }
283         }
284         if (old_netmask) {
285                 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
286                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
287                                 vpninfo->vpn_netmask, old_netmask);
288                         return -EINVAL;
289                 }
290         }
291         if (old_addr6) {
292                 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
293                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
294                                 vpninfo->vpn_addr6, old_addr6);
295                         return -EINVAL;
296                 }
297         }
298         if (old_netmask6) {
299                 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
300                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
301                                 vpninfo->vpn_netmask6, old_netmask6);
302                         return -EINVAL;
303                 }
304         }
305
306         while (old_dtls_opts) {
307                 struct vpn_option *tmp = old_dtls_opts;
308                 old_dtls_opts = old_dtls_opts->next;
309                 free(tmp->value);
310                 free(tmp->option);
311                 free(tmp);
312         }
313         while (old_cstp_opts) {
314                 struct vpn_option *tmp = old_cstp_opts;
315                 old_cstp_opts = old_cstp_opts->next;
316                 free(tmp->value);
317                 free(tmp->option);
318                 free(tmp);
319         }
320         vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
321                           vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
322
323         BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
324         BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
325
326         fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
327         if (vpninfo->select_nfds <= vpninfo->ssl_fd)
328                 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
329
330         FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
331         FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
332
333         vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
334         return 0;
335 }
336
337
338 int make_cstp_connection(struct openconnect_info *vpninfo)
339 {
340         int ret;
341
342         if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
343                 return ret;
344
345         if (vpninfo->deflate) {
346                 vpninfo->deflate_adler32 = 1;
347                 vpninfo->inflate_adler32 = 1;
348
349                 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
350                     deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
351                                  Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
352                         vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
353                         vpninfo->deflate = 0;
354                 }
355
356                 if (!vpninfo->deflate_pkt) {
357                         vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
358                         if (!vpninfo->deflate_pkt) {
359                                 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
360                                 vpninfo->deflate = 0;
361                         }
362                         memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
363                         memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
364                         vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
365                 }
366         }
367
368         return start_cstp_connection(vpninfo);
369 }
370
371 static int cstp_reconnect(struct openconnect_info *vpninfo)
372 {
373         int ret;
374         int timeout;
375         int interval;
376
377         timeout = vpninfo->reconnect_timeout;
378         interval = vpninfo->reconnect_interval;
379
380         while ((ret = make_cstp_connection(vpninfo))) {
381                 if (timeout <= 0)
382                         return ret;
383                 vpninfo->progress(vpninfo, PRG_INFO,
384                                   "sleep %ds, remaining timeout %ds\n",
385                                   interval, timeout);
386                 sleep(interval);
387                 if (killed)
388                         return 1;
389                 timeout -= interval;
390                 interval += vpninfo->reconnect_interval;
391                 if (interval > RECONNECT_INTERVAL_MAX)
392                         interval = RECONNECT_INTERVAL_MAX;
393         }
394         return 0;
395 }
396
397 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
398 {
399         struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
400
401         if (!new)
402                 return -ENOMEM;
403
404         new->next = NULL;
405
406         vpninfo->inflate_strm.next_in = buf;
407         vpninfo->inflate_strm.avail_in = len - 4;
408
409         vpninfo->inflate_strm.next_out = new->data;
410         vpninfo->inflate_strm.avail_out = vpninfo->mtu;
411         vpninfo->inflate_strm.total_out = 0;
412
413         if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
414                 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
415                 free(new);
416                 return -EINVAL;
417         }
418
419         new->len = vpninfo->inflate_strm.total_out;
420
421         vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
422                                            new->data, new->len);
423
424         if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
425                 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
426         }
427
428         vpninfo->progress(vpninfo, PRG_TRACE,
429                           "Received compressed data packet of %ld bytes\n",
430                           vpninfo->inflate_strm.total_out);
431
432         queue_packet(&vpninfo->incoming_queue, new);
433         return 0;
434 }
435
436 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
437 {
438         unsigned char buf[16384];
439         int len, ret;
440         int work_done = 0;
441
442         /* FIXME: The poll() handling here is fairly simplistic. Actually,
443            if the SSL connection stalls it could return a WANT_WRITE error
444            on _either_ of the SSL_read() or SSL_write() calls. In that case,
445            we should probably remove POLLIN from the events we're looking for,
446            and add POLLOUT. As it is, though, it'll just chew CPU time in that
447            fairly unlikely situation, until the write backlog clears. */
448         while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
449                 int payload_len;
450
451                 if (buf[0] != 'S' || buf[1] != 'T' ||
452                     buf[2] != 'F' || buf[3] != 1 || buf[7])
453                         goto unknown_pkt;
454
455                 payload_len = (buf[4] << 8) + buf[5];
456                 if (len != 8 + payload_len) {
457                         vpninfo->progress(vpninfo, PRG_ERR,
458                                           "Unexpected packet length. SSL_read returned %d but packet is\n",
459                                           len);
460                         vpninfo->progress(vpninfo, PRG_ERR,
461                                           "%02x %02x %02x %02x %02x %02x %02x %02x\n",
462                                           buf[0], buf[1], buf[2], buf[3],
463                                           buf[4], buf[5], buf[6], buf[7]);
464                         continue;
465                 }
466                 vpninfo->ssl_times.last_rx = time(NULL);
467                 switch(buf[6]) {
468                 case AC_PKT_DPD_OUT:
469                         vpninfo->progress(vpninfo, PRG_TRACE,
470                                           "Got CSTP DPD request\n");
471                         vpninfo->owe_ssl_dpd_response = 1;
472                         continue;
473
474                 case AC_PKT_DPD_RESP:
475                         vpninfo->progress(vpninfo, PRG_TRACE,
476                                           "Got CSTP DPD response\n");
477                         continue;
478
479                 case AC_PKT_KEEPALIVE:
480                         vpninfo->progress(vpninfo, PRG_TRACE,
481                                           "Got CSTP Keepalive\n");
482                         continue;
483
484                 case AC_PKT_DATA:
485                         vpninfo->progress(vpninfo, PRG_TRACE,
486                                           "Received uncompressed data packet of %d bytes\n",
487                                           payload_len);
488                         queue_new_packet(&vpninfo->incoming_queue, buf + 8,
489                                          payload_len);
490                         work_done = 1;
491                         continue;
492
493                 case AC_PKT_DISCONN: {
494                         int i;
495                         for (i = 0; i < payload_len; i++) {
496                                 if (!isprint(buf[payload_len + 8 + i]))
497                                         buf[payload_len + 8 + i] = '.';
498                         }
499                         buf[payload_len + 8] = 0;
500                         vpninfo->progress(vpninfo, PRG_ERR,
501                                           "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
502                         vpninfo->quit_reason = "Server request";
503                         return 1;
504                 }
505                 case AC_PKT_COMPRESSED:
506                         if (!vpninfo->deflate) {
507                                 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
508                                 goto unknown_pkt;
509                         }
510                         inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
511                         work_done = 1;
512                         continue;
513
514                 case AC_PKT_TERM_SERVER:
515                         vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
516                         vpninfo->quit_reason = "Server request";
517                         return 1;
518                 }
519
520         unknown_pkt:
521                 vpninfo->progress(vpninfo, PRG_ERR,
522                                   "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
523                                   buf[0], buf[1], buf[2], buf[3],
524                                   buf[4], buf[5], buf[6], buf[7]);
525                 vpninfo->quit_reason = "Unknown packet received";
526                 return 1;
527         }
528
529         ret = SSL_get_error(vpninfo->https_ssl, len);
530         if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
531                 vpninfo->progress(vpninfo, PRG_ERR,
532                                   "SSL read error %d (server probably closed connection); reconnecting.\n",
533                                   ret);
534                         goto do_reconnect;
535         }
536
537
538         /* If SSL_write() fails we are expected to try again. With exactly
539            the same data, at exactly the same location. So we keep the
540            packet we had before.... */
541         if (vpninfo->current_ssl_pkt) {
542         handle_outgoing:
543                 vpninfo->ssl_times.last_tx = time(NULL);
544                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
545                 ret = SSL_write(vpninfo->https_ssl,
546                                 vpninfo->current_ssl_pkt->hdr,
547                                 vpninfo->current_ssl_pkt->len + 8);
548                 if (ret <= 0) {
549                         ret = SSL_get_error(vpninfo->https_ssl, ret);
550                         switch (ret) {
551                         case SSL_ERROR_WANT_WRITE:
552                                 /* Waiting for the socket to become writable -- it's
553                                    probably stalled, and/or the buffers are full */
554                                 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
555
556                         case SSL_ERROR_WANT_READ:
557                                 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
558                                         goto peer_dead;
559                                 return work_done;
560                         default:
561                                 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
562                                 report_ssl_errors(vpninfo);
563                                 goto do_reconnect;
564                         }
565                 }
566                 if (ret != vpninfo->current_ssl_pkt->len + 8) {
567                         vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
568                                 vpninfo->current_ssl_pkt->len + 8, ret);
569                         vpninfo->quit_reason = "Internal error";
570                         return 1;
571                 }
572                 /* Don't free the 'special' packets */
573                 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
574                     vpninfo->current_ssl_pkt != &dpd_pkt &&
575                     vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
576                     vpninfo->current_ssl_pkt != &keepalive_pkt)
577                         free(vpninfo->current_ssl_pkt);
578
579                 vpninfo->current_ssl_pkt = NULL;
580         }
581
582         if (vpninfo->owe_ssl_dpd_response) {
583                 vpninfo->owe_ssl_dpd_response = 0;
584                 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
585                 goto handle_outgoing;
586         }
587
588         switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
589         case KA_REKEY:
590                 /* Not that this will ever happen; we don't even process
591                    the setting when we're asked for it. */
592                 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
593                 time(&vpninfo->ssl_times.last_rekey);
594                 work_done = 1;
595                 break;
596
597         case KA_DPD_DEAD:
598         peer_dead:
599                 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
600         do_reconnect:
601                 openconnect_close_https(vpninfo);
602
603                 /* It's already deflated in the old stream. Extremely
604                    non-trivial to reconstitute it; just throw it away */
605                 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
606                         vpninfo->current_ssl_pkt = NULL;
607
608                 if (cstp_reconnect(vpninfo)) {
609                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
610                         vpninfo->quit_reason = "CSTP reconnect failed";
611                         return 1;
612                 }
613                 /* I think we can leave DTLS to its own devices; when we reconnect
614                    with the same master secret, we do seem to get the same sessid */
615                 return 1;
616
617         case KA_DPD:
618                 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
619
620                 vpninfo->current_ssl_pkt = &dpd_pkt;
621                 goto handle_outgoing;
622
623         case KA_KEEPALIVE:
624                 /* No need to send an explicit keepalive
625                    if we have real data to send */
626                 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
627                         break;
628
629                 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
630
631                 vpninfo->current_ssl_pkt = &keepalive_pkt;
632                 goto handle_outgoing;
633
634         case KA_NONE:
635                 ;
636         }
637
638         /* Service outgoing packet queue, if no DTLS */
639         while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
640                 struct pkt *this = vpninfo->outgoing_queue;
641                 vpninfo->outgoing_queue = this->next;
642                 vpninfo->outgoing_qlen--;
643
644                 if (vpninfo->deflate) {
645                         unsigned char *adler;
646                         int ret;
647
648                         vpninfo->deflate_strm.next_in = this->data;
649                         vpninfo->deflate_strm.avail_in = this->len;
650                         vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
651                         vpninfo->deflate_strm.avail_out = 2040;
652                         vpninfo->deflate_strm.total_out = 0;
653
654                         ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
655                         if (ret) {
656                                 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
657                                 goto uncompr;
658                         }
659
660                         vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
661                         vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
662
663                         /* Add ongoing adler32 to tail of compressed packet */
664                         vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
665                                                            this->data, this->len);
666
667                         adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
668                         *(adler++) =  vpninfo->deflate_adler32 >> 24;
669                         *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
670                         *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
671                         *(adler)   =  vpninfo->deflate_adler32 & 0xff;
672
673                         vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
674
675                         vpninfo->progress(vpninfo, PRG_TRACE,
676                                           "Sending compressed data packet of %d bytes\n",
677                                           this->len);
678
679                         vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
680                 } else {
681                 uncompr:
682                         memcpy(this->hdr, data_hdr, 8);
683                         this->hdr[4] = this->len >> 8;
684                         this->hdr[5] = this->len & 0xff;
685
686                         vpninfo->progress(vpninfo, PRG_TRACE,
687                                           "Sending uncompressed data packet of %d bytes\n",
688                                           this->len);
689
690                         vpninfo->current_ssl_pkt = this;
691                 }
692                 goto handle_outgoing;
693         }
694
695         /* Work is not done if we just got rid of packets off the queue */
696         return work_done;
697 }
698
699 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
700 {
701         unsigned char *bye_pkt;
702         int reason_len;
703
704         /* already lost connection? */
705         if (!vpninfo->https_ssl)
706                 return 0;
707
708         reason_len = strlen(reason);
709         bye_pkt = malloc(reason_len + 9);
710         if (!bye_pkt)
711                 return -ENOMEM;
712
713         memcpy(bye_pkt, data_hdr, 8);
714         memcpy(bye_pkt + 9, reason, reason_len);
715
716         bye_pkt[4] = (reason_len + 1) >> 8;
717         bye_pkt[5] = (reason_len + 1) & 0xff;
718         bye_pkt[6] = AC_PKT_DISCONN;
719         bye_pkt[8] = 0xb0;
720
721         SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
722         free(bye_pkt);
723
724         vpninfo->progress(vpninfo, PRG_INFO,
725                           "Send BYE packet: %s\n", reason);
726
727         return 0;
728 }