Portability fixes for Solaris, *BSD
[platform/upstream/openconnect.git] / cstp.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 Intel Corporation.
5  * Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
6  *
7  * Author: David Woodhouse <dwmw2@infradead.org>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1, as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to:
20  *
21  *   Free Software Foundation, Inc.
22  *   51 Franklin Street, Fifth Floor,
23  *   Boston, MA 02110-1301 USA
24  */
25
26 #include <netdb.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <time.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39
40 #include <openssl/ssl.h>
41 #include <openssl/err.h>
42
43 #include "openconnect-internal.h"
44
45 /*
46  * Data packets are encapsulated in the SSL stream as follows:
47  *
48  * 0000: Magic "STF\x1"
49  * 0004: Big-endian 16-bit length (not including 8-byte header)
50  * 0006: Byte packet type (see openconnect-internal.h)
51  * 0008: data payload
52  */
53
54 static char data_hdr[8] = {
55         'S', 'T', 'F', 1,
56         0, 0,           /* Length */
57         AC_PKT_DATA,    /* Type */
58         0               /* Unknown */
59 };
60
61 static struct pkt keepalive_pkt = {
62         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
63 };
64
65 static struct pkt dpd_pkt = {
66         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
67 };
68
69 static struct pkt dpd_resp_pkt = {
70         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
71 };
72
73 static int  __attribute__ ((format (printf, 3, 4)))
74     buf_append(char *buf, int len, const char *fmt, ...)
75 {
76         int start = strlen(buf);
77         int ret;
78         va_list args;
79
80         if (start >= len)
81                 return 0;
82
83         va_start(args, fmt);
84         ret = vsnprintf(buf + start, len - start, fmt, args);
85         va_end(args);
86
87         if (ret > len)
88                 ret = len;
89
90         return ret;
91 }
92
93 /* Calculate MTU to request. Old servers simply use the X-CSTP-MTU: header,
94  * which represents the tunnel MTU, while new servers do calculations on the
95  * X-CSTP-Base-MTU: header which represents the cleartext MTU between client
96  * and server.
97  *
98  * If possible, the legacy MTU value should be the TCP MSS less 5 bytes of
99  * TLS and 8 bytes of CSTP overhead. We can get the MSS from either the
100  * TCP_INFO or TCP_MAXSEG sockopts.
101  *
102  * The base MTU comes from the TCP_INFO sockopt under Linux, but I don't know
103  * how to work it out on other systems. So leave it blank and do things the
104  * legacy way there. Contributions welcome...
105  *
106  * If we don't even have TCP_MAXSEG, then default to sending a legacy MTU of
107  * 1406 which is what we always used to do.
108  */
109 static void calculate_mtu(struct openconnect_info *vpninfo, int *base_mtu, int *mtu)
110 {
111         *mtu = vpninfo->mtu;
112         *base_mtu = vpninfo->basemtu;
113
114 #if defined(__linux__) && defined(TCP_INFO)
115         if (!*mtu || !*base_mtu) {
116                 struct tcp_info ti;
117                 socklen_t ti_size = sizeof(ti);
118
119                 if (!getsockopt(vpninfo->ssl_fd, IPPROTO_TCP, TCP_INFO,
120                                 &ti, &ti_size)) {
121                         vpn_progress(vpninfo, PRG_TRACE,
122                                      _("TCP_INFO rcv mss %d, snd mss %d, adv mss %d, pmtu %d\n"),
123                                      ti.tcpi_rcv_mss, ti.tcpi_snd_mss, ti.tcpi_advmss, ti.tcpi_pmtu);
124                         if (!*base_mtu) *base_mtu = ti.tcpi_pmtu;
125                         if (!*mtu) {
126                                 if (ti.tcpi_rcv_mss < ti.tcpi_snd_mss)
127                                         *mtu = ti.tcpi_rcv_mss - 13;
128                                 else
129                                         *mtu = ti.tcpi_snd_mss - 13;
130                         }
131                 }
132         }
133 #endif
134 #ifdef TCP_MAXSEG
135         if (!*mtu) {
136                 int mss;
137                 socklen_t mss_size = sizeof(mss);
138                 if (!getsockopt(vpninfo->ssl_fd, IPPROTO_TCP, TCP_MAXSEG,
139                                 &mss, &mss_size)) {
140                         vpn_progress(vpninfo, PRG_TRACE, _("TCP_MAXSEG %d\n"), mss);
141                         *mtu = mss - 13;
142                 }
143         }
144 #endif
145         if (!*mtu) {
146                 /* Default */
147                 *mtu = 1406;
148         }
149 }
150
151 static int start_cstp_connection(struct openconnect_info *vpninfo)
152 {
153         char buf[65536];
154         int i;
155         int retried = 0, sessid_found = 0;
156         struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
157         struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
158         struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
159         struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
160         const char *old_addr = vpninfo->vpn_addr;
161         const char *old_netmask = vpninfo->vpn_netmask;
162         const char *old_addr6 = vpninfo->vpn_addr6;
163         const char *old_netmask6 = vpninfo->vpn_netmask6;
164         struct split_include *inc;
165         int base_mtu, mtu;
166
167         /* Clear old options which will be overwritten */
168         vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
169         vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
170         vpninfo->cstp_options = vpninfo->dtls_options = NULL;
171         vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
172         vpninfo->banner = NULL;
173
174         for (i=0; i<3; i++)
175                 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
176
177         for (inc = vpninfo->split_includes; inc; ) {
178                 struct split_include *next = inc->next;
179                 free(inc);
180                 inc = next;
181         }
182         for (inc = vpninfo->split_excludes; inc; ) {
183                 struct split_include *next = inc->next;
184                 free(inc);
185                 inc = next;
186         }
187         for (inc = vpninfo->split_dns; inc; ) {
188                 struct split_include *next = inc->next;
189                 free(inc);
190                 inc = next;
191         }
192         vpninfo->split_dns = vpninfo->split_includes = vpninfo->split_excludes = NULL;
193
194         /* Create (new) random master key for DTLS connection, if needed */
195         if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
196             time(NULL) + 300 &&
197             openconnect_random(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret))) {
198                 fprintf(stderr, _("Failed to initialise DTLS secret\n"));
199                 exit(1);
200         }
201
202  retry:
203         calculate_mtu(vpninfo, &base_mtu, &mtu);
204
205         buf[0] = 0;
206         buf_append(buf, sizeof(buf), "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
207         buf_append(buf, sizeof(buf), "Host: %s\r\n", vpninfo->hostname);
208         buf_append(buf, sizeof(buf), "User-Agent: %s\r\n", vpninfo->useragent);
209         buf_append(buf, sizeof(buf), "Cookie: webvpn=%s\r\n", vpninfo->cookie);
210         buf_append(buf, sizeof(buf), "X-CSTP-Version: 1\r\n");
211         buf_append(buf, sizeof(buf), "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
212         if (vpninfo->deflate && i < sizeof(buf))
213                 buf_append(buf, sizeof(buf), "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
214         if (base_mtu)
215                 buf_append(buf, sizeof(buf), "X-CSTP-Base-MTU: %d\r\n", base_mtu);
216         buf_append(buf, sizeof(buf), "X-CSTP-MTU: %d\r\n", mtu);
217         buf_append(buf, sizeof(buf), "X-CSTP-Address-Type: %s\r\n",
218                                vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
219         buf_append(buf, sizeof(buf), "X-DTLS-Master-Secret: ");
220         for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
221                 buf_append(buf, sizeof(buf), "%02X", vpninfo->dtls_secret[i]);
222         buf_append(buf, sizeof(buf), "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
223                                vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
224
225         openconnect_SSL_write(vpninfo, buf, strlen(buf));
226
227         if ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
228                 if (i == -EINTR)
229                         return i;
230                 vpn_progress(vpninfo, PRG_ERR,
231                              _("Error fetching HTTPS response\n"));
232                 if (!retried) {
233                         retried = 1;
234                         openconnect_close_https(vpninfo, 0);
235
236                         if (openconnect_open_https(vpninfo)) {
237                                 vpn_progress(vpninfo, PRG_ERR,
238                                              _("Failed to open HTTPS connection to %s\n"),
239                                              vpninfo->hostname);
240                                 exit(1);
241                         }
242                         goto retry;
243                 }
244                 return -EINVAL;
245         }
246
247         if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
248                 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
249                         /* "Service Unavailable. Why? */
250                         const char *reason = "<unknown>";
251                         while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
252                                 if (!strncmp(buf, "X-Reason: ", 10)) {
253                                         reason = buf + 10;
254                                         break;
255                                 }
256                         }
257                         vpn_progress(vpninfo, PRG_ERR,
258                                      _("VPN service unavailable; reason: %s\n"),
259                                      reason);
260                         return -EINVAL;
261                 }
262                 vpn_progress(vpninfo, PRG_ERR,
263                              _("Got inappropriate HTTP CONNECT response: %s\n"),
264                              buf);
265                 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
266                         exit(2);
267                 return -EINVAL;
268         }
269
270         vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
271
272         /* We may have advertised it, but we only do it if the server agrees */
273         vpninfo->deflate = 0;
274
275         while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
276                 struct vpn_option *new_option;
277                 char *colon;
278
279                 if (i < 0)
280                         return i;
281
282                 colon = strchr(buf, ':');
283                 if (!colon)
284                         continue;
285
286                 *colon = 0;
287                 colon++;
288                 if (*colon == ' ')
289                         colon++;
290
291                 if (strncmp(buf, "X-DTLS-", 7) &&
292                     strncmp(buf, "X-CSTP-", 7))
293                         continue;
294
295                 new_option = malloc(sizeof(*new_option));
296                 if (!new_option) {
297                         vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
298                         return -ENOMEM;
299                 }
300                 new_option->option = strdup(buf);
301                 new_option->value = strdup(colon);
302                 new_option->next = NULL;
303
304                 if (!new_option->option || !new_option->value) {
305                         vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
306                         return -ENOMEM;
307                 }
308
309                 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
310
311                 if (!strncmp(buf, "X-DTLS-", 7)) {
312                         *next_dtls_option = new_option;
313                         next_dtls_option = &new_option->next;
314
315                         if (!strcmp(buf + 7, "MTU")) {
316                                 int mtu = atol(colon);
317                                 if (mtu > vpninfo->mtu)
318                                         vpninfo->mtu = mtu;
319                         } else if (!strcmp(buf + 7, "Session-ID")) {
320                                 if (strlen(colon) != 64) {
321                                         vpn_progress(vpninfo, PRG_ERR,
322                                                      _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
323                                                      colon);
324                                         vpninfo->dtls_attempt_period = 0;
325                                         return -EINVAL;
326                                 }
327                                 for (i = 0; i < 64; i += 2)
328                                         vpninfo->dtls_session_id[i/2] = unhex(colon + i);
329                                 sessid_found = 1;
330                                 time(&vpninfo->dtls_times.last_rekey);
331                         }
332                         continue;
333                 }
334                 /* CSTP options... */
335                 *next_cstp_option = new_option;
336                 next_cstp_option = &new_option->next;
337
338
339                 if (!strcmp(buf + 7, "Keepalive")) {
340                         vpninfo->ssl_times.keepalive = atol(colon);
341                 } else if (!strcmp(buf + 7, "DPD")) {
342                         int j = atol(colon);
343                         if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
344                                 vpninfo->ssl_times.dpd = j;
345                 } else if (!strcmp(buf + 7, "Rekey-Time")) {
346                         vpninfo->ssl_times.rekey = atol(colon);
347                 } else if (!strcmp(buf + 7, "Content-Encoding")) {
348                         if (!strcmp(colon, "deflate"))
349                                 vpninfo->deflate = 1;
350                         else {
351                                 vpn_progress(vpninfo, PRG_ERR,
352                                              _("Unknown CSTP-Content-Encoding %s\n"),
353                                              colon);
354                                 return -EINVAL;
355                         }
356                 } else if (!strcmp(buf + 7, "MTU")) {
357                         int mtu = atol(colon);
358                         if (mtu > vpninfo->mtu)
359                                 vpninfo->mtu = mtu;
360                 } else if (!strcmp(buf + 7, "Address")) {
361                         if (strchr(new_option->value, ':'))
362                                 vpninfo->vpn_addr6 = new_option->value;
363                         else
364                                 vpninfo->vpn_addr = new_option->value;
365                 } else if (!strcmp(buf + 7, "Netmask")) {
366                         if (strchr(new_option->value, ':'))
367                                 vpninfo->vpn_netmask6 = new_option->value;
368                         else
369                                 vpninfo->vpn_netmask = new_option->value;
370                 } else if (!strcmp(buf + 7, "DNS")) {
371                         int j;
372                         for (j = 0; j < 3; j++) {
373                                 if (!vpninfo->vpn_dns[j]) {
374                                         vpninfo->vpn_dns[j] = new_option->value;
375                                         break;
376                                 }
377                         }
378                 } else if (!strcmp(buf + 7, "NBNS")) {
379                         int j;
380                         for (j = 0; j < 3; j++) {
381                                 if (!vpninfo->vpn_nbns[j]) {
382                                         vpninfo->vpn_nbns[j] = new_option->value;
383                                         break;
384                                 }
385                         }
386                 } else if (!strcmp(buf + 7, "Default-Domain")) {
387                         vpninfo->vpn_domain = new_option->value;
388                 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
389                         vpninfo->vpn_proxy_pac = new_option->value;
390                 } else if (!strcmp(buf + 7, "Banner")) {
391                         vpninfo->banner = new_option->value;
392                 } else if (!strcmp(buf + 7, "Split-DNS")) {
393                         struct split_include *dns = malloc(sizeof(*dns));
394                         if (!dns)
395                                 continue;
396                         dns->route = new_option->value;
397                         dns->next = vpninfo->split_dns;
398                         vpninfo->split_dns = dns;
399                 } else if (!strcmp(buf + 7, "Split-Include")) {
400                         struct split_include *inc = malloc(sizeof(*inc));
401                         if (!inc)
402                                 continue;
403                         inc->route = new_option->value;
404                         inc->next = vpninfo->split_includes;
405                         vpninfo->split_includes = inc;
406                 } else if (!strcmp(buf + 7, "Split-Exclude")) {
407                         struct split_include *exc = malloc(sizeof(*exc));
408                         if (!exc)
409                                 continue;
410                         exc->route = new_option->value;
411                         exc->next = vpninfo->split_excludes;
412                         vpninfo->split_excludes = exc;
413                 }
414         }
415
416         if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
417                 vpn_progress(vpninfo, PRG_ERR,
418                              _("No IP address received. Aborting\n"));
419                 return -EINVAL;
420         }
421         if (old_addr) {
422                 if (strcmp(old_addr, vpninfo->vpn_addr)) {
423                         vpn_progress(vpninfo, PRG_ERR,
424                                      _("Reconnect gave different Legacy IP address (%s != %s)\n"),
425                                      vpninfo->vpn_addr, old_addr);
426                         return -EINVAL;
427                 }
428         }
429         if (old_netmask) {
430                 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
431                         vpn_progress(vpninfo, PRG_ERR,
432                                      _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
433                                      vpninfo->vpn_netmask, old_netmask);
434                         return -EINVAL;
435                 }
436         }
437         if (old_addr6) {
438                 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
439                         vpn_progress(vpninfo, PRG_ERR,
440                                      _("Reconnect gave different IPv6 address (%s != %s)\n"),
441                                      vpninfo->vpn_addr6, old_addr6);
442                         return -EINVAL;
443                 }
444         }
445         if (old_netmask6) {
446                 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
447                         vpn_progress(vpninfo, PRG_ERR,
448                                      _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
449                                      vpninfo->vpn_netmask6, old_netmask6);
450                         return -EINVAL;
451                 }
452         }
453
454         while (old_dtls_opts) {
455                 struct vpn_option *tmp = old_dtls_opts;
456                 old_dtls_opts = old_dtls_opts->next;
457                 free(tmp->value);
458                 free(tmp->option);
459                 free(tmp);
460         }
461         while (old_cstp_opts) {
462                 struct vpn_option *tmp = old_cstp_opts;
463                 old_cstp_opts = old_cstp_opts->next;
464                 free(tmp->value);
465                 free(tmp->option);
466                 free(tmp);
467         }
468         vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
469                      vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
470
471         if (vpninfo->select_nfds <= vpninfo->ssl_fd)
472                 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
473
474         FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
475         FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
476
477         if (!sessid_found)
478                 vpninfo->dtls_attempt_period = 0;
479
480         vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
481                 vpninfo->ssl_times.last_tx = time(NULL);
482         return 0;
483 }
484
485
486 int make_cstp_connection(struct openconnect_info *vpninfo)
487 {
488         int ret;
489
490         ret = openconnect_open_https(vpninfo);
491         if (ret)
492                 return ret;
493
494         if (vpninfo->deflate) {
495                 vpninfo->deflate_adler32 = 1;
496                 vpninfo->inflate_adler32 = 1;
497
498                 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
499                     deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
500                                  Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
501                         vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
502                         vpninfo->deflate = 0;
503                 }
504
505                 if (!vpninfo->deflate_pkt) {
506                         vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
507                         if (!vpninfo->deflate_pkt) {
508                                 vpn_progress(vpninfo, PRG_ERR,
509                                              _("Allocation of deflate buffer failed\n"));
510                                 inflateEnd(&vpninfo->inflate_strm);
511                                 deflateEnd(&vpninfo->deflate_strm);
512                                 vpninfo->deflate = 0;
513                         } else {
514                                 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
515                                 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
516                                 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
517                         }
518                 }
519         }
520
521         return start_cstp_connection(vpninfo);
522 }
523
524 int cstp_reconnect(struct openconnect_info *vpninfo)
525 {
526         int ret;
527         int timeout;
528         int interval;
529
530         openconnect_close_https(vpninfo, 0);
531
532         /* Requeue the original packet that was deflated */
533         if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
534                 vpninfo->current_ssl_pkt = NULL;
535                 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
536                 vpninfo->pending_deflated_pkt = NULL;
537         }
538         if (vpninfo->deflate) {
539                 inflateEnd(&vpninfo->inflate_strm);
540                 deflateEnd(&vpninfo->deflate_strm);
541         }
542         timeout = vpninfo->reconnect_timeout;
543         interval = vpninfo->reconnect_interval;
544
545         while ((ret = make_cstp_connection(vpninfo))) {
546                 if (timeout <= 0)
547                         return ret;
548                 vpn_progress(vpninfo, PRG_INFO,
549                              _("sleep %ds, remaining timeout %ds\n"),
550                              interval, timeout);
551                 sleep(interval);
552                 if (killed)
553                         return 1;
554                 timeout -= interval;
555                 interval += vpninfo->reconnect_interval;
556                 if (interval > RECONNECT_INTERVAL_MAX)
557                         interval = RECONNECT_INTERVAL_MAX;
558         }
559         script_config_tun(vpninfo, "reconnect");
560         return 0;
561 }
562
563 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
564                                     unsigned char *buf, int len)
565 {
566         struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
567         uint32_t pkt_sum;
568
569         if (!new)
570                 return -ENOMEM;
571
572         new->next = NULL;
573
574         vpninfo->inflate_strm.next_in = buf;
575         vpninfo->inflate_strm.avail_in = len - 4;
576
577         vpninfo->inflate_strm.next_out = new->data;
578         vpninfo->inflate_strm.avail_out = vpninfo->mtu;
579         vpninfo->inflate_strm.total_out = 0;
580
581         if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
582                 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
583                 free(new);
584                 return -EINVAL;
585         }
586
587         new->len = vpninfo->inflate_strm.total_out;
588
589         vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
590                                            new->data, new->len);
591
592         pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
593                 (buf[len - 3] << 16) | (buf[len - 4] << 24);
594
595         if (vpninfo->inflate_adler32 != pkt_sum) {
596                 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
597         }
598
599         vpn_progress(vpninfo, PRG_TRACE,
600                      _("Received compressed data packet of %ld bytes\n"),
601                      (long)vpninfo->inflate_strm.total_out);
602
603         queue_packet(&vpninfo->incoming_queue, new);
604         return 0;
605 }
606
607 #if defined (OPENCONNECT_OPENSSL)
608 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
609 {
610         int len, ret;
611
612         len = SSL_read(vpninfo->https_ssl, buf, maxlen);
613         if (len > 0)
614                 return len;
615
616         ret = SSL_get_error(vpninfo->https_ssl, len);
617         if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
618                 vpn_progress(vpninfo, PRG_ERR,
619                              _("SSL read error %d (server probably closed connection); reconnecting.\n"),
620                              ret);
621                 return -EIO;
622         }
623         return 0;
624 }
625
626 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
627 {
628         int ret;
629
630         ret = SSL_write(vpninfo->https_ssl, buf, buflen);
631         if (ret > 0)
632                 return ret;
633
634         ret = SSL_get_error(vpninfo->https_ssl, ret);
635         switch (ret) {
636         case SSL_ERROR_WANT_WRITE:
637                 /* Waiting for the socket to become writable -- it's
638                    probably stalled, and/or the buffers are full */
639                 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
640         case SSL_ERROR_WANT_READ:
641                 return 0;
642
643         default:
644                 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
645                 openconnect_report_ssl_errors(vpninfo);
646                 return -1;
647         }
648 }
649 #elif defined (OPENCONNECT_GNUTLS)
650 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
651 {
652         int ret;
653
654         ret = gnutls_record_recv(vpninfo->https_sess, buf, maxlen);
655         if (ret > 0)
656                 return ret;
657
658         if (ret != GNUTLS_E_AGAIN) {
659                 vpn_progress(vpninfo, PRG_ERR,
660                              _("SSL read error: %s; reconnecting.\n"),
661                              gnutls_strerror(ret));
662                 return -EIO;
663         }
664         return 0;
665 }
666
667 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
668 {
669         int ret;
670
671         ret = gnutls_record_send(vpninfo->https_sess, buf, buflen);
672         if (ret > 0)
673                 return ret;
674
675         if (ret == GNUTLS_E_AGAIN) {
676                 if (gnutls_record_get_direction(vpninfo->https_sess)) {
677                         /* Waiting for the socket to become writable -- it's
678                            probably stalled, and/or the buffers are full */
679                         FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
680                 }
681                 return 0;
682         }
683         vpn_progress(vpninfo, PRG_ERR, _("SSL send failed: %s\n"),
684                      gnutls_strerror(ret));
685         return -1;
686 }
687 #endif
688
689 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
690 {
691         unsigned char buf[16384];
692         int len, ret;
693         int work_done = 0;
694
695         /* FIXME: The poll() handling here is fairly simplistic. Actually,
696            if the SSL connection stalls it could return a WANT_WRITE error
697            on _either_ of the SSL_read() or SSL_write() calls. In that case,
698            we should probably remove POLLIN from the events we're looking for,
699            and add POLLOUT. As it is, though, it'll just chew CPU time in that
700            fairly unlikely situation, until the write backlog clears. */
701         while ( (len = cstp_read(vpninfo, buf, sizeof(buf))) > 0) {
702                 int payload_len;
703
704                 if (buf[0] != 'S' || buf[1] != 'T' ||
705                     buf[2] != 'F' || buf[3] != 1 || buf[7])
706                         goto unknown_pkt;
707
708                 payload_len = (buf[4] << 8) + buf[5];
709                 if (len != 8 + payload_len) {
710                         vpn_progress(vpninfo, PRG_ERR,
711                                      _("Unexpected packet length. SSL_read returned %d but packet is\n"),
712                                      len);
713                         vpn_progress(vpninfo, PRG_ERR,
714                                      "%02x %02x %02x %02x %02x %02x %02x %02x\n",
715                                      buf[0], buf[1], buf[2], buf[3],
716                                      buf[4], buf[5], buf[6], buf[7]);
717                         continue;
718                 }
719                 vpninfo->ssl_times.last_rx = time(NULL);
720                 switch(buf[6]) {
721                 case AC_PKT_DPD_OUT:
722                         vpn_progress(vpninfo, PRG_TRACE,
723                                      _("Got CSTP DPD request\n"));
724                         vpninfo->owe_ssl_dpd_response = 1;
725                         continue;
726
727                 case AC_PKT_DPD_RESP:
728                         vpn_progress(vpninfo, PRG_TRACE,
729                                      _("Got CSTP DPD response\n"));
730                         continue;
731
732                 case AC_PKT_KEEPALIVE:
733                         vpn_progress(vpninfo, PRG_TRACE,
734                                      _("Got CSTP Keepalive\n"));
735                         continue;
736
737                 case AC_PKT_DATA:
738                         vpn_progress(vpninfo, PRG_TRACE,
739                                      _("Received uncompressed data packet of %d bytes\n"),
740                                      payload_len);
741                         queue_new_packet(&vpninfo->incoming_queue, buf + 8,
742                                          payload_len);
743                         work_done = 1;
744                         continue;
745
746                 case AC_PKT_DISCONN: {
747                         int i;
748                         for (i = 0; i < payload_len; i++) {
749                                 if (!isprint(buf[payload_len + 8 + i]))
750                                         buf[payload_len + 8 + i] = '.';
751                         }
752                         buf[payload_len + 8] = 0;
753                         vpn_progress(vpninfo, PRG_ERR,
754                                      _("Received server disconnect: %02x '%s'\n"),
755                                      buf[8], buf + 9);
756                         vpninfo->quit_reason = "Server request";
757                         return 1;
758                 }
759                 case AC_PKT_COMPRESSED:
760                         if (!vpninfo->deflate) {
761                                 vpn_progress(vpninfo, PRG_ERR,
762                                              _("Compressed packet received in !deflate mode\n"));
763                                 goto unknown_pkt;
764                         }
765                         inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
766                         work_done = 1;
767                         continue;
768
769                 case AC_PKT_TERM_SERVER:
770                         vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
771                         vpninfo->quit_reason = "Server request";
772                         return 1;
773                 }
774
775         unknown_pkt:
776                 vpn_progress(vpninfo, PRG_ERR,
777                              _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
778                              buf[0], buf[1], buf[2], buf[3],
779                              buf[4], buf[5], buf[6], buf[7]);
780                 vpninfo->quit_reason = "Unknown packet received";
781                 return 1;
782         }
783         if (len < 0)
784                 goto do_reconnect;
785
786
787         /* If SSL_write() fails we are expected to try again. With exactly
788            the same data, at exactly the same location. So we keep the
789            packet we had before.... */
790         if (vpninfo->current_ssl_pkt) {
791         handle_outgoing:
792                 vpninfo->ssl_times.last_tx = time(NULL);
793                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
794
795                 ret = cstp_write(vpninfo,
796                                  vpninfo->current_ssl_pkt->hdr,
797                                  vpninfo->current_ssl_pkt->len + 8);
798                 
799                 if (ret < 0)
800                         goto do_reconnect;
801                 else if (!ret && ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
802                         goto peer_dead;
803
804                 if (ret != vpninfo->current_ssl_pkt->len + 8) {
805                         vpn_progress(vpninfo, PRG_ERR,
806                                      _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
807                                      vpninfo->current_ssl_pkt->len + 8, ret);
808                         vpninfo->quit_reason = "Internal error";
809                         return 1;
810                 }
811                 /* Don't free the 'special' packets */
812                 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
813                         free(vpninfo->pending_deflated_pkt);
814                 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
815                          vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
816                          vpninfo->current_ssl_pkt != &keepalive_pkt)
817                         free(vpninfo->current_ssl_pkt);
818
819                 vpninfo->current_ssl_pkt = NULL;
820         }
821
822         if (vpninfo->owe_ssl_dpd_response) {
823                 vpninfo->owe_ssl_dpd_response = 0;
824                 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
825                 goto handle_outgoing;
826         }
827
828         switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
829         case KA_REKEY:
830                 /* Not that this will ever happen; we don't even process
831                    the setting when we're asked for it. */
832                 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
833                 goto do_reconnect;
834                 break;
835
836         case KA_DPD_DEAD:
837         peer_dead:
838                 vpn_progress(vpninfo, PRG_ERR,
839                              _("CSTP Dead Peer Detection detected dead peer!\n"));
840         do_reconnect:
841                 if (cstp_reconnect(vpninfo)) {
842                         vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
843                         vpninfo->quit_reason = "CSTP reconnect failed";
844                         return 1;
845                 }
846                 /* I think we can leave DTLS to its own devices; when we reconnect
847                    with the same master secret, we do seem to get the same sessid */
848                 return 1;
849
850         case KA_DPD:
851                 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
852
853                 vpninfo->current_ssl_pkt = &dpd_pkt;
854                 goto handle_outgoing;
855
856         case KA_KEEPALIVE:
857                 /* No need to send an explicit keepalive
858                    if we have real data to send */
859                 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
860                         break;
861
862                 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
863
864                 vpninfo->current_ssl_pkt = &keepalive_pkt;
865                 goto handle_outgoing;
866
867         case KA_NONE:
868                 ;
869         }
870
871         /* Service outgoing packet queue, if no DTLS */
872         while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
873                 struct pkt *this = vpninfo->outgoing_queue;
874                 vpninfo->outgoing_queue = this->next;
875                 vpninfo->outgoing_qlen--;
876
877                 if (vpninfo->deflate) {
878                         unsigned char *adler;
879                         int ret;
880
881                         vpninfo->deflate_strm.next_in = this->data;
882                         vpninfo->deflate_strm.avail_in = this->len;
883                         vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
884                         vpninfo->deflate_strm.avail_out = 2040;
885                         vpninfo->deflate_strm.total_out = 0;
886
887                         ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
888                         if (ret) {
889                                 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
890                                 goto uncompr;
891                         }
892
893                         vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
894                         vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
895
896                         /* Add ongoing adler32 to tail of compressed packet */
897                         vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
898                                                            this->data, this->len);
899
900                         adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
901                         *(adler++) =  vpninfo->deflate_adler32 >> 24;
902                         *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
903                         *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
904                         *(adler)   =  vpninfo->deflate_adler32 & 0xff;
905
906                         vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
907
908                         vpn_progress(vpninfo, PRG_TRACE,
909                                      _("Sending compressed data packet of %d bytes\n"),
910                                      this->len);
911
912                         vpninfo->pending_deflated_pkt = this;
913                         vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
914                 } else {
915                 uncompr:
916                         memcpy(this->hdr, data_hdr, 8);
917                         this->hdr[4] = this->len >> 8;
918                         this->hdr[5] = this->len & 0xff;
919
920                         vpn_progress(vpninfo, PRG_TRACE,
921                                      _("Sending uncompressed data packet of %d bytes\n"),
922                                      this->len);
923
924                         vpninfo->current_ssl_pkt = this;
925                 }
926                 goto handle_outgoing;
927         }
928
929         /* Work is not done if we just got rid of packets off the queue */
930         return work_done;
931 }
932
933 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
934 {
935         unsigned char *bye_pkt;
936         int reason_len;
937
938         /* already lost connection? */
939 #if defined (OPENCONNECT_OPENSSL)
940         if (!vpninfo->https_ssl)
941                 return 0;
942 #elif defined (OPENCONNECT_GNUTLS)
943         if (!vpninfo->https_sess)
944                 return 0;
945 #endif
946
947         reason_len = strlen(reason);
948         bye_pkt = malloc(reason_len + 9);
949         if (!bye_pkt)
950                 return -ENOMEM;
951
952         memcpy(bye_pkt, data_hdr, 8);
953         memcpy(bye_pkt + 9, reason, reason_len);
954
955         bye_pkt[4] = (reason_len + 1) >> 8;
956         bye_pkt[5] = (reason_len + 1) & 0xff;
957         bye_pkt[6] = AC_PKT_DISCONN;
958         bye_pkt[8] = 0xb0;
959
960         vpn_progress(vpninfo, PRG_INFO,
961                      _("Send BYE packet: %s\n"), reason);
962
963         cstp_write(vpninfo, bye_pkt, reason_len + 9);
964         free(bye_pkt);
965
966         return 0;
967 }