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
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, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
115 openconnect_SSL_printf(vpninfo, "Host: %s\r\n", vpninfo->hostname);
116 openconnect_SSL_printf(vpninfo, "User-Agent: %s\r\n", vpninfo->useragent);
117 openconnect_SSL_printf(vpninfo, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
118 openconnect_SSL_printf(vpninfo, "X-CSTP-Version: 1\r\n");
119 openconnect_SSL_printf(vpninfo, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
120 if (vpninfo->deflate)
121 openconnect_SSL_printf(vpninfo, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
122 openconnect_SSL_printf(vpninfo, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
123 openconnect_SSL_printf(vpninfo, "X-CSTP-Address-Type: %s\r\n",
124 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
125 openconnect_SSL_printf(vpninfo, "X-DTLS-Master-Secret: ");
126 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
127 openconnect_SSL_printf(vpninfo, "%02X", vpninfo->dtls_secret[i]);
128 openconnect_SSL_printf(vpninfo, "\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 ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
134 vpn_progress(vpninfo, PRG_ERR,
135 _("Error fetching HTTPS response\n"));
138 openconnect_close_https(vpninfo);
140 if (openconnect_open_https(vpninfo)) {
141 vpn_progress(vpninfo, PRG_ERR,
142 _("Failed to open HTTPS connection to %s\n"),
151 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
152 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
153 /* "Service Unavailable. Why? */
154 const char *reason = "<unknown>";
155 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
156 if (!strncmp(buf, "X-Reason: ", 10)) {
161 vpn_progress(vpninfo, PRG_ERR,
162 _("VPN service unavailable; reason: %s\n"),
166 vpn_progress(vpninfo, PRG_ERR,
167 _("Got inappropriate HTTP CONNECT response: %s\n"),
169 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
174 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
176 /* We may have advertised it, but we only do it if the server agrees */
177 vpninfo->deflate = 0;
179 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
180 struct vpn_option *new_option;
186 colon = strchr(buf, ':');
195 if (strncmp(buf, "X-DTLS-", 7) &&
196 strncmp(buf, "X-CSTP-", 7))
199 new_option = malloc(sizeof(*new_option));
201 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
204 new_option->option = strdup(buf);
205 new_option->value = strdup(colon);
206 new_option->next = NULL;
208 if (!new_option->option || !new_option->value) {
209 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
213 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
215 if (!strncmp(buf, "X-DTLS-", 7)) {
216 *next_dtls_option = new_option;
217 next_dtls_option = &new_option->next;
219 if (!strcmp(buf + 7, "Session-ID")) {
220 if (strlen(colon) != 64) {
221 vpn_progress(vpninfo, PRG_ERR,
222 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
224 vpninfo->dtls_attempt_period = 0;
227 for (i = 0; i < 64; i += 2)
228 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
230 time(&vpninfo->dtls_times.last_rekey);
234 /* CSTP options... */
235 *next_cstp_option = new_option;
236 next_cstp_option = &new_option->next;
239 if (!strcmp(buf + 7, "Keepalive")) {
240 vpninfo->ssl_times.keepalive = atol(colon);
241 } else if (!strcmp(buf + 7, "DPD")) {
243 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
244 vpninfo->ssl_times.dpd = j;
245 } else if (!strcmp(buf + 7, "Rekey-Time")) {
246 vpninfo->ssl_times.rekey = atol(colon);
247 } else if (!strcmp(buf + 7, "Content-Encoding")) {
248 if (!strcmp(colon, "deflate"))
249 vpninfo->deflate = 1;
251 vpn_progress(vpninfo, PRG_ERR,
252 _("Unknown CSTP-Content-Encoding %s\n"),
256 } else if (!strcmp(buf + 7, "MTU")) {
257 vpninfo->mtu = atol(colon);
258 } else if (!strcmp(buf + 7, "Address")) {
259 if (strchr(new_option->value, ':'))
260 vpninfo->vpn_addr6 = new_option->value;
262 vpninfo->vpn_addr = new_option->value;
263 } else if (!strcmp(buf + 7, "Netmask")) {
264 if (strchr(new_option->value, ':'))
265 vpninfo->vpn_netmask6 = new_option->value;
267 vpninfo->vpn_netmask = new_option->value;
268 } else if (!strcmp(buf + 7, "DNS")) {
270 for (j = 0; j < 3; j++) {
271 if (!vpninfo->vpn_dns[j]) {
272 vpninfo->vpn_dns[j] = new_option->value;
276 } else if (!strcmp(buf + 7, "NBNS")) {
278 for (j = 0; j < 3; j++) {
279 if (!vpninfo->vpn_nbns[j]) {
280 vpninfo->vpn_nbns[j] = new_option->value;
284 } else if (!strcmp(buf + 7, "Default-Domain")) {
285 vpninfo->vpn_domain = new_option->value;
286 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
287 vpninfo->vpn_proxy_pac = new_option->value;
288 } else if (!strcmp(buf + 7, "Banner")) {
289 vpninfo->banner = new_option->value;
290 } else if (!strcmp(buf + 7, "Split-Include")) {
291 struct split_include *inc = malloc(sizeof(*inc));
294 inc->route = new_option->value;
295 inc->next = vpninfo->split_includes;
296 vpninfo->split_includes = inc;
297 } else if (!strcmp(buf + 7, "Split-Exclude")) {
298 struct split_include *exc = malloc(sizeof(*exc));
301 exc->route = new_option->value;
302 exc->next = vpninfo->split_excludes;
303 vpninfo->split_excludes = exc;
307 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
308 vpn_progress(vpninfo, PRG_ERR,
309 _("No IP address received. Aborting\n"));
313 if (strcmp(old_addr, vpninfo->vpn_addr)) {
314 vpn_progress(vpninfo, PRG_ERR,
315 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
316 vpninfo->vpn_addr, old_addr);
321 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
322 vpn_progress(vpninfo, PRG_ERR,
323 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
324 vpninfo->vpn_netmask, old_netmask);
329 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
330 vpn_progress(vpninfo, PRG_ERR,
331 _("Reconnect gave different IPv6 address (%s != %s)\n"),
332 vpninfo->vpn_addr6, old_addr6);
337 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
338 vpn_progress(vpninfo, PRG_ERR,
339 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
340 vpninfo->vpn_netmask6, old_netmask6);
345 while (old_dtls_opts) {
346 struct vpn_option *tmp = old_dtls_opts;
347 old_dtls_opts = old_dtls_opts->next;
352 while (old_cstp_opts) {
353 struct vpn_option *tmp = old_cstp_opts;
354 old_cstp_opts = old_cstp_opts->next;
359 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
360 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
362 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
363 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
365 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
366 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
369 vpninfo->dtls_attempt_period = 0;
371 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
372 vpninfo->ssl_times.last_tx = time(NULL);
377 int make_cstp_connection(struct openconnect_info *vpninfo)
381 ret = openconnect_open_https(vpninfo);
385 if (vpninfo->deflate) {
386 vpninfo->deflate_adler32 = 1;
387 vpninfo->inflate_adler32 = 1;
389 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
390 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
391 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
392 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
393 vpninfo->deflate = 0;
396 if (!vpninfo->deflate_pkt) {
397 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
398 if (!vpninfo->deflate_pkt) {
399 vpn_progress(vpninfo, PRG_ERR,
400 _("Allocation of deflate buffer failed\n"));
401 inflateEnd(&vpninfo->inflate_strm);
402 deflateEnd(&vpninfo->deflate_strm);
403 vpninfo->deflate = 0;
405 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
406 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
407 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
412 return start_cstp_connection(vpninfo);
415 int cstp_reconnect(struct openconnect_info *vpninfo)
421 openconnect_close_https(vpninfo);
423 /* Requeue the original packet that was deflated */
424 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
425 vpninfo->current_ssl_pkt = NULL;
426 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
427 vpninfo->pending_deflated_pkt = NULL;
429 if (vpninfo->deflate) {
430 inflateEnd(&vpninfo->inflate_strm);
431 deflateEnd(&vpninfo->deflate_strm);
433 timeout = vpninfo->reconnect_timeout;
434 interval = vpninfo->reconnect_interval;
436 while ((ret = make_cstp_connection(vpninfo))) {
439 vpn_progress(vpninfo, PRG_INFO,
440 _("sleep %ds, remaining timeout %ds\n"),
446 interval += vpninfo->reconnect_interval;
447 if (interval > RECONNECT_INTERVAL_MAX)
448 interval = RECONNECT_INTERVAL_MAX;
450 script_config_tun(vpninfo, "reconnect");
454 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
455 unsigned char *buf, int len)
457 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
465 vpninfo->inflate_strm.next_in = buf;
466 vpninfo->inflate_strm.avail_in = len - 4;
468 vpninfo->inflate_strm.next_out = new->data;
469 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
470 vpninfo->inflate_strm.total_out = 0;
472 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
473 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
478 new->len = vpninfo->inflate_strm.total_out;
480 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
481 new->data, new->len);
483 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
484 (buf[len - 3] << 16) | (buf[len - 4] << 24);
486 if (vpninfo->inflate_adler32 != pkt_sum) {
487 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
490 vpn_progress(vpninfo, PRG_TRACE,
491 _("Received compressed data packet of %ld bytes\n"),
492 (long)vpninfo->inflate_strm.total_out);
494 queue_packet(&vpninfo->incoming_queue, new);
498 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
500 unsigned char buf[16384];
504 /* FIXME: The poll() handling here is fairly simplistic. Actually,
505 if the SSL connection stalls it could return a WANT_WRITE error
506 on _either_ of the SSL_read() or SSL_write() calls. In that case,
507 we should probably remove POLLIN from the events we're looking for,
508 and add POLLOUT. As it is, though, it'll just chew CPU time in that
509 fairly unlikely situation, until the write backlog clears. */
510 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
513 if (buf[0] != 'S' || buf[1] != 'T' ||
514 buf[2] != 'F' || buf[3] != 1 || buf[7])
517 payload_len = (buf[4] << 8) + buf[5];
518 if (len != 8 + payload_len) {
519 vpn_progress(vpninfo, PRG_ERR,
520 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
522 vpn_progress(vpninfo, PRG_ERR,
523 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
524 buf[0], buf[1], buf[2], buf[3],
525 buf[4], buf[5], buf[6], buf[7]);
528 vpninfo->ssl_times.last_rx = time(NULL);
531 vpn_progress(vpninfo, PRG_TRACE,
532 _("Got CSTP DPD request\n"));
533 vpninfo->owe_ssl_dpd_response = 1;
536 case AC_PKT_DPD_RESP:
537 vpn_progress(vpninfo, PRG_TRACE,
538 _("Got CSTP DPD response\n"));
541 case AC_PKT_KEEPALIVE:
542 vpn_progress(vpninfo, PRG_TRACE,
543 _("Got CSTP Keepalive\n"));
547 vpn_progress(vpninfo, PRG_TRACE,
548 _("Received uncompressed data packet of %d bytes\n"),
550 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
555 case AC_PKT_DISCONN: {
557 for (i = 0; i < payload_len; i++) {
558 if (!isprint(buf[payload_len + 8 + i]))
559 buf[payload_len + 8 + i] = '.';
561 buf[payload_len + 8] = 0;
562 vpn_progress(vpninfo, PRG_ERR,
563 _("Received server disconnect: %02x '%s'\n"),
565 vpninfo->quit_reason = "Server request";
568 case AC_PKT_COMPRESSED:
569 if (!vpninfo->deflate) {
570 vpn_progress(vpninfo, PRG_ERR,
571 _("Compressed packet received in !deflate mode\n"));
574 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
578 case AC_PKT_TERM_SERVER:
579 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
580 vpninfo->quit_reason = "Server request";
585 vpn_progress(vpninfo, PRG_ERR,
586 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
587 buf[0], buf[1], buf[2], buf[3],
588 buf[4], buf[5], buf[6], buf[7]);
589 vpninfo->quit_reason = "Unknown packet received";
593 ret = SSL_get_error(vpninfo->https_ssl, len);
594 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
595 vpn_progress(vpninfo, PRG_ERR,
596 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
602 /* If SSL_write() fails we are expected to try again. With exactly
603 the same data, at exactly the same location. So we keep the
604 packet we had before.... */
605 if (vpninfo->current_ssl_pkt) {
607 vpninfo->ssl_times.last_tx = time(NULL);
608 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
609 ret = SSL_write(vpninfo->https_ssl,
610 vpninfo->current_ssl_pkt->hdr,
611 vpninfo->current_ssl_pkt->len + 8);
613 ret = SSL_get_error(vpninfo->https_ssl, ret);
615 case SSL_ERROR_WANT_WRITE:
616 /* Waiting for the socket to become writable -- it's
617 probably stalled, and/or the buffers are full */
618 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
620 case SSL_ERROR_WANT_READ:
621 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
625 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
626 openconnect_report_ssl_errors(vpninfo);
630 if (ret != vpninfo->current_ssl_pkt->len + 8) {
631 vpn_progress(vpninfo, PRG_ERR,
632 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
633 vpninfo->current_ssl_pkt->len + 8, ret);
634 vpninfo->quit_reason = "Internal error";
637 /* Don't free the 'special' packets */
638 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
639 free(vpninfo->pending_deflated_pkt);
640 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
641 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
642 vpninfo->current_ssl_pkt != &keepalive_pkt)
643 free(vpninfo->current_ssl_pkt);
645 vpninfo->current_ssl_pkt = NULL;
648 if (vpninfo->owe_ssl_dpd_response) {
649 vpninfo->owe_ssl_dpd_response = 0;
650 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
651 goto handle_outgoing;
654 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
656 /* Not that this will ever happen; we don't even process
657 the setting when we're asked for it. */
658 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
664 vpn_progress(vpninfo, PRG_ERR,
665 _("CSTP Dead Peer Detection detected dead peer!\n"));
667 if (cstp_reconnect(vpninfo)) {
668 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
669 vpninfo->quit_reason = "CSTP reconnect failed";
672 /* I think we can leave DTLS to its own devices; when we reconnect
673 with the same master secret, we do seem to get the same sessid */
677 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
679 vpninfo->current_ssl_pkt = &dpd_pkt;
680 goto handle_outgoing;
683 /* No need to send an explicit keepalive
684 if we have real data to send */
685 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
688 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
690 vpninfo->current_ssl_pkt = &keepalive_pkt;
691 goto handle_outgoing;
697 /* Service outgoing packet queue, if no DTLS */
698 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
699 struct pkt *this = vpninfo->outgoing_queue;
700 vpninfo->outgoing_queue = this->next;
701 vpninfo->outgoing_qlen--;
703 if (vpninfo->deflate) {
704 unsigned char *adler;
707 vpninfo->deflate_strm.next_in = this->data;
708 vpninfo->deflate_strm.avail_in = this->len;
709 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
710 vpninfo->deflate_strm.avail_out = 2040;
711 vpninfo->deflate_strm.total_out = 0;
713 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
715 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
719 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
720 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
722 /* Add ongoing adler32 to tail of compressed packet */
723 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
724 this->data, this->len);
726 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
727 *(adler++) = vpninfo->deflate_adler32 >> 24;
728 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
729 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
730 *(adler) = vpninfo->deflate_adler32 & 0xff;
732 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
734 vpn_progress(vpninfo, PRG_TRACE,
735 _("Sending compressed data packet of %d bytes\n"),
738 vpninfo->pending_deflated_pkt = this;
739 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
742 memcpy(this->hdr, data_hdr, 8);
743 this->hdr[4] = this->len >> 8;
744 this->hdr[5] = this->len & 0xff;
746 vpn_progress(vpninfo, PRG_TRACE,
747 _("Sending uncompressed data packet of %d bytes\n"),
750 vpninfo->current_ssl_pkt = this;
752 goto handle_outgoing;
755 /* Work is not done if we just got rid of packets off the queue */
759 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
761 unsigned char *bye_pkt;
764 /* already lost connection? */
765 if (!vpninfo->https_ssl)
768 reason_len = strlen(reason);
769 bye_pkt = malloc(reason_len + 9);
773 memcpy(bye_pkt, data_hdr, 8);
774 memcpy(bye_pkt + 9, reason, reason_len);
776 bye_pkt[4] = (reason_len + 1) >> 8;
777 bye_pkt[5] = (reason_len + 1) & 0xff;
778 bye_pkt[6] = AC_PKT_DISCONN;
781 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
784 vpn_progress(vpninfo, PRG_INFO,
785 _("Send BYE packet: %s\n"), reason);