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