2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2012 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
36 #include <openssl/ssl.h>
37 #include <openssl/err.h>
39 #include "openconnect-internal.h"
42 * Data packets are encapsulated in the SSL stream as follows:
44 * 0000: Magic "STF\x1"
45 * 0004: Big-endian 16-bit length (not including 8-byte header)
46 * 0006: Byte packet type (see openconnect-internal.h)
50 static char data_hdr[8] = {
53 AC_PKT_DATA, /* Type */
57 static struct pkt keepalive_pkt = {
58 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
61 static struct pkt dpd_pkt = {
62 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
65 static struct pkt dpd_resp_pkt = {
66 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
70 static int start_cstp_connection(struct openconnect_info *vpninfo)
74 int retried = 0, sessid_found = 0;
75 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
76 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
77 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
78 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
79 const char *old_addr = vpninfo->vpn_addr;
80 const char *old_netmask = vpninfo->vpn_netmask;
81 const char *old_addr6 = vpninfo->vpn_addr6;
82 const char *old_netmask6 = vpninfo->vpn_netmask6;
83 struct split_include *inc;
85 /* Clear old options which will be overwritten */
86 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
87 vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
88 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
89 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
90 vpninfo->banner = NULL;
93 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
95 for (inc = vpninfo->split_includes; inc; ) {
96 struct split_include *next = inc->next;
100 for (inc = vpninfo->split_excludes; inc; ) {
101 struct split_include *next = inc->next;
105 vpninfo->split_includes = vpninfo->split_excludes = NULL;
107 /* Create (new) random master key for DTLS connection, if needed */
108 if (vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey <
110 openconnect_random(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret))) {
111 fprintf(stderr, _("Failed to initialise DTLS secret\n"));
116 openconnect_SSL_printf(vpninfo, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
117 openconnect_SSL_printf(vpninfo, "Host: %s\r\n", vpninfo->hostname);
118 openconnect_SSL_printf(vpninfo, "User-Agent: %s\r\n", vpninfo->useragent);
119 openconnect_SSL_printf(vpninfo, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
120 openconnect_SSL_printf(vpninfo, "X-CSTP-Version: 1\r\n");
121 openconnect_SSL_printf(vpninfo, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
122 if (vpninfo->deflate)
123 openconnect_SSL_printf(vpninfo, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
124 openconnect_SSL_printf(vpninfo, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
125 openconnect_SSL_printf(vpninfo, "X-CSTP-Address-Type: %s\r\n",
126 vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
127 openconnect_SSL_printf(vpninfo, "X-DTLS-Master-Secret: ");
128 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
129 openconnect_SSL_printf(vpninfo, "%02X", vpninfo->dtls_secret[i]);
130 openconnect_SSL_printf(vpninfo, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
131 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
133 if ((i = openconnect_SSL_gets(vpninfo, buf, 65536) < 0)) {
136 vpn_progress(vpninfo, PRG_ERR,
137 _("Error fetching HTTPS response\n"));
140 openconnect_close_https(vpninfo);
142 if (openconnect_open_https(vpninfo)) {
143 vpn_progress(vpninfo, PRG_ERR,
144 _("Failed to open HTTPS connection to %s\n"),
153 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
154 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
155 /* "Service Unavailable. Why? */
156 const char *reason = "<unknown>";
157 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
158 if (!strncmp(buf, "X-Reason: ", 10)) {
163 vpn_progress(vpninfo, PRG_ERR,
164 _("VPN service unavailable; reason: %s\n"),
168 vpn_progress(vpninfo, PRG_ERR,
169 _("Got inappropriate HTTP CONNECT response: %s\n"),
171 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
176 vpn_progress(vpninfo, PRG_INFO, _("Got CONNECT response: %s\n"), buf);
178 /* We may have advertised it, but we only do it if the server agrees */
179 vpninfo->deflate = 0;
181 while ((i = openconnect_SSL_gets(vpninfo, buf, sizeof(buf)))) {
182 struct vpn_option *new_option;
188 colon = strchr(buf, ':');
197 if (strncmp(buf, "X-DTLS-", 7) &&
198 strncmp(buf, "X-CSTP-", 7))
201 new_option = malloc(sizeof(*new_option));
203 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
206 new_option->option = strdup(buf);
207 new_option->value = strdup(colon);
208 new_option->next = NULL;
210 if (!new_option->option || !new_option->value) {
211 vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
215 vpn_progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
217 if (!strncmp(buf, "X-DTLS-", 7)) {
218 *next_dtls_option = new_option;
219 next_dtls_option = &new_option->next;
221 if (!strcmp(buf + 7, "Session-ID")) {
222 if (strlen(colon) != 64) {
223 vpn_progress(vpninfo, PRG_ERR,
224 _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
226 vpninfo->dtls_attempt_period = 0;
229 for (i = 0; i < 64; i += 2)
230 vpninfo->dtls_session_id[i/2] = unhex(colon + i);
232 time(&vpninfo->dtls_times.last_rekey);
236 /* CSTP options... */
237 *next_cstp_option = new_option;
238 next_cstp_option = &new_option->next;
241 if (!strcmp(buf + 7, "Keepalive")) {
242 vpninfo->ssl_times.keepalive = atol(colon);
243 } else if (!strcmp(buf + 7, "DPD")) {
245 if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
246 vpninfo->ssl_times.dpd = j;
247 } else if (!strcmp(buf + 7, "Rekey-Time")) {
248 vpninfo->ssl_times.rekey = atol(colon);
249 } else if (!strcmp(buf + 7, "Content-Encoding")) {
250 if (!strcmp(colon, "deflate"))
251 vpninfo->deflate = 1;
253 vpn_progress(vpninfo, PRG_ERR,
254 _("Unknown CSTP-Content-Encoding %s\n"),
258 } else if (!strcmp(buf + 7, "MTU")) {
259 vpninfo->mtu = atol(colon);
260 } else if (!strcmp(buf + 7, "Address")) {
261 if (strchr(new_option->value, ':'))
262 vpninfo->vpn_addr6 = new_option->value;
264 vpninfo->vpn_addr = new_option->value;
265 } else if (!strcmp(buf + 7, "Netmask")) {
266 if (strchr(new_option->value, ':'))
267 vpninfo->vpn_netmask6 = new_option->value;
269 vpninfo->vpn_netmask = new_option->value;
270 } else if (!strcmp(buf + 7, "DNS")) {
272 for (j = 0; j < 3; j++) {
273 if (!vpninfo->vpn_dns[j]) {
274 vpninfo->vpn_dns[j] = new_option->value;
278 } else if (!strcmp(buf + 7, "NBNS")) {
280 for (j = 0; j < 3; j++) {
281 if (!vpninfo->vpn_nbns[j]) {
282 vpninfo->vpn_nbns[j] = new_option->value;
286 } else if (!strcmp(buf + 7, "Default-Domain")) {
287 vpninfo->vpn_domain = new_option->value;
288 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
289 vpninfo->vpn_proxy_pac = new_option->value;
290 } else if (!strcmp(buf + 7, "Banner")) {
291 vpninfo->banner = new_option->value;
292 } else if (!strcmp(buf + 7, "Split-Include")) {
293 struct split_include *inc = malloc(sizeof(*inc));
296 inc->route = new_option->value;
297 inc->next = vpninfo->split_includes;
298 vpninfo->split_includes = inc;
299 } else if (!strcmp(buf + 7, "Split-Exclude")) {
300 struct split_include *exc = malloc(sizeof(*exc));
303 exc->route = new_option->value;
304 exc->next = vpninfo->split_excludes;
305 vpninfo->split_excludes = exc;
309 if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
310 vpn_progress(vpninfo, PRG_ERR,
311 _("No IP address received. Aborting\n"));
315 if (strcmp(old_addr, vpninfo->vpn_addr)) {
316 vpn_progress(vpninfo, PRG_ERR,
317 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
318 vpninfo->vpn_addr, old_addr);
323 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
324 vpn_progress(vpninfo, PRG_ERR,
325 _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
326 vpninfo->vpn_netmask, old_netmask);
331 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
332 vpn_progress(vpninfo, PRG_ERR,
333 _("Reconnect gave different IPv6 address (%s != %s)\n"),
334 vpninfo->vpn_addr6, old_addr6);
339 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
340 vpn_progress(vpninfo, PRG_ERR,
341 _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
342 vpninfo->vpn_netmask6, old_netmask6);
347 while (old_dtls_opts) {
348 struct vpn_option *tmp = old_dtls_opts;
349 old_dtls_opts = old_dtls_opts->next;
354 while (old_cstp_opts) {
355 struct vpn_option *tmp = old_cstp_opts;
356 old_cstp_opts = old_cstp_opts->next;
361 vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
362 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
364 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
365 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
367 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
368 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
371 vpninfo->dtls_attempt_period = 0;
373 vpninfo->ssl_times.last_rekey = vpninfo->ssl_times.last_rx =
374 vpninfo->ssl_times.last_tx = time(NULL);
379 int make_cstp_connection(struct openconnect_info *vpninfo)
383 ret = openconnect_open_https(vpninfo);
387 if (vpninfo->deflate) {
388 vpninfo->deflate_adler32 = 1;
389 vpninfo->inflate_adler32 = 1;
391 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
392 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
393 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
394 vpn_progress(vpninfo, PRG_ERR, _("Compression setup failed\n"));
395 vpninfo->deflate = 0;
398 if (!vpninfo->deflate_pkt) {
399 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
400 if (!vpninfo->deflate_pkt) {
401 vpn_progress(vpninfo, PRG_ERR,
402 _("Allocation of deflate buffer failed\n"));
403 inflateEnd(&vpninfo->inflate_strm);
404 deflateEnd(&vpninfo->deflate_strm);
405 vpninfo->deflate = 0;
407 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
408 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
409 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
414 return start_cstp_connection(vpninfo);
417 int cstp_reconnect(struct openconnect_info *vpninfo)
423 openconnect_close_https(vpninfo);
425 /* Requeue the original packet that was deflated */
426 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) {
427 vpninfo->current_ssl_pkt = NULL;
428 queue_packet(&vpninfo->outgoing_queue, vpninfo->pending_deflated_pkt);
429 vpninfo->pending_deflated_pkt = NULL;
431 if (vpninfo->deflate) {
432 inflateEnd(&vpninfo->inflate_strm);
433 deflateEnd(&vpninfo->deflate_strm);
435 timeout = vpninfo->reconnect_timeout;
436 interval = vpninfo->reconnect_interval;
438 while ((ret = make_cstp_connection(vpninfo))) {
441 vpn_progress(vpninfo, PRG_INFO,
442 _("sleep %ds, remaining timeout %ds\n"),
448 interval += vpninfo->reconnect_interval;
449 if (interval > RECONNECT_INTERVAL_MAX)
450 interval = RECONNECT_INTERVAL_MAX;
452 script_config_tun(vpninfo, "reconnect");
456 static int inflate_and_queue_packet(struct openconnect_info *vpninfo,
457 unsigned char *buf, int len)
459 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
467 vpninfo->inflate_strm.next_in = buf;
468 vpninfo->inflate_strm.avail_in = len - 4;
470 vpninfo->inflate_strm.next_out = new->data;
471 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
472 vpninfo->inflate_strm.total_out = 0;
474 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
475 vpn_progress(vpninfo, PRG_ERR, _("inflate failed\n"));
480 new->len = vpninfo->inflate_strm.total_out;
482 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
483 new->data, new->len);
485 pkt_sum = buf[len - 1] | (buf[len - 2] << 8) |
486 (buf[len - 3] << 16) | (buf[len - 4] << 24);
488 if (vpninfo->inflate_adler32 != pkt_sum) {
489 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
492 vpn_progress(vpninfo, PRG_TRACE,
493 _("Received compressed data packet of %ld bytes\n"),
494 (long)vpninfo->inflate_strm.total_out);
496 queue_packet(&vpninfo->incoming_queue, new);
500 #if defined (OPENCONNECT_OPENSSL)
501 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
505 len = SSL_read(vpninfo->https_ssl, buf, maxlen);
509 ret = SSL_get_error(vpninfo->https_ssl, len);
510 if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
511 vpn_progress(vpninfo, PRG_ERR,
512 _("SSL read error %d (server probably closed connection); reconnecting.\n"),
519 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
523 ret = SSL_write(vpninfo->https_ssl, buf, buflen);
527 ret = SSL_get_error(vpninfo->https_ssl, ret);
529 case SSL_ERROR_WANT_WRITE:
530 /* Waiting for the socket to become writable -- it's
531 probably stalled, and/or the buffers are full */
532 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
533 case SSL_ERROR_WANT_READ:
537 vpn_progress(vpninfo, PRG_ERR, _("SSL_write failed: %d\n"), ret);
538 openconnect_report_ssl_errors(vpninfo);
542 #elif defined (OPENCONNECT_GNUTLS)
543 static int cstp_read(struct openconnect_info *vpninfo, void *buf, int maxlen)
547 ret = gnutls_record_recv(vpninfo->https_sess, buf, maxlen);
551 if (ret != GNUTLS_E_AGAIN) {
552 vpn_progress(vpninfo, PRG_ERR,
553 _("SSL read error: %s; reconnecting.\n"),
554 gnutls_strerror(ret));
560 static int cstp_write(struct openconnect_info *vpninfo, void *buf, int buflen)
564 ret = gnutls_record_send(vpninfo->https_sess, buf, buflen);
568 if (ret == GNUTLS_E_AGAIN) {
569 if (gnutls_record_get_direction(vpninfo->https_sess)) {
570 /* Waiting for the socket to become writable -- it's
571 probably stalled, and/or the buffers are full */
572 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
576 vpn_progress(vpninfo, PRG_ERR, _("SSL send failed: %s\n"),
577 gnutls_strerror(ret));
582 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
584 unsigned char buf[16384];
588 /* FIXME: The poll() handling here is fairly simplistic. Actually,
589 if the SSL connection stalls it could return a WANT_WRITE error
590 on _either_ of the SSL_read() or SSL_write() calls. In that case,
591 we should probably remove POLLIN from the events we're looking for,
592 and add POLLOUT. As it is, though, it'll just chew CPU time in that
593 fairly unlikely situation, until the write backlog clears. */
594 while ( (len = cstp_read(vpninfo, buf, sizeof(buf))) > 0) {
597 if (buf[0] != 'S' || buf[1] != 'T' ||
598 buf[2] != 'F' || buf[3] != 1 || buf[7])
601 payload_len = (buf[4] << 8) + buf[5];
602 if (len != 8 + payload_len) {
603 vpn_progress(vpninfo, PRG_ERR,
604 _("Unexpected packet length. SSL_read returned %d but packet is\n"),
606 vpn_progress(vpninfo, PRG_ERR,
607 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
608 buf[0], buf[1], buf[2], buf[3],
609 buf[4], buf[5], buf[6], buf[7]);
612 vpninfo->ssl_times.last_rx = time(NULL);
615 vpn_progress(vpninfo, PRG_TRACE,
616 _("Got CSTP DPD request\n"));
617 vpninfo->owe_ssl_dpd_response = 1;
620 case AC_PKT_DPD_RESP:
621 vpn_progress(vpninfo, PRG_TRACE,
622 _("Got CSTP DPD response\n"));
625 case AC_PKT_KEEPALIVE:
626 vpn_progress(vpninfo, PRG_TRACE,
627 _("Got CSTP Keepalive\n"));
631 vpn_progress(vpninfo, PRG_TRACE,
632 _("Received uncompressed data packet of %d bytes\n"),
634 queue_new_packet(&vpninfo->incoming_queue, buf + 8,
639 case AC_PKT_DISCONN: {
641 for (i = 0; i < payload_len; i++) {
642 if (!isprint(buf[payload_len + 8 + i]))
643 buf[payload_len + 8 + i] = '.';
645 buf[payload_len + 8] = 0;
646 vpn_progress(vpninfo, PRG_ERR,
647 _("Received server disconnect: %02x '%s'\n"),
649 vpninfo->quit_reason = "Server request";
652 case AC_PKT_COMPRESSED:
653 if (!vpninfo->deflate) {
654 vpn_progress(vpninfo, PRG_ERR,
655 _("Compressed packet received in !deflate mode\n"));
658 inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
662 case AC_PKT_TERM_SERVER:
663 vpn_progress(vpninfo, PRG_ERR, _("received server terminate packet\n"));
664 vpninfo->quit_reason = "Server request";
669 vpn_progress(vpninfo, PRG_ERR,
670 _("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n"),
671 buf[0], buf[1], buf[2], buf[3],
672 buf[4], buf[5], buf[6], buf[7]);
673 vpninfo->quit_reason = "Unknown packet received";
680 /* If SSL_write() fails we are expected to try again. With exactly
681 the same data, at exactly the same location. So we keep the
682 packet we had before.... */
683 if (vpninfo->current_ssl_pkt) {
685 vpninfo->ssl_times.last_tx = time(NULL);
686 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
688 ret = cstp_write(vpninfo,
689 vpninfo->current_ssl_pkt->hdr,
690 vpninfo->current_ssl_pkt->len + 8);
694 else if (!ret && ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
697 if (ret != vpninfo->current_ssl_pkt->len + 8) {
698 vpn_progress(vpninfo, PRG_ERR,
699 _("SSL wrote too few bytes! Asked for %d, sent %d\n"),
700 vpninfo->current_ssl_pkt->len + 8, ret);
701 vpninfo->quit_reason = "Internal error";
704 /* Don't free the 'special' packets */
705 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
706 free(vpninfo->pending_deflated_pkt);
707 else if (vpninfo->current_ssl_pkt != &dpd_pkt &&
708 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
709 vpninfo->current_ssl_pkt != &keepalive_pkt)
710 free(vpninfo->current_ssl_pkt);
712 vpninfo->current_ssl_pkt = NULL;
715 if (vpninfo->owe_ssl_dpd_response) {
716 vpninfo->owe_ssl_dpd_response = 0;
717 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
718 goto handle_outgoing;
721 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
723 /* Not that this will ever happen; we don't even process
724 the setting when we're asked for it. */
725 vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n"));
731 vpn_progress(vpninfo, PRG_ERR,
732 _("CSTP Dead Peer Detection detected dead peer!\n"));
734 if (cstp_reconnect(vpninfo)) {
735 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
736 vpninfo->quit_reason = "CSTP reconnect failed";
739 /* I think we can leave DTLS to its own devices; when we reconnect
740 with the same master secret, we do seem to get the same sessid */
744 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP DPD\n"));
746 vpninfo->current_ssl_pkt = &dpd_pkt;
747 goto handle_outgoing;
750 /* No need to send an explicit keepalive
751 if we have real data to send */
752 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
755 vpn_progress(vpninfo, PRG_TRACE, _("Send CSTP Keepalive\n"));
757 vpninfo->current_ssl_pkt = &keepalive_pkt;
758 goto handle_outgoing;
764 /* Service outgoing packet queue, if no DTLS */
765 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
766 struct pkt *this = vpninfo->outgoing_queue;
767 vpninfo->outgoing_queue = this->next;
768 vpninfo->outgoing_qlen--;
770 if (vpninfo->deflate) {
771 unsigned char *adler;
774 vpninfo->deflate_strm.next_in = this->data;
775 vpninfo->deflate_strm.avail_in = this->len;
776 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
777 vpninfo->deflate_strm.avail_out = 2040;
778 vpninfo->deflate_strm.total_out = 0;
780 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
782 vpn_progress(vpninfo, PRG_ERR, _("deflate failed %d\n"), ret);
786 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
787 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
789 /* Add ongoing adler32 to tail of compressed packet */
790 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
791 this->data, this->len);
793 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
794 *(adler++) = vpninfo->deflate_adler32 >> 24;
795 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
796 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
797 *(adler) = vpninfo->deflate_adler32 & 0xff;
799 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
801 vpn_progress(vpninfo, PRG_TRACE,
802 _("Sending compressed data packet of %d bytes\n"),
805 vpninfo->pending_deflated_pkt = this;
806 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
809 memcpy(this->hdr, data_hdr, 8);
810 this->hdr[4] = this->len >> 8;
811 this->hdr[5] = this->len & 0xff;
813 vpn_progress(vpninfo, PRG_TRACE,
814 _("Sending uncompressed data packet of %d bytes\n"),
817 vpninfo->current_ssl_pkt = this;
819 goto handle_outgoing;
822 /* Work is not done if we just got rid of packets off the queue */
826 int cstp_bye(struct openconnect_info *vpninfo, const char *reason)
828 unsigned char *bye_pkt;
831 /* already lost connection? */
832 #if defined (OPENCONNECT_OPENSSL)
833 if (!vpninfo->https_ssl)
835 #elif defined (OPENCONNECT_GNUTLS)
836 if (!vpninfo->https_sess)
840 reason_len = strlen(reason);
841 bye_pkt = malloc(reason_len + 9);
845 memcpy(bye_pkt, data_hdr, 8);
846 memcpy(bye_pkt + 9, reason, reason_len);
848 bye_pkt[4] = (reason_len + 1) >> 8;
849 bye_pkt[5] = (reason_len + 1) & 0xff;
850 bye_pkt[6] = AC_PKT_DISCONN;
853 vpn_progress(vpninfo, PRG_INFO,
854 _("Send BYE packet: %s\n"), reason);
856 cstp_write(vpninfo, bye_pkt, reason_len + 9);