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 /* To enable IPv6, send 'IPv6,IPv4'.
113 We don't know how most of that works yet though. */
114 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
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")) {
210 vpninfo->ssl_times.dpd = atol(colon);
211 } else if (!strcmp(buf + 7, "Content-Encoding")) {
212 if (!strcmp(colon, "deflate"))
213 vpninfo->deflate = 1;
215 vpninfo->progress(vpninfo, PRG_ERR,
216 "Unknown CSTP-Content-Encoding %s\n",
220 } else if (!strcmp(buf + 7, "MTU")) {
221 vpninfo->mtu = atol(colon);
222 } else if (!strcmp(buf + 7, "Address")) {
223 if (strchr(new_option->value, ':'))
224 vpninfo->vpn_addr6 = new_option->value;
226 vpninfo->vpn_addr = new_option->value;
227 } else if (!strcmp(buf + 7, "Netmask")) {
228 if (strchr(new_option->value, ':'))
229 vpninfo->vpn_netmask6 = new_option->value;
231 vpninfo->vpn_netmask = new_option->value;
232 } else if (!strcmp(buf + 7, "DNS")) {
234 for (j = 0; j < 3; j++) {
235 if (!vpninfo->vpn_dns[j]) {
236 vpninfo->vpn_dns[j] = new_option->value;
240 } else if (!strcmp(buf + 7, "NBNS")) {
242 for (j = 0; j < 3; j++) {
243 if (!vpninfo->vpn_nbns[j]) {
244 vpninfo->vpn_nbns[j] = new_option->value;
248 } else if (!strcmp(buf + 7, "Default-Domain")) {
249 vpninfo->vpn_domain = new_option->value;
250 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
251 vpninfo->vpn_proxy_pac = new_option->value;
252 } else if (!strcmp(buf + 7, "Split-Include")) {
253 struct split_include *inc = malloc(sizeof(*inc));
256 inc->route = new_option->value;
257 inc->next = vpninfo->split_includes;
258 vpninfo->split_includes = inc;
259 } else if (!strcmp(buf + 7, "Split-Exclude")) {
260 struct split_include *exc = malloc(sizeof(*exc));
263 exc->route = new_option->value;
264 exc->next = vpninfo->split_excludes;
265 vpninfo->split_excludes = exc;
269 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
270 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
273 if (vpninfo->vpn_addr && !vpninfo->vpn_netmask)
274 vpninfo->vpn_netmask = "255.255.255.255";
276 if (strcmp(old_addr, vpninfo->vpn_addr)) {
277 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
278 vpninfo->vpn_addr, old_addr);
283 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
284 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
285 vpninfo->vpn_netmask, old_netmask);
290 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
291 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
292 vpninfo->vpn_addr6, old_addr6);
297 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
298 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
299 vpninfo->vpn_netmask6, old_netmask6);
304 while (old_dtls_opts) {
305 struct vpn_option *tmp = old_dtls_opts;
306 old_dtls_opts = old_dtls_opts->next;
311 while (old_cstp_opts) {
312 struct vpn_option *tmp = old_cstp_opts;
313 old_cstp_opts = old_cstp_opts->next;
318 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
319 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
321 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
322 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
324 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
325 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
326 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
328 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
329 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
331 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
336 int make_cstp_connection(struct openconnect_info *vpninfo)
340 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
343 if (vpninfo->deflate) {
344 vpninfo->deflate_adler32 = 1;
345 vpninfo->inflate_adler32 = 1;
347 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
348 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
349 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
350 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
351 vpninfo->deflate = 0;
354 if (!vpninfo->deflate_pkt) {
355 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
356 if (!vpninfo->deflate_pkt) {
357 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
358 vpninfo->deflate = 0;
360 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
361 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
362 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
366 return start_cstp_connection(vpninfo);
369 static int cstp_reconnect(struct openconnect_info *vpninfo)
375 timeout = vpninfo->reconnect_timeout;
376 interval = vpninfo->reconnect_interval;
378 while ((ret = make_cstp_connection(vpninfo))) {
381 vpninfo->progress(vpninfo, PRG_INFO,
382 "sleep %ds, remaining timeout %ds\n",
388 interval += vpninfo->reconnect_interval;
389 if (interval > RECONNECT_INTERVAL_MAX)
390 interval = RECONNECT_INTERVAL_MAX;
395 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
397 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
404 vpninfo->inflate_strm.next_in = buf;
405 vpninfo->inflate_strm.avail_in = len - 4;
407 vpninfo->inflate_strm.next_out = new->data;
408 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
409 vpninfo->inflate_strm.total_out = 0;
411 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
412 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
417 new->len = vpninfo->inflate_strm.total_out;
419 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
420 new->data, new->len);
422 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
423 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
426 vpninfo->progress(vpninfo, PRG_TRACE,
427 "Received compressed data packet of %ld bytes\n",
428 vpninfo->inflate_strm.total_out);
430 queue_packet(&vpninfo->incoming_queue, new);
434 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
436 unsigned char buf[16384];
440 /* FIXME: The poll() handling here is fairly simplistic. Actually,
441 if the SSL connection stalls it could return a WANT_WRITE error
442 on _either_ of the SSL_read() or SSL_write() calls. In that case,
443 we should probably remove POLLIN from the events we're looking for,
444 and add POLLOUT. As it is, though, it'll just chew CPU time in that
445 fairly unlikely situation, until the write backlog clears. */
446 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
449 if (buf[0] != 'S' || buf[1] != 'T' ||
450 buf[2] != 'F' || buf[3] != 1 || buf[7])
453 payload_len = (buf[4] << 8) + buf[5];
454 if (len != 8 + payload_len) {
455 vpninfo->progress(vpninfo, PRG_ERR,
456 "Unexpected packet length. SSL_read returned %d but packet is\n",
458 vpninfo->progress(vpninfo, PRG_ERR,
459 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
460 buf[0], buf[1], buf[2], buf[3],
461 buf[4], buf[5], buf[6], buf[7]);
464 vpninfo->ssl_times.last_rx = time(NULL);
467 vpninfo->progress(vpninfo, PRG_TRACE,
468 "Got CSTP DPD request\n");
469 vpninfo->owe_ssl_dpd_response = 1;
472 case AC_PKT_DPD_RESP:
473 vpninfo->progress(vpninfo, PRG_TRACE,
474 "Got CSTP DPD response\n");
477 case AC_PKT_KEEPALIVE:
478 vpninfo->progress(vpninfo, PRG_TRACE,
479 "Got CSTP Keepalive\n");
483 vpninfo->progress(vpninfo, PRG_TRACE,
484 "Received uncompressed data packet of %d bytes\n",
486 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
491 case AC_PKT_DISCONN: {
493 for (i = 0; i < payload_len; i++) {
494 if (!isprint(buf[payload_len + 8 + i]))
495 buf[payload_len + 8 + i] = '.';
497 buf[payload_len + 8] = 0;
498 vpninfo->progress(vpninfo, PRG_ERR,
499 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
500 vpninfo->quit_reason = "Server request";
503 case AC_PKT_COMPRESSED:
504 if (!vpninfo->deflate) {
505 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
508 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
512 case AC_PKT_TERM_SERVER:
513 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
514 vpninfo->quit_reason = "Server request";
519 vpninfo->progress(vpninfo, PRG_ERR,
520 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
521 buf[0], buf[1], buf[2], buf[3],
522 buf[4], buf[5], buf[6], buf[7]);
523 vpninfo->quit_reason = "Unknown packet received";
527 ret = SSL_get_error(vpninfo->https_ssl, len);
528 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
529 vpninfo->progress(vpninfo, PRG_ERR,
530 "SSL read error %d (server probably closed connection); reconnecting.\n",
536 /* If SSL_write() fails we are expected to try again. With exactly
537 the same data, at exactly the same location. So we keep the
538 packet we had before.... */
539 if (vpninfo->current_ssl_pkt) {
541 vpninfo->ssl_times.last_tx = time(NULL);
542 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
543 ret = SSL_write(vpninfo->https_ssl,
544 vpninfo->current_ssl_pkt->hdr,
545 vpninfo->current_ssl_pkt->len + 8);
547 ret = SSL_get_error(vpninfo->https_ssl, ret);
549 case SSL_ERROR_WANT_WRITE:
550 /* Waiting for the socket to become writable -- it's
551 probably stalled, and/or the buffers are full */
552 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
554 case SSL_ERROR_WANT_READ:
555 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
559 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
560 report_ssl_errors(vpninfo);
564 if (ret != vpninfo->current_ssl_pkt->len + 8) {
565 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
566 vpninfo->current_ssl_pkt->len + 8, ret);
567 vpninfo->quit_reason = "Internal error";
570 /* Don't free the 'special' packets */
571 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
572 vpninfo->current_ssl_pkt != &dpd_pkt &&
573 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
574 vpninfo->current_ssl_pkt != &keepalive_pkt)
575 free(vpninfo->current_ssl_pkt);
577 vpninfo->current_ssl_pkt = NULL;
580 if (vpninfo->owe_ssl_dpd_response) {
581 vpninfo->owe_ssl_dpd_response = 0;
582 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
583 goto handle_outgoing;
586 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
588 /* Not that this will ever happen; we don't even process
589 the setting when we're asked for it. */
590 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
591 time(&vpninfo->ssl_times.last_rekey);
597 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
599 openconnect_close_https(vpninfo);
601 /* It's already deflated in the old stream. Extremely
602 non-trivial to reconstitute it; just throw it away */
603 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
604 vpninfo->current_ssl_pkt = NULL;
606 if (cstp_reconnect(vpninfo)) {
607 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
608 vpninfo->quit_reason = "CSTP reconnect failed";
611 /* I think we can leave DTLS to its own devices; when we reconnect
612 with the same master secret, we do seem to get the same sessid */
616 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
618 vpninfo->current_ssl_pkt = &dpd_pkt;
619 goto handle_outgoing;
622 /* No need to send an explicit keepalive
623 if we have real data to send */
624 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
627 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
629 vpninfo->current_ssl_pkt = &keepalive_pkt;
630 goto handle_outgoing;
636 /* Service outgoing packet queue, if no DTLS */
637 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
638 struct pkt *this = vpninfo->outgoing_queue;
639 vpninfo->outgoing_queue = this->next;
640 vpninfo->outgoing_qlen--;
642 if (vpninfo->deflate) {
643 unsigned char *adler;
646 vpninfo->deflate_strm.next_in = this->data;
647 vpninfo->deflate_strm.avail_in = this->len;
648 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
649 vpninfo->deflate_strm.avail_out = 2040;
650 vpninfo->deflate_strm.total_out = 0;
652 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
654 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
658 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
659 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
661 /* Add ongoing adler32 to tail of compressed packet */
662 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
663 this->data, this->len);
665 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
666 *(adler++) = vpninfo->deflate_adler32 >> 24;
667 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
668 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
669 *(adler) = vpninfo->deflate_adler32 & 0xff;
671 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
673 vpninfo->progress(vpninfo, PRG_TRACE,
674 "Sending compressed data packet of %d bytes\n",
677 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
680 memcpy(this->hdr, data_hdr, 8);
681 this->hdr[4] = this->len >> 8;
682 this->hdr[5] = this->len & 0xff;
684 vpninfo->progress(vpninfo, PRG_TRACE,
685 "Sending uncompressed data packet of %d bytes\n",
688 vpninfo->current_ssl_pkt = this;
690 goto handle_outgoing;
693 /* Work is not done if we just got rid of packets off the queue */
697 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
699 unsigned char *bye_pkt;
702 /* already lost connection? */
703 if (!vpninfo->https_ssl)
706 reason_len = strlen(reason);
707 bye_pkt = malloc(reason_len + 9);
711 memcpy(bye_pkt, data_hdr, 8);
712 memcpy(bye_pkt + 9, reason, reason_len);
714 bye_pkt[4] = (reason_len + 1) >> 8;
715 bye_pkt[5] = (reason_len + 1) & 0xff;
716 bye_pkt[6] = AC_PKT_DISCONN;
719 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
722 vpninfo->progress(vpninfo, PRG_INFO,
723 "Send BYE packet: %s\n", reason);