2 * Open AnyConnect (SSL + DTLS) client
4 * © 2008 David Woodhouse <dwmw2@infradead.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to:
19 * Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
29 #include <openssl/ssl.h>
30 #include <openssl/err.h>
32 #include "openconnect.h"
35 * Data packets are encapsulated in the SSL stream as follows:
37 * 0000: Magic "STF\x1"
38 * 0004: Big-endian 16-bit length (not including 8-byte header)
39 * 0006: Byte packet type (see openconnect.h)
43 static char data_hdr[8] = {
46 AC_PKT_DATA, /* Type */
50 static struct pkt keepalive_pkt = {
51 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
54 static struct pkt dpd_pkt = {
55 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
58 static struct pkt dpd_resp_pkt = {
59 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
63 static int start_cstp_connection(struct openconnect_info *vpninfo)
68 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
69 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
70 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
71 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
72 const char *old_addr = vpninfo->vpn_addr;
73 const char *old_netmask = vpninfo->vpn_netmask;
74 struct split_include *inc;
76 /* Clear old options which will be overwritten */
77 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
78 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
80 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
82 for (inc = vpninfo->split_includes; inc; inc = inc->next) {
83 struct split_include *next = inc->next;
88 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
89 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
90 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
91 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
92 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
93 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
95 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
96 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
97 /* To enable IPv6, send 'IPv6,IPv4'.
98 We don't know how most of that works yet though. */
99 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
100 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
101 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
102 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
103 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
105 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
106 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
109 openconnect_close_https(vpninfo);
111 if (openconnect_open_https(vpninfo)) {
112 vpninfo->progress(vpninfo, PRG_ERR,
113 "Failed to open HTTPS connection to %s\n",
122 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
123 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
124 /* "Service Unavailable. Why? */
125 char *reason = "<unknown>";
126 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
127 if (!strncmp(buf, "X-Reason: ", 10)) {
132 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
136 vpninfo->progress(vpninfo, PRG_ERR,
137 "Got inappropriate HTTP CONNECT response: %s\n",
139 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
144 vpninfo->progress(vpninfo, PRG_INFO,
145 "Got CONNECT response: %s\n", buf);
147 /* We may have advertised it, but we only do it if the server agrees */
148 vpninfo->deflate = 0;
150 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
151 struct vpn_option *new_option;
152 char *colon = strchr(buf, ':');
161 if (strncmp(buf, "X-DTLS-", 7) &&
162 strncmp(buf, "X-CSTP-", 7))
165 new_option = malloc(sizeof(*new_option));
167 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
170 new_option->option = strdup(buf);
171 new_option->value = strdup(colon);
172 new_option->next = NULL;
174 if (!new_option->option || !new_option->value) {
175 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
179 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
181 if (!strncmp(buf, "X-DTLS-", 7)) {
182 *next_dtls_option = new_option;
183 next_dtls_option = &new_option->next;
186 /* CSTP options... */
187 *next_cstp_option = new_option;
188 next_cstp_option = &new_option->next;
191 if (!strcmp(buf + 7, "Keepalive")) {
192 vpninfo->ssl_times.keepalive = atol(colon);
193 } else if (!strcmp(buf + 7, "DPD")) {
194 vpninfo->ssl_times.dpd = atol(colon);
195 } else if (!strcmp(buf + 7, "Content-Encoding")) {
196 if (!strcmp(colon, "deflate"))
197 vpninfo->deflate = 1;
199 vpninfo->progress(vpninfo, PRG_ERR,
200 "Unknown CSTP-Content-Encoding %s\n",
204 } else if (!strcmp(buf + 7, "MTU")) {
205 vpninfo->mtu = atol(colon);
206 } else if (!strcmp(buf + 7, "Address")) {
207 vpninfo->vpn_addr = new_option->value;
208 } else if (!strcmp(buf + 7, "Netmask")) {
209 vpninfo->vpn_netmask = new_option->value;
210 } else if (!strcmp(buf + 7, "DNS")) {
212 for (j = 0; j < 3; j++) {
213 if (!vpninfo->vpn_dns[j]) {
214 vpninfo->vpn_dns[j] = new_option->value;
218 } else if (!strcmp(buf + 7, "NBNS")) {
220 for (j = 0; j < 3; j++) {
221 if (!vpninfo->vpn_nbns[j]) {
222 vpninfo->vpn_nbns[j] = new_option->value;
226 } else if (!strcmp(buf + 7, "Default-Domain")) {
227 vpninfo->vpn_domain = new_option->value;
228 } else if (!strcmp(buf + 7, "Split-Include")) {
229 struct split_include *inc = malloc(sizeof(*inc));
232 inc->route = new_option->value;
233 inc->next = vpninfo->split_includes;
234 vpninfo->split_includes = inc;
238 if (!vpninfo->vpn_addr) {
239 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
242 if (!vpninfo->vpn_netmask)
243 vpninfo->vpn_netmask = "255.255.255.255";
245 if (strcmp(old_addr, vpninfo->vpn_addr)) {
246 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IP address (%s != %s)\n",
247 vpninfo->vpn_addr, old_addr);
252 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
253 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different netmask (%s != %s)\n",
254 vpninfo->vpn_netmask, old_netmask);
259 while (old_dtls_opts) {
260 struct vpn_option *tmp = old_dtls_opts;
261 old_dtls_opts = old_dtls_opts->next;
266 while (old_cstp_opts) {
267 struct vpn_option *tmp = old_cstp_opts;
268 old_cstp_opts = old_cstp_opts->next;
273 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
274 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
276 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
277 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);
279 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
280 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
281 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
283 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
284 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
286 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
291 int make_cstp_connection(struct openconnect_info *vpninfo)
293 if (!vpninfo->https_ssl && openconnect_open_https(vpninfo))
296 if (vpninfo->deflate) {
297 vpninfo->deflate_adler32 = 1;
298 vpninfo->inflate_adler32 = 1;
300 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
301 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
302 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
303 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
304 vpninfo->deflate = 0;
307 if (!vpninfo->deflate_pkt) {
308 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
309 if (!vpninfo->deflate_pkt) {
310 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
311 vpninfo->deflate = 0;
313 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
314 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
315 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
319 if (start_cstp_connection(vpninfo))
326 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
328 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
336 vpninfo->inflate_strm.next_in = buf;
337 vpninfo->inflate_strm.avail_in = len - 4;
339 vpninfo->inflate_strm.next_out = new->data;
340 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
341 vpninfo->inflate_strm.total_out = 0;
343 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
344 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
349 new->len = vpninfo->inflate_strm.total_out;
351 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
352 new->data, new->len);
354 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
355 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
358 vpninfo->progress(vpninfo, PRG_TRACE,
359 "Received compressed data packet of %ld bytes\n",
360 vpninfo->inflate_strm.total_out);
362 queue_packet(&vpninfo->incoming_queue, new);
366 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
368 unsigned char buf[16384];
372 /* FIXME: The poll() handling here is fairly simplistic. Actually,
373 if the SSL connection stalls it could return a WANT_WRITE error
374 on _either_ of the SSL_read() or SSL_write() calls. In that case,
375 we should probably remove POLLIN from the events we're looking for,
376 and add POLLOUT. As it is, though, it'll just chew CPU time in that
377 fairly unlikely situation, until the write backlog clears. */
378 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
381 if (buf[0] != 'S' || buf[1] != 'T' ||
382 buf[2] != 'F' || buf[3] != 1 || buf[7])
385 payload_len = (buf[4] << 8) + buf[5];
386 if (len != 8 + payload_len) {
387 vpninfo->progress(vpninfo, PRG_ERR,
388 "Unexpected packet length. SSL_read returned %d but packet is\n",
390 vpninfo->progress(vpninfo, PRG_ERR,
391 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
392 buf[0], buf[1], buf[2], buf[3],
393 buf[4], buf[5], buf[6], buf[7]);
396 vpninfo->ssl_times.last_rx = time(NULL);
399 vpninfo->progress(vpninfo, PRG_TRACE,
400 "Got CSTP DPD request\n");
401 vpninfo->owe_ssl_dpd_response = 1;
404 case AC_PKT_DPD_RESP:
405 vpninfo->progress(vpninfo, PRG_TRACE,
406 "Got CSTP DPD response\n");
409 case AC_PKT_KEEPALIVE:
410 vpninfo->progress(vpninfo, PRG_TRACE,
411 "Got CSTP Keepalive\n");
415 vpninfo->progress(vpninfo, PRG_TRACE,
416 "Received uncompressed data packet of %d bytes\n",
418 queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
423 case AC_PKT_DISCONN: {
425 for (i = 0; i < payload_len; i++) {
426 if (!isprint(buf[payload_len + 8 + i]))
427 buf[payload_len + 8 + i] = '.';
429 buf[payload_len + 8] = 0;
430 vpninfo->progress(vpninfo, PRG_ERR,
431 "Received server disconnect: '%s'\n", buf + 8);
432 vpninfo->quit_reason = "Server request";
435 case AC_PKT_COMPRESSED:
436 if (!vpninfo->deflate) {
437 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
440 inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
444 case AC_PKT_TERM_SERVER:
445 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
446 vpninfo->quit_reason = "Server request";
451 vpninfo->progress(vpninfo, PRG_ERR,
452 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
453 buf[0], buf[1], buf[2], buf[3],
454 buf[4], buf[5], buf[6], buf[7]);
455 vpninfo->quit_reason = "Unknown packet received";
460 /* If SSL_write() fails we are expected to try again. With exactly
461 the same data, at exactly the same location. So we keep the
462 packet we had before.... */
463 if (vpninfo->current_ssl_pkt) {
465 vpninfo->ssl_times.last_tx = time(NULL);
466 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
467 ret = SSL_write(vpninfo->https_ssl,
468 vpninfo->current_ssl_pkt->hdr,
469 vpninfo->current_ssl_pkt->len + 8);
471 ret = SSL_get_error(vpninfo->https_ssl, ret);
473 case SSL_ERROR_WANT_WRITE:
474 /* Waiting for the socket to become writable -- it's
475 probably stalled, and/or the buffers are full */
476 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
478 case SSL_ERROR_WANT_READ:
479 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
483 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
484 ERR_print_errors_fp(stderr);
485 vpninfo->quit_reason = "SSL write error";
489 if (ret != vpninfo->current_ssl_pkt->len + 8) {
490 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
491 vpninfo->current_ssl_pkt->len + 8, ret);
492 vpninfo->quit_reason = "Internal error";
495 /* Don't free the 'special' packets */
496 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
497 vpninfo->current_ssl_pkt != &dpd_pkt &&
498 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
499 vpninfo->current_ssl_pkt != &keepalive_pkt)
500 free(vpninfo->current_ssl_pkt);
502 vpninfo->current_ssl_pkt = NULL;
505 if (vpninfo->owe_ssl_dpd_response) {
506 vpninfo->owe_ssl_dpd_response = 0;
507 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
508 goto handle_outgoing;
511 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
513 /* Not that this will ever happen; we don't even process
514 the setting when we're asked for it. */
515 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
516 time(&vpninfo->ssl_times.last_rekey);
522 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
523 openconnect_close_https(vpninfo);
525 /* It's already deflated in the old stream. Extremely
526 non-trivial to reconstitute it; just throw it away */
527 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
528 vpninfo->current_ssl_pkt = NULL;
530 if (make_cstp_connection(vpninfo)) {
531 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
532 vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
535 /* I think we can leave DTLS to its own devices; when we reconnect
536 with the same master secret, we do seem to get the same sessid */
540 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
542 vpninfo->current_ssl_pkt = &dpd_pkt;
543 goto handle_outgoing;
546 /* No need to send an explicit keepalive
547 if we have real data to send */
548 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
551 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
553 vpninfo->current_ssl_pkt = &keepalive_pkt;
554 goto handle_outgoing;
560 /* Service outgoing packet queue, if no DTLS */
561 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
562 struct pkt *this = vpninfo->outgoing_queue;
563 vpninfo->outgoing_queue = this->next;
564 vpninfo->outgoing_qlen--;
566 if (vpninfo->deflate) {
567 unsigned char *adler;
570 vpninfo->deflate_strm.next_in = this->data;
571 vpninfo->deflate_strm.avail_in = this->len;
572 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
573 vpninfo->deflate_strm.avail_out = 2040;
574 vpninfo->deflate_strm.total_out = 0;
576 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
578 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
582 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
583 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
585 /* Add ongoing adler32 to tail of compressed packet */
586 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
587 this->data, this->len);
589 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
590 *(adler++) = vpninfo->deflate_adler32 >> 24;
591 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
592 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
593 *(adler) = vpninfo->deflate_adler32 & 0xff;
595 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
597 vpninfo->progress(vpninfo, PRG_TRACE,
598 "Sending compressed data packet of %d bytes\n",
601 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
604 memcpy(this->hdr, data_hdr, 8);
605 this->hdr[4] = this->len >> 8;
606 this->hdr[5] = this->len & 0xff;
608 vpninfo->progress(vpninfo, PRG_TRACE,
609 "Sending uncompressed data packet of %d bytes\n",
612 vpninfo->current_ssl_pkt = this;
614 goto handle_outgoing;
617 /* Work is not done if we just got rid of packets off the queue */
621 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
623 unsigned char *bye_pkt;
624 int reason_len = strlen(reason);
625 bye_pkt = malloc(reason_len + 8);
629 memcpy(bye_pkt, data_hdr, 8);
630 memcpy(bye_pkt + 8, reason, strlen(reason));
632 bye_pkt[4] = reason_len >> 8;
633 bye_pkt[5] = reason_len & 0xff;
634 bye_pkt[6] = AC_PKT_DISCONN;
636 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
639 vpninfo->progress(vpninfo, PRG_INFO,
640 "Send BYE packet: %s\n", reason);