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
33 #include <arpa/inet.h>
35 #include <openssl/ssl.h>
36 #include <openssl/err.h>
37 #include <openssl/rand.h>
39 #include "openconnect-internal.h"
42 * Data packets are encapsulated in the SSL stream as follows:
44 * 0000: Magic "STF\x1"
45 * 0004: Big-endian 16-bit length (not including 8-byte header)
46 * 0006: Byte packet type (see openconnect-internal.h)
50 static char data_hdr[8] = {
53 AC_PKT_DATA, /* Type */
57 static struct pkt keepalive_pkt = {
58 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
61 static struct pkt dpd_pkt = {
62 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
65 static struct pkt dpd_resp_pkt = {
66 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
70 static int start_cstp_connection(struct openconnect_info *vpninfo)
74 int retried = 0, sessid_found = 0;
75 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
76 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
77 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
78 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
79 const char *old_addr = vpninfo->vpn_addr;
80 const char *old_netmask = vpninfo->vpn_netmask;
81 const char *old_addr6 = vpninfo->vpn_addr6;
82 const char *old_netmask6 = vpninfo->vpn_netmask6;
83 struct split_include *inc;
85 /* Clear old options which will be overwritten */
86 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
87 vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
88 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
89 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
90 vpninfo->banner = NULL;
93 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
95 for (inc = vpninfo->split_includes; inc; ) {
96 struct split_include *next = inc->next;
100 for (inc = vpninfo->split_excludes; inc; ) {
101 struct split_include *next = inc->next;
105 vpninfo->split_includes = vpninfo->split_excludes = NULL;
107 /* Create (new) random master key for DTLS connection, if needed */
108 if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
110 RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
111 fprintf(stderr, _("Failed to initialise DTLS secret\n"));
116 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
117 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
118 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
119 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
120 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
121 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
122 if (vpninfo->deflate)
123 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
124 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
125 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
126 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
127 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
128 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
129 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
130 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
131 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
133 if (openconnect_SSL_gets(vpninfo->https_ssl, 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->https_ssl, 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->https_ssl, buf, sizeof(buf)))) {
180 struct vpn_option *new_option;
181 char *colon = strchr(buf, ':');
190 if (strncmp(buf, "X-DTLS-", 7) &&
191 strncmp(buf, "X-CSTP-", 7))
194 new_option = malloc(sizeof(*new_option));
196 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
199 new_option->option = strdup(buf);
200 new_option->value = strdup(colon);
201 new_option->next = NULL;
203 if (!new_option->option || !new_option->value) {
204 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
208 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
210 if (!strncmp(buf, "X-DTLS-", 7)) {
211 *next_dtls_option = new_option;
212 next_dtls_option = &new_option->next;
214 if (!strcmp(buf + 7, "Session-ID")) {
215 if (strlen(colon) != 64) {
216 vpn_progress(vpninfo, PRG_ERR,
217 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
219 vpninfo->dtls_attempt_period = 0;
222 for (i = 0; i < 64; i += 2)
223 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
225 time(&vpninfo->dtls_times.last_rekey);
229 /* CSTP options... */
230 *next_cstp_option = new_option;
231 next_cstp_option = &new_option->next;
234 if (!strcmp(buf + 7, "Keepalive")) {
235 vpninfo->ssl_times.keepalive = atol(colon);
236 } else if (!strcmp(buf + 7, "DPD")) {
238 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
239 vpninfo->ssl_times.dpd = j;
240 } else if (!strcmp(buf + 7, "Rekey-Time")) {
241 vpninfo->ssl_times.rekey = atol(colon);
242 } else if (!strcmp(buf + 7, "Content-Encoding")) {
243 if (!strcmp(colon, "deflate"))
244 vpninfo->deflate = 1;
246 vpn_progress(vpninfo, PRG_ERR,
247 _("Unknown CSTP-Content-Encoding %s\n"),
251 } else if (!strcmp(buf + 7, "MTU")) {
252 vpninfo->mtu = atol(colon);
253 } else if (!strcmp(buf + 7, "Address")) {
254 if (strchr(new_option->value, ':'))
255 vpninfo->vpn_addr6 = new_option->value;
257 vpninfo->vpn_addr = new_option->value;
258 } else if (!strcmp(buf + 7, "Netmask")) {
259 if (strchr(new_option->value, ':'))
260 vpninfo->vpn_netmask6 = new_option->value;
262 vpninfo->vpn_netmask = new_option->value;
263 } else if (!strcmp(buf + 7, "DNS")) {
265 for (j = 0; j < 3; j++) {
266 if (!vpninfo->vpn_dns[j]) {
267 vpninfo->vpn_dns[j] = new_option->value;
271 } else if (!strcmp(buf + 7, "NBNS")) {
273 for (j = 0; j < 3; j++) {
274 if (!vpninfo->vpn_nbns[j]) {
275 vpninfo->vpn_nbns[j] = new_option->value;
279 } else if (!strcmp(buf + 7, "Default-Domain")) {
280 vpninfo->vpn_domain = new_option->value;
281 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
282 vpninfo->vpn_proxy_pac = new_option->value;
283 } else if (!strcmp(buf + 7, "Banner")) {
284 vpninfo->banner = new_option->value;
285 } else if (!strcmp(buf + 7, "Split-Include")) {
286 struct split_include *inc = malloc(sizeof(*inc));
289 inc->route = new_option->value;
290 inc->next = vpninfo->split_includes;
291 vpninfo->split_includes = inc;
292 } else if (!strcmp(buf + 7, "Split-Exclude")) {
293 struct split_include *exc = malloc(sizeof(*exc));
296 exc->route = new_option->value;
297 exc->next = vpninfo->split_excludes;
298 vpninfo->split_excludes = exc;
302 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
303 vpn_progress(vpninfo, PRG_ERR,
304 _("No IP address received. Aborting\n"));
308 if (strcmp(old_addr, vpninfo->vpn_addr)) {
309 vpn_progress(vpninfo, PRG_ERR,
310 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
311 vpninfo->vpn_addr, old_addr);
316 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
317 vpn_progress(vpninfo, PRG_ERR,
318 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
319 vpninfo->vpn_netmask, old_netmask);
324 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
325 vpn_progress(vpninfo, PRG_ERR,
326 _("Reconnect gave different IPv6 address (%s != %s)\n"),
327 vpninfo->vpn_addr6, old_addr6);
332 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
333 vpn_progress(vpninfo, PRG_ERR,
334 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
335 vpninfo->vpn_netmask6, old_netmask6);
340 while (old_dtls_opts) {
341 struct vpn_option *tmp = old_dtls_opts;
342 old_dtls_opts = old_dtls_opts->next;
347 while (old_cstp_opts) {
348 struct vpn_option *tmp = old_cstp_opts;
349 old_cstp_opts = old_cstp_opts->next;
354 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
355 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
357 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
358 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
360 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
361 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
362 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
364 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
365 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
368 vpninfo->dtls_attempt_period = 0;
370 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
371 vpninfo->ssl_times.last_tx = time(NULL);
376 int make_cstp_connection(struct openconnect_info *vpninfo)
380 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
383 if (vpninfo->deflate) {
384 vpninfo->deflate_adler32 = 1;
385 vpninfo->inflate_adler32 = 1;
387 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
388 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
389 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
390 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
391 vpninfo->deflate = 0;
394 if (!vpninfo->deflate_pkt) {
395 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
396 if (!vpninfo->deflate_pkt) {
397 vpn_progress(vpninfo, PRG_ERR,
398 _("Allocation of deflate buffer failed\n"));
399 vpninfo->deflate = 0;
401 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
402 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
403 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
407 return start_cstp_connection(vpninfo);
410 int cstp_reconnect(struct openconnect_info *vpninfo)
416 openconnect_close_https(vpninfo);
418 /* It's already deflated in the old stream. Extremely
419 non-trivial to reconstitute it; just throw it away */
420 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
421 vpninfo->current_ssl_pkt = NULL;
423 timeout = vpninfo->reconnect_timeout;
424 interval = vpninfo->reconnect_interval;
426 while ((ret = make_cstp_connection(vpninfo))) {
429 vpn_progress(vpninfo, PRG_INFO,
430 _("sleep %ds, remaining timeout %ds\n"),
436 interval += vpninfo->reconnect_interval;
437 if (interval > RECONNECT_INTERVAL_MAX)
438 interval = RECONNECT_INTERVAL_MAX;
440 script_reconnect(vpninfo);
444 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
445 unsigned char *buf, int len)
447 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
455 vpninfo->inflate_strm.next_in = buf;
456 vpninfo->inflate_strm.avail_in = len - 4;
458 vpninfo->inflate_strm.next_out = new->data;
459 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
460 vpninfo->inflate_strm.total_out = 0;
462 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
463 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
468 new->len = vpninfo->inflate_strm.total_out;
470 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
471 new->data, new->len);
473 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
474 (buf[len - 3] << 16) | (buf[len - 4] << 24);
476 if (vpninfo->inflate_adler32 != pkt_sum) {
477 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
480 vpn_progress(vpninfo, PRG_TRACE,
481 _("Received compressed data packet of %ld bytes\n"),
482 vpninfo->inflate_strm.total_out);
484 queue_packet(&vpninfo->incoming_queue, new);
488 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
490 unsigned char buf[16384];
494 /* FIXME: The poll() handling here is fairly simplistic. Actually,
495 if the SSL connection stalls it could return a WANT_WRITE error
496 on _either_ of the SSL_read() or SSL_write() calls. In that case,
497 we should probably remove POLLIN from the events we're looking for,
498 and add POLLOUT. As it is, though, it'll just chew CPU time in that
499 fairly unlikely situation, until the write backlog clears. */
500 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
503 if (buf[0] != 'S' || buf[1] != 'T' ||
504 buf[2] != 'F' || buf[3] != 1 || buf[7])
507 payload_len = (buf[4] << 8) + buf[5];
508 if (len != 8 + payload_len) {
509 vpn_progress(vpninfo, PRG_ERR,
510 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
512 vpn_progress(vpninfo, PRG_ERR,
513 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
514 buf[0], buf[1], buf[2], buf[3],
515 buf[4], buf[5], buf[6], buf[7]);
518 vpninfo->ssl_times.last_rx = time(NULL);
521 vpn_progress(vpninfo, PRG_TRACE,
522 _("Got CSTP DPD request\n"));
523 vpninfo->owe_ssl_dpd_response = 1;
526 case AC_PKT_DPD_RESP:
527 vpn_progress(vpninfo, PRG_TRACE,
528 _("Got CSTP DPD response\n"));
531 case AC_PKT_KEEPALIVE:
532 vpn_progress(vpninfo, PRG_TRACE,
533 _("Got CSTP Keepalive\n"));
537 vpn_progress(vpninfo, PRG_TRACE,
538 _("Received uncompressed data packet of %d bytes\n"),
540 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
545 case AC_PKT_DISCONN: {
547 for (i = 0; i < payload_len; i++) {
548 if (!isprint(buf[payload_len + 8 + i]))
549 buf[payload_len + 8 + i] = '.';
551 buf[payload_len + 8] = 0;
552 vpn_progress(vpninfo, PRG_ERR,
553 _("Received server disconnect: %02x '%s'\n"),
555 vpninfo->quit_reason = "Server request";
558 case AC_PKT_COMPRESSED:
559 if (!vpninfo->deflate) {
560 vpn_progress(vpninfo, PRG_ERR,
561 _("Compressed packet received in !deflate mode\n"));
564 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
568 case AC_PKT_TERM_SERVER:
569 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
570 vpninfo->quit_reason = "Server request";
575 vpn_progress(vpninfo, PRG_ERR,
576 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
577 buf[0], buf[1], buf[2], buf[3],
578 buf[4], buf[5], buf[6], buf[7]);
579 vpninfo->quit_reason = "Unknown packet received";
583 ret = SSL_get_error(vpninfo->https_ssl, len);
584 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
585 vpn_progress(vpninfo, PRG_ERR,
586 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
592 /* If SSL_write() fails we are expected to try again. With exactly
593 the same data, at exactly the same location. So we keep the
594 packet we had before.... */
595 if (vpninfo->current_ssl_pkt) {
597 vpninfo->ssl_times.last_tx = time(NULL);
598 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
599 ret = SSL_write(vpninfo->https_ssl,
600 vpninfo->current_ssl_pkt->hdr,
601 vpninfo->current_ssl_pkt->len + 8);
603 ret = SSL_get_error(vpninfo->https_ssl, ret);
605 case SSL_ERROR_WANT_WRITE:
606 /* Waiting for the socket to become writable -- it's
607 probably stalled, and/or the buffers are full */
608 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
610 case SSL_ERROR_WANT_READ:
611 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
615 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
616 report_ssl_errors(vpninfo);
620 if (ret != vpninfo->current_ssl_pkt->len + 8) {
621 vpn_progress(vpninfo, PRG_ERR,
622 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
623 vpninfo->current_ssl_pkt->len + 8, ret);
624 vpninfo->quit_reason = "Internal error";
627 /* Don't free the 'special' packets */
628 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
629 vpninfo->current_ssl_pkt != &dpd_pkt &&
630 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
631 vpninfo->current_ssl_pkt != &keepalive_pkt)
632 free(vpninfo->current_ssl_pkt);
634 vpninfo->current_ssl_pkt = NULL;
637 if (vpninfo->owe_ssl_dpd_response) {
638 vpninfo->owe_ssl_dpd_response = 0;
639 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
640 goto handle_outgoing;
643 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
645 /* Not that this will ever happen; we don't even process
646 the setting when we're asked for it. */
647 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
653 vpn_progress(vpninfo, PRG_ERR,
654 _("CSTP Dead Peer Detection detected dead peer!\n"));
656 if (cstp_reconnect(vpninfo)) {
657 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
658 vpninfo->quit_reason = "CSTP reconnect failed";
661 /* I think we can leave DTLS to its own devices; when we reconnect
662 with the same master secret, we do seem to get the same sessid */
666 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
668 vpninfo->current_ssl_pkt = &dpd_pkt;
669 goto handle_outgoing;
672 /* No need to send an explicit keepalive
673 if we have real data to send */
674 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
677 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
679 vpninfo->current_ssl_pkt = &keepalive_pkt;
680 goto handle_outgoing;
686 /* Service outgoing packet queue, if no DTLS */
687 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
688 struct pkt *this = vpninfo->outgoing_queue;
689 vpninfo->outgoing_queue = this->next;
690 vpninfo->outgoing_qlen--;
692 if (vpninfo->deflate) {
693 unsigned char *adler;
696 vpninfo->deflate_strm.next_in = this->data;
697 vpninfo->deflate_strm.avail_in = this->len;
698 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
699 vpninfo->deflate_strm.avail_out = 2040;
700 vpninfo->deflate_strm.total_out = 0;
702 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
704 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
708 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
709 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
711 /* Add ongoing adler32 to tail of compressed packet */
712 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
713 this->data, this->len);
715 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
716 *(adler++) = vpninfo->deflate_adler32 >> 24;
717 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
718 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
719 *(adler) = vpninfo->deflate_adler32 & 0xff;
721 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
723 vpn_progress(vpninfo, PRG_TRACE,
724 _("Sending compressed data packet of %d bytes\n"),
727 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
730 memcpy(this->hdr, data_hdr, 8);
731 this->hdr[4] = this->len >> 8;
732 this->hdr[5] = this->len & 0xff;
734 vpn_progress(vpninfo, PRG_TRACE,
735 _("Sending uncompressed data packet of %d bytes\n"),
738 vpninfo->current_ssl_pkt = this;
740 goto handle_outgoing;
743 /* Work is not done if we just got rid of packets off the queue */
747 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
749 unsigned char *bye_pkt;
752 /* already lost connection? */
753 if (!vpninfo->https_ssl)
756 reason_len = strlen(reason);
757 bye_pkt = malloc(reason_len + 9);
761 memcpy(bye_pkt, data_hdr, 8);
762 memcpy(bye_pkt + 9, reason, reason_len);
764 bye_pkt[4] = (reason_len + 1) >> 8;
765 bye_pkt[5] = (reason_len + 1) & 0xff;
766 bye_pkt[6] = AC_PKT_DISCONN;
769 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
772 vpn_progress(vpninfo, PRG_INFO,
773 _("Send BYE packet: %s\n"), reason);