2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008 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;
89 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
91 for (inc = vpninfo->split_includes; inc; ) {
92 struct split_include *next = inc->next;
96 for (inc = vpninfo->split_excludes; inc; ) {
97 struct split_include *next = inc->next;
101 vpninfo->split_includes = vpninfo->split_excludes = NULL;
103 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
104 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
105 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
106 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
107 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
108 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
109 if (vpninfo->deflate)
110 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
111 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
112 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
113 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
114 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
115 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
116 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
117 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
118 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
120 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
121 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
124 openconnect_close_https(vpninfo);
126 if (openconnect_open_https(vpninfo)) {
127 vpninfo->progress(vpninfo, PRG_ERR,
128 "Failed to open HTTPS connection to %s\n",
137 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
138 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
139 /* "Service Unavailable. Why? */
140 char *reason = "<unknown>";
141 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
142 if (!strncmp(buf, "X-Reason: ", 10)) {
147 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
151 vpninfo->progress(vpninfo, PRG_ERR,
152 "Got inappropriate HTTP CONNECT response: %s\n",
154 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
159 vpninfo->progress(vpninfo, PRG_INFO,
160 "Got CONNECT response: %s\n", buf);
162 /* We may have advertised it, but we only do it if the server agrees */
163 vpninfo->deflate = 0;
165 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
166 struct vpn_option *new_option;
167 char *colon = strchr(buf, ':');
176 if (strncmp(buf, "X-DTLS-", 7) &&
177 strncmp(buf, "X-CSTP-", 7))
180 new_option = malloc(sizeof(*new_option));
182 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
185 new_option->option = strdup(buf);
186 new_option->value = strdup(colon);
187 new_option->next = NULL;
189 if (!new_option->option || !new_option->value) {
190 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
194 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
196 if (!strncmp(buf, "X-DTLS-", 7)) {
197 *next_dtls_option = new_option;
198 next_dtls_option = &new_option->next;
201 /* CSTP options... */
202 *next_cstp_option = new_option;
203 next_cstp_option = &new_option->next;
206 if (!strcmp(buf + 7, "Keepalive")) {
207 vpninfo->ssl_times.keepalive = atol(colon);
208 } else if (!strcmp(buf + 7, "DPD")) {
209 vpninfo->ssl_times.dpd = atol(colon);
210 } else if (!strcmp(buf + 7, "Content-Encoding")) {
211 if (!strcmp(colon, "deflate"))
212 vpninfo->deflate = 1;
214 vpninfo->progress(vpninfo, PRG_ERR,
215 "Unknown CSTP-Content-Encoding %s\n",
219 } else if (!strcmp(buf + 7, "MTU")) {
220 vpninfo->mtu = atol(colon);
221 } else if (!strcmp(buf + 7, "Address")) {
222 if (strchr(new_option->value, ':'))
223 vpninfo->vpn_addr6 = new_option->value;
225 vpninfo->vpn_addr = new_option->value;
226 } else if (!strcmp(buf + 7, "Netmask")) {
227 if (strchr(new_option->value, ':'))
228 vpninfo->vpn_netmask6 = new_option->value;
230 vpninfo->vpn_netmask = new_option->value;
231 } else if (!strcmp(buf + 7, "DNS")) {
233 for (j = 0; j < 3; j++) {
234 if (!vpninfo->vpn_dns[j]) {
235 vpninfo->vpn_dns[j] = new_option->value;
239 } else if (!strcmp(buf + 7, "NBNS")) {
241 for (j = 0; j < 3; j++) {
242 if (!vpninfo->vpn_nbns[j]) {
243 vpninfo->vpn_nbns[j] = new_option->value;
247 } else if (!strcmp(buf + 7, "Default-Domain")) {
248 vpninfo->vpn_domain = new_option->value;
249 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
250 vpninfo->vpn_proxy_pac = new_option->value;
251 } else if (!strcmp(buf + 7, "Split-Include")) {
252 struct split_include *inc = malloc(sizeof(*inc));
255 inc->route = new_option->value;
256 inc->next = vpninfo->split_includes;
257 vpninfo->split_includes = inc;
258 } else if (!strcmp(buf + 7, "Split-Exclude")) {
259 struct split_include *exc = malloc(sizeof(*exc));
262 exc->route = new_option->value;
263 exc->next = vpninfo->split_excludes;
264 vpninfo->split_excludes = exc;
268 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
269 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
272 if (vpninfo->vpn_addr && !vpninfo->vpn_netmask)
273 vpninfo->vpn_netmask = "255.255.255.255";
275 if (strcmp(old_addr, vpninfo->vpn_addr)) {
276 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
277 vpninfo->vpn_addr, old_addr);
282 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
283 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
284 vpninfo->vpn_netmask, old_netmask);
289 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
290 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
291 vpninfo->vpn_addr6, old_addr6);
296 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
297 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
298 vpninfo->vpn_netmask6, old_netmask6);
303 while (old_dtls_opts) {
304 struct vpn_option *tmp = old_dtls_opts;
305 old_dtls_opts = old_dtls_opts->next;
310 while (old_cstp_opts) {
311 struct vpn_option *tmp = old_cstp_opts;
312 old_cstp_opts = old_cstp_opts->next;
317 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
318 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
320 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
321 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
323 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
324 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
325 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
327 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
328 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
330 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
335 int make_cstp_connection(struct openconnect_info *vpninfo)
339 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
342 if (vpninfo->deflate) {
343 vpninfo->deflate_adler32 = 1;
344 vpninfo->inflate_adler32 = 1;
346 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
347 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
348 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
349 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
350 vpninfo->deflate = 0;
353 if (!vpninfo->deflate_pkt) {
354 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
355 if (!vpninfo->deflate_pkt) {
356 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
357 vpninfo->deflate = 0;
359 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
360 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
361 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
365 return start_cstp_connection(vpninfo);
368 static int cstp_reconnect(struct openconnect_info *vpninfo)
374 timeout = vpninfo->reconnect_timeout;
375 interval = vpninfo->reconnect_interval;
377 while ((ret = make_cstp_connection(vpninfo))) {
380 vpninfo->progress(vpninfo, PRG_INFO,
381 "sleep %ds, remaining timeout %ds\n",
387 interval += vpninfo->reconnect_interval;
388 if (interval > RECONNECT_INTERVAL_MAX)
389 interval = RECONNECT_INTERVAL_MAX;
394 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
396 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
403 vpninfo->inflate_strm.next_in = buf;
404 vpninfo->inflate_strm.avail_in = len - 4;
406 vpninfo->inflate_strm.next_out = new->data;
407 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
408 vpninfo->inflate_strm.total_out = 0;
410 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
411 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
416 new->len = vpninfo->inflate_strm.total_out;
418 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
419 new->data, new->len);
421 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
422 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
425 vpninfo->progress(vpninfo, PRG_TRACE,
426 "Received compressed data packet of %ld bytes\n",
427 vpninfo->inflate_strm.total_out);
429 queue_packet(&vpninfo->incoming_queue, new);
433 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
435 unsigned char buf[16384];
439 /* FIXME: The poll() handling here is fairly simplistic. Actually,
440 if the SSL connection stalls it could return a WANT_WRITE error
441 on _either_ of the SSL_read() or SSL_write() calls. In that case,
442 we should probably remove POLLIN from the events we're looking for,
443 and add POLLOUT. As it is, though, it'll just chew CPU time in that
444 fairly unlikely situation, until the write backlog clears. */
445 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
448 if (buf[0] != 'S' || buf[1] != 'T' ||
449 buf[2] != 'F' || buf[3] != 1 || buf[7])
452 payload_len = (buf[4] << 8) + buf[5];
453 if (len != 8 + payload_len) {
454 vpninfo->progress(vpninfo, PRG_ERR,
455 "Unexpected packet length. SSL_read returned %d but packet is\n",
457 vpninfo->progress(vpninfo, PRG_ERR,
458 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
459 buf[0], buf[1], buf[2], buf[3],
460 buf[4], buf[5], buf[6], buf[7]);
463 vpninfo->ssl_times.last_rx = time(NULL);
466 vpninfo->progress(vpninfo, PRG_TRACE,
467 "Got CSTP DPD request\n");
468 vpninfo->owe_ssl_dpd_response = 1;
471 case AC_PKT_DPD_RESP:
472 vpninfo->progress(vpninfo, PRG_TRACE,
473 "Got CSTP DPD response\n");
476 case AC_PKT_KEEPALIVE:
477 vpninfo->progress(vpninfo, PRG_TRACE,
478 "Got CSTP Keepalive\n");
482 vpninfo->progress(vpninfo, PRG_TRACE,
483 "Received uncompressed data packet of %d bytes\n",
485 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
490 case AC_PKT_DISCONN: {
492 for (i = 0; i < payload_len; i++) {
493 if (!isprint(buf[payload_len + 8 + i]))
494 buf[payload_len + 8 + i] = '.';
496 buf[payload_len + 8] = 0;
497 vpninfo->progress(vpninfo, PRG_ERR,
498 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
499 vpninfo->quit_reason = "Server request";
502 case AC_PKT_COMPRESSED:
503 if (!vpninfo->deflate) {
504 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
507 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
511 case AC_PKT_TERM_SERVER:
512 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
513 vpninfo->quit_reason = "Server request";
518 vpninfo->progress(vpninfo, PRG_ERR,
519 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
520 buf[0], buf[1], buf[2], buf[3],
521 buf[4], buf[5], buf[6], buf[7]);
522 vpninfo->quit_reason = "Unknown packet received";
526 ret = SSL_get_error(vpninfo->https_ssl, len);
527 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
528 vpninfo->progress(vpninfo, PRG_ERR,
529 "SSL read error %d (server probably closed connection); reconnecting.\n",
535 /* If SSL_write() fails we are expected to try again. With exactly
536 the same data, at exactly the same location. So we keep the
537 packet we had before.... */
538 if (vpninfo->current_ssl_pkt) {
540 vpninfo->ssl_times.last_tx = time(NULL);
541 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
542 ret = SSL_write(vpninfo->https_ssl,
543 vpninfo->current_ssl_pkt->hdr,
544 vpninfo->current_ssl_pkt->len + 8);
546 ret = SSL_get_error(vpninfo->https_ssl, ret);
548 case SSL_ERROR_WANT_WRITE:
549 /* Waiting for the socket to become writable -- it's
550 probably stalled, and/or the buffers are full */
551 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
553 case SSL_ERROR_WANT_READ:
554 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
558 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
559 report_ssl_errors(vpninfo);
563 if (ret != vpninfo->current_ssl_pkt->len + 8) {
564 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
565 vpninfo->current_ssl_pkt->len + 8, ret);
566 vpninfo->quit_reason = "Internal error";
569 /* Don't free the 'special' packets */
570 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
571 vpninfo->current_ssl_pkt != &dpd_pkt &&
572 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
573 vpninfo->current_ssl_pkt != &keepalive_pkt)
574 free(vpninfo->current_ssl_pkt);
576 vpninfo->current_ssl_pkt = NULL;
579 if (vpninfo->owe_ssl_dpd_response) {
580 vpninfo->owe_ssl_dpd_response = 0;
581 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
582 goto handle_outgoing;
585 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
587 /* Not that this will ever happen; we don't even process
588 the setting when we're asked for it. */
589 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
590 time(&vpninfo->ssl_times.last_rekey);
596 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
598 openconnect_close_https(vpninfo);
600 /* It's already deflated in the old stream. Extremely
601 non-trivial to reconstitute it; just throw it away */
602 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
603 vpninfo->current_ssl_pkt = NULL;
605 if (cstp_reconnect(vpninfo)) {
606 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
607 vpninfo->quit_reason = "CSTP reconnect failed";
610 /* I think we can leave DTLS to its own devices; when we reconnect
611 with the same master secret, we do seem to get the same sessid */
615 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
617 vpninfo->current_ssl_pkt = &dpd_pkt;
618 goto handle_outgoing;
621 /* No need to send an explicit keepalive
622 if we have real data to send */
623 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
626 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
628 vpninfo->current_ssl_pkt = &keepalive_pkt;
629 goto handle_outgoing;
635 /* Service outgoing packet queue, if no DTLS */
636 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
637 struct pkt *this = vpninfo->outgoing_queue;
638 vpninfo->outgoing_queue = this->next;
639 vpninfo->outgoing_qlen--;
641 if (vpninfo->deflate) {
642 unsigned char *adler;
645 vpninfo->deflate_strm.next_in = this->data;
646 vpninfo->deflate_strm.avail_in = this->len;
647 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
648 vpninfo->deflate_strm.avail_out = 2040;
649 vpninfo->deflate_strm.total_out = 0;
651 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
653 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
657 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
658 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
660 /* Add ongoing adler32 to tail of compressed packet */
661 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
662 this->data, this->len);
664 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
665 *(adler++) = vpninfo->deflate_adler32 >> 24;
666 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
667 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
668 *(adler) = vpninfo->deflate_adler32 & 0xff;
670 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
672 vpninfo->progress(vpninfo, PRG_TRACE,
673 "Sending compressed data packet of %d bytes\n",
676 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
679 memcpy(this->hdr, data_hdr, 8);
680 this->hdr[4] = this->len >> 8;
681 this->hdr[5] = this->len & 0xff;
683 vpninfo->progress(vpninfo, PRG_TRACE,
684 "Sending uncompressed data packet of %d bytes\n",
687 vpninfo->current_ssl_pkt = this;
689 goto handle_outgoing;
692 /* Work is not done if we just got rid of packets off the queue */
696 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
698 unsigned char *bye_pkt;
701 /* already lost connection? */
702 if (!vpninfo->https_ssl)
705 reason_len = strlen(reason);
706 bye_pkt = malloc(reason_len + 9);
710 memcpy(bye_pkt, data_hdr, 8);
711 memcpy(bye_pkt + 9, reason, reason_len);
713 bye_pkt[4] = (reason_len + 1) >> 8;
714 bye_pkt[5] = (reason_len + 1) & 0xff;
715 bye_pkt[6] = AC_PKT_DISCONN;
718 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
721 vpninfo->progress(vpninfo, PRG_INFO,
722 "Send BYE packet: %s\n", reason);