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 <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 /* We don't cope with nonblocking mode... yet */
115 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) & ~O_NONBLOCK);
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 (openconnect_SSL_gets(vpninfo, buf, 65536) < 0) {
135 vpn_progress(vpninfo, PRG_ERR,
136 _("Error fetching HTTPS response\n"));
139 openconnect_close_https(vpninfo);
141 if (openconnect_open_https(vpninfo)) {
142 vpn_progress(vpninfo, PRG_ERR,
143 _("Failed to open HTTPS connection to %s\n"),
152 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
153 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
154 /* "Service Unavailable. Why? */
155 const char *reason = "<unknown>";
156 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
157 if (!strncmp(buf, "X-Reason: ", 10)) {
162 vpn_progress(vpninfo, PRG_ERR,
163 _("VPN service unavailable; reason: %s\n"),
167 vpn_progress(vpninfo, PRG_ERR,
168 _("Got inappropriate HTTP CONNECT response: %s\n"),
170 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
175 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
177 /* We may have advertised it, but we only do it if the server agrees */
178 vpninfo->deflate = 0;
180 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
181 struct vpn_option *new_option;
182 char *colon = strchr(buf, ':');
191 if (strncmp(buf, "X-DTLS-", 7) &&
192 strncmp(buf, "X-CSTP-", 7))
195 new_option = malloc(sizeof(*new_option));
197 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
200 new_option->option = strdup(buf);
201 new_option->value = strdup(colon);
202 new_option->next = NULL;
204 if (!new_option->option || !new_option->value) {
205 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
209 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
211 if (!strncmp(buf, "X-DTLS-", 7)) {
212 *next_dtls_option = new_option;
213 next_dtls_option = &new_option->next;
215 if (!strcmp(buf + 7, "Session-ID")) {
216 if (strlen(colon) != 64) {
217 vpn_progress(vpninfo, PRG_ERR,
218 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
220 vpninfo->dtls_attempt_period = 0;
223 for (i = 0; i < 64; i += 2)
224 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
226 time(&vpninfo->dtls_times.last_rekey);
230 /* CSTP options... */
231 *next_cstp_option = new_option;
232 next_cstp_option = &new_option->next;
235 if (!strcmp(buf + 7, "Keepalive")) {
236 vpninfo->ssl_times.keepalive = atol(colon);
237 } else if (!strcmp(buf + 7, "DPD")) {
239 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
240 vpninfo->ssl_times.dpd = j;
241 } else if (!strcmp(buf + 7, "Rekey-Time")) {
242 vpninfo->ssl_times.rekey = atol(colon);
243 } else if (!strcmp(buf + 7, "Content-Encoding")) {
244 if (!strcmp(colon, "deflate"))
245 vpninfo->deflate = 1;
247 vpn_progress(vpninfo, PRG_ERR,
248 _("Unknown CSTP-Content-Encoding %s\n"),
252 } else if (!strcmp(buf + 7, "MTU")) {
253 vpninfo->mtu = atol(colon);
254 } else if (!strcmp(buf + 7, "Address")) {
255 if (strchr(new_option->value, ':'))
256 vpninfo->vpn_addr6 = new_option->value;
258 vpninfo->vpn_addr = new_option->value;
259 } else if (!strcmp(buf + 7, "Netmask")) {
260 if (strchr(new_option->value, ':'))
261 vpninfo->vpn_netmask6 = new_option->value;
263 vpninfo->vpn_netmask = new_option->value;
264 } else if (!strcmp(buf + 7, "DNS")) {
266 for (j = 0; j < 3; j++) {
267 if (!vpninfo->vpn_dns[j]) {
268 vpninfo->vpn_dns[j] = new_option->value;
272 } else if (!strcmp(buf + 7, "NBNS")) {
274 for (j = 0; j < 3; j++) {
275 if (!vpninfo->vpn_nbns[j]) {
276 vpninfo->vpn_nbns[j] = new_option->value;
280 } else if (!strcmp(buf + 7, "Default-Domain")) {
281 vpninfo->vpn_domain = new_option->value;
282 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
283 vpninfo->vpn_proxy_pac = new_option->value;
284 } else if (!strcmp(buf + 7, "Banner")) {
285 vpninfo->banner = new_option->value;
286 } else if (!strcmp(buf + 7, "Split-Include")) {
287 struct split_include *inc = malloc(sizeof(*inc));
290 inc->route = new_option->value;
291 inc->next = vpninfo->split_includes;
292 vpninfo->split_includes = inc;
293 } else if (!strcmp(buf + 7, "Split-Exclude")) {
294 struct split_include *exc = malloc(sizeof(*exc));
297 exc->route = new_option->value;
298 exc->next = vpninfo->split_excludes;
299 vpninfo->split_excludes = exc;
303 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
304 vpn_progress(vpninfo, PRG_ERR,
305 _("No IP address received. Aborting\n"));
309 if (strcmp(old_addr, vpninfo->vpn_addr)) {
310 vpn_progress(vpninfo, PRG_ERR,
311 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
312 vpninfo->vpn_addr, old_addr);
317 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
318 vpn_progress(vpninfo, PRG_ERR,
319 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
320 vpninfo->vpn_netmask, old_netmask);
325 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
326 vpn_progress(vpninfo, PRG_ERR,
327 _("Reconnect gave different IPv6 address (%s != %s)\n"),
328 vpninfo->vpn_addr6, old_addr6);
333 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
334 vpn_progress(vpninfo, PRG_ERR,
335 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
336 vpninfo->vpn_netmask6, old_netmask6);
341 while (old_dtls_opts) {
342 struct vpn_option *tmp = old_dtls_opts;
343 old_dtls_opts = old_dtls_opts->next;
348 while (old_cstp_opts) {
349 struct vpn_option *tmp = old_cstp_opts;
350 old_cstp_opts = old_cstp_opts->next;
355 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
356 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
358 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
359 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
361 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
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 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
384 if (vpninfo->deflate) {
385 vpninfo->deflate_adler32 = 1;
386 vpninfo->inflate_adler32 = 1;
388 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
389 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
390 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
391 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
392 vpninfo->deflate = 0;
395 if (!vpninfo->deflate_pkt) {
396 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
397 if (!vpninfo->deflate_pkt) {
398 vpn_progress(vpninfo, PRG_ERR,
399 _("Allocation of deflate buffer failed\n"));
400 inflateEnd(&vpninfo->inflate_strm);
401 deflateEnd(&vpninfo->deflate_strm);
402 vpninfo->deflate = 0;
404 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
405 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
406 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
411 return start_cstp_connection(vpninfo);
414 int cstp_reconnect(struct openconnect_info *vpninfo)
420 openconnect_close_https(vpninfo);
422 /* Requeue the original packet that was deflated */
423 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
424 vpninfo->current_ssl_pkt = NULL;
425 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
426 vpninfo->pending_deflated_pkt = NULL;
428 if (vpninfo->deflate) {
429 inflateEnd(&vpninfo->inflate_strm);
430 deflateEnd(&vpninfo->deflate_strm);
432 timeout = vpninfo->reconnect_timeout;
433 interval = vpninfo->reconnect_interval;
435 while ((ret = make_cstp_connection(vpninfo))) {
438 vpn_progress(vpninfo, PRG_INFO,
439 _("sleep %ds, remaining timeout %ds\n"),
445 interval += vpninfo->reconnect_interval;
446 if (interval > RECONNECT_INTERVAL_MAX)
447 interval = RECONNECT_INTERVAL_MAX;
449 script_config_tun(vpninfo, "reconnect");
453 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
454 unsigned char *buf, int len)
456 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
464 vpninfo->inflate_strm.next_in = buf;
465 vpninfo->inflate_strm.avail_in = len - 4;
467 vpninfo->inflate_strm.next_out = new->data;
468 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
469 vpninfo->inflate_strm.total_out = 0;
471 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
472 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
477 new->len = vpninfo->inflate_strm.total_out;
479 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
480 new->data, new->len);
482 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
483 (buf[len - 3] << 16) | (buf[len - 4] << 24);
485 if (vpninfo->inflate_adler32 != pkt_sum) {
486 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
489 vpn_progress(vpninfo, PRG_TRACE,
490 _("Received compressed data packet of %ld bytes\n"),
491 (long)vpninfo->inflate_strm.total_out);
493 queue_packet(&vpninfo->incoming_queue, new);
497 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
499 unsigned char buf[16384];
503 /* FIXME: The poll() handling here is fairly simplistic. Actually,
504 if the SSL connection stalls it could return a WANT_WRITE error
505 on _either_ of the SSL_read() or SSL_write() calls. In that case,
506 we should probably remove POLLIN from the events we're looking for,
507 and add POLLOUT. As it is, though, it'll just chew CPU time in that
508 fairly unlikely situation, until the write backlog clears. */
509 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
512 if (buf[0] != 'S' || buf[1] != 'T' ||
513 buf[2] != 'F' || buf[3] != 1 || buf[7])
516 payload_len = (buf[4] << 8) + buf[5];
517 if (len != 8 + payload_len) {
518 vpn_progress(vpninfo, PRG_ERR,
519 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
521 vpn_progress(vpninfo, PRG_ERR,
522 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
523 buf[0], buf[1], buf[2], buf[3],
524 buf[4], buf[5], buf[6], buf[7]);
527 vpninfo->ssl_times.last_rx = time(NULL);
530 vpn_progress(vpninfo, PRG_TRACE,
531 _("Got CSTP DPD request\n"));
532 vpninfo->owe_ssl_dpd_response = 1;
535 case AC_PKT_DPD_RESP:
536 vpn_progress(vpninfo, PRG_TRACE,
537 _("Got CSTP DPD response\n"));
540 case AC_PKT_KEEPALIVE:
541 vpn_progress(vpninfo, PRG_TRACE,
542 _("Got CSTP Keepalive\n"));
546 vpn_progress(vpninfo, PRG_TRACE,
547 _("Received uncompressed data packet of %d bytes\n"),
549 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
554 case AC_PKT_DISCONN: {
556 for (i = 0; i < payload_len; i++) {
557 if (!isprint(buf[payload_len + 8 + i]))
558 buf[payload_len + 8 + i] = '.';
560 buf[payload_len + 8] = 0;
561 vpn_progress(vpninfo, PRG_ERR,
562 _("Received server disconnect: %02x '%s'\n"),
564 vpninfo->quit_reason = "Server request";
567 case AC_PKT_COMPRESSED:
568 if (!vpninfo->deflate) {
569 vpn_progress(vpninfo, PRG_ERR,
570 _("Compressed packet received in !deflate mode\n"));
573 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
577 case AC_PKT_TERM_SERVER:
578 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
579 vpninfo->quit_reason = "Server request";
584 vpn_progress(vpninfo, PRG_ERR,
585 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
586 buf[0], buf[1], buf[2], buf[3],
587 buf[4], buf[5], buf[6], buf[7]);
588 vpninfo->quit_reason = "Unknown packet received";
592 ret = SSL_get_error(vpninfo->https_ssl, len);
593 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
594 vpn_progress(vpninfo, PRG_ERR,
595 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
601 /* If SSL_write() fails we are expected to try again. With exactly
602 the same data, at exactly the same location. So we keep the
603 packet we had before.... */
604 if (vpninfo->current_ssl_pkt) {
606 vpninfo->ssl_times.last_tx = time(NULL);
607 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
608 ret = SSL_write(vpninfo->https_ssl,
609 vpninfo->current_ssl_pkt->hdr,
610 vpninfo->current_ssl_pkt->len + 8);
612 ret = SSL_get_error(vpninfo->https_ssl, ret);
614 case SSL_ERROR_WANT_WRITE:
615 /* Waiting for the socket to become writable -- it's
616 probably stalled, and/or the buffers are full */
617 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
619 case SSL_ERROR_WANT_READ:
620 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
624 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
625 report_ssl_errors(vpninfo);
629 if (ret != vpninfo->current_ssl_pkt->len + 8) {
630 vpn_progress(vpninfo, PRG_ERR,
631 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
632 vpninfo->current_ssl_pkt->len + 8, ret);
633 vpninfo->quit_reason = "Internal error";
636 /* Don't free the 'special' packets */
637 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
638 free(vpninfo->pending_deflated_pkt);
639 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
640 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
641 vpninfo->current_ssl_pkt != &keepalive_pkt)
642 free(vpninfo->current_ssl_pkt);
644 vpninfo->current_ssl_pkt = NULL;
647 if (vpninfo->owe_ssl_dpd_response) {
648 vpninfo->owe_ssl_dpd_response = 0;
649 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
650 goto handle_outgoing;
653 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
655 /* Not that this will ever happen; we don't even process
656 the setting when we're asked for it. */
657 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
663 vpn_progress(vpninfo, PRG_ERR,
664 _("CSTP Dead Peer Detection detected dead peer!\n"));
666 if (cstp_reconnect(vpninfo)) {
667 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
668 vpninfo->quit_reason = "CSTP reconnect failed";
671 /* I think we can leave DTLS to its own devices; when we reconnect
672 with the same master secret, we do seem to get the same sessid */
676 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
678 vpninfo->current_ssl_pkt = &dpd_pkt;
679 goto handle_outgoing;
682 /* No need to send an explicit keepalive
683 if we have real data to send */
684 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
687 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
689 vpninfo->current_ssl_pkt = &keepalive_pkt;
690 goto handle_outgoing;
696 /* Service outgoing packet queue, if no DTLS */
697 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
698 struct pkt *this = vpninfo->outgoing_queue;
699 vpninfo->outgoing_queue = this->next;
700 vpninfo->outgoing_qlen--;
702 if (vpninfo->deflate) {
703 unsigned char *adler;
706 vpninfo->deflate_strm.next_in = this->data;
707 vpninfo->deflate_strm.avail_in = this->len;
708 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
709 vpninfo->deflate_strm.avail_out = 2040;
710 vpninfo->deflate_strm.total_out = 0;
712 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
714 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
718 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
719 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
721 /* Add ongoing adler32 to tail of compressed packet */
722 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
723 this->data, this->len);
725 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
726 *(adler++) = vpninfo->deflate_adler32 >> 24;
727 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
728 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
729 *(adler) = vpninfo->deflate_adler32 & 0xff;
731 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
733 vpn_progress(vpninfo, PRG_TRACE,
734 _("Sending compressed data packet of %d bytes\n"),
737 vpninfo->pending_deflated_pkt = this;
738 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
741 memcpy(this->hdr, data_hdr, 8);
742 this->hdr[4] = this->len >> 8;
743 this->hdr[5] = this->len & 0xff;
745 vpn_progress(vpninfo, PRG_TRACE,
746 _("Sending uncompressed data packet of %d bytes\n"),
749 vpninfo->current_ssl_pkt = this;
751 goto handle_outgoing;
754 /* Work is not done if we just got rid of packets off the queue */
758 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
760 unsigned char *bye_pkt;
763 /* already lost connection? */
764 if (!vpninfo->https_ssl)
767 reason_len = strlen(reason);
768 bye_pkt = malloc(reason_len + 9);
772 memcpy(bye_pkt, data_hdr, 8);
773 memcpy(bye_pkt + 9, reason, reason_len);
775 bye_pkt[4] = (reason_len + 1) >> 8;
776 bye_pkt[5] = (reason_len + 1) & 0xff;
777 bye_pkt[6] = AC_PKT_DISCONN;
780 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
783 vpn_progress(vpninfo, PRG_INFO,
784 _("Send BYE packet: %s\n"), reason);