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