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 <openssl/ssl.h>
32 #include <openssl/err.h>
34 #include "openconnect.h"
37 * Data packets are encapsulated in the SSL stream as follows:
39 * 0000: Magic "STF\x1"
40 * 0004: Big-endian 16-bit length (not including 8-byte header)
41 * 0006: Byte packet type (see openconnect.h)
45 static char data_hdr[8] = {
48 AC_PKT_DATA, /* Type */
52 static struct pkt keepalive_pkt = {
53 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
56 static struct pkt dpd_pkt = {
57 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
60 static struct pkt dpd_resp_pkt = {
61 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
65 static int start_cstp_connection(struct openconnect_info *vpninfo)
70 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
71 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
72 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
73 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
74 const char *old_addr = vpninfo->vpn_addr;
75 const char *old_netmask = vpninfo->vpn_netmask;
76 struct split_include *inc;
78 /* Clear old options which will be overwritten */
79 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
80 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
82 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
84 for (inc = vpninfo->split_includes; inc; inc = inc->next) {
85 struct split_include *next = inc->next;
90 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
91 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
92 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
93 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
94 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
95 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
97 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
98 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
99 /* To enable IPv6, send 'IPv6,IPv4'.
100 We don't know how most of that works yet though. */
101 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
102 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
103 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
104 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
105 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
107 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
108 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
111 openconnect_close_https(vpninfo);
113 if (openconnect_open_https(vpninfo)) {
114 vpninfo->progress(vpninfo, PRG_ERR,
115 "Failed to open HTTPS connection to %s\n",
124 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
125 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
126 /* "Service Unavailable. Why? */
127 char *reason = "<unknown>";
128 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
129 if (!strncmp(buf, "X-Reason: ", 10)) {
134 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
138 vpninfo->progress(vpninfo, PRG_ERR,
139 "Got inappropriate HTTP CONNECT response: %s\n",
141 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
146 vpninfo->progress(vpninfo, PRG_INFO,
147 "Got CONNECT response: %s\n", buf);
149 /* We may have advertised it, but we only do it if the server agrees */
150 vpninfo->deflate = 0;
152 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
153 struct vpn_option *new_option;
154 char *colon = strchr(buf, ':');
163 if (strncmp(buf, "X-DTLS-", 7) &&
164 strncmp(buf, "X-CSTP-", 7))
167 new_option = malloc(sizeof(*new_option));
169 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
172 new_option->option = strdup(buf);
173 new_option->value = strdup(colon);
174 new_option->next = NULL;
176 if (!new_option->option || !new_option->value) {
177 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
181 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
183 if (!strncmp(buf, "X-DTLS-", 7)) {
184 *next_dtls_option = new_option;
185 next_dtls_option = &new_option->next;
188 /* CSTP options... */
189 *next_cstp_option = new_option;
190 next_cstp_option = &new_option->next;
193 if (!strcmp(buf + 7, "Keepalive")) {
194 vpninfo->ssl_times.keepalive = atol(colon);
195 } else if (!strcmp(buf + 7, "DPD")) {
196 vpninfo->ssl_times.dpd = atol(colon);
197 } else if (!strcmp(buf + 7, "Content-Encoding")) {
198 if (!strcmp(colon, "deflate"))
199 vpninfo->deflate = 1;
201 vpninfo->progress(vpninfo, PRG_ERR,
202 "Unknown CSTP-Content-Encoding %s\n",
206 } else if (!strcmp(buf + 7, "MTU")) {
207 vpninfo->mtu = atol(colon);
208 } else if (!strcmp(buf + 7, "Address")) {
209 vpninfo->vpn_addr = new_option->value;
210 } else if (!strcmp(buf + 7, "Netmask")) {
211 vpninfo->vpn_netmask = new_option->value;
212 } else if (!strcmp(buf + 7, "DNS")) {
214 for (j = 0; j < 3; j++) {
215 if (!vpninfo->vpn_dns[j]) {
216 vpninfo->vpn_dns[j] = new_option->value;
220 } else if (!strcmp(buf + 7, "NBNS")) {
222 for (j = 0; j < 3; j++) {
223 if (!vpninfo->vpn_nbns[j]) {
224 vpninfo->vpn_nbns[j] = new_option->value;
228 } else if (!strcmp(buf + 7, "Default-Domain")) {
229 vpninfo->vpn_domain = new_option->value;
230 } else if (!strcmp(buf + 7, "Split-Include")) {
231 struct split_include *inc = malloc(sizeof(*inc));
234 inc->route = new_option->value;
235 inc->next = vpninfo->split_includes;
236 vpninfo->split_includes = inc;
240 if (!vpninfo->vpn_addr) {
241 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
244 if (!vpninfo->vpn_netmask)
245 vpninfo->vpn_netmask = "255.255.255.255";
247 if (strcmp(old_addr, vpninfo->vpn_addr)) {
248 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IP address (%s != %s)\n",
249 vpninfo->vpn_addr, old_addr);
254 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
255 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different netmask (%s != %s)\n",
256 vpninfo->vpn_netmask, old_netmask);
261 while (old_dtls_opts) {
262 struct vpn_option *tmp = old_dtls_opts;
263 old_dtls_opts = old_dtls_opts->next;
268 while (old_cstp_opts) {
269 struct vpn_option *tmp = old_cstp_opts;
270 old_cstp_opts = old_cstp_opts->next;
275 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
276 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
278 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
279 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);
281 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
282 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
283 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
285 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
286 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
288 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
293 int make_cstp_connection(struct openconnect_info *vpninfo)
297 if (!vpninfo->https_ssl && (ret=openconnect_open_https(vpninfo)))
300 if (vpninfo->deflate) {
301 vpninfo->deflate_adler32 = 1;
302 vpninfo->inflate_adler32 = 1;
304 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
305 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
306 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
307 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
308 vpninfo->deflate = 0;
311 if (!vpninfo->deflate_pkt) {
312 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
313 if (!vpninfo->deflate_pkt) {
314 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
315 vpninfo->deflate = 0;
317 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
318 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
319 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
323 return start_cstp_connection(vpninfo);
326 static int cstp_reconnect(struct openconnect_info *vpninfo)
332 timeout = vpninfo->reconnect_timeout;
333 interval = vpninfo->reconnect_interval;
335 while ((ret = make_cstp_connection(vpninfo))) {
338 vpninfo->progress(vpninfo, PRG_INFO,
339 "sleep %ds, remaining timeout %ds\n",
345 interval += vpninfo->reconnect_interval;
346 if (interval > RECONNECT_INTERVAL_MAX)
347 interval = RECONNECT_INTERVAL_MAX;
352 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
354 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
362 vpninfo->inflate_strm.next_in = buf;
363 vpninfo->inflate_strm.avail_in = len - 4;
365 vpninfo->inflate_strm.next_out = new->data;
366 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
367 vpninfo->inflate_strm.total_out = 0;
369 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
370 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
375 new->len = vpninfo->inflate_strm.total_out;
377 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
378 new->data, new->len);
380 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
381 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
384 vpninfo->progress(vpninfo, PRG_TRACE,
385 "Received compressed data packet of %ld bytes\n",
386 vpninfo->inflate_strm.total_out);
388 queue_packet(&vpninfo->incoming_queue, new);
392 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
394 unsigned char buf[16384];
398 /* FIXME: The poll() handling here is fairly simplistic. Actually,
399 if the SSL connection stalls it could return a WANT_WRITE error
400 on _either_ of the SSL_read() or SSL_write() calls. In that case,
401 we should probably remove POLLIN from the events we're looking for,
402 and add POLLOUT. As it is, though, it'll just chew CPU time in that
403 fairly unlikely situation, until the write backlog clears. */
404 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
407 if (buf[0] != 'S' || buf[1] != 'T' ||
408 buf[2] != 'F' || buf[3] != 1 || buf[7])
411 payload_len = (buf[4] << 8) + buf[5];
412 if (len != 8 + payload_len) {
413 vpninfo->progress(vpninfo, PRG_ERR,
414 "Unexpected packet length. SSL_read returned %d but packet is\n",
416 vpninfo->progress(vpninfo, PRG_ERR,
417 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
418 buf[0], buf[1], buf[2], buf[3],
419 buf[4], buf[5], buf[6], buf[7]);
422 vpninfo->ssl_times.last_rx = time(NULL);
425 vpninfo->progress(vpninfo, PRG_TRACE,
426 "Got CSTP DPD request\n");
427 vpninfo->owe_ssl_dpd_response = 1;
430 case AC_PKT_DPD_RESP:
431 vpninfo->progress(vpninfo, PRG_TRACE,
432 "Got CSTP DPD response\n");
435 case AC_PKT_KEEPALIVE:
436 vpninfo->progress(vpninfo, PRG_TRACE,
437 "Got CSTP Keepalive\n");
441 vpninfo->progress(vpninfo, PRG_TRACE,
442 "Received uncompressed data packet of %d bytes\n",
444 queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
449 case AC_PKT_DISCONN: {
451 for (i = 0; i < payload_len; i++) {
452 if (!isprint(buf[payload_len + 8 + i]))
453 buf[payload_len + 8 + i] = '.';
455 buf[payload_len + 8] = 0;
456 vpninfo->progress(vpninfo, PRG_ERR,
457 "Received server disconnect: '%s'\n", buf + 8);
458 vpninfo->quit_reason = "Server request";
461 case AC_PKT_COMPRESSED:
462 if (!vpninfo->deflate) {
463 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
466 inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
470 case AC_PKT_TERM_SERVER:
471 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
472 vpninfo->quit_reason = "Server request";
477 vpninfo->progress(vpninfo, PRG_ERR,
478 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
479 buf[0], buf[1], buf[2], buf[3],
480 buf[4], buf[5], buf[6], buf[7]);
481 vpninfo->quit_reason = "Unknown packet received";
486 /* If SSL_write() fails we are expected to try again. With exactly
487 the same data, at exactly the same location. So we keep the
488 packet we had before.... */
489 if (vpninfo->current_ssl_pkt) {
491 vpninfo->ssl_times.last_tx = time(NULL);
492 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
493 ret = SSL_write(vpninfo->https_ssl,
494 vpninfo->current_ssl_pkt->hdr,
495 vpninfo->current_ssl_pkt->len + 8);
497 ret = SSL_get_error(vpninfo->https_ssl, ret);
499 case SSL_ERROR_WANT_WRITE:
500 /* Waiting for the socket to become writable -- it's
501 probably stalled, and/or the buffers are full */
502 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
504 case SSL_ERROR_WANT_READ:
505 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
509 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
510 ERR_print_errors_fp(stderr);
511 vpninfo->quit_reason = "SSL write error";
515 if (ret != vpninfo->current_ssl_pkt->len + 8) {
516 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
517 vpninfo->current_ssl_pkt->len + 8, ret);
518 vpninfo->quit_reason = "Internal error";
521 /* Don't free the 'special' packets */
522 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
523 vpninfo->current_ssl_pkt != &dpd_pkt &&
524 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
525 vpninfo->current_ssl_pkt != &keepalive_pkt)
526 free(vpninfo->current_ssl_pkt);
528 vpninfo->current_ssl_pkt = NULL;
531 if (vpninfo->owe_ssl_dpd_response) {
532 vpninfo->owe_ssl_dpd_response = 0;
533 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
534 goto handle_outgoing;
537 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
539 /* Not that this will ever happen; we don't even process
540 the setting when we're asked for it. */
541 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
542 time(&vpninfo->ssl_times.last_rekey);
548 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
549 openconnect_close_https(vpninfo);
551 /* It's already deflated in the old stream. Extremely
552 non-trivial to reconstitute it; just throw it away */
553 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
554 vpninfo->current_ssl_pkt = NULL;
556 if (cstp_reconnect(vpninfo)) {
557 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
558 vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
561 /* I think we can leave DTLS to its own devices; when we reconnect
562 with the same master secret, we do seem to get the same sessid */
566 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
568 vpninfo->current_ssl_pkt = &dpd_pkt;
569 goto handle_outgoing;
572 /* No need to send an explicit keepalive
573 if we have real data to send */
574 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
577 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
579 vpninfo->current_ssl_pkt = &keepalive_pkt;
580 goto handle_outgoing;
586 /* Service outgoing packet queue, if no DTLS */
587 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
588 struct pkt *this = vpninfo->outgoing_queue;
589 vpninfo->outgoing_queue = this->next;
590 vpninfo->outgoing_qlen--;
592 if (vpninfo->deflate) {
593 unsigned char *adler;
596 vpninfo->deflate_strm.next_in = this->data;
597 vpninfo->deflate_strm.avail_in = this->len;
598 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
599 vpninfo->deflate_strm.avail_out = 2040;
600 vpninfo->deflate_strm.total_out = 0;
602 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
604 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
608 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
609 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
611 /* Add ongoing adler32 to tail of compressed packet */
612 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
613 this->data, this->len);
615 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
616 *(adler++) = vpninfo->deflate_adler32 >> 24;
617 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
618 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
619 *(adler) = vpninfo->deflate_adler32 & 0xff;
621 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
623 vpninfo->progress(vpninfo, PRG_TRACE,
624 "Sending compressed data packet of %d bytes\n",
627 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
630 memcpy(this->hdr, data_hdr, 8);
631 this->hdr[4] = this->len >> 8;
632 this->hdr[5] = this->len & 0xff;
634 vpninfo->progress(vpninfo, PRG_TRACE,
635 "Sending uncompressed data packet of %d bytes\n",
638 vpninfo->current_ssl_pkt = this;
640 goto handle_outgoing;
643 /* Work is not done if we just got rid of packets off the queue */
647 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
649 unsigned char *bye_pkt;
652 /* already lost connection? */
653 if (!vpninfo->https_ssl)
656 reason_len = strlen(reason);
657 bye_pkt = malloc(reason_len + 8);
661 memcpy(bye_pkt, data_hdr, 8);
662 memcpy(bye_pkt + 8, reason, reason_len);
664 bye_pkt[4] = reason_len >> 8;
665 bye_pkt[5] = reason_len & 0xff;
666 bye_pkt[6] = AC_PKT_DISCONN;
668 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
671 vpninfo->progress(vpninfo, PRG_INFO,
672 "Send BYE packet: %s\n", reason);