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