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