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