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