2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2010 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
31 #include <arpa/inet.h>
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35 #include <openssl/rand.h>
37 #include "openconnect-internal.h"
40 * Data packets are encapsulated in the SSL stream as follows:
42 * 0000: Magic "STF\x1"
43 * 0004: Big-endian 16-bit length (not including 8-byte header)
44 * 0006: Byte packet type (see openconnect-internal.h)
48 static char data_hdr[8] = {
51 AC_PKT_DATA, /* Type */
55 static struct pkt keepalive_pkt = {
56 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
59 static struct pkt dpd_pkt = {
60 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
63 static struct pkt dpd_resp_pkt = {
64 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
68 static int start_cstp_connection(struct openconnect_info *vpninfo)
72 int retried = 0, sessid_found = 0;
73 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
74 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
75 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
76 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
77 const char *old_addr = vpninfo->vpn_addr;
78 const char *old_netmask = vpninfo->vpn_netmask;
79 const char *old_addr6 = vpninfo->vpn_addr6;
80 const char *old_netmask6 = vpninfo->vpn_netmask6;
81 struct split_include *inc;
83 /* Clear old options which will be overwritten */
84 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
85 vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
86 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
87 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
88 vpninfo->banner = NULL;
91 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
93 for (inc = vpninfo->split_includes; inc; ) {
94 struct split_include *next = inc->next;
98 for (inc = vpninfo->split_excludes; inc; ) {
99 struct split_include *next = inc->next;
103 vpninfo->split_includes = vpninfo->split_excludes = NULL;
105 /* Create (new) random master key for DTLS connection, if needed */
106 if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
108 RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
109 fprintf(stderr, "Failed to initialise DTLS secret\n");
114 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
115 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
116 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
117 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
118 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
119 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
120 if (vpninfo->deflate)
121 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
122 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
123 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
124 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
125 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
126 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
127 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
128 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
129 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
131 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
132 vpn_progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
135 openconnect_close_https(vpninfo);
137 if (openconnect_open_https(vpninfo)) {
138 vpn_progress(vpninfo, PRG_ERR,
139 "Failed to open HTTPS connection to %s\n",
148 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
149 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
150 /* "Service Unavailable. Why? */
151 const char *reason = "<unknown>";
152 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
153 if (!strncmp(buf, "X-Reason: ", 10)) {
158 vpn_progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
162 vpn_progress(vpninfo, PRG_ERR,
163 "Got inappropriate HTTP CONNECT response: %s\n",
165 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
170 vpn_progress(vpninfo, PRG_INFO,
171 "Got CONNECT response: %s\n", buf);
173 /* We may have advertised it, but we only do it if the server agrees */
174 vpninfo->deflate = 0;
176 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
177 struct vpn_option *new_option;
178 char *colon = strchr(buf, ':');
187 if (strncmp(buf, "X-DTLS-", 7) &&
188 strncmp(buf, "X-CSTP-", 7))
191 new_option = malloc(sizeof(*new_option));
193 vpn_progress(vpninfo, PRG_ERR, "No memory for options\n");
196 new_option->option = strdup(buf);
197 new_option->value = strdup(colon);
198 new_option->next = NULL;
200 if (!new_option->option || !new_option->value) {
201 vpn_progress(vpninfo, PRG_ERR, "No memory for options\n");
205 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
207 if (!strncmp(buf, "X-DTLS-", 7)) {
208 *next_dtls_option = new_option;
209 next_dtls_option = &new_option->next;
211 if (!strcmp(buf + 7, "Session-ID")) {
212 if (strlen(colon) != 64) {
213 vpn_progress(vpninfo, PRG_ERR, "X-DTLS-Session-ID not 64 characters\n");
214 vpn_progress(vpninfo, PRG_ERR, "Is: %s\n", colon);
215 vpninfo->dtls_attempt_period = 0;
218 for (i = 0; i < 64; i += 2)
219 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
221 time(&vpninfo->dtls_times.last_rekey);
225 /* CSTP options... */
226 *next_cstp_option = new_option;
227 next_cstp_option = &new_option->next;
230 if (!strcmp(buf + 7, "Keepalive")) {
231 vpninfo->ssl_times.keepalive = atol(colon);
232 } else if (!strcmp(buf + 7, "DPD")) {
234 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
235 vpninfo->ssl_times.dpd = j;
236 } else if (!strcmp(buf + 7, "Rekey-Time")) {
237 vpninfo->ssl_times.rekey = atol(colon);
238 } else if (!strcmp(buf + 7, "Content-Encoding")) {
239 if (!strcmp(colon, "deflate"))
240 vpninfo->deflate = 1;
242 vpn_progress(vpninfo, PRG_ERR,
243 "Unknown CSTP-Content-Encoding %s\n",
247 } else if (!strcmp(buf + 7, "MTU")) {
248 vpninfo->mtu = atol(colon);
249 } else if (!strcmp(buf + 7, "Address")) {
250 if (strchr(new_option->value, ':'))
251 vpninfo->vpn_addr6 = new_option->value;
253 vpninfo->vpn_addr = new_option->value;
254 } else if (!strcmp(buf + 7, "Netmask")) {
255 if (strchr(new_option->value, ':'))
256 vpninfo->vpn_netmask6 = new_option->value;
258 vpninfo->vpn_netmask = new_option->value;
259 } else if (!strcmp(buf + 7, "DNS")) {
261 for (j = 0; j < 3; j++) {
262 if (!vpninfo->vpn_dns[j]) {
263 vpninfo->vpn_dns[j] = new_option->value;
267 } else if (!strcmp(buf + 7, "NBNS")) {
269 for (j = 0; j < 3; j++) {
270 if (!vpninfo->vpn_nbns[j]) {
271 vpninfo->vpn_nbns[j] = new_option->value;
275 } else if (!strcmp(buf + 7, "Default-Domain")) {
276 vpninfo->vpn_domain = new_option->value;
277 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
278 vpninfo->vpn_proxy_pac = new_option->value;
279 } else if (!strcmp(buf + 7, "Banner")) {
280 vpninfo->banner = new_option->value;
281 } else if (!strcmp(buf + 7, "Split-Include")) {
282 struct split_include *inc = malloc(sizeof(*inc));
285 inc->route = new_option->value;
286 inc->next = vpninfo->split_includes;
287 vpninfo->split_includes = inc;
288 } else if (!strcmp(buf + 7, "Split-Exclude")) {
289 struct split_include *exc = malloc(sizeof(*exc));
292 exc->route = new_option->value;
293 exc->next = vpninfo->split_excludes;
294 vpninfo->split_excludes = exc;
298 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
299 vpn_progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
303 if (strcmp(old_addr, vpninfo->vpn_addr)) {
304 vpn_progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
305 vpninfo->vpn_addr, old_addr);
310 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
311 vpn_progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
312 vpninfo->vpn_netmask, old_netmask);
317 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
318 vpn_progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
319 vpninfo->vpn_addr6, old_addr6);
324 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
325 vpn_progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
326 vpninfo->vpn_netmask6, old_netmask6);
331 while (old_dtls_opts) {
332 struct vpn_option *tmp = old_dtls_opts;
333 old_dtls_opts = old_dtls_opts->next;
338 while (old_cstp_opts) {
339 struct vpn_option *tmp = old_cstp_opts;
340 old_cstp_opts = old_cstp_opts->next;
345 vpn_progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
346 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
348 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
349 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
351 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
352 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
353 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
355 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
356 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
359 vpninfo->dtls_attempt_period = 0;
361 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
362 vpninfo->ssl_times.last_tx = time(NULL);
367 int make_cstp_connection(struct openconnect_info *vpninfo)
371 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
374 if (vpninfo->deflate) {
375 vpninfo->deflate_adler32 = 1;
376 vpninfo->inflate_adler32 = 1;
378 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
379 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
380 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
381 vpn_progress(vpninfo, PRG_ERR, "Compression setup failed\n");
382 vpninfo->deflate = 0;
385 if (!vpninfo->deflate_pkt) {
386 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
387 if (!vpninfo->deflate_pkt) {
388 vpn_progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
389 vpninfo->deflate = 0;
391 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
392 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
393 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
397 return start_cstp_connection(vpninfo);
400 int cstp_reconnect(struct openconnect_info *vpninfo)
406 openconnect_close_https(vpninfo);
408 /* It's already deflated in the old stream. Extremely
409 non-trivial to reconstitute it; just throw it away */
410 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
411 vpninfo->current_ssl_pkt = NULL;
413 timeout = vpninfo->reconnect_timeout;
414 interval = vpninfo->reconnect_interval;
416 while ((ret = make_cstp_connection(vpninfo))) {
419 vpn_progress(vpninfo, PRG_INFO,
420 "sleep %ds, remaining timeout %ds\n",
426 interval += vpninfo->reconnect_interval;
427 if (interval > RECONNECT_INTERVAL_MAX)
428 interval = RECONNECT_INTERVAL_MAX;
430 script_reconnect(vpninfo);
434 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
436 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
443 vpninfo->inflate_strm.next_in = buf;
444 vpninfo->inflate_strm.avail_in = len - 4;
446 vpninfo->inflate_strm.next_out = new->data;
447 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
448 vpninfo->inflate_strm.total_out = 0;
450 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
451 vpn_progress(vpninfo, PRG_ERR, "inflate failed\n");
456 new->len = vpninfo->inflate_strm.total_out;
458 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
459 new->data, new->len);
461 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
462 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
465 vpn_progress(vpninfo, PRG_TRACE,
466 "Received compressed data packet of %ld bytes\n",
467 vpninfo->inflate_strm.total_out);
469 queue_packet(&vpninfo->incoming_queue, new);
473 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
475 unsigned char buf[16384];
479 /* FIXME: The poll() handling here is fairly simplistic. Actually,
480 if the SSL connection stalls it could return a WANT_WRITE error
481 on _either_ of the SSL_read() or SSL_write() calls. In that case,
482 we should probably remove POLLIN from the events we're looking for,
483 and add POLLOUT. As it is, though, it'll just chew CPU time in that
484 fairly unlikely situation, until the write backlog clears. */
485 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
488 if (buf[0] != 'S' || buf[1] != 'T' ||
489 buf[2] != 'F' || buf[3] != 1 || buf[7])
492 payload_len = (buf[4] << 8) + buf[5];
493 if (len != 8 + payload_len) {
494 vpn_progress(vpninfo, PRG_ERR,
495 "Unexpected packet length. SSL_read returned %d but packet is\n",
497 vpn_progress(vpninfo, PRG_ERR,
498 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
499 buf[0], buf[1], buf[2], buf[3],
500 buf[4], buf[5], buf[6], buf[7]);
503 vpninfo->ssl_times.last_rx = time(NULL);
506 vpn_progress(vpninfo, PRG_TRACE,
507 "Got CSTP DPD request\n");
508 vpninfo->owe_ssl_dpd_response = 1;
511 case AC_PKT_DPD_RESP:
512 vpn_progress(vpninfo, PRG_TRACE,
513 "Got CSTP DPD response\n");
516 case AC_PKT_KEEPALIVE:
517 vpn_progress(vpninfo, PRG_TRACE,
518 "Got CSTP Keepalive\n");
522 vpn_progress(vpninfo, PRG_TRACE,
523 "Received uncompressed data packet of %d bytes\n",
525 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
530 case AC_PKT_DISCONN: {
532 for (i = 0; i < payload_len; i++) {
533 if (!isprint(buf[payload_len + 8 + i]))
534 buf[payload_len + 8 + i] = '.';
536 buf[payload_len + 8] = 0;
537 vpn_progress(vpninfo, PRG_ERR,
538 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
539 vpninfo->quit_reason = "Server request";
542 case AC_PKT_COMPRESSED:
543 if (!vpninfo->deflate) {
544 vpn_progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
547 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
551 case AC_PKT_TERM_SERVER:
552 vpn_progress(vpninfo, PRG_ERR, "received server terminate packet\n");
553 vpninfo->quit_reason = "Server request";
558 vpn_progress(vpninfo, PRG_ERR,
559 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
560 buf[0], buf[1], buf[2], buf[3],
561 buf[4], buf[5], buf[6], buf[7]);
562 vpninfo->quit_reason = "Unknown packet received";
566 ret = SSL_get_error(vpninfo->https_ssl, len);
567 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
568 vpn_progress(vpninfo, PRG_ERR,
569 "SSL read error %d (server probably closed connection); reconnecting.\n",
575 /* If SSL_write() fails we are expected to try again. With exactly
576 the same data, at exactly the same location. So we keep the
577 packet we had before.... */
578 if (vpninfo->current_ssl_pkt) {
580 vpninfo->ssl_times.last_tx = time(NULL);
581 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
582 ret = SSL_write(vpninfo->https_ssl,
583 vpninfo->current_ssl_pkt->hdr,
584 vpninfo->current_ssl_pkt->len + 8);
586 ret = SSL_get_error(vpninfo->https_ssl, ret);
588 case SSL_ERROR_WANT_WRITE:
589 /* Waiting for the socket to become writable -- it's
590 probably stalled, and/or the buffers are full */
591 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
593 case SSL_ERROR_WANT_READ:
594 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
598 vpn_progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
599 report_ssl_errors(vpninfo);
603 if (ret != vpninfo->current_ssl_pkt->len + 8) {
604 vpn_progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
605 vpninfo->current_ssl_pkt->len + 8, ret);
606 vpninfo->quit_reason = "Internal error";
609 /* Don't free the 'special' packets */
610 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
611 vpninfo->current_ssl_pkt != &dpd_pkt &&
612 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
613 vpninfo->current_ssl_pkt != &keepalive_pkt)
614 free(vpninfo->current_ssl_pkt);
616 vpninfo->current_ssl_pkt = NULL;
619 if (vpninfo->owe_ssl_dpd_response) {
620 vpninfo->owe_ssl_dpd_response = 0;
621 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
622 goto handle_outgoing;
625 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
627 /* Not that this will ever happen; we don't even process
628 the setting when we're asked for it. */
629 vpn_progress(vpninfo, PRG_INFO, "CSTP rekey due\n");
635 vpn_progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
637 if (cstp_reconnect(vpninfo)) {
638 vpn_progress(vpninfo, PRG_ERR, "Reconnect failed\n");
639 vpninfo->quit_reason = "CSTP reconnect failed";
642 /* I think we can leave DTLS to its own devices; when we reconnect
643 with the same master secret, we do seem to get the same sessid */
647 vpn_progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
649 vpninfo->current_ssl_pkt = &dpd_pkt;
650 goto handle_outgoing;
653 /* No need to send an explicit keepalive
654 if we have real data to send */
655 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
658 vpn_progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
660 vpninfo->current_ssl_pkt = &keepalive_pkt;
661 goto handle_outgoing;
667 /* Service outgoing packet queue, if no DTLS */
668 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
669 struct pkt *this = vpninfo->outgoing_queue;
670 vpninfo->outgoing_queue = this->next;
671 vpninfo->outgoing_qlen--;
673 if (vpninfo->deflate) {
674 unsigned char *adler;
677 vpninfo->deflate_strm.next_in = this->data;
678 vpninfo->deflate_strm.avail_in = this->len;
679 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
680 vpninfo->deflate_strm.avail_out = 2040;
681 vpninfo->deflate_strm.total_out = 0;
683 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
685 vpn_progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
689 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
690 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
692 /* Add ongoing adler32 to tail of compressed packet */
693 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
694 this->data, this->len);
696 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
697 *(adler++) = vpninfo->deflate_adler32 >> 24;
698 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
699 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
700 *(adler) = vpninfo->deflate_adler32 & 0xff;
702 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
704 vpn_progress(vpninfo, PRG_TRACE,
705 "Sending compressed data packet of %d bytes\n",
708 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
711 memcpy(this->hdr, data_hdr, 8);
712 this->hdr[4] = this->len >> 8;
713 this->hdr[5] = this->len & 0xff;
715 vpn_progress(vpninfo, PRG_TRACE,
716 "Sending uncompressed data packet of %d bytes\n",
719 vpninfo->current_ssl_pkt = this;
721 goto handle_outgoing;
724 /* Work is not done if we just got rid of packets off the queue */
728 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
730 unsigned char *bye_pkt;
733 /* already lost connection? */
734 if (!vpninfo->https_ssl)
737 reason_len = strlen(reason);
738 bye_pkt = malloc(reason_len + 9);
742 memcpy(bye_pkt, data_hdr, 8);
743 memcpy(bye_pkt + 9, reason, reason_len);
745 bye_pkt[4] = (reason_len + 1) >> 8;
746 bye_pkt[5] = (reason_len + 1) & 0xff;
747 bye_pkt[6] = AC_PKT_DISCONN;
750 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
753 vpn_progress(vpninfo, PRG_INFO,
754 "Send BYE packet: %s\n", reason);