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