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;
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");
273 if (strcmp(old_addr, vpninfo->vpn_addr)) {
274 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
275 vpninfo->vpn_addr, old_addr);
280 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
281 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
282 vpninfo->vpn_netmask, old_netmask);
287 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
288 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
289 vpninfo->vpn_addr6, old_addr6);
294 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
295 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
296 vpninfo->vpn_netmask6, old_netmask6);
301 while (old_dtls_opts) {
302 struct vpn_option *tmp = old_dtls_opts;
303 old_dtls_opts = old_dtls_opts->next;
308 while (old_cstp_opts) {
309 struct vpn_option *tmp = old_cstp_opts;
310 old_cstp_opts = old_cstp_opts->next;
315 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
316 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
318 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
319 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
321 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
322 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
323 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
325 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
326 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
328 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
333 int make_cstp_connection(struct openconnect_info *vpninfo)
337 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
340 if (vpninfo->deflate) {
341 vpninfo->deflate_adler32 = 1;
342 vpninfo->inflate_adler32 = 1;
344 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
345 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
346 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
347 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
348 vpninfo->deflate = 0;
351 if (!vpninfo->deflate_pkt) {
352 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
353 if (!vpninfo->deflate_pkt) {
354 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
355 vpninfo->deflate = 0;
357 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
358 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
359 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
363 return start_cstp_connection(vpninfo);
366 static int cstp_reconnect(struct openconnect_info *vpninfo)
372 timeout = vpninfo->reconnect_timeout;
373 interval = vpninfo->reconnect_interval;
375 while ((ret = make_cstp_connection(vpninfo))) {
378 vpninfo->progress(vpninfo, PRG_INFO,
379 "sleep %ds, remaining timeout %ds\n",
385 interval += vpninfo->reconnect_interval;
386 if (interval > RECONNECT_INTERVAL_MAX)
387 interval = RECONNECT_INTERVAL_MAX;
392 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
394 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
401 vpninfo->inflate_strm.next_in = buf;
402 vpninfo->inflate_strm.avail_in = len - 4;
404 vpninfo->inflate_strm.next_out = new->data;
405 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
406 vpninfo->inflate_strm.total_out = 0;
408 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
409 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
414 new->len = vpninfo->inflate_strm.total_out;
416 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
417 new->data, new->len);
419 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
420 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
423 vpninfo->progress(vpninfo, PRG_TRACE,
424 "Received compressed data packet of %ld bytes\n",
425 vpninfo->inflate_strm.total_out);
427 queue_packet(&vpninfo->incoming_queue, new);
431 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
433 unsigned char buf[16384];
437 /* FIXME: The poll() handling here is fairly simplistic. Actually,
438 if the SSL connection stalls it could return a WANT_WRITE error
439 on _either_ of the SSL_read() or SSL_write() calls. In that case,
440 we should probably remove POLLIN from the events we're looking for,
441 and add POLLOUT. As it is, though, it'll just chew CPU time in that
442 fairly unlikely situation, until the write backlog clears. */
443 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
446 if (buf[0] != 'S' || buf[1] != 'T' ||
447 buf[2] != 'F' || buf[3] != 1 || buf[7])
450 payload_len = (buf[4] << 8) + buf[5];
451 if (len != 8 + payload_len) {
452 vpninfo->progress(vpninfo, PRG_ERR,
453 "Unexpected packet length. SSL_read returned %d but packet is\n",
455 vpninfo->progress(vpninfo, PRG_ERR,
456 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
457 buf[0], buf[1], buf[2], buf[3],
458 buf[4], buf[5], buf[6], buf[7]);
461 vpninfo->ssl_times.last_rx = time(NULL);
464 vpninfo->progress(vpninfo, PRG_TRACE,
465 "Got CSTP DPD request\n");
466 vpninfo->owe_ssl_dpd_response = 1;
469 case AC_PKT_DPD_RESP:
470 vpninfo->progress(vpninfo, PRG_TRACE,
471 "Got CSTP DPD response\n");
474 case AC_PKT_KEEPALIVE:
475 vpninfo->progress(vpninfo, PRG_TRACE,
476 "Got CSTP Keepalive\n");
480 vpninfo->progress(vpninfo, PRG_TRACE,
481 "Received uncompressed data packet of %d bytes\n",
483 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
488 case AC_PKT_DISCONN: {
490 for (i = 0; i < payload_len; i++) {
491 if (!isprint(buf[payload_len + 8 + i]))
492 buf[payload_len + 8 + i] = '.';
494 buf[payload_len + 8] = 0;
495 vpninfo->progress(vpninfo, PRG_ERR,
496 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
497 vpninfo->quit_reason = "Server request";
500 case AC_PKT_COMPRESSED:
501 if (!vpninfo->deflate) {
502 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
505 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
509 case AC_PKT_TERM_SERVER:
510 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
511 vpninfo->quit_reason = "Server request";
516 vpninfo->progress(vpninfo, PRG_ERR,
517 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
518 buf[0], buf[1], buf[2], buf[3],
519 buf[4], buf[5], buf[6], buf[7]);
520 vpninfo->quit_reason = "Unknown packet received";
524 ret = SSL_get_error(vpninfo->https_ssl, len);
525 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
526 vpninfo->progress(vpninfo, PRG_ERR,
527 "SSL read error %d (server probably closed connection); reconnecting.\n",
533 /* If SSL_write() fails we are expected to try again. With exactly
534 the same data, at exactly the same location. So we keep the
535 packet we had before.... */
536 if (vpninfo->current_ssl_pkt) {
538 vpninfo->ssl_times.last_tx = time(NULL);
539 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
540 ret = SSL_write(vpninfo->https_ssl,
541 vpninfo->current_ssl_pkt->hdr,
542 vpninfo->current_ssl_pkt->len + 8);
544 ret = SSL_get_error(vpninfo->https_ssl, ret);
546 case SSL_ERROR_WANT_WRITE:
547 /* Waiting for the socket to become writable -- it's
548 probably stalled, and/or the buffers are full */
549 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
551 case SSL_ERROR_WANT_READ:
552 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
556 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
557 report_ssl_errors(vpninfo);
561 if (ret != vpninfo->current_ssl_pkt->len + 8) {
562 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
563 vpninfo->current_ssl_pkt->len + 8, ret);
564 vpninfo->quit_reason = "Internal error";
567 /* Don't free the 'special' packets */
568 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
569 vpninfo->current_ssl_pkt != &dpd_pkt &&
570 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
571 vpninfo->current_ssl_pkt != &keepalive_pkt)
572 free(vpninfo->current_ssl_pkt);
574 vpninfo->current_ssl_pkt = NULL;
577 if (vpninfo->owe_ssl_dpd_response) {
578 vpninfo->owe_ssl_dpd_response = 0;
579 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
580 goto handle_outgoing;
583 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
585 /* Not that this will ever happen; we don't even process
586 the setting when we're asked for it. */
587 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
588 time(&vpninfo->ssl_times.last_rekey);
594 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
596 openconnect_close_https(vpninfo);
598 /* It's already deflated in the old stream. Extremely
599 non-trivial to reconstitute it; just throw it away */
600 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
601 vpninfo->current_ssl_pkt = NULL;
603 if (cstp_reconnect(vpninfo)) {
604 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
605 vpninfo->quit_reason = "CSTP reconnect failed";
608 /* I think we can leave DTLS to its own devices; when we reconnect
609 with the same master secret, we do seem to get the same sessid */
613 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
615 vpninfo->current_ssl_pkt = &dpd_pkt;
616 goto handle_outgoing;
619 /* No need to send an explicit keepalive
620 if we have real data to send */
621 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
624 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
626 vpninfo->current_ssl_pkt = &keepalive_pkt;
627 goto handle_outgoing;
633 /* Service outgoing packet queue, if no DTLS */
634 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
635 struct pkt *this = vpninfo->outgoing_queue;
636 vpninfo->outgoing_queue = this->next;
637 vpninfo->outgoing_qlen--;
639 if (vpninfo->deflate) {
640 unsigned char *adler;
643 vpninfo->deflate_strm.next_in = this->data;
644 vpninfo->deflate_strm.avail_in = this->len;
645 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
646 vpninfo->deflate_strm.avail_out = 2040;
647 vpninfo->deflate_strm.total_out = 0;
649 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
651 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
655 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
656 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
658 /* Add ongoing adler32 to tail of compressed packet */
659 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
660 this->data, this->len);
662 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
663 *(adler++) = vpninfo->deflate_adler32 >> 24;
664 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
665 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
666 *(adler) = vpninfo->deflate_adler32 & 0xff;
668 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
670 vpninfo->progress(vpninfo, PRG_TRACE,
671 "Sending compressed data packet of %d bytes\n",
674 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
677 memcpy(this->hdr, data_hdr, 8);
678 this->hdr[4] = this->len >> 8;
679 this->hdr[5] = this->len & 0xff;
681 vpninfo->progress(vpninfo, PRG_TRACE,
682 "Sending uncompressed data packet of %d bytes\n",
685 vpninfo->current_ssl_pkt = this;
687 goto handle_outgoing;
690 /* Work is not done if we just got rid of packets off the queue */
694 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
696 unsigned char *bye_pkt;
699 /* already lost connection? */
700 if (!vpninfo->https_ssl)
703 reason_len = strlen(reason);
704 bye_pkt = malloc(reason_len + 9);
708 memcpy(bye_pkt, data_hdr, 8);
709 memcpy(bye_pkt + 9, reason, reason_len);
711 bye_pkt[4] = (reason_len + 1) >> 8;
712 bye_pkt[5] = (reason_len + 1) & 0xff;
713 bye_pkt[6] = AC_PKT_DISCONN;
716 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
719 vpninfo->progress(vpninfo, PRG_INFO,
720 "Send BYE packet: %s\n", reason);