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>
35 #include <openssl/rand.h>
37 #include "openconnect.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.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 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
115 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
116 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
117 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
118 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
119 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
120 if (vpninfo->deflate)
121 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
122 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
123 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
124 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
125 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
126 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
127 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
128 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
129 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
131 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
132 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
135 openconnect_close_https(vpninfo);
137 if (openconnect_open_https(vpninfo)) {
138 vpninfo->progress(vpninfo, PRG_ERR,
139 "Failed to open HTTPS connection to %s\n",
148 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
149 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
150 /* "Service Unavailable. Why? */
151 char *reason = "<unknown>";
152 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
153 if (!strncmp(buf, "X-Reason: ", 10)) {
158 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
162 vpninfo->progress(vpninfo, PRG_ERR,
163 "Got inappropriate HTTP CONNECT response: %s\n",
165 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
170 vpninfo->progress(vpninfo, PRG_INFO,
171 "Got CONNECT response: %s\n", buf);
173 /* We may have advertised it, but we only do it if the server agrees */
174 vpninfo->deflate = 0;
176 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
177 struct vpn_option *new_option;
178 char *colon = strchr(buf, ':');
187 if (strncmp(buf, "X-DTLS-", 7) &&
188 strncmp(buf, "X-CSTP-", 7))
191 new_option = malloc(sizeof(*new_option));
193 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
196 new_option->option = strdup(buf);
197 new_option->value = strdup(colon);
198 new_option->next = NULL;
200 if (!new_option->option || !new_option->value) {
201 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
205 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
207 if (!strncmp(buf, "X-DTLS-", 7)) {
208 *next_dtls_option = new_option;
209 next_dtls_option = &new_option->next;
211 if (!strcmp(buf + 7, "Session-ID")) {
212 if (strlen(colon) != 64) {
213 vpninfo->progress(vpninfo, PRG_ERR, "X-DTLS-Session-ID not 64 characters\n");
214 vpninfo->progress(vpninfo, PRG_ERR, "Is: %s\n", colon);
215 vpninfo->dtls_attempt_period = 0;
218 for (i = 0; i < 64; i += 2)
219 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
221 time(&vpninfo->dtls_times.last_rekey);
225 /* CSTP options... */
226 *next_cstp_option = new_option;
227 next_cstp_option = &new_option->next;
230 if (!strcmp(buf + 7, "Keepalive")) {
231 vpninfo->ssl_times.keepalive = atol(colon);
232 } else if (!strcmp(buf + 7, "DPD")) {
234 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
235 vpninfo->ssl_times.dpd = j;
236 } else if (!strcmp(buf + 7, "Rekey-Time")) {
237 vpninfo->ssl_times.rekey = atol(colon);
238 } else if (!strcmp(buf + 7, "Content-Encoding")) {
239 if (!strcmp(colon, "deflate"))
240 vpninfo->deflate = 1;
242 vpninfo->progress(vpninfo, PRG_ERR,
243 "Unknown CSTP-Content-Encoding %s\n",
247 } else if (!strcmp(buf + 7, "MTU")) {
248 vpninfo->mtu = atol(colon);
249 } else if (!strcmp(buf + 7, "Address")) {
250 if (strchr(new_option->value, ':'))
251 vpninfo->vpn_addr6 = new_option->value;
253 vpninfo->vpn_addr = new_option->value;
254 } else if (!strcmp(buf + 7, "Netmask")) {
255 if (strchr(new_option->value, ':'))
256 vpninfo->vpn_netmask6 = new_option->value;
258 vpninfo->vpn_netmask = new_option->value;
259 } else if (!strcmp(buf + 7, "DNS")) {
261 for (j = 0; j < 3; j++) {
262 if (!vpninfo->vpn_dns[j]) {
263 vpninfo->vpn_dns[j] = new_option->value;
267 } else if (!strcmp(buf + 7, "NBNS")) {
269 for (j = 0; j < 3; j++) {
270 if (!vpninfo->vpn_nbns[j]) {
271 vpninfo->vpn_nbns[j] = new_option->value;
275 } else if (!strcmp(buf + 7, "Default-Domain")) {
276 vpninfo->vpn_domain = new_option->value;
277 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
278 vpninfo->vpn_proxy_pac = new_option->value;
279 } else if (!strcmp(buf + 7, "Banner")) {
280 vpninfo->banner = new_option->value;
281 } else if (!strcmp(buf + 7, "Split-Include")) {
282 struct split_include *inc = malloc(sizeof(*inc));
285 inc->route = new_option->value;
286 inc->next = vpninfo->split_includes;
287 vpninfo->split_includes = inc;
288 } else if (!strcmp(buf + 7, "Split-Exclude")) {
289 struct split_include *exc = malloc(sizeof(*exc));
292 exc->route = new_option->value;
293 exc->next = vpninfo->split_excludes;
294 vpninfo->split_excludes = exc;
298 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
299 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
303 if (strcmp(old_addr, vpninfo->vpn_addr)) {
304 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
305 vpninfo->vpn_addr, old_addr);
310 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
311 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
312 vpninfo->vpn_netmask, old_netmask);
317 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
318 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
319 vpninfo->vpn_addr6, old_addr6);
324 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
325 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
326 vpninfo->vpn_netmask6, old_netmask6);
331 while (old_dtls_opts) {
332 struct vpn_option *tmp = old_dtls_opts;
333 old_dtls_opts = old_dtls_opts->next;
338 while (old_cstp_opts) {
339 struct vpn_option *tmp = old_cstp_opts;
340 old_cstp_opts = old_cstp_opts->next;
345 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
346 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
348 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
349 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
351 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
352 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
353 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
355 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
356 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
359 vpninfo->dtls_attempt_period = 0;
361 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
362 vpninfo->ssl_times.last_tx = time(NULL);
367 int make_cstp_connection(struct openconnect_info *vpninfo)
371 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
374 if (vpninfo->deflate) {
375 vpninfo->deflate_adler32 = 1;
376 vpninfo->inflate_adler32 = 1;
378 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
379 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
380 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
381 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
382 vpninfo->deflate = 0;
385 if (!vpninfo->deflate_pkt) {
386 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
387 if (!vpninfo->deflate_pkt) {
388 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
389 vpninfo->deflate = 0;
391 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
392 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
393 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
397 return start_cstp_connection(vpninfo);
400 int cstp_reconnect(struct openconnect_info *vpninfo)
406 timeout = vpninfo->reconnect_timeout;
407 interval = vpninfo->reconnect_interval;
409 while ((ret = make_cstp_connection(vpninfo))) {
412 vpninfo->progress(vpninfo, PRG_INFO,
413 "sleep %ds, remaining timeout %ds\n",
419 interval += vpninfo->reconnect_interval;
420 if (interval > RECONNECT_INTERVAL_MAX)
421 interval = RECONNECT_INTERVAL_MAX;
426 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
428 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
435 vpninfo->inflate_strm.next_in = buf;
436 vpninfo->inflate_strm.avail_in = len - 4;
438 vpninfo->inflate_strm.next_out = new->data;
439 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
440 vpninfo->inflate_strm.total_out = 0;
442 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
443 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
448 new->len = vpninfo->inflate_strm.total_out;
450 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
451 new->data, new->len);
453 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
454 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
457 vpninfo->progress(vpninfo, PRG_TRACE,
458 "Received compressed data packet of %ld bytes\n",
459 vpninfo->inflate_strm.total_out);
461 queue_packet(&vpninfo->incoming_queue, new);
465 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
467 unsigned char buf[16384];
471 /* FIXME: The poll() handling here is fairly simplistic. Actually,
472 if the SSL connection stalls it could return a WANT_WRITE error
473 on _either_ of the SSL_read() or SSL_write() calls. In that case,
474 we should probably remove POLLIN from the events we're looking for,
475 and add POLLOUT. As it is, though, it'll just chew CPU time in that
476 fairly unlikely situation, until the write backlog clears. */
477 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
480 if (buf[0] != 'S' || buf[1] != 'T' ||
481 buf[2] != 'F' || buf[3] != 1 || buf[7])
484 payload_len = (buf[4] << 8) + buf[5];
485 if (len != 8 + payload_len) {
486 vpninfo->progress(vpninfo, PRG_ERR,
487 "Unexpected packet length. SSL_read returned %d but packet is\n",
489 vpninfo->progress(vpninfo, PRG_ERR,
490 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
491 buf[0], buf[1], buf[2], buf[3],
492 buf[4], buf[5], buf[6], buf[7]);
495 vpninfo->ssl_times.last_rx = time(NULL);
498 vpninfo->progress(vpninfo, PRG_TRACE,
499 "Got CSTP DPD request\n");
500 vpninfo->owe_ssl_dpd_response = 1;
503 case AC_PKT_DPD_RESP:
504 vpninfo->progress(vpninfo, PRG_TRACE,
505 "Got CSTP DPD response\n");
508 case AC_PKT_KEEPALIVE:
509 vpninfo->progress(vpninfo, PRG_TRACE,
510 "Got CSTP Keepalive\n");
514 vpninfo->progress(vpninfo, PRG_TRACE,
515 "Received uncompressed data packet of %d bytes\n",
517 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
522 case AC_PKT_DISCONN: {
524 for (i = 0; i < payload_len; i++) {
525 if (!isprint(buf[payload_len + 8 + i]))
526 buf[payload_len + 8 + i] = '.';
528 buf[payload_len + 8] = 0;
529 vpninfo->progress(vpninfo, PRG_ERR,
530 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
531 vpninfo->quit_reason = "Server request";
534 case AC_PKT_COMPRESSED:
535 if (!vpninfo->deflate) {
536 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
539 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
543 case AC_PKT_TERM_SERVER:
544 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
545 vpninfo->quit_reason = "Server request";
550 vpninfo->progress(vpninfo, PRG_ERR,
551 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
552 buf[0], buf[1], buf[2], buf[3],
553 buf[4], buf[5], buf[6], buf[7]);
554 vpninfo->quit_reason = "Unknown packet received";
558 ret = SSL_get_error(vpninfo->https_ssl, len);
559 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
560 vpninfo->progress(vpninfo, PRG_ERR,
561 "SSL read error %d (server probably closed connection); reconnecting.\n",
567 /* If SSL_write() fails we are expected to try again. With exactly
568 the same data, at exactly the same location. So we keep the
569 packet we had before.... */
570 if (vpninfo->current_ssl_pkt) {
572 vpninfo->ssl_times.last_tx = time(NULL);
573 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
574 ret = SSL_write(vpninfo->https_ssl,
575 vpninfo->current_ssl_pkt->hdr,
576 vpninfo->current_ssl_pkt->len + 8);
578 ret = SSL_get_error(vpninfo->https_ssl, ret);
580 case SSL_ERROR_WANT_WRITE:
581 /* Waiting for the socket to become writable -- it's
582 probably stalled, and/or the buffers are full */
583 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
585 case SSL_ERROR_WANT_READ:
586 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
590 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
591 report_ssl_errors(vpninfo);
595 if (ret != vpninfo->current_ssl_pkt->len + 8) {
596 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
597 vpninfo->current_ssl_pkt->len + 8, ret);
598 vpninfo->quit_reason = "Internal error";
601 /* Don't free the 'special' packets */
602 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
603 vpninfo->current_ssl_pkt != &dpd_pkt &&
604 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
605 vpninfo->current_ssl_pkt != &keepalive_pkt)
606 free(vpninfo->current_ssl_pkt);
608 vpninfo->current_ssl_pkt = NULL;
611 if (vpninfo->owe_ssl_dpd_response) {
612 vpninfo->owe_ssl_dpd_response = 0;
613 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
614 goto handle_outgoing;
617 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
619 /* Not that this will ever happen; we don't even process
620 the setting when we're asked for it. */
621 vpninfo->progress(vpninfo, PRG_INFO, "CSTP rekey due\n");
627 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
629 openconnect_close_https(vpninfo);
631 /* It's already deflated in the old stream. Extremely
632 non-trivial to reconstitute it; just throw it away */
633 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
634 vpninfo->current_ssl_pkt = NULL;
636 if (cstp_reconnect(vpninfo)) {
637 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
638 vpninfo->quit_reason = "CSTP reconnect failed";
641 /* I think we can leave DTLS to its own devices; when we reconnect
642 with the same master secret, we do seem to get the same sessid */
646 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
648 vpninfo->current_ssl_pkt = &dpd_pkt;
649 goto handle_outgoing;
652 /* No need to send an explicit keepalive
653 if we have real data to send */
654 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
657 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
659 vpninfo->current_ssl_pkt = &keepalive_pkt;
660 goto handle_outgoing;
666 /* Service outgoing packet queue, if no DTLS */
667 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
668 struct pkt *this = vpninfo->outgoing_queue;
669 vpninfo->outgoing_queue = this->next;
670 vpninfo->outgoing_qlen--;
672 if (vpninfo->deflate) {
673 unsigned char *adler;
676 vpninfo->deflate_strm.next_in = this->data;
677 vpninfo->deflate_strm.avail_in = this->len;
678 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
679 vpninfo->deflate_strm.avail_out = 2040;
680 vpninfo->deflate_strm.total_out = 0;
682 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
684 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
688 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
689 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
691 /* Add ongoing adler32 to tail of compressed packet */
692 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
693 this->data, this->len);
695 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
696 *(adler++) = vpninfo->deflate_adler32 >> 24;
697 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
698 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
699 *(adler) = vpninfo->deflate_adler32 & 0xff;
701 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
703 vpninfo->progress(vpninfo, PRG_TRACE,
704 "Sending compressed data packet of %d bytes\n",
707 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
710 memcpy(this->hdr, data_hdr, 8);
711 this->hdr[4] = this->len >> 8;
712 this->hdr[5] = this->len & 0xff;
714 vpninfo->progress(vpninfo, PRG_TRACE,
715 "Sending uncompressed data packet of %d bytes\n",
718 vpninfo->current_ssl_pkt = this;
720 goto handle_outgoing;
723 /* Work is not done if we just got rid of packets off the queue */
727 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
729 unsigned char *bye_pkt;
732 /* already lost connection? */
733 if (!vpninfo->https_ssl)
736 reason_len = strlen(reason);
737 bye_pkt = malloc(reason_len + 9);
741 memcpy(bye_pkt, data_hdr, 8);
742 memcpy(bye_pkt + 9, reason, reason_len);
744 bye_pkt[4] = (reason_len + 1) >> 8;
745 bye_pkt[5] = (reason_len + 1) & 0xff;
746 bye_pkt[6] = AC_PKT_DISCONN;
749 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
752 vpninfo->progress(vpninfo, PRG_INFO,
753 "Send BYE packet: %s\n", reason);