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 <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
40 #include <openssl/ssl.h>
41 #include <openssl/err.h>
43 #include "openconnect-internal.h"
46 * Data packets are encapsulated in the SSL stream as follows:
48 * 0000: Magic "STF\x1"
49 * 0004: Big-endian 16-bit length (not including 8-byte header)
50 * 0006: Byte packet type (see openconnect-internal.h)
54 static char data_hdr[8] = {
57 AC_PKT_DATA, /* Type */
61 static struct pkt keepalive_pkt = {
62 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
65 static struct pkt dpd_pkt = {
66 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
69 static struct pkt dpd_resp_pkt = {
70 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
73 static int __attribute__ ((format (printf, 3, 4)))
74 buf_append(char *buf, int len, const char *fmt, ...)
76 int start = strlen(buf);
84 ret = vsnprintf(buf + start, len - start, fmt, args);
93 /* Calculate MTU to request. Old servers simply use the X-CSTP-MTU: header,
94 * which represents the tunnel MTU, while new servers do calculations on the
95 * X-CSTP-Base-MTU: header which represents the cleartext MTU between client
98 * If possible, the legacy MTU value should be the TCP MSS less 5 bytes of
99 * TLS and 8 bytes of CSTP overhead. We can get the MSS from either the
100 * TCP_INFO or TCP_MAXSEG sockopts.
102 * The base MTU comes from the TCP_INFO sockopt under Linux, but I don't know
103 * how to work it out on other systems. So leave it blank and do things the
104 * legacy way there. Contributions welcome...
106 * If we don't even have TCP_MAXSEG, then default to sending a legacy MTU of
107 * 1406 which is what we always used to do.
109 static void calculate_mtu(struct openconnect_info *vpninfo, int *base_mtu, int *mtu)
112 *base_mtu = vpninfo->basemtu;
114 #if defined(__linux__) && defined(TCP_INFO)
115 if (!*mtu || !*base_mtu) {
117 socklen_t ti_size = sizeof(ti);
119 if (!getsockopt(vpninfo->ssl_fd, IPPROTO_TCP, TCP_INFO,
121 vpn_progress(vpninfo, PRG_TRACE,
122 _("TCP_INFO rcv mss %d, snd mss %d, adv mss %d, pmtu %d\n"),
123 ti.tcpi_rcv_mss, ti.tcpi_snd_mss, ti.tcpi_advmss, ti.tcpi_pmtu);
124 if (!*base_mtu) *base_mtu = ti.tcpi_pmtu;
126 if (ti.tcpi_rcv_mss < ti.tcpi_snd_mss)
127 *mtu = ti.tcpi_rcv_mss - 13;
129 *mtu = ti.tcpi_snd_mss - 13;
137 socklen_t mss_size = sizeof(mss);
138 if (!getsockopt(vpninfo->ssl_fd, IPPROTO_TCP, TCP_MAXSEG,
140 vpn_progress(vpninfo, PRG_TRACE, _("TCP_MAXSEG %d\n"), mss);
151 static int start_cstp_connection(struct openconnect_info *vpninfo)
155 int retried = 0, sessid_found = 0;
156 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
157 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
158 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
159 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
160 const char *old_addr = vpninfo->vpn_addr;
161 const char *old_netmask = vpninfo->vpn_netmask;
162 const char *old_addr6 = vpninfo->vpn_addr6;
163 const char *old_netmask6 = vpninfo->vpn_netmask6;
164 struct split_include *inc;
167 /* Clear old options which will be overwritten */
168 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
169 vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
170 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
171 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
172 vpninfo->banner = NULL;
175 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
177 for (inc = vpninfo->split_includes; inc; ) {
178 struct split_include *next = inc->next;
182 for (inc = vpninfo->split_excludes; inc; ) {
183 struct split_include *next = inc->next;
187 for (inc = vpninfo->split_dns; inc; ) {
188 struct split_include *next = inc->next;
192 vpninfo->split_dns = vpninfo->split_includes = vpninfo->split_excludes = NULL;
194 /* Create (new) random master key for DTLS connection, if needed */
195 if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
197 openconnect_random(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret))) {
198 fprintf(stderr, _("Failed to initialise DTLS secret\n"));
203 calculate_mtu(vpninfo, &base_mtu, &mtu);
206 buf_append(buf, sizeof(buf), "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
207 buf_append(buf, sizeof(buf), "Host: %s\r\n", vpninfo->hostname);
208 buf_append(buf, sizeof(buf), "User-Agent: %s\r\n", vpninfo->useragent);
209 buf_append(buf, sizeof(buf), "Cookie: webvpn=%s\r\n", vpninfo->cookie);
210 buf_append(buf, sizeof(buf), "X-CSTP-Version: 1\r\n");
211 buf_append(buf, sizeof(buf), "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
212 if (vpninfo->deflate && i < sizeof(buf))
213 buf_append(buf, sizeof(buf), "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
215 buf_append(buf, sizeof(buf), "X-CSTP-Base-MTU: %d\r\n", base_mtu);
216 buf_append(buf, sizeof(buf), "X-CSTP-MTU: %d\r\n", mtu);
217 buf_append(buf, sizeof(buf), "X-CSTP-Address-Type: %s\r\n",
218 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
219 buf_append(buf, sizeof(buf), "X-DTLS-Master-Secret: ");
220 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
221 buf_append(buf, sizeof(buf), "%02X", vpninfo->dtls_secret[i]);
222 buf_append(buf, sizeof(buf), "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
223 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
225 openconnect_SSL_write(vpninfo, buf, strlen(buf));
227 if ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
230 vpn_progress(vpninfo, PRG_ERR,
231 _("Error fetching HTTPS response\n"));
234 openconnect_close_https(vpninfo, 0);
236 if (openconnect_open_https(vpninfo)) {
237 vpn_progress(vpninfo, PRG_ERR,
238 _("Failed to open HTTPS connection to %s\n"),
247 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
248 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
249 /* "Service Unavailable. Why? */
250 const char *reason = "<unknown>";
251 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
252 if (!strncmp(buf, "X-Reason: ", 10)) {
257 vpn_progress(vpninfo, PRG_ERR,
258 _("VPN service unavailable; reason: %s\n"),
262 vpn_progress(vpninfo, PRG_ERR,
263 _("Got inappropriate HTTP CONNECT response: %s\n"),
265 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
270 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
272 /* We may have advertised it, but we only do it if the server agrees */
273 vpninfo->deflate = 0;
275 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
276 struct vpn_option *new_option;
282 colon = strchr(buf, ':');
291 if (strncmp(buf, "X-DTLS-", 7) &&
292 strncmp(buf, "X-CSTP-", 7))
295 new_option = malloc(sizeof(*new_option));
297 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
300 new_option->option = strdup(buf);
301 new_option->value = strdup(colon);
302 new_option->next = NULL;
304 if (!new_option->option || !new_option->value) {
305 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
309 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
311 if (!strncmp(buf, "X-DTLS-", 7)) {
312 *next_dtls_option = new_option;
313 next_dtls_option = &new_option->next;
315 if (!strcmp(buf + 7, "MTU")) {
316 int mtu = atol(colon);
317 if (mtu > vpninfo->mtu)
319 } else if (!strcmp(buf + 7, "Session-ID")) {
320 if (strlen(colon) != 64) {
321 vpn_progress(vpninfo, PRG_ERR,
322 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
324 vpninfo->dtls_attempt_period = 0;
327 for (i = 0; i < 64; i += 2)
328 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
330 time(&vpninfo->dtls_times.last_rekey);
334 /* CSTP options... */
335 *next_cstp_option = new_option;
336 next_cstp_option = &new_option->next;
339 if (!strcmp(buf + 7, "Keepalive")) {
340 vpninfo->ssl_times.keepalive = atol(colon);
341 } else if (!strcmp(buf + 7, "DPD")) {
343 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
344 vpninfo->ssl_times.dpd = j;
345 } else if (!strcmp(buf + 7, "Rekey-Time")) {
346 vpninfo->ssl_times.rekey = atol(colon);
347 } else if (!strcmp(buf + 7, "Content-Encoding")) {
348 if (!strcmp(colon, "deflate"))
349 vpninfo->deflate = 1;
351 vpn_progress(vpninfo, PRG_ERR,
352 _("Unknown CSTP-Content-Encoding %s\n"),
356 } else if (!strcmp(buf + 7, "MTU")) {
357 int mtu = atol(colon);
358 if (mtu > vpninfo->mtu)
360 } else if (!strcmp(buf + 7, "Address")) {
361 if (strchr(new_option->value, ':'))
362 vpninfo->vpn_addr6 = new_option->value;
364 vpninfo->vpn_addr = new_option->value;
365 } else if (!strcmp(buf + 7, "Netmask")) {
366 if (strchr(new_option->value, ':'))
367 vpninfo->vpn_netmask6 = new_option->value;
369 vpninfo->vpn_netmask = new_option->value;
370 } else if (!strcmp(buf + 7, "DNS")) {
372 for (j = 0; j < 3; j++) {
373 if (!vpninfo->vpn_dns[j]) {
374 vpninfo->vpn_dns[j] = new_option->value;
378 } else if (!strcmp(buf + 7, "NBNS")) {
380 for (j = 0; j < 3; j++) {
381 if (!vpninfo->vpn_nbns[j]) {
382 vpninfo->vpn_nbns[j] = new_option->value;
386 } else if (!strcmp(buf + 7, "Default-Domain")) {
387 vpninfo->vpn_domain = new_option->value;
388 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
389 vpninfo->vpn_proxy_pac = new_option->value;
390 } else if (!strcmp(buf + 7, "Banner")) {
391 vpninfo->banner = new_option->value;
392 } else if (!strcmp(buf + 7, "Split-DNS")) {
393 struct split_include *dns = malloc(sizeof(*dns));
396 dns->route = new_option->value;
397 dns->next = vpninfo->split_dns;
398 vpninfo->split_dns = dns;
399 } else if (!strcmp(buf + 7, "Split-Include")) {
400 struct split_include *inc = malloc(sizeof(*inc));
403 inc->route = new_option->value;
404 inc->next = vpninfo->split_includes;
405 vpninfo->split_includes = inc;
406 } else if (!strcmp(buf + 7, "Split-Exclude")) {
407 struct split_include *exc = malloc(sizeof(*exc));
410 exc->route = new_option->value;
411 exc->next = vpninfo->split_excludes;
412 vpninfo->split_excludes = exc;
416 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
417 vpn_progress(vpninfo, PRG_ERR,
418 _("No IP address received. Aborting\n"));
422 if (strcmp(old_addr, vpninfo->vpn_addr)) {
423 vpn_progress(vpninfo, PRG_ERR,
424 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
425 vpninfo->vpn_addr, old_addr);
430 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
431 vpn_progress(vpninfo, PRG_ERR,
432 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
433 vpninfo->vpn_netmask, old_netmask);
438 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
439 vpn_progress(vpninfo, PRG_ERR,
440 _("Reconnect gave different IPv6 address (%s != %s)\n"),
441 vpninfo->vpn_addr6, old_addr6);
446 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
447 vpn_progress(vpninfo, PRG_ERR,
448 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
449 vpninfo->vpn_netmask6, old_netmask6);
454 while (old_dtls_opts) {
455 struct vpn_option *tmp = old_dtls_opts;
456 old_dtls_opts = old_dtls_opts->next;
461 while (old_cstp_opts) {
462 struct vpn_option *tmp = old_cstp_opts;
463 old_cstp_opts = old_cstp_opts->next;
468 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
469 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
471 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
472 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
474 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
475 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
478 vpninfo->dtls_attempt_period = 0;
480 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
481 vpninfo->ssl_times.last_tx = time(NULL);
486 int make_cstp_connection(struct openconnect_info *vpninfo)
490 ret = openconnect_open_https(vpninfo);
494 if (vpninfo->deflate) {
495 vpninfo->deflate_adler32 = 1;
496 vpninfo->inflate_adler32 = 1;
498 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
499 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
500 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
501 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
502 vpninfo->deflate = 0;
505 if (!vpninfo->deflate_pkt) {
506 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
507 if (!vpninfo->deflate_pkt) {
508 vpn_progress(vpninfo, PRG_ERR,
509 _("Allocation of deflate buffer failed\n"));
510 inflateEnd(&vpninfo->inflate_strm);
511 deflateEnd(&vpninfo->deflate_strm);
512 vpninfo->deflate = 0;
514 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
515 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
516 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
521 return start_cstp_connection(vpninfo);
524 int cstp_reconnect(struct openconnect_info *vpninfo)
530 openconnect_close_https(vpninfo, 0);
532 /* Requeue the original packet that was deflated */
533 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
534 vpninfo->current_ssl_pkt = NULL;
535 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
536 vpninfo->pending_deflated_pkt = NULL;
538 if (vpninfo->deflate) {
539 inflateEnd(&vpninfo->inflate_strm);
540 deflateEnd(&vpninfo->deflate_strm);
542 timeout = vpninfo->reconnect_timeout;
543 interval = vpninfo->reconnect_interval;
545 while ((ret = make_cstp_connection(vpninfo))) {
548 vpn_progress(vpninfo, PRG_INFO,
549 _("sleep %ds, remaining timeout %ds\n"),
555 interval += vpninfo->reconnect_interval;
556 if (interval > RECONNECT_INTERVAL_MAX)
557 interval = RECONNECT_INTERVAL_MAX;
559 script_config_tun(vpninfo, "reconnect");
563 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
564 unsigned char *buf, int len)
566 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
574 vpninfo->inflate_strm.next_in = buf;
575 vpninfo->inflate_strm.avail_in = len - 4;
577 vpninfo->inflate_strm.next_out = new->data;
578 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
579 vpninfo->inflate_strm.total_out = 0;
581 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
582 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
587 new->len = vpninfo->inflate_strm.total_out;
589 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
590 new->data, new->len);
592 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
593 (buf[len - 3] << 16) | (buf[len - 4] << 24);
595 if (vpninfo->inflate_adler32 != pkt_sum) {
596 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
599 vpn_progress(vpninfo, PRG_TRACE,
600 _("Received compressed data packet of %ld bytes\n"),
601 (long)vpninfo->inflate_strm.total_out);
603 queue_packet(&vpninfo->incoming_queue, new);
607 #if defined (OPENCONNECT_OPENSSL)
608 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
612 len = SSL_read(vpninfo->https_ssl, buf, maxlen);
616 ret = SSL_get_error(vpninfo->https_ssl, len);
617 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
618 vpn_progress(vpninfo, PRG_ERR,
619 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
626 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
630 ret = SSL_write(vpninfo->https_ssl, buf, buflen);
634 ret = SSL_get_error(vpninfo->https_ssl, ret);
636 case SSL_ERROR_WANT_WRITE:
637 /* Waiting for the socket to become writable -- it's
638 probably stalled, and/or the buffers are full */
639 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
640 case SSL_ERROR_WANT_READ:
644 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
645 openconnect_report_ssl_errors(vpninfo);
649 #elif defined (OPENCONNECT_GNUTLS)
650 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
654 ret = gnutls_record_recv(vpninfo->https_sess, buf, maxlen);
658 if (ret != GNUTLS_E_AGAIN) {
659 vpn_progress(vpninfo, PRG_ERR,
660 _("SSL read error: %s; reconnecting.\n"),
661 gnutls_strerror(ret));
667 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
671 ret = gnutls_record_send(vpninfo->https_sess, buf, buflen);
675 if (ret == GNUTLS_E_AGAIN) {
676 if (gnutls_record_get_direction(vpninfo->https_sess)) {
677 /* Waiting for the socket to become writable -- it's
678 probably stalled, and/or the buffers are full */
679 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
683 vpn_progress(vpninfo, PRG_ERR, _("SSL send failed: %s\n"),
684 gnutls_strerror(ret));
689 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
691 unsigned char buf[16384];
695 /* FIXME: The poll() handling here is fairly simplistic. Actually,
696 if the SSL connection stalls it could return a WANT_WRITE error
697 on _either_ of the SSL_read() or SSL_write() calls. In that case,
698 we should probably remove POLLIN from the events we're looking for,
699 and add POLLOUT. As it is, though, it'll just chew CPU time in that
700 fairly unlikely situation, until the write backlog clears. */
701 while ( (len = cstp_read(vpninfo, buf, sizeof(buf))) > 0) {
704 if (buf[0] != 'S' || buf[1] != 'T' ||
705 buf[2] != 'F' || buf[3] != 1 || buf[7])
708 payload_len = (buf[4] << 8) + buf[5];
709 if (len != 8 + payload_len) {
710 vpn_progress(vpninfo, PRG_ERR,
711 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
713 vpn_progress(vpninfo, PRG_ERR,
714 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
715 buf[0], buf[1], buf[2], buf[3],
716 buf[4], buf[5], buf[6], buf[7]);
719 vpninfo->ssl_times.last_rx = time(NULL);
722 vpn_progress(vpninfo, PRG_TRACE,
723 _("Got CSTP DPD request\n"));
724 vpninfo->owe_ssl_dpd_response = 1;
727 case AC_PKT_DPD_RESP:
728 vpn_progress(vpninfo, PRG_TRACE,
729 _("Got CSTP DPD response\n"));
732 case AC_PKT_KEEPALIVE:
733 vpn_progress(vpninfo, PRG_TRACE,
734 _("Got CSTP Keepalive\n"));
738 vpn_progress(vpninfo, PRG_TRACE,
739 _("Received uncompressed data packet of %d bytes\n"),
741 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
746 case AC_PKT_DISCONN: {
748 for (i = 0; i < payload_len; i++) {
749 if (!isprint(buf[payload_len + 8 + i]))
750 buf[payload_len + 8 + i] = '.';
752 buf[payload_len + 8] = 0;
753 vpn_progress(vpninfo, PRG_ERR,
754 _("Received server disconnect: %02x '%s'\n"),
756 vpninfo->quit_reason = "Server request";
759 case AC_PKT_COMPRESSED:
760 if (!vpninfo->deflate) {
761 vpn_progress(vpninfo, PRG_ERR,
762 _("Compressed packet received in !deflate mode\n"));
765 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
769 case AC_PKT_TERM_SERVER:
770 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
771 vpninfo->quit_reason = "Server request";
776 vpn_progress(vpninfo, PRG_ERR,
777 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
778 buf[0], buf[1], buf[2], buf[3],
779 buf[4], buf[5], buf[6], buf[7]);
780 vpninfo->quit_reason = "Unknown packet received";
787 /* If SSL_write() fails we are expected to try again. With exactly
788 the same data, at exactly the same location. So we keep the
789 packet we had before.... */
790 if (vpninfo->current_ssl_pkt) {
792 vpninfo->ssl_times.last_tx = time(NULL);
793 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
795 ret = cstp_write(vpninfo,
796 vpninfo->current_ssl_pkt->hdr,
797 vpninfo->current_ssl_pkt->len + 8);
801 else if (!ret && ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
804 if (ret != vpninfo->current_ssl_pkt->len + 8) {
805 vpn_progress(vpninfo, PRG_ERR,
806 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
807 vpninfo->current_ssl_pkt->len + 8, ret);
808 vpninfo->quit_reason = "Internal error";
811 /* Don't free the 'special' packets */
812 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
813 free(vpninfo->pending_deflated_pkt);
814 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
815 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
816 vpninfo->current_ssl_pkt != &keepalive_pkt)
817 free(vpninfo->current_ssl_pkt);
819 vpninfo->current_ssl_pkt = NULL;
822 if (vpninfo->owe_ssl_dpd_response) {
823 vpninfo->owe_ssl_dpd_response = 0;
824 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
825 goto handle_outgoing;
828 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
830 /* Not that this will ever happen; we don't even process
831 the setting when we're asked for it. */
832 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
838 vpn_progress(vpninfo, PRG_ERR,
839 _("CSTP Dead Peer Detection detected dead peer!\n"));
841 if (cstp_reconnect(vpninfo)) {
842 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
843 vpninfo->quit_reason = "CSTP reconnect failed";
846 /* I think we can leave DTLS to its own devices; when we reconnect
847 with the same master secret, we do seem to get the same sessid */
851 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
853 vpninfo->current_ssl_pkt = &dpd_pkt;
854 goto handle_outgoing;
857 /* No need to send an explicit keepalive
858 if we have real data to send */
859 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
862 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
864 vpninfo->current_ssl_pkt = &keepalive_pkt;
865 goto handle_outgoing;
871 /* Service outgoing packet queue, if no DTLS */
872 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
873 struct pkt *this = vpninfo->outgoing_queue;
874 vpninfo->outgoing_queue = this->next;
875 vpninfo->outgoing_qlen--;
877 if (vpninfo->deflate) {
878 unsigned char *adler;
881 vpninfo->deflate_strm.next_in = this->data;
882 vpninfo->deflate_strm.avail_in = this->len;
883 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
884 vpninfo->deflate_strm.avail_out = 2040;
885 vpninfo->deflate_strm.total_out = 0;
887 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
889 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
893 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
894 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
896 /* Add ongoing adler32 to tail of compressed packet */
897 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
898 this->data, this->len);
900 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
901 *(adler++) = vpninfo->deflate_adler32 >> 24;
902 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
903 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
904 *(adler) = vpninfo->deflate_adler32 & 0xff;
906 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
908 vpn_progress(vpninfo, PRG_TRACE,
909 _("Sending compressed data packet of %d bytes\n"),
912 vpninfo->pending_deflated_pkt = this;
913 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
916 memcpy(this->hdr, data_hdr, 8);
917 this->hdr[4] = this->len >> 8;
918 this->hdr[5] = this->len & 0xff;
920 vpn_progress(vpninfo, PRG_TRACE,
921 _("Sending uncompressed data packet of %d bytes\n"),
924 vpninfo->current_ssl_pkt = this;
926 goto handle_outgoing;
929 /* Work is not done if we just got rid of packets off the queue */
933 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
935 unsigned char *bye_pkt;
938 /* already lost connection? */
939 #if defined (OPENCONNECT_OPENSSL)
940 if (!vpninfo->https_ssl)
942 #elif defined (OPENCONNECT_GNUTLS)
943 if (!vpninfo->https_sess)
947 reason_len = strlen(reason);
948 bye_pkt = malloc(reason_len + 9);
952 memcpy(bye_pkt, data_hdr, 8);
953 memcpy(bye_pkt + 9, reason, reason_len);
955 bye_pkt[4] = (reason_len + 1) >> 8;
956 bye_pkt[5] = (reason_len + 1) & 0xff;
957 bye_pkt[6] = AC_PKT_DISCONN;
960 vpn_progress(vpninfo, PRG_INFO,
961 _("Send BYE packet: %s\n"), reason);
963 cstp_write(vpninfo, bye_pkt, reason_len + 9);