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