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>
36 #include "openconnect.h"
39 * Data packets are encapsulated in the SSL stream as follows:
41 * 0000: Magic "STF\x1"
42 * 0004: Big-endian 16-bit length (not including 8-byte header)
43 * 0006: Byte packet type (see openconnect.h)
47 static char data_hdr[8] = {
50 AC_PKT_DATA, /* Type */
54 static struct pkt keepalive_pkt = {
55 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
58 static struct pkt dpd_pkt = {
59 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
62 static struct pkt dpd_resp_pkt = {
63 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
67 static int start_cstp_connection(struct openconnect_info *vpninfo)
72 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
73 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
74 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
75 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
76 const char *old_addr = vpninfo->vpn_addr;
77 const char *old_netmask = vpninfo->vpn_netmask;
78 const char *old_addr6 = vpninfo->vpn_addr6;
79 const char *old_netmask6 = vpninfo->vpn_netmask6;
80 struct split_include *inc;
82 /* Clear old options which will be overwritten */
83 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
84 vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
85 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
86 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
87 vpninfo->banner = NULL;
90 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
92 for (inc = vpninfo->split_includes; inc; ) {
93 struct split_include *next = inc->next;
97 for (inc = vpninfo->split_excludes; inc; ) {
98 struct split_include *next = inc->next;
102 vpninfo->split_includes = vpninfo->split_excludes = NULL;
104 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
105 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
106 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
107 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
108 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
109 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
110 if (vpninfo->deflate)
111 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
112 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
113 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
114 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
115 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
116 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
117 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
118 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
119 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
121 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
122 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
125 openconnect_close_https(vpninfo);
127 if (openconnect_open_https(vpninfo)) {
128 vpninfo->progress(vpninfo, PRG_ERR,
129 "Failed to open HTTPS connection to %s\n",
138 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
139 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
140 /* "Service Unavailable. Why? */
141 char *reason = "<unknown>";
142 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
143 if (!strncmp(buf, "X-Reason: ", 10)) {
148 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
152 vpninfo->progress(vpninfo, PRG_ERR,
153 "Got inappropriate HTTP CONNECT response: %s\n",
155 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
160 vpninfo->progress(vpninfo, PRG_INFO,
161 "Got CONNECT response: %s\n", buf);
163 /* We may have advertised it, but we only do it if the server agrees */
164 vpninfo->deflate = 0;
166 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
167 struct vpn_option *new_option;
168 char *colon = strchr(buf, ':');
177 if (strncmp(buf, "X-DTLS-", 7) &&
178 strncmp(buf, "X-CSTP-", 7))
181 new_option = malloc(sizeof(*new_option));
183 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
186 new_option->option = strdup(buf);
187 new_option->value = strdup(colon);
188 new_option->next = NULL;
190 if (!new_option->option || !new_option->value) {
191 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
195 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
197 if (!strncmp(buf, "X-DTLS-", 7)) {
198 *next_dtls_option = new_option;
199 next_dtls_option = &new_option->next;
202 /* CSTP options... */
203 *next_cstp_option = new_option;
204 next_cstp_option = &new_option->next;
207 if (!strcmp(buf + 7, "Keepalive")) {
208 vpninfo->ssl_times.keepalive = atol(colon);
209 } else if (!strcmp(buf + 7, "DPD")) {
211 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
212 vpninfo->ssl_times.dpd = j;
213 } else if (!strcmp(buf + 7, "Content-Encoding")) {
214 if (!strcmp(colon, "deflate"))
215 vpninfo->deflate = 1;
217 vpninfo->progress(vpninfo, PRG_ERR,
218 "Unknown CSTP-Content-Encoding %s\n",
222 } else if (!strcmp(buf + 7, "MTU")) {
223 vpninfo->mtu = atol(colon);
224 } else if (!strcmp(buf + 7, "Address")) {
225 if (strchr(new_option->value, ':'))
226 vpninfo->vpn_addr6 = new_option->value;
228 vpninfo->vpn_addr = new_option->value;
229 } else if (!strcmp(buf + 7, "Netmask")) {
230 if (strchr(new_option->value, ':'))
231 vpninfo->vpn_netmask6 = new_option->value;
233 vpninfo->vpn_netmask = new_option->value;
234 } else if (!strcmp(buf + 7, "DNS")) {
236 for (j = 0; j < 3; j++) {
237 if (!vpninfo->vpn_dns[j]) {
238 vpninfo->vpn_dns[j] = new_option->value;
242 } else if (!strcmp(buf + 7, "NBNS")) {
244 for (j = 0; j < 3; j++) {
245 if (!vpninfo->vpn_nbns[j]) {
246 vpninfo->vpn_nbns[j] = new_option->value;
250 } else if (!strcmp(buf + 7, "Default-Domain")) {
251 vpninfo->vpn_domain = new_option->value;
252 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
253 vpninfo->vpn_proxy_pac = new_option->value;
254 } else if (!strcmp(buf + 7, "Banner")) {
255 vpninfo->banner = new_option->value;
256 } else if (!strcmp(buf + 7, "Split-Include")) {
257 struct split_include *inc = malloc(sizeof(*inc));
260 inc->route = new_option->value;
261 inc->next = vpninfo->split_includes;
262 vpninfo->split_includes = inc;
263 } else if (!strcmp(buf + 7, "Split-Exclude")) {
264 struct split_include *exc = malloc(sizeof(*exc));
267 exc->route = new_option->value;
268 exc->next = vpninfo->split_excludes;
269 vpninfo->split_excludes = exc;
273 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
274 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
278 if (strcmp(old_addr, vpninfo->vpn_addr)) {
279 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
280 vpninfo->vpn_addr, old_addr);
285 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
286 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
287 vpninfo->vpn_netmask, old_netmask);
292 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
293 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
294 vpninfo->vpn_addr6, old_addr6);
299 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
300 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
301 vpninfo->vpn_netmask6, old_netmask6);
306 while (old_dtls_opts) {
307 struct vpn_option *tmp = old_dtls_opts;
308 old_dtls_opts = old_dtls_opts->next;
313 while (old_cstp_opts) {
314 struct vpn_option *tmp = old_cstp_opts;
315 old_cstp_opts = old_cstp_opts->next;
320 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
321 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
323 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
324 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
326 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
327 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
328 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
330 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
331 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
333 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
338 int make_cstp_connection(struct openconnect_info *vpninfo)
342 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
345 if (vpninfo->deflate) {
346 vpninfo->deflate_adler32 = 1;
347 vpninfo->inflate_adler32 = 1;
349 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
350 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
351 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
352 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
353 vpninfo->deflate = 0;
356 if (!vpninfo->deflate_pkt) {
357 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
358 if (!vpninfo->deflate_pkt) {
359 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
360 vpninfo->deflate = 0;
362 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
363 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
364 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
368 return start_cstp_connection(vpninfo);
371 static int cstp_reconnect(struct openconnect_info *vpninfo)
377 timeout = vpninfo->reconnect_timeout;
378 interval = vpninfo->reconnect_interval;
380 while ((ret = make_cstp_connection(vpninfo))) {
383 vpninfo->progress(vpninfo, PRG_INFO,
384 "sleep %ds, remaining timeout %ds\n",
390 interval += vpninfo->reconnect_interval;
391 if (interval > RECONNECT_INTERVAL_MAX)
392 interval = RECONNECT_INTERVAL_MAX;
397 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
399 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
406 vpninfo->inflate_strm.next_in = buf;
407 vpninfo->inflate_strm.avail_in = len - 4;
409 vpninfo->inflate_strm.next_out = new->data;
410 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
411 vpninfo->inflate_strm.total_out = 0;
413 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
414 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
419 new->len = vpninfo->inflate_strm.total_out;
421 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
422 new->data, new->len);
424 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
425 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
428 vpninfo->progress(vpninfo, PRG_TRACE,
429 "Received compressed data packet of %ld bytes\n",
430 vpninfo->inflate_strm.total_out);
432 queue_packet(&vpninfo->incoming_queue, new);
436 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
438 unsigned char buf[16384];
442 /* FIXME: The poll() handling here is fairly simplistic. Actually,
443 if the SSL connection stalls it could return a WANT_WRITE error
444 on _either_ of the SSL_read() or SSL_write() calls. In that case,
445 we should probably remove POLLIN from the events we're looking for,
446 and add POLLOUT. As it is, though, it'll just chew CPU time in that
447 fairly unlikely situation, until the write backlog clears. */
448 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
451 if (buf[0] != 'S' || buf[1] != 'T' ||
452 buf[2] != 'F' || buf[3] != 1 || buf[7])
455 payload_len = (buf[4] << 8) + buf[5];
456 if (len != 8 + payload_len) {
457 vpninfo->progress(vpninfo, PRG_ERR,
458 "Unexpected packet length. SSL_read returned %d but packet is\n",
460 vpninfo->progress(vpninfo, PRG_ERR,
461 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
462 buf[0], buf[1], buf[2], buf[3],
463 buf[4], buf[5], buf[6], buf[7]);
466 vpninfo->ssl_times.last_rx = time(NULL);
469 vpninfo->progress(vpninfo, PRG_TRACE,
470 "Got CSTP DPD request\n");
471 vpninfo->owe_ssl_dpd_response = 1;
474 case AC_PKT_DPD_RESP:
475 vpninfo->progress(vpninfo, PRG_TRACE,
476 "Got CSTP DPD response\n");
479 case AC_PKT_KEEPALIVE:
480 vpninfo->progress(vpninfo, PRG_TRACE,
481 "Got CSTP Keepalive\n");
485 vpninfo->progress(vpninfo, PRG_TRACE,
486 "Received uncompressed data packet of %d bytes\n",
488 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
493 case AC_PKT_DISCONN: {
495 for (i = 0; i < payload_len; i++) {
496 if (!isprint(buf[payload_len + 8 + i]))
497 buf[payload_len + 8 + i] = '.';
499 buf[payload_len + 8] = 0;
500 vpninfo->progress(vpninfo, PRG_ERR,
501 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
502 vpninfo->quit_reason = "Server request";
505 case AC_PKT_COMPRESSED:
506 if (!vpninfo->deflate) {
507 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
510 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
514 case AC_PKT_TERM_SERVER:
515 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
516 vpninfo->quit_reason = "Server request";
521 vpninfo->progress(vpninfo, PRG_ERR,
522 "Unknown packet %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]);
525 vpninfo->quit_reason = "Unknown packet received";
529 ret = SSL_get_error(vpninfo->https_ssl, len);
530 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
531 vpninfo->progress(vpninfo, PRG_ERR,
532 "SSL read error %d (server probably closed connection); reconnecting.\n",
538 /* If SSL_write() fails we are expected to try again. With exactly
539 the same data, at exactly the same location. So we keep the
540 packet we had before.... */
541 if (vpninfo->current_ssl_pkt) {
543 vpninfo->ssl_times.last_tx = time(NULL);
544 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
545 ret = SSL_write(vpninfo->https_ssl,
546 vpninfo->current_ssl_pkt->hdr,
547 vpninfo->current_ssl_pkt->len + 8);
549 ret = SSL_get_error(vpninfo->https_ssl, ret);
551 case SSL_ERROR_WANT_WRITE:
552 /* Waiting for the socket to become writable -- it's
553 probably stalled, and/or the buffers are full */
554 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
556 case SSL_ERROR_WANT_READ:
557 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
561 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
562 report_ssl_errors(vpninfo);
566 if (ret != vpninfo->current_ssl_pkt->len + 8) {
567 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
568 vpninfo->current_ssl_pkt->len + 8, ret);
569 vpninfo->quit_reason = "Internal error";
572 /* Don't free the 'special' packets */
573 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
574 vpninfo->current_ssl_pkt != &dpd_pkt &&
575 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
576 vpninfo->current_ssl_pkt != &keepalive_pkt)
577 free(vpninfo->current_ssl_pkt);
579 vpninfo->current_ssl_pkt = NULL;
582 if (vpninfo->owe_ssl_dpd_response) {
583 vpninfo->owe_ssl_dpd_response = 0;
584 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
585 goto handle_outgoing;
588 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
590 /* Not that this will ever happen; we don't even process
591 the setting when we're asked for it. */
592 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
593 time(&vpninfo->ssl_times.last_rekey);
599 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
601 openconnect_close_https(vpninfo);
603 /* It's already deflated in the old stream. Extremely
604 non-trivial to reconstitute it; just throw it away */
605 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
606 vpninfo->current_ssl_pkt = NULL;
608 if (cstp_reconnect(vpninfo)) {
609 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
610 vpninfo->quit_reason = "CSTP reconnect failed";
613 /* I think we can leave DTLS to its own devices; when we reconnect
614 with the same master secret, we do seem to get the same sessid */
618 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
620 vpninfo->current_ssl_pkt = &dpd_pkt;
621 goto handle_outgoing;
624 /* No need to send an explicit keepalive
625 if we have real data to send */
626 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
629 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
631 vpninfo->current_ssl_pkt = &keepalive_pkt;
632 goto handle_outgoing;
638 /* Service outgoing packet queue, if no DTLS */
639 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
640 struct pkt *this = vpninfo->outgoing_queue;
641 vpninfo->outgoing_queue = this->next;
642 vpninfo->outgoing_qlen--;
644 if (vpninfo->deflate) {
645 unsigned char *adler;
648 vpninfo->deflate_strm.next_in = this->data;
649 vpninfo->deflate_strm.avail_in = this->len;
650 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
651 vpninfo->deflate_strm.avail_out = 2040;
652 vpninfo->deflate_strm.total_out = 0;
654 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
656 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
660 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
661 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
663 /* Add ongoing adler32 to tail of compressed packet */
664 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
665 this->data, this->len);
667 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
668 *(adler++) = vpninfo->deflate_adler32 >> 24;
669 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
670 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
671 *(adler) = vpninfo->deflate_adler32 & 0xff;
673 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
675 vpninfo->progress(vpninfo, PRG_TRACE,
676 "Sending compressed data packet of %d bytes\n",
679 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
682 memcpy(this->hdr, data_hdr, 8);
683 this->hdr[4] = this->len >> 8;
684 this->hdr[5] = this->len & 0xff;
686 vpninfo->progress(vpninfo, PRG_TRACE,
687 "Sending uncompressed data packet of %d bytes\n",
690 vpninfo->current_ssl_pkt = this;
692 goto handle_outgoing;
695 /* Work is not done if we just got rid of packets off the queue */
699 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
701 unsigned char *bye_pkt;
704 /* already lost connection? */
705 if (!vpninfo->https_ssl)
708 reason_len = strlen(reason);
709 bye_pkt = malloc(reason_len + 9);
713 memcpy(bye_pkt, data_hdr, 8);
714 memcpy(bye_pkt + 9, reason, reason_len);
716 bye_pkt[4] = (reason_len + 1) >> 8;
717 bye_pkt[5] = (reason_len + 1) & 0xff;
718 bye_pkt[6] = AC_PKT_DISCONN;
721 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
724 vpninfo->progress(vpninfo, PRG_INFO,
725 "Send BYE packet: %s\n", reason);