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
36 #include <openssl/ssl.h>
37 #include <openssl/err.h>
38 #include <openssl/rand.h>
40 #include "openconnect-internal.h"
43 * Data packets are encapsulated in the SSL stream as follows:
45 * 0000: Magic "STF\x1"
46 * 0004: Big-endian 16-bit length (not including 8-byte header)
47 * 0006: Byte packet type (see openconnect-internal.h)
51 static char data_hdr[8] = {
54 AC_PKT_DATA, /* Type */
58 static struct pkt keepalive_pkt = {
59 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
62 static struct pkt dpd_pkt = {
63 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
66 static struct pkt dpd_resp_pkt = {
67 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
71 static int start_cstp_connection(struct openconnect_info *vpninfo)
75 int retried = 0, sessid_found = 0;
76 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
77 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
78 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
79 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
80 const char *old_addr = vpninfo->vpn_addr;
81 const char *old_netmask = vpninfo->vpn_netmask;
82 const char *old_addr6 = vpninfo->vpn_addr6;
83 const char *old_netmask6 = vpninfo->vpn_netmask6;
84 struct split_include *inc;
86 /* Clear old options which will be overwritten */
87 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
88 vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
89 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
90 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
91 vpninfo->banner = NULL;
94 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
96 for (inc = vpninfo->split_includes; inc; ) {
97 struct split_include *next = inc->next;
101 for (inc = vpninfo->split_excludes; inc; ) {
102 struct split_include *next = inc->next;
106 vpninfo->split_includes = vpninfo->split_excludes = NULL;
108 /* Create (new) random master key for DTLS connection, if needed */
109 if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
111 RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
112 fprintf(stderr, _("Failed to initialise DTLS secret\n"));
117 openconnect_SSL_printf(vpninfo, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
118 openconnect_SSL_printf(vpninfo, "Host: %s\r\n", vpninfo->hostname);
119 openconnect_SSL_printf(vpninfo, "User-Agent: %s\r\n", vpninfo->useragent);
120 openconnect_SSL_printf(vpninfo, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
121 openconnect_SSL_printf(vpninfo, "X-CSTP-Version: 1\r\n");
122 openconnect_SSL_printf(vpninfo, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
123 if (vpninfo->deflate)
124 openconnect_SSL_printf(vpninfo, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
125 openconnect_SSL_printf(vpninfo, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
126 openconnect_SSL_printf(vpninfo, "X-CSTP-Address-Type: %s\r\n",
127 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
128 openconnect_SSL_printf(vpninfo, "X-DTLS-Master-Secret: ");
129 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
130 openconnect_SSL_printf(vpninfo, "%02X", vpninfo->dtls_secret[i]);
131 openconnect_SSL_printf(vpninfo, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
132 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
134 if ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
137 vpn_progress(vpninfo, PRG_ERR,
138 _("Error fetching HTTPS response\n"));
141 openconnect_close_https(vpninfo);
143 if (openconnect_open_https(vpninfo)) {
144 vpn_progress(vpninfo, PRG_ERR,
145 _("Failed to open HTTPS connection to %s\n"),
154 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
155 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
156 /* "Service Unavailable. Why? */
157 const char *reason = "<unknown>";
158 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
159 if (!strncmp(buf, "X-Reason: ", 10)) {
164 vpn_progress(vpninfo, PRG_ERR,
165 _("VPN service unavailable; reason: %s\n"),
169 vpn_progress(vpninfo, PRG_ERR,
170 _("Got inappropriate HTTP CONNECT response: %s\n"),
172 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
177 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
179 /* We may have advertised it, but we only do it if the server agrees */
180 vpninfo->deflate = 0;
182 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
183 struct vpn_option *new_option;
189 colon = strchr(buf, ':');
198 if (strncmp(buf, "X-DTLS-", 7) &&
199 strncmp(buf, "X-CSTP-", 7))
202 new_option = malloc(sizeof(*new_option));
204 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
207 new_option->option = strdup(buf);
208 new_option->value = strdup(colon);
209 new_option->next = NULL;
211 if (!new_option->option || !new_option->value) {
212 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
216 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
218 if (!strncmp(buf, "X-DTLS-", 7)) {
219 *next_dtls_option = new_option;
220 next_dtls_option = &new_option->next;
222 if (!strcmp(buf + 7, "Session-ID")) {
223 if (strlen(colon) != 64) {
224 vpn_progress(vpninfo, PRG_ERR,
225 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
227 vpninfo->dtls_attempt_period = 0;
230 for (i = 0; i < 64; i += 2)
231 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
233 time(&vpninfo->dtls_times.last_rekey);
237 /* CSTP options... */
238 *next_cstp_option = new_option;
239 next_cstp_option = &new_option->next;
242 if (!strcmp(buf + 7, "Keepalive")) {
243 vpninfo->ssl_times.keepalive = atol(colon);
244 } else if (!strcmp(buf + 7, "DPD")) {
246 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
247 vpninfo->ssl_times.dpd = j;
248 } else if (!strcmp(buf + 7, "Rekey-Time")) {
249 vpninfo->ssl_times.rekey = atol(colon);
250 } else if (!strcmp(buf + 7, "Content-Encoding")) {
251 if (!strcmp(colon, "deflate"))
252 vpninfo->deflate = 1;
254 vpn_progress(vpninfo, PRG_ERR,
255 _("Unknown CSTP-Content-Encoding %s\n"),
259 } else if (!strcmp(buf + 7, "MTU")) {
260 vpninfo->mtu = atol(colon);
261 } else if (!strcmp(buf + 7, "Address")) {
262 if (strchr(new_option->value, ':'))
263 vpninfo->vpn_addr6 = new_option->value;
265 vpninfo->vpn_addr = new_option->value;
266 } else if (!strcmp(buf + 7, "Netmask")) {
267 if (strchr(new_option->value, ':'))
268 vpninfo->vpn_netmask6 = new_option->value;
270 vpninfo->vpn_netmask = new_option->value;
271 } else if (!strcmp(buf + 7, "DNS")) {
273 for (j = 0; j < 3; j++) {
274 if (!vpninfo->vpn_dns[j]) {
275 vpninfo->vpn_dns[j] = new_option->value;
279 } else if (!strcmp(buf + 7, "NBNS")) {
281 for (j = 0; j < 3; j++) {
282 if (!vpninfo->vpn_nbns[j]) {
283 vpninfo->vpn_nbns[j] = new_option->value;
287 } else if (!strcmp(buf + 7, "Default-Domain")) {
288 vpninfo->vpn_domain = new_option->value;
289 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
290 vpninfo->vpn_proxy_pac = new_option->value;
291 } else if (!strcmp(buf + 7, "Banner")) {
292 vpninfo->banner = new_option->value;
293 } else if (!strcmp(buf + 7, "Split-Include")) {
294 struct split_include *inc = malloc(sizeof(*inc));
297 inc->route = new_option->value;
298 inc->next = vpninfo->split_includes;
299 vpninfo->split_includes = inc;
300 } else if (!strcmp(buf + 7, "Split-Exclude")) {
301 struct split_include *exc = malloc(sizeof(*exc));
304 exc->route = new_option->value;
305 exc->next = vpninfo->split_excludes;
306 vpninfo->split_excludes = exc;
310 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
311 vpn_progress(vpninfo, PRG_ERR,
312 _("No IP address received. Aborting\n"));
316 if (strcmp(old_addr, vpninfo->vpn_addr)) {
317 vpn_progress(vpninfo, PRG_ERR,
318 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
319 vpninfo->vpn_addr, old_addr);
324 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
325 vpn_progress(vpninfo, PRG_ERR,
326 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
327 vpninfo->vpn_netmask, old_netmask);
332 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
333 vpn_progress(vpninfo, PRG_ERR,
334 _("Reconnect gave different IPv6 address (%s != %s)\n"),
335 vpninfo->vpn_addr6, old_addr6);
340 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
341 vpn_progress(vpninfo, PRG_ERR,
342 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
343 vpninfo->vpn_netmask6, old_netmask6);
348 while (old_dtls_opts) {
349 struct vpn_option *tmp = old_dtls_opts;
350 old_dtls_opts = old_dtls_opts->next;
355 while (old_cstp_opts) {
356 struct vpn_option *tmp = old_cstp_opts;
357 old_cstp_opts = old_cstp_opts->next;
362 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
363 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
365 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
366 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
368 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
369 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
372 vpninfo->dtls_attempt_period = 0;
374 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
375 vpninfo->ssl_times.last_tx = time(NULL);
380 int make_cstp_connection(struct openconnect_info *vpninfo)
384 ret = openconnect_open_https(vpninfo);
388 if (vpninfo->deflate) {
389 vpninfo->deflate_adler32 = 1;
390 vpninfo->inflate_adler32 = 1;
392 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
393 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
394 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
395 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
396 vpninfo->deflate = 0;
399 if (!vpninfo->deflate_pkt) {
400 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
401 if (!vpninfo->deflate_pkt) {
402 vpn_progress(vpninfo, PRG_ERR,
403 _("Allocation of deflate buffer failed\n"));
404 inflateEnd(&vpninfo->inflate_strm);
405 deflateEnd(&vpninfo->deflate_strm);
406 vpninfo->deflate = 0;
408 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
409 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
410 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
415 return start_cstp_connection(vpninfo);
418 int cstp_reconnect(struct openconnect_info *vpninfo)
424 openconnect_close_https(vpninfo);
426 /* Requeue the original packet that was deflated */
427 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
428 vpninfo->current_ssl_pkt = NULL;
429 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
430 vpninfo->pending_deflated_pkt = NULL;
432 if (vpninfo->deflate) {
433 inflateEnd(&vpninfo->inflate_strm);
434 deflateEnd(&vpninfo->deflate_strm);
436 timeout = vpninfo->reconnect_timeout;
437 interval = vpninfo->reconnect_interval;
439 while ((ret = make_cstp_connection(vpninfo))) {
442 vpn_progress(vpninfo, PRG_INFO,
443 _("sleep %ds, remaining timeout %ds\n"),
449 interval += vpninfo->reconnect_interval;
450 if (interval > RECONNECT_INTERVAL_MAX)
451 interval = RECONNECT_INTERVAL_MAX;
453 script_config_tun(vpninfo, "reconnect");
457 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
458 unsigned char *buf, int len)
460 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
468 vpninfo->inflate_strm.next_in = buf;
469 vpninfo->inflate_strm.avail_in = len - 4;
471 vpninfo->inflate_strm.next_out = new->data;
472 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
473 vpninfo->inflate_strm.total_out = 0;
475 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
476 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
481 new->len = vpninfo->inflate_strm.total_out;
483 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
484 new->data, new->len);
486 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
487 (buf[len - 3] << 16) | (buf[len - 4] << 24);
489 if (vpninfo->inflate_adler32 != pkt_sum) {
490 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
493 vpn_progress(vpninfo, PRG_TRACE,
494 _("Received compressed data packet of %ld bytes\n"),
495 (long)vpninfo->inflate_strm.total_out);
497 queue_packet(&vpninfo->incoming_queue, new);
501 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
503 unsigned char buf[16384];
507 /* FIXME: The poll() handling here is fairly simplistic. Actually,
508 if the SSL connection stalls it could return a WANT_WRITE error
509 on _either_ of the SSL_read() or SSL_write() calls. In that case,
510 we should probably remove POLLIN from the events we're looking for,
511 and add POLLOUT. As it is, though, it'll just chew CPU time in that
512 fairly unlikely situation, until the write backlog clears. */
513 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
516 if (buf[0] != 'S' || buf[1] != 'T' ||
517 buf[2] != 'F' || buf[3] != 1 || buf[7])
520 payload_len = (buf[4] << 8) + buf[5];
521 if (len != 8 + payload_len) {
522 vpn_progress(vpninfo, PRG_ERR,
523 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
525 vpn_progress(vpninfo, PRG_ERR,
526 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
527 buf[0], buf[1], buf[2], buf[3],
528 buf[4], buf[5], buf[6], buf[7]);
531 vpninfo->ssl_times.last_rx = time(NULL);
534 vpn_progress(vpninfo, PRG_TRACE,
535 _("Got CSTP DPD request\n"));
536 vpninfo->owe_ssl_dpd_response = 1;
539 case AC_PKT_DPD_RESP:
540 vpn_progress(vpninfo, PRG_TRACE,
541 _("Got CSTP DPD response\n"));
544 case AC_PKT_KEEPALIVE:
545 vpn_progress(vpninfo, PRG_TRACE,
546 _("Got CSTP Keepalive\n"));
550 vpn_progress(vpninfo, PRG_TRACE,
551 _("Received uncompressed data packet of %d bytes\n"),
553 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
558 case AC_PKT_DISCONN: {
560 for (i = 0; i < payload_len; i++) {
561 if (!isprint(buf[payload_len + 8 + i]))
562 buf[payload_len + 8 + i] = '.';
564 buf[payload_len + 8] = 0;
565 vpn_progress(vpninfo, PRG_ERR,
566 _("Received server disconnect: %02x '%s'\n"),
568 vpninfo->quit_reason = "Server request";
571 case AC_PKT_COMPRESSED:
572 if (!vpninfo->deflate) {
573 vpn_progress(vpninfo, PRG_ERR,
574 _("Compressed packet received in !deflate mode\n"));
577 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
581 case AC_PKT_TERM_SERVER:
582 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
583 vpninfo->quit_reason = "Server request";
588 vpn_progress(vpninfo, PRG_ERR,
589 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
590 buf[0], buf[1], buf[2], buf[3],
591 buf[4], buf[5], buf[6], buf[7]);
592 vpninfo->quit_reason = "Unknown packet received";
596 ret = SSL_get_error(vpninfo->https_ssl, len);
597 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
598 vpn_progress(vpninfo, PRG_ERR,
599 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
605 /* If SSL_write() fails we are expected to try again. With exactly
606 the same data, at exactly the same location. So we keep the
607 packet we had before.... */
608 if (vpninfo->current_ssl_pkt) {
610 vpninfo->ssl_times.last_tx = time(NULL);
611 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
612 ret = SSL_write(vpninfo->https_ssl,
613 vpninfo->current_ssl_pkt->hdr,
614 vpninfo->current_ssl_pkt->len + 8);
616 ret = SSL_get_error(vpninfo->https_ssl, ret);
618 case SSL_ERROR_WANT_WRITE:
619 /* Waiting for the socket to become writable -- it's
620 probably stalled, and/or the buffers are full */
621 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
623 case SSL_ERROR_WANT_READ:
624 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
628 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
629 openconnect_report_ssl_errors(vpninfo);
633 if (ret != vpninfo->current_ssl_pkt->len + 8) {
634 vpn_progress(vpninfo, PRG_ERR,
635 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
636 vpninfo->current_ssl_pkt->len + 8, ret);
637 vpninfo->quit_reason = "Internal error";
640 /* Don't free the 'special' packets */
641 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
642 free(vpninfo->pending_deflated_pkt);
643 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
644 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
645 vpninfo->current_ssl_pkt != &keepalive_pkt)
646 free(vpninfo->current_ssl_pkt);
648 vpninfo->current_ssl_pkt = NULL;
651 if (vpninfo->owe_ssl_dpd_response) {
652 vpninfo->owe_ssl_dpd_response = 0;
653 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
654 goto handle_outgoing;
657 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
659 /* Not that this will ever happen; we don't even process
660 the setting when we're asked for it. */
661 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
667 vpn_progress(vpninfo, PRG_ERR,
668 _("CSTP Dead Peer Detection detected dead peer!\n"));
670 if (cstp_reconnect(vpninfo)) {
671 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
672 vpninfo->quit_reason = "CSTP reconnect failed";
675 /* I think we can leave DTLS to its own devices; when we reconnect
676 with the same master secret, we do seem to get the same sessid */
680 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
682 vpninfo->current_ssl_pkt = &dpd_pkt;
683 goto handle_outgoing;
686 /* No need to send an explicit keepalive
687 if we have real data to send */
688 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
691 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
693 vpninfo->current_ssl_pkt = &keepalive_pkt;
694 goto handle_outgoing;
700 /* Service outgoing packet queue, if no DTLS */
701 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
702 struct pkt *this = vpninfo->outgoing_queue;
703 vpninfo->outgoing_queue = this->next;
704 vpninfo->outgoing_qlen--;
706 if (vpninfo->deflate) {
707 unsigned char *adler;
710 vpninfo->deflate_strm.next_in = this->data;
711 vpninfo->deflate_strm.avail_in = this->len;
712 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
713 vpninfo->deflate_strm.avail_out = 2040;
714 vpninfo->deflate_strm.total_out = 0;
716 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
718 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
722 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
723 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
725 /* Add ongoing adler32 to tail of compressed packet */
726 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
727 this->data, this->len);
729 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
730 *(adler++) = vpninfo->deflate_adler32 >> 24;
731 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
732 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
733 *(adler) = vpninfo->deflate_adler32 & 0xff;
735 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
737 vpn_progress(vpninfo, PRG_TRACE,
738 _("Sending compressed data packet of %d bytes\n"),
741 vpninfo->pending_deflated_pkt = this;
742 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
745 memcpy(this->hdr, data_hdr, 8);
746 this->hdr[4] = this->len >> 8;
747 this->hdr[5] = this->len & 0xff;
749 vpn_progress(vpninfo, PRG_TRACE,
750 _("Sending uncompressed data packet of %d bytes\n"),
753 vpninfo->current_ssl_pkt = this;
755 goto handle_outgoing;
758 /* Work is not done if we just got rid of packets off the queue */
762 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
764 unsigned char *bye_pkt;
767 /* already lost connection? */
768 if (!vpninfo->https_ssl)
771 reason_len = strlen(reason);
772 bye_pkt = malloc(reason_len + 9);
776 memcpy(bye_pkt, data_hdr, 8);
777 memcpy(bye_pkt + 9, reason, reason_len);
779 bye_pkt[4] = (reason_len + 1) >> 8;
780 bye_pkt[5] = (reason_len + 1) & 0xff;
781 bye_pkt[6] = AC_PKT_DISCONN;
784 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
787 vpn_progress(vpninfo, PRG_INFO,
788 _("Send BYE packet: %s\n"), reason);