2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2012 Intel Corporation.
5 * Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
7 * Author: David Woodhouse <dwmw2@infradead.org>
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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to:
21 * Free Software Foundation, Inc.
22 * 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301 USA
35 #include <netinet/tcp.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
39 #include <openssl/ssl.h>
40 #include <openssl/err.h>
42 #include "openconnect-internal.h"
45 * Data packets are encapsulated in the SSL stream as follows:
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)
53 static char data_hdr[8] = {
56 AC_PKT_DATA, /* Type */
60 static struct pkt keepalive_pkt = {
61 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
64 static struct pkt dpd_pkt = {
65 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
68 static struct pkt dpd_resp_pkt = {
69 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
72 static int __attribute__ ((format (printf, 3, 4)))
73 buf_append(char *buf, int len, const char *fmt, ...)
75 int start = strlen(buf);
83 ret = vsnprintf(buf + start, len - start, fmt, args);
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
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.
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...
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.
108 static void calculate_mtu(struct openconnect_info *vpninfo, int *base_mtu, int *mtu)
111 *base_mtu = vpninfo->basemtu;
114 if (!*mtu || !*base_mtu) {
116 socklen_t ti_size = sizeof(ti);
118 if (!getsockopt(vpninfo->ssl_fd, SOL_TCP, TCP_INFO,
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;
125 if (ti.tcpi_rcv_mss < ti.tcpi_snd_mss)
126 *mtu = ti.tcpi_rcv_mss - 13;
128 *mtu = ti.tcpi_snd_mss - 13;
136 socklen_t mss_size = sizeof(mss);
137 if (!getsockopt(vpninfo->ssl_fd, SOL_TCP, TCP_MAXSEG,
139 vpn_progress(vpninfo, PRG_TRACE, _("TCP_MAXSEG %d\n"), mss);
150 static int start_cstp_connection(struct openconnect_info *vpninfo)
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;
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;
174 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
176 for (inc = vpninfo->split_includes; inc; ) {
177 struct split_include *next = inc->next;
181 for (inc = vpninfo->split_excludes; inc; ) {
182 struct split_include *next = inc->next;
186 for (inc = vpninfo->split_dns; inc; ) {
187 struct split_include *next = inc->next;
191 vpninfo->split_dns = vpninfo->split_includes = vpninfo->split_excludes = NULL;
193 /* Create (new) random master key for DTLS connection, if needed */
194 if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
196 openconnect_random(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret))) {
197 fprintf(stderr, _("Failed to initialise DTLS secret\n"));
202 calculate_mtu(vpninfo, &base_mtu, &mtu);
205 buf_append(buf, sizeof(buf), "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
206 buf_append(buf, sizeof(buf), "Host: %s\r\n", vpninfo->hostname);
207 buf_append(buf, sizeof(buf), "User-Agent: %s\r\n", vpninfo->useragent);
208 buf_append(buf, sizeof(buf), "Cookie: webvpn=%s\r\n", vpninfo->cookie);
209 buf_append(buf, sizeof(buf), "X-CSTP-Version: 1\r\n");
210 buf_append(buf, sizeof(buf), "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
211 if (vpninfo->deflate && i < sizeof(buf))
212 buf_append(buf, sizeof(buf), "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
214 buf_append(buf, sizeof(buf), "X-CSTP-Base-MTU: %d\r\n", base_mtu);
215 buf_append(buf, sizeof(buf), "X-CSTP-MTU: %d\r\n", mtu);
216 buf_append(buf, sizeof(buf), "X-CSTP-Address-Type: %s\r\n",
217 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
218 buf_append(buf, sizeof(buf), "X-DTLS-Master-Secret: ");
219 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
220 buf_append(buf, sizeof(buf), "%02X", vpninfo->dtls_secret[i]);
221 buf_append(buf, sizeof(buf), "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
222 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
224 openconnect_SSL_write(vpninfo, buf, strlen(buf));
226 if ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
229 vpn_progress(vpninfo, PRG_ERR,
230 _("Error fetching HTTPS response\n"));
233 openconnect_close_https(vpninfo, 0);
235 if (openconnect_open_https(vpninfo)) {
236 vpn_progress(vpninfo, PRG_ERR,
237 _("Failed to open HTTPS connection to %s\n"),
246 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
247 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
248 /* "Service Unavailable. Why? */
249 const char *reason = "<unknown>";
250 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
251 if (!strncmp(buf, "X-Reason: ", 10)) {
256 vpn_progress(vpninfo, PRG_ERR,
257 _("VPN service unavailable; reason: %s\n"),
261 vpn_progress(vpninfo, PRG_ERR,
262 _("Got inappropriate HTTP CONNECT response: %s\n"),
264 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
269 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
271 /* We may have advertised it, but we only do it if the server agrees */
272 vpninfo->deflate = 0;
274 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
275 struct vpn_option *new_option;
281 colon = strchr(buf, ':');
290 if (strncmp(buf, "X-DTLS-", 7) &&
291 strncmp(buf, "X-CSTP-", 7))
294 new_option = malloc(sizeof(*new_option));
296 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
299 new_option->option = strdup(buf);
300 new_option->value = strdup(colon);
301 new_option->next = NULL;
303 if (!new_option->option || !new_option->value) {
304 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
308 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
310 if (!strncmp(buf, "X-DTLS-", 7)) {
311 *next_dtls_option = new_option;
312 next_dtls_option = &new_option->next;
314 if (!strcmp(buf + 7, "MTU")) {
315 int mtu = atol(colon);
316 if (mtu > vpninfo->mtu)
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"),
323 vpninfo->dtls_attempt_period = 0;
326 for (i = 0; i < 64; i += 2)
327 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
329 time(&vpninfo->dtls_times.last_rekey);
333 /* CSTP options... */
334 *next_cstp_option = new_option;
335 next_cstp_option = &new_option->next;
338 if (!strcmp(buf + 7, "Keepalive")) {
339 vpninfo->ssl_times.keepalive = atol(colon);
340 } else if (!strcmp(buf + 7, "DPD")) {
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;
350 vpn_progress(vpninfo, PRG_ERR,
351 _("Unknown CSTP-Content-Encoding %s\n"),
355 } else if (!strcmp(buf + 7, "MTU")) {
356 int mtu = atol(colon);
357 if (mtu > vpninfo->mtu)
359 } else if (!strcmp(buf + 7, "Address")) {
360 if (strchr(new_option->value, ':'))
361 vpninfo->vpn_addr6 = new_option->value;
363 vpninfo->vpn_addr = new_option->value;
364 } else if (!strcmp(buf + 7, "Netmask")) {
365 if (strchr(new_option->value, ':'))
366 vpninfo->vpn_netmask6 = new_option->value;
368 vpninfo->vpn_netmask = new_option->value;
369 } else if (!strcmp(buf + 7, "DNS")) {
371 for (j = 0; j < 3; j++) {
372 if (!vpninfo->vpn_dns[j]) {
373 vpninfo->vpn_dns[j] = new_option->value;
377 } else if (!strcmp(buf + 7, "NBNS")) {
379 for (j = 0; j < 3; j++) {
380 if (!vpninfo->vpn_nbns[j]) {
381 vpninfo->vpn_nbns[j] = new_option->value;
385 } else if (!strcmp(buf + 7, "Default-Domain")) {
386 vpninfo->vpn_domain = new_option->value;
387 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
388 vpninfo->vpn_proxy_pac = new_option->value;
389 } else if (!strcmp(buf + 7, "Banner")) {
390 vpninfo->banner = new_option->value;
391 } else if (!strcmp(buf + 7, "Split-DNS")) {
392 struct split_include *dns = malloc(sizeof(*dns));
395 dns->route = new_option->value;
396 dns->next = vpninfo->split_dns;
397 vpninfo->split_dns = dns;
398 } else if (!strcmp(buf + 7, "Split-Include")) {
399 struct split_include *inc = malloc(sizeof(*inc));
402 inc->route = new_option->value;
403 inc->next = vpninfo->split_includes;
404 vpninfo->split_includes = inc;
405 } else if (!strcmp(buf + 7, "Split-Exclude")) {
406 struct split_include *exc = malloc(sizeof(*exc));
409 exc->route = new_option->value;
410 exc->next = vpninfo->split_excludes;
411 vpninfo->split_excludes = exc;
415 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
416 vpn_progress(vpninfo, PRG_ERR,
417 _("No IP address received. Aborting\n"));
421 if (strcmp(old_addr, vpninfo->vpn_addr)) {
422 vpn_progress(vpninfo, PRG_ERR,
423 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
424 vpninfo->vpn_addr, old_addr);
429 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
430 vpn_progress(vpninfo, PRG_ERR,
431 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
432 vpninfo->vpn_netmask, old_netmask);
437 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
438 vpn_progress(vpninfo, PRG_ERR,
439 _("Reconnect gave different IPv6 address (%s != %s)\n"),
440 vpninfo->vpn_addr6, old_addr6);
445 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
446 vpn_progress(vpninfo, PRG_ERR,
447 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
448 vpninfo->vpn_netmask6, old_netmask6);
453 while (old_dtls_opts) {
454 struct vpn_option *tmp = old_dtls_opts;
455 old_dtls_opts = old_dtls_opts->next;
460 while (old_cstp_opts) {
461 struct vpn_option *tmp = old_cstp_opts;
462 old_cstp_opts = old_cstp_opts->next;
467 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
468 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
470 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
471 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
473 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
474 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
477 vpninfo->dtls_attempt_period = 0;
479 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
480 vpninfo->ssl_times.last_tx = time(NULL);
485 int make_cstp_connection(struct openconnect_info *vpninfo)
489 ret = openconnect_open_https(vpninfo);
493 if (vpninfo->deflate) {
494 vpninfo->deflate_adler32 = 1;
495 vpninfo->inflate_adler32 = 1;
497 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
498 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
499 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
500 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
501 vpninfo->deflate = 0;
504 if (!vpninfo->deflate_pkt) {
505 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
506 if (!vpninfo->deflate_pkt) {
507 vpn_progress(vpninfo, PRG_ERR,
508 _("Allocation of deflate buffer failed\n"));
509 inflateEnd(&vpninfo->inflate_strm);
510 deflateEnd(&vpninfo->deflate_strm);
511 vpninfo->deflate = 0;
513 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
514 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
515 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
520 return start_cstp_connection(vpninfo);
523 int cstp_reconnect(struct openconnect_info *vpninfo)
529 openconnect_close_https(vpninfo, 0);
531 /* Requeue the original packet that was deflated */
532 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
533 vpninfo->current_ssl_pkt = NULL;
534 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
535 vpninfo->pending_deflated_pkt = NULL;
537 if (vpninfo->deflate) {
538 inflateEnd(&vpninfo->inflate_strm);
539 deflateEnd(&vpninfo->deflate_strm);
541 timeout = vpninfo->reconnect_timeout;
542 interval = vpninfo->reconnect_interval;
544 while ((ret = make_cstp_connection(vpninfo))) {
547 vpn_progress(vpninfo, PRG_INFO,
548 _("sleep %ds, remaining timeout %ds\n"),
554 interval += vpninfo->reconnect_interval;
555 if (interval > RECONNECT_INTERVAL_MAX)
556 interval = RECONNECT_INTERVAL_MAX;
558 script_config_tun(vpninfo, "reconnect");
562 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
563 unsigned char *buf, int len)
565 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
573 vpninfo->inflate_strm.next_in = buf;
574 vpninfo->inflate_strm.avail_in = len - 4;
576 vpninfo->inflate_strm.next_out = new->data;
577 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
578 vpninfo->inflate_strm.total_out = 0;
580 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
581 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
586 new->len = vpninfo->inflate_strm.total_out;
588 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
589 new->data, new->len);
591 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
592 (buf[len - 3] << 16) | (buf[len - 4] << 24);
594 if (vpninfo->inflate_adler32 != pkt_sum) {
595 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
598 vpn_progress(vpninfo, PRG_TRACE,
599 _("Received compressed data packet of %ld bytes\n"),
600 (long)vpninfo->inflate_strm.total_out);
602 queue_packet(&vpninfo->incoming_queue, new);
606 #if defined (OPENCONNECT_OPENSSL)
607 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
611 len = SSL_read(vpninfo->https_ssl, buf, maxlen);
615 ret = SSL_get_error(vpninfo->https_ssl, len);
616 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
617 vpn_progress(vpninfo, PRG_ERR,
618 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
625 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
629 ret = SSL_write(vpninfo->https_ssl, buf, buflen);
633 ret = SSL_get_error(vpninfo->https_ssl, ret);
635 case SSL_ERROR_WANT_WRITE:
636 /* Waiting for the socket to become writable -- it's
637 probably stalled, and/or the buffers are full */
638 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
639 case SSL_ERROR_WANT_READ:
643 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
644 openconnect_report_ssl_errors(vpninfo);
648 #elif defined (OPENCONNECT_GNUTLS)
649 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
653 ret = gnutls_record_recv(vpninfo->https_sess, buf, maxlen);
657 if (ret != GNUTLS_E_AGAIN) {
658 vpn_progress(vpninfo, PRG_ERR,
659 _("SSL read error: %s; reconnecting.\n"),
660 gnutls_strerror(ret));
666 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
670 ret = gnutls_record_send(vpninfo->https_sess, buf, buflen);
674 if (ret == GNUTLS_E_AGAIN) {
675 if (gnutls_record_get_direction(vpninfo->https_sess)) {
676 /* Waiting for the socket to become writable -- it's
677 probably stalled, and/or the buffers are full */
678 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
682 vpn_progress(vpninfo, PRG_ERR, _("SSL send failed: %s\n"),
683 gnutls_strerror(ret));
688 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
690 unsigned char buf[16384];
694 /* FIXME: The poll() handling here is fairly simplistic. Actually,
695 if the SSL connection stalls it could return a WANT_WRITE error
696 on _either_ of the SSL_read() or SSL_write() calls. In that case,
697 we should probably remove POLLIN from the events we're looking for,
698 and add POLLOUT. As it is, though, it'll just chew CPU time in that
699 fairly unlikely situation, until the write backlog clears. */
700 while ( (len = cstp_read(vpninfo, buf, sizeof(buf))) > 0) {
703 if (buf[0] != 'S' || buf[1] != 'T' ||
704 buf[2] != 'F' || buf[3] != 1 || buf[7])
707 payload_len = (buf[4] << 8) + buf[5];
708 if (len != 8 + payload_len) {
709 vpn_progress(vpninfo, PRG_ERR,
710 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
712 vpn_progress(vpninfo, PRG_ERR,
713 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
714 buf[0], buf[1], buf[2], buf[3],
715 buf[4], buf[5], buf[6], buf[7]);
718 vpninfo->ssl_times.last_rx = time(NULL);
721 vpn_progress(vpninfo, PRG_TRACE,
722 _("Got CSTP DPD request\n"));
723 vpninfo->owe_ssl_dpd_response = 1;
726 case AC_PKT_DPD_RESP:
727 vpn_progress(vpninfo, PRG_TRACE,
728 _("Got CSTP DPD response\n"));
731 case AC_PKT_KEEPALIVE:
732 vpn_progress(vpninfo, PRG_TRACE,
733 _("Got CSTP Keepalive\n"));
737 vpn_progress(vpninfo, PRG_TRACE,
738 _("Received uncompressed data packet of %d bytes\n"),
740 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
745 case AC_PKT_DISCONN: {
747 for (i = 0; i < payload_len; i++) {
748 if (!isprint(buf[payload_len + 8 + i]))
749 buf[payload_len + 8 + i] = '.';
751 buf[payload_len + 8] = 0;
752 vpn_progress(vpninfo, PRG_ERR,
753 _("Received server disconnect: %02x '%s'\n"),
755 vpninfo->quit_reason = "Server request";
758 case AC_PKT_COMPRESSED:
759 if (!vpninfo->deflate) {
760 vpn_progress(vpninfo, PRG_ERR,
761 _("Compressed packet received in !deflate mode\n"));
764 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
768 case AC_PKT_TERM_SERVER:
769 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
770 vpninfo->quit_reason = "Server request";
775 vpn_progress(vpninfo, PRG_ERR,
776 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
777 buf[0], buf[1], buf[2], buf[3],
778 buf[4], buf[5], buf[6], buf[7]);
779 vpninfo->quit_reason = "Unknown packet received";
786 /* If SSL_write() fails we are expected to try again. With exactly
787 the same data, at exactly the same location. So we keep the
788 packet we had before.... */
789 if (vpninfo->current_ssl_pkt) {
791 vpninfo->ssl_times.last_tx = time(NULL);
792 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
794 ret = cstp_write(vpninfo,
795 vpninfo->current_ssl_pkt->hdr,
796 vpninfo->current_ssl_pkt->len + 8);
800 else if (!ret && ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
803 if (ret != vpninfo->current_ssl_pkt->len + 8) {
804 vpn_progress(vpninfo, PRG_ERR,
805 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
806 vpninfo->current_ssl_pkt->len + 8, ret);
807 vpninfo->quit_reason = "Internal error";
810 /* Don't free the 'special' packets */
811 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
812 free(vpninfo->pending_deflated_pkt);
813 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
814 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
815 vpninfo->current_ssl_pkt != &keepalive_pkt)
816 free(vpninfo->current_ssl_pkt);
818 vpninfo->current_ssl_pkt = NULL;
821 if (vpninfo->owe_ssl_dpd_response) {
822 vpninfo->owe_ssl_dpd_response = 0;
823 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
824 goto handle_outgoing;
827 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
829 /* Not that this will ever happen; we don't even process
830 the setting when we're asked for it. */
831 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
837 vpn_progress(vpninfo, PRG_ERR,
838 _("CSTP Dead Peer Detection detected dead peer!\n"));
840 if (cstp_reconnect(vpninfo)) {
841 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
842 vpninfo->quit_reason = "CSTP reconnect failed";
845 /* I think we can leave DTLS to its own devices; when we reconnect
846 with the same master secret, we do seem to get the same sessid */
850 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
852 vpninfo->current_ssl_pkt = &dpd_pkt;
853 goto handle_outgoing;
856 /* No need to send an explicit keepalive
857 if we have real data to send */
858 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
861 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
863 vpninfo->current_ssl_pkt = &keepalive_pkt;
864 goto handle_outgoing;
870 /* Service outgoing packet queue, if no DTLS */
871 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
872 struct pkt *this = vpninfo->outgoing_queue;
873 vpninfo->outgoing_queue = this->next;
874 vpninfo->outgoing_qlen--;
876 if (vpninfo->deflate) {
877 unsigned char *adler;
880 vpninfo->deflate_strm.next_in = this->data;
881 vpninfo->deflate_strm.avail_in = this->len;
882 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
883 vpninfo->deflate_strm.avail_out = 2040;
884 vpninfo->deflate_strm.total_out = 0;
886 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
888 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
892 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
893 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
895 /* Add ongoing adler32 to tail of compressed packet */
896 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
897 this->data, this->len);
899 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
900 *(adler++) = vpninfo->deflate_adler32 >> 24;
901 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
902 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
903 *(adler) = vpninfo->deflate_adler32 & 0xff;
905 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
907 vpn_progress(vpninfo, PRG_TRACE,
908 _("Sending compressed data packet of %d bytes\n"),
911 vpninfo->pending_deflated_pkt = this;
912 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
915 memcpy(this->hdr, data_hdr, 8);
916 this->hdr[4] = this->len >> 8;
917 this->hdr[5] = this->len & 0xff;
919 vpn_progress(vpninfo, PRG_TRACE,
920 _("Sending uncompressed data packet of %d bytes\n"),
923 vpninfo->current_ssl_pkt = this;
925 goto handle_outgoing;
928 /* Work is not done if we just got rid of packets off the queue */
932 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
934 unsigned char *bye_pkt;
937 /* already lost connection? */
938 #if defined (OPENCONNECT_OPENSSL)
939 if (!vpninfo->https_ssl)
941 #elif defined (OPENCONNECT_GNUTLS)
942 if (!vpninfo->https_sess)
946 reason_len = strlen(reason);
947 bye_pkt = malloc(reason_len + 9);
951 memcpy(bye_pkt, data_hdr, 8);
952 memcpy(bye_pkt + 9, reason, reason_len);
954 bye_pkt[4] = (reason_len + 1) >> 8;
955 bye_pkt[5] = (reason_len + 1) & 0xff;
956 bye_pkt[6] = AC_PKT_DISCONN;
959 vpn_progress(vpninfo, PRG_INFO,
960 _("Send BYE packet: %s\n"), reason);
962 cstp_write(vpninfo, bye_pkt, reason_len + 9);