2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008 Intel Corporation.
6 * Author: David Woodhouse <dwmw2@infradead.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * version 2.1, as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
30 #include <openssl/ssl.h>
31 #include <openssl/err.h>
33 #include "openconnect.h"
36 * Data packets are encapsulated in the SSL stream as follows:
38 * 0000: Magic "STF\x1"
39 * 0004: Big-endian 16-bit length (not including 8-byte header)
40 * 0006: Byte packet type (see openconnect.h)
44 static char data_hdr[8] = {
47 AC_PKT_DATA, /* Type */
51 static struct pkt keepalive_pkt = {
52 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
55 static struct pkt dpd_pkt = {
56 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
59 static struct pkt dpd_resp_pkt = {
60 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
64 static int start_cstp_connection(struct openconnect_info *vpninfo)
69 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
70 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
71 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
72 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
73 const char *old_addr = vpninfo->vpn_addr;
74 const char *old_netmask = vpninfo->vpn_netmask;
75 struct split_include *inc;
77 /* Clear old options which will be overwritten */
78 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
79 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
81 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
83 for (inc = vpninfo->split_includes; inc; inc = inc->next) {
84 struct split_include *next = inc->next;
89 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
90 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
91 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
92 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
93 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
94 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
96 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
97 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
98 /* To enable IPv6, send 'IPv6,IPv4'.
99 We don't know how most of that works yet though. */
100 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
101 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
102 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
103 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
104 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
106 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
107 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
110 openconnect_close_https(vpninfo);
112 if (openconnect_open_https(vpninfo)) {
113 vpninfo->progress(vpninfo, PRG_ERR,
114 "Failed to open HTTPS connection to %s\n",
123 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
124 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
125 /* "Service Unavailable. Why? */
126 char *reason = "<unknown>";
127 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
128 if (!strncmp(buf, "X-Reason: ", 10)) {
133 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
137 vpninfo->progress(vpninfo, PRG_ERR,
138 "Got inappropriate HTTP CONNECT response: %s\n",
140 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
145 vpninfo->progress(vpninfo, PRG_INFO,
146 "Got CONNECT response: %s\n", buf);
148 /* We may have advertised it, but we only do it if the server agrees */
149 vpninfo->deflate = 0;
151 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
152 struct vpn_option *new_option;
153 char *colon = strchr(buf, ':');
162 if (strncmp(buf, "X-DTLS-", 7) &&
163 strncmp(buf, "X-CSTP-", 7))
166 new_option = malloc(sizeof(*new_option));
168 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
171 new_option->option = strdup(buf);
172 new_option->value = strdup(colon);
173 new_option->next = NULL;
175 if (!new_option->option || !new_option->value) {
176 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
180 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
182 if (!strncmp(buf, "X-DTLS-", 7)) {
183 *next_dtls_option = new_option;
184 next_dtls_option = &new_option->next;
187 /* CSTP options... */
188 *next_cstp_option = new_option;
189 next_cstp_option = &new_option->next;
192 if (!strcmp(buf + 7, "Keepalive")) {
193 vpninfo->ssl_times.keepalive = atol(colon);
194 } else if (!strcmp(buf + 7, "DPD")) {
195 vpninfo->ssl_times.dpd = atol(colon);
196 } else if (!strcmp(buf + 7, "Content-Encoding")) {
197 if (!strcmp(colon, "deflate"))
198 vpninfo->deflate = 1;
200 vpninfo->progress(vpninfo, PRG_ERR,
201 "Unknown CSTP-Content-Encoding %s\n",
205 } else if (!strcmp(buf + 7, "MTU")) {
206 vpninfo->mtu = atol(colon);
207 } else if (!strcmp(buf + 7, "Address")) {
208 vpninfo->vpn_addr = new_option->value;
209 } else if (!strcmp(buf + 7, "Netmask")) {
210 vpninfo->vpn_netmask = new_option->value;
211 } else if (!strcmp(buf + 7, "DNS")) {
213 for (j = 0; j < 3; j++) {
214 if (!vpninfo->vpn_dns[j]) {
215 vpninfo->vpn_dns[j] = new_option->value;
219 } else if (!strcmp(buf + 7, "NBNS")) {
221 for (j = 0; j < 3; j++) {
222 if (!vpninfo->vpn_nbns[j]) {
223 vpninfo->vpn_nbns[j] = new_option->value;
227 } else if (!strcmp(buf + 7, "Default-Domain")) {
228 vpninfo->vpn_domain = new_option->value;
229 } else if (!strcmp(buf + 7, "Split-Include")) {
230 struct split_include *inc = malloc(sizeof(*inc));
233 inc->route = new_option->value;
234 inc->next = vpninfo->split_includes;
235 vpninfo->split_includes = inc;
239 if (!vpninfo->vpn_addr) {
240 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
243 if (!vpninfo->vpn_netmask)
244 vpninfo->vpn_netmask = "255.255.255.255";
246 if (strcmp(old_addr, vpninfo->vpn_addr)) {
247 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IP address (%s != %s)\n",
248 vpninfo->vpn_addr, old_addr);
253 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
254 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different netmask (%s != %s)\n",
255 vpninfo->vpn_netmask, old_netmask);
260 while (old_dtls_opts) {
261 struct vpn_option *tmp = old_dtls_opts;
262 old_dtls_opts = old_dtls_opts->next;
267 while (old_cstp_opts) {
268 struct vpn_option *tmp = old_cstp_opts;
269 old_cstp_opts = old_cstp_opts->next;
274 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
275 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
277 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
278 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);
280 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
281 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
282 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
284 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
285 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
287 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
292 int make_cstp_connection(struct openconnect_info *vpninfo)
296 if (!vpninfo->https_ssl && (ret=openconnect_open_https(vpninfo)))
299 if (vpninfo->deflate) {
300 vpninfo->deflate_adler32 = 1;
301 vpninfo->inflate_adler32 = 1;
303 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
304 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
305 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
306 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
307 vpninfo->deflate = 0;
310 if (!vpninfo->deflate_pkt) {
311 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
312 if (!vpninfo->deflate_pkt) {
313 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
314 vpninfo->deflate = 0;
316 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
317 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
318 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
322 return start_cstp_connection(vpninfo);
325 static int cstp_reconnect(struct openconnect_info *vpninfo)
331 timeout = vpninfo->reconnect_timeout;
332 interval = vpninfo->reconnect_interval;
334 while ((ret = make_cstp_connection(vpninfo))) {
337 vpninfo->progress(vpninfo, PRG_INFO,
338 "sleep %ds, remain timeout %ds\n",
342 interval += vpninfo->reconnect_interval;
343 if (interval > RECONNECT_INTERVAL_MAX)
344 interval = RECONNECT_INTERVAL_MAX;
349 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
351 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
359 vpninfo->inflate_strm.next_in = buf;
360 vpninfo->inflate_strm.avail_in = len - 4;
362 vpninfo->inflate_strm.next_out = new->data;
363 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
364 vpninfo->inflate_strm.total_out = 0;
366 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
367 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
372 new->len = vpninfo->inflate_strm.total_out;
374 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
375 new->data, new->len);
377 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
378 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
381 vpninfo->progress(vpninfo, PRG_TRACE,
382 "Received compressed data packet of %ld bytes\n",
383 vpninfo->inflate_strm.total_out);
385 queue_packet(&vpninfo->incoming_queue, new);
389 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
391 unsigned char buf[16384];
395 /* FIXME: The poll() handling here is fairly simplistic. Actually,
396 if the SSL connection stalls it could return a WANT_WRITE error
397 on _either_ of the SSL_read() or SSL_write() calls. In that case,
398 we should probably remove POLLIN from the events we're looking for,
399 and add POLLOUT. As it is, though, it'll just chew CPU time in that
400 fairly unlikely situation, until the write backlog clears. */
401 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
404 if (buf[0] != 'S' || buf[1] != 'T' ||
405 buf[2] != 'F' || buf[3] != 1 || buf[7])
408 payload_len = (buf[4] << 8) + buf[5];
409 if (len != 8 + payload_len) {
410 vpninfo->progress(vpninfo, PRG_ERR,
411 "Unexpected packet length. SSL_read returned %d but packet is\n",
413 vpninfo->progress(vpninfo, PRG_ERR,
414 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
415 buf[0], buf[1], buf[2], buf[3],
416 buf[4], buf[5], buf[6], buf[7]);
419 vpninfo->ssl_times.last_rx = time(NULL);
422 vpninfo->progress(vpninfo, PRG_TRACE,
423 "Got CSTP DPD request\n");
424 vpninfo->owe_ssl_dpd_response = 1;
427 case AC_PKT_DPD_RESP:
428 vpninfo->progress(vpninfo, PRG_TRACE,
429 "Got CSTP DPD response\n");
432 case AC_PKT_KEEPALIVE:
433 vpninfo->progress(vpninfo, PRG_TRACE,
434 "Got CSTP Keepalive\n");
438 vpninfo->progress(vpninfo, PRG_TRACE,
439 "Received uncompressed data packet of %d bytes\n",
441 queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
446 case AC_PKT_DISCONN: {
448 for (i = 0; i < payload_len; i++) {
449 if (!isprint(buf[payload_len + 8 + i]))
450 buf[payload_len + 8 + i] = '.';
452 buf[payload_len + 8] = 0;
453 vpninfo->progress(vpninfo, PRG_ERR,
454 "Received server disconnect: '%s'\n", buf + 8);
455 vpninfo->quit_reason = "Server request";
458 case AC_PKT_COMPRESSED:
459 if (!vpninfo->deflate) {
460 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
463 inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
467 case AC_PKT_TERM_SERVER:
468 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
469 vpninfo->quit_reason = "Server request";
474 vpninfo->progress(vpninfo, PRG_ERR,
475 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
476 buf[0], buf[1], buf[2], buf[3],
477 buf[4], buf[5], buf[6], buf[7]);
478 vpninfo->quit_reason = "Unknown packet received";
483 /* If SSL_write() fails we are expected to try again. With exactly
484 the same data, at exactly the same location. So we keep the
485 packet we had before.... */
486 if (vpninfo->current_ssl_pkt) {
488 vpninfo->ssl_times.last_tx = time(NULL);
489 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
490 ret = SSL_write(vpninfo->https_ssl,
491 vpninfo->current_ssl_pkt->hdr,
492 vpninfo->current_ssl_pkt->len + 8);
494 ret = SSL_get_error(vpninfo->https_ssl, ret);
496 case SSL_ERROR_WANT_WRITE:
497 /* Waiting for the socket to become writable -- it's
498 probably stalled, and/or the buffers are full */
499 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
501 case SSL_ERROR_WANT_READ:
502 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
506 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
507 ERR_print_errors_fp(stderr);
508 vpninfo->quit_reason = "SSL write error";
512 if (ret != vpninfo->current_ssl_pkt->len + 8) {
513 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
514 vpninfo->current_ssl_pkt->len + 8, ret);
515 vpninfo->quit_reason = "Internal error";
518 /* Don't free the 'special' packets */
519 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
520 vpninfo->current_ssl_pkt != &dpd_pkt &&
521 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
522 vpninfo->current_ssl_pkt != &keepalive_pkt)
523 free(vpninfo->current_ssl_pkt);
525 vpninfo->current_ssl_pkt = NULL;
528 if (vpninfo->owe_ssl_dpd_response) {
529 vpninfo->owe_ssl_dpd_response = 0;
530 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
531 goto handle_outgoing;
534 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
536 /* Not that this will ever happen; we don't even process
537 the setting when we're asked for it. */
538 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
539 time(&vpninfo->ssl_times.last_rekey);
545 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
546 openconnect_close_https(vpninfo);
548 /* It's already deflated in the old stream. Extremely
549 non-trivial to reconstitute it; just throw it away */
550 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
551 vpninfo->current_ssl_pkt = NULL;
553 if (cstp_reconnect(vpninfo)) {
554 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
555 vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
558 /* I think we can leave DTLS to its own devices; when we reconnect
559 with the same master secret, we do seem to get the same sessid */
563 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
565 vpninfo->current_ssl_pkt = &dpd_pkt;
566 goto handle_outgoing;
569 /* No need to send an explicit keepalive
570 if we have real data to send */
571 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
574 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
576 vpninfo->current_ssl_pkt = &keepalive_pkt;
577 goto handle_outgoing;
583 /* Service outgoing packet queue, if no DTLS */
584 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
585 struct pkt *this = vpninfo->outgoing_queue;
586 vpninfo->outgoing_queue = this->next;
587 vpninfo->outgoing_qlen--;
589 if (vpninfo->deflate) {
590 unsigned char *adler;
593 vpninfo->deflate_strm.next_in = this->data;
594 vpninfo->deflate_strm.avail_in = this->len;
595 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
596 vpninfo->deflate_strm.avail_out = 2040;
597 vpninfo->deflate_strm.total_out = 0;
599 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
601 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
605 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
606 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
608 /* Add ongoing adler32 to tail of compressed packet */
609 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
610 this->data, this->len);
612 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
613 *(adler++) = vpninfo->deflate_adler32 >> 24;
614 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
615 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
616 *(adler) = vpninfo->deflate_adler32 & 0xff;
618 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
620 vpninfo->progress(vpninfo, PRG_TRACE,
621 "Sending compressed data packet of %d bytes\n",
624 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
627 memcpy(this->hdr, data_hdr, 8);
628 this->hdr[4] = this->len >> 8;
629 this->hdr[5] = this->len & 0xff;
631 vpninfo->progress(vpninfo, PRG_TRACE,
632 "Sending uncompressed data packet of %d bytes\n",
635 vpninfo->current_ssl_pkt = this;
637 goto handle_outgoing;
640 /* Work is not done if we just got rid of packets off the queue */
644 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
646 unsigned char *bye_pkt;
649 /* already lost connection? */
650 if (!vpninfo->https_ssl)
653 reason_len = strlen(reason);
654 bye_pkt = malloc(reason_len + 8);
658 memcpy(bye_pkt, data_hdr, 8);
659 memcpy(bye_pkt + 8, reason, reason_len);
661 bye_pkt[4] = reason_len >> 8;
662 bye_pkt[5] = reason_len & 0xff;
663 bye_pkt[6] = AC_PKT_DISCONN;
665 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
668 vpninfo->progress(vpninfo, PRG_INFO,
669 "Send BYE packet: %s\n", reason);