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
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35 #include <openssl/rand.h>
37 #include "openconnect-internal.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-internal.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, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
115 openconnect_SSL_printf(vpninfo, "Host: %s\r\n", vpninfo->hostname);
116 openconnect_SSL_printf(vpninfo, "User-Agent: %s\r\n", vpninfo->useragent);
117 openconnect_SSL_printf(vpninfo, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
118 openconnect_SSL_printf(vpninfo, "X-CSTP-Version: 1\r\n");
119 openconnect_SSL_printf(vpninfo, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
120 if (vpninfo->deflate)
121 openconnect_SSL_printf(vpninfo, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
122 openconnect_SSL_printf(vpninfo, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
123 openconnect_SSL_printf(vpninfo, "X-CSTP-Address-Type: %s\r\n",
124 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
125 openconnect_SSL_printf(vpninfo, "X-DTLS-Master-Secret: ");
126 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
127 openconnect_SSL_printf(vpninfo, "%02X", vpninfo->dtls_secret[i]);
128 openconnect_SSL_printf(vpninfo, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
129 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
131 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) & ~O_NONBLOCK);
132 if (openconnect_SSL_gets(vpninfo, buf, 65536) < 0) {
133 vpn_progress(vpninfo, PRG_ERR,
134 _("Error fetching HTTPS response\n"));
137 openconnect_close_https(vpninfo);
139 if (openconnect_open_https(vpninfo)) {
140 vpn_progress(vpninfo, PRG_ERR,
141 _("Failed to open HTTPS connection to %s\n"),
150 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
151 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
152 /* "Service Unavailable. Why? */
153 const char *reason = "<unknown>";
154 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
155 if (!strncmp(buf, "X-Reason: ", 10)) {
160 vpn_progress(vpninfo, PRG_ERR,
161 _("VPN service unavailable; reason: %s\n"),
165 vpn_progress(vpninfo, PRG_ERR,
166 _("Got inappropriate HTTP CONNECT response: %s\n"),
168 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
173 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
175 /* We may have advertised it, but we only do it if the server agrees */
176 vpninfo->deflate = 0;
178 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
179 struct vpn_option *new_option;
180 char *colon = strchr(buf, ':');
189 if (strncmp(buf, "X-DTLS-", 7) &&
190 strncmp(buf, "X-CSTP-", 7))
193 new_option = malloc(sizeof(*new_option));
195 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
198 new_option->option = strdup(buf);
199 new_option->value = strdup(colon);
200 new_option->next = NULL;
202 if (!new_option->option || !new_option->value) {
203 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
207 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
209 if (!strncmp(buf, "X-DTLS-", 7)) {
210 *next_dtls_option = new_option;
211 next_dtls_option = &new_option->next;
213 if (!strcmp(buf + 7, "Session-ID")) {
214 if (strlen(colon) != 64) {
215 vpn_progress(vpninfo, PRG_ERR,
216 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
218 vpninfo->dtls_attempt_period = 0;
221 for (i = 0; i < 64; i += 2)
222 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
224 time(&vpninfo->dtls_times.last_rekey);
228 /* CSTP options... */
229 *next_cstp_option = new_option;
230 next_cstp_option = &new_option->next;
233 if (!strcmp(buf + 7, "Keepalive")) {
234 vpninfo->ssl_times.keepalive = atol(colon);
235 } else if (!strcmp(buf + 7, "DPD")) {
237 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
238 vpninfo->ssl_times.dpd = j;
239 } else if (!strcmp(buf + 7, "Rekey-Time")) {
240 vpninfo->ssl_times.rekey = atol(colon);
241 } else if (!strcmp(buf + 7, "Content-Encoding")) {
242 if (!strcmp(colon, "deflate"))
243 vpninfo->deflate = 1;
245 vpn_progress(vpninfo, PRG_ERR,
246 _("Unknown CSTP-Content-Encoding %s\n"),
250 } else if (!strcmp(buf + 7, "MTU")) {
251 vpninfo->mtu = atol(colon);
252 } else if (!strcmp(buf + 7, "Address")) {
253 if (strchr(new_option->value, ':'))
254 vpninfo->vpn_addr6 = new_option->value;
256 vpninfo->vpn_addr = new_option->value;
257 } else if (!strcmp(buf + 7, "Netmask")) {
258 if (strchr(new_option->value, ':'))
259 vpninfo->vpn_netmask6 = new_option->value;
261 vpninfo->vpn_netmask = new_option->value;
262 } else if (!strcmp(buf + 7, "DNS")) {
264 for (j = 0; j < 3; j++) {
265 if (!vpninfo->vpn_dns[j]) {
266 vpninfo->vpn_dns[j] = new_option->value;
270 } else if (!strcmp(buf + 7, "NBNS")) {
272 for (j = 0; j < 3; j++) {
273 if (!vpninfo->vpn_nbns[j]) {
274 vpninfo->vpn_nbns[j] = new_option->value;
278 } else if (!strcmp(buf + 7, "Default-Domain")) {
279 vpninfo->vpn_domain = new_option->value;
280 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
281 vpninfo->vpn_proxy_pac = new_option->value;
282 } else if (!strcmp(buf + 7, "Banner")) {
283 vpninfo->banner = new_option->value;
284 } else if (!strcmp(buf + 7, "Split-Include")) {
285 struct split_include *inc = malloc(sizeof(*inc));
288 inc->route = new_option->value;
289 inc->next = vpninfo->split_includes;
290 vpninfo->split_includes = inc;
291 } else if (!strcmp(buf + 7, "Split-Exclude")) {
292 struct split_include *exc = malloc(sizeof(*exc));
295 exc->route = new_option->value;
296 exc->next = vpninfo->split_excludes;
297 vpninfo->split_excludes = exc;
301 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
302 vpn_progress(vpninfo, PRG_ERR,
303 _("No IP address received. Aborting\n"));
307 if (strcmp(old_addr, vpninfo->vpn_addr)) {
308 vpn_progress(vpninfo, PRG_ERR,
309 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
310 vpninfo->vpn_addr, old_addr);
315 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
316 vpn_progress(vpninfo, PRG_ERR,
317 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
318 vpninfo->vpn_netmask, old_netmask);
323 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
324 vpn_progress(vpninfo, PRG_ERR,
325 _("Reconnect gave different IPv6 address (%s != %s)\n"),
326 vpninfo->vpn_addr6, old_addr6);
331 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
332 vpn_progress(vpninfo, PRG_ERR,
333 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
334 vpninfo->vpn_netmask6, old_netmask6);
339 while (old_dtls_opts) {
340 struct vpn_option *tmp = old_dtls_opts;
341 old_dtls_opts = old_dtls_opts->next;
346 while (old_cstp_opts) {
347 struct vpn_option *tmp = old_cstp_opts;
348 old_cstp_opts = old_cstp_opts->next;
353 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
354 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
356 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
357 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
359 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
360 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
361 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
363 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
364 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
367 vpninfo->dtls_attempt_period = 0;
369 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
370 vpninfo->ssl_times.last_tx = time(NULL);
375 int make_cstp_connection(struct openconnect_info *vpninfo)
379 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
382 if (vpninfo->deflate) {
383 vpninfo->deflate_adler32 = 1;
384 vpninfo->inflate_adler32 = 1;
386 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
387 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
388 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
389 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
390 vpninfo->deflate = 0;
393 if (!vpninfo->deflate_pkt) {
394 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
395 if (!vpninfo->deflate_pkt) {
396 vpn_progress(vpninfo, PRG_ERR,
397 _("Allocation of deflate buffer failed\n"));
398 inflateEnd(&vpninfo->inflate_strm);
399 deflateEnd(&vpninfo->deflate_strm);
400 vpninfo->deflate = 0;
402 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
403 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
404 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
409 return start_cstp_connection(vpninfo);
412 int cstp_reconnect(struct openconnect_info *vpninfo)
418 openconnect_close_https(vpninfo);
420 /* Requeue the original packet that was deflated */
421 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
422 vpninfo->current_ssl_pkt = NULL;
423 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
424 vpninfo->pending_deflated_pkt = NULL;
426 if (vpninfo->deflate) {
427 inflateEnd(&vpninfo->inflate_strm);
428 deflateEnd(&vpninfo->deflate_strm);
430 timeout = vpninfo->reconnect_timeout;
431 interval = vpninfo->reconnect_interval;
433 while ((ret = make_cstp_connection(vpninfo))) {
436 vpn_progress(vpninfo, PRG_INFO,
437 _("sleep %ds, remaining timeout %ds\n"),
443 interval += vpninfo->reconnect_interval;
444 if (interval > RECONNECT_INTERVAL_MAX)
445 interval = RECONNECT_INTERVAL_MAX;
447 script_config_tun(vpninfo, "reconnect");
451 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
452 unsigned char *buf, int len)
454 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
462 vpninfo->inflate_strm.next_in = buf;
463 vpninfo->inflate_strm.avail_in = len - 4;
465 vpninfo->inflate_strm.next_out = new->data;
466 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
467 vpninfo->inflate_strm.total_out = 0;
469 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
470 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
475 new->len = vpninfo->inflate_strm.total_out;
477 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
478 new->data, new->len);
480 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
481 (buf[len - 3] << 16) | (buf[len - 4] << 24);
483 if (vpninfo->inflate_adler32 != pkt_sum) {
484 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
487 vpn_progress(vpninfo, PRG_TRACE,
488 _("Received compressed data packet of %ld bytes\n"),
489 (long)vpninfo->inflate_strm.total_out);
491 queue_packet(&vpninfo->incoming_queue, new);
495 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
497 unsigned char buf[16384];
501 /* FIXME: The poll() handling here is fairly simplistic. Actually,
502 if the SSL connection stalls it could return a WANT_WRITE error
503 on _either_ of the SSL_read() or SSL_write() calls. In that case,
504 we should probably remove POLLIN from the events we're looking for,
505 and add POLLOUT. As it is, though, it'll just chew CPU time in that
506 fairly unlikely situation, until the write backlog clears. */
507 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
510 if (buf[0] != 'S' || buf[1] != 'T' ||
511 buf[2] != 'F' || buf[3] != 1 || buf[7])
514 payload_len = (buf[4] << 8) + buf[5];
515 if (len != 8 + payload_len) {
516 vpn_progress(vpninfo, PRG_ERR,
517 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
519 vpn_progress(vpninfo, PRG_ERR,
520 "%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]);
525 vpninfo->ssl_times.last_rx = time(NULL);
528 vpn_progress(vpninfo, PRG_TRACE,
529 _("Got CSTP DPD request\n"));
530 vpninfo->owe_ssl_dpd_response = 1;
533 case AC_PKT_DPD_RESP:
534 vpn_progress(vpninfo, PRG_TRACE,
535 _("Got CSTP DPD response\n"));
538 case AC_PKT_KEEPALIVE:
539 vpn_progress(vpninfo, PRG_TRACE,
540 _("Got CSTP Keepalive\n"));
544 vpn_progress(vpninfo, PRG_TRACE,
545 _("Received uncompressed data packet of %d bytes\n"),
547 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
552 case AC_PKT_DISCONN: {
554 for (i = 0; i < payload_len; i++) {
555 if (!isprint(buf[payload_len + 8 + i]))
556 buf[payload_len + 8 + i] = '.';
558 buf[payload_len + 8] = 0;
559 vpn_progress(vpninfo, PRG_ERR,
560 _("Received server disconnect: %02x '%s'\n"),
562 vpninfo->quit_reason = "Server request";
565 case AC_PKT_COMPRESSED:
566 if (!vpninfo->deflate) {
567 vpn_progress(vpninfo, PRG_ERR,
568 _("Compressed packet received in !deflate mode\n"));
571 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
575 case AC_PKT_TERM_SERVER:
576 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
577 vpninfo->quit_reason = "Server request";
582 vpn_progress(vpninfo, PRG_ERR,
583 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
584 buf[0], buf[1], buf[2], buf[3],
585 buf[4], buf[5], buf[6], buf[7]);
586 vpninfo->quit_reason = "Unknown packet received";
590 ret = SSL_get_error(vpninfo->https_ssl, len);
591 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
592 vpn_progress(vpninfo, PRG_ERR,
593 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
599 /* If SSL_write() fails we are expected to try again. With exactly
600 the same data, at exactly the same location. So we keep the
601 packet we had before.... */
602 if (vpninfo->current_ssl_pkt) {
604 vpninfo->ssl_times.last_tx = time(NULL);
605 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
606 ret = SSL_write(vpninfo->https_ssl,
607 vpninfo->current_ssl_pkt->hdr,
608 vpninfo->current_ssl_pkt->len + 8);
610 ret = SSL_get_error(vpninfo->https_ssl, ret);
612 case SSL_ERROR_WANT_WRITE:
613 /* Waiting for the socket to become writable -- it's
614 probably stalled, and/or the buffers are full */
615 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
617 case SSL_ERROR_WANT_READ:
618 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
622 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
623 report_ssl_errors(vpninfo);
627 if (ret != vpninfo->current_ssl_pkt->len + 8) {
628 vpn_progress(vpninfo, PRG_ERR,
629 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
630 vpninfo->current_ssl_pkt->len + 8, ret);
631 vpninfo->quit_reason = "Internal error";
634 /* Don't free the 'special' packets */
635 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
636 free(vpninfo->pending_deflated_pkt);
637 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
638 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
639 vpninfo->current_ssl_pkt != &keepalive_pkt)
640 free(vpninfo->current_ssl_pkt);
642 vpninfo->current_ssl_pkt = NULL;
645 if (vpninfo->owe_ssl_dpd_response) {
646 vpninfo->owe_ssl_dpd_response = 0;
647 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
648 goto handle_outgoing;
651 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
653 /* Not that this will ever happen; we don't even process
654 the setting when we're asked for it. */
655 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
661 vpn_progress(vpninfo, PRG_ERR,
662 _("CSTP Dead Peer Detection detected dead peer!\n"));
664 if (cstp_reconnect(vpninfo)) {
665 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
666 vpninfo->quit_reason = "CSTP reconnect failed";
669 /* I think we can leave DTLS to its own devices; when we reconnect
670 with the same master secret, we do seem to get the same sessid */
674 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
676 vpninfo->current_ssl_pkt = &dpd_pkt;
677 goto handle_outgoing;
680 /* No need to send an explicit keepalive
681 if we have real data to send */
682 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
685 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
687 vpninfo->current_ssl_pkt = &keepalive_pkt;
688 goto handle_outgoing;
694 /* Service outgoing packet queue, if no DTLS */
695 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
696 struct pkt *this = vpninfo->outgoing_queue;
697 vpninfo->outgoing_queue = this->next;
698 vpninfo->outgoing_qlen--;
700 if (vpninfo->deflate) {
701 unsigned char *adler;
704 vpninfo->deflate_strm.next_in = this->data;
705 vpninfo->deflate_strm.avail_in = this->len;
706 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
707 vpninfo->deflate_strm.avail_out = 2040;
708 vpninfo->deflate_strm.total_out = 0;
710 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
712 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
716 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
717 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
719 /* Add ongoing adler32 to tail of compressed packet */
720 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
721 this->data, this->len);
723 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
724 *(adler++) = vpninfo->deflate_adler32 >> 24;
725 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
726 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
727 *(adler) = vpninfo->deflate_adler32 & 0xff;
729 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
731 vpn_progress(vpninfo, PRG_TRACE,
732 _("Sending compressed data packet of %d bytes\n"),
735 vpninfo->pending_deflated_pkt = this;
736 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
739 memcpy(this->hdr, data_hdr, 8);
740 this->hdr[4] = this->len >> 8;
741 this->hdr[5] = this->len & 0xff;
743 vpn_progress(vpninfo, PRG_TRACE,
744 _("Sending uncompressed data packet of %d bytes\n"),
747 vpninfo->current_ssl_pkt = this;
749 goto handle_outgoing;
752 /* Work is not done if we just got rid of packets off the queue */
756 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
758 unsigned char *bye_pkt;
761 /* already lost connection? */
762 if (!vpninfo->https_ssl)
765 reason_len = strlen(reason);
766 bye_pkt = malloc(reason_len + 9);
770 memcpy(bye_pkt, data_hdr, 8);
771 memcpy(bye_pkt + 9, reason, reason_len);
773 bye_pkt[4] = (reason_len + 1) >> 8;
774 bye_pkt[5] = (reason_len + 1) & 0xff;
775 bye_pkt[6] = AC_PKT_DISCONN;
778 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
781 vpn_progress(vpninfo, PRG_INFO,
782 _("Send BYE packet: %s\n"), reason);