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;
81 vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
84 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
86 for (inc = vpninfo->split_includes; inc; ) {
87 struct split_include *next = inc->next;
91 for (inc = vpninfo->split_excludes; inc; ) {
92 struct split_include *next = inc->next;
96 vpninfo->split_includes = vpninfo->split_excludes = NULL;
98 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
99 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
100 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
101 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
102 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
103 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
104 if (vpninfo->deflate)
105 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
106 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
107 /* To enable IPv6, send 'IPv6,IPv4'.
108 We don't know how most of that works yet though. */
109 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
110 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
111 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
112 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
113 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
114 vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
116 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
117 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
120 openconnect_close_https(vpninfo);
122 if (openconnect_open_https(vpninfo)) {
123 vpninfo->progress(vpninfo, PRG_ERR,
124 "Failed to open HTTPS connection to %s\n",
133 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
134 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
135 /* "Service Unavailable. Why? */
136 char *reason = "<unknown>";
137 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
138 if (!strncmp(buf, "X-Reason: ", 10)) {
143 vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
147 vpninfo->progress(vpninfo, PRG_ERR,
148 "Got inappropriate HTTP CONNECT response: %s\n",
150 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
155 vpninfo->progress(vpninfo, PRG_INFO,
156 "Got CONNECT response: %s\n", buf);
158 /* We may have advertised it, but we only do it if the server agrees */
159 vpninfo->deflate = 0;
161 while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
162 struct vpn_option *new_option;
163 char *colon = strchr(buf, ':');
172 if (strncmp(buf, "X-DTLS-", 7) &&
173 strncmp(buf, "X-CSTP-", 7))
176 new_option = malloc(sizeof(*new_option));
178 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
181 new_option->option = strdup(buf);
182 new_option->value = strdup(colon);
183 new_option->next = NULL;
185 if (!new_option->option || !new_option->value) {
186 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
190 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
192 if (!strncmp(buf, "X-DTLS-", 7)) {
193 *next_dtls_option = new_option;
194 next_dtls_option = &new_option->next;
197 /* CSTP options... */
198 *next_cstp_option = new_option;
199 next_cstp_option = &new_option->next;
202 if (!strcmp(buf + 7, "Keepalive")) {
203 vpninfo->ssl_times.keepalive = atol(colon);
204 } else if (!strcmp(buf + 7, "DPD")) {
205 vpninfo->ssl_times.dpd = atol(colon);
206 } else if (!strcmp(buf + 7, "Content-Encoding")) {
207 if (!strcmp(colon, "deflate"))
208 vpninfo->deflate = 1;
210 vpninfo->progress(vpninfo, PRG_ERR,
211 "Unknown CSTP-Content-Encoding %s\n",
215 } else if (!strcmp(buf + 7, "MTU")) {
216 vpninfo->mtu = atol(colon);
217 } else if (!strcmp(buf + 7, "Address")) {
218 vpninfo->vpn_addr = new_option->value;
219 } else if (!strcmp(buf + 7, "Netmask")) {
220 vpninfo->vpn_netmask = new_option->value;
221 } else if (!strcmp(buf + 7, "DNS")) {
223 for (j = 0; j < 3; j++) {
224 if (!vpninfo->vpn_dns[j]) {
225 vpninfo->vpn_dns[j] = new_option->value;
229 } else if (!strcmp(buf + 7, "NBNS")) {
231 for (j = 0; j < 3; j++) {
232 if (!vpninfo->vpn_nbns[j]) {
233 vpninfo->vpn_nbns[j] = new_option->value;
237 } else if (!strcmp(buf + 7, "Default-Domain")) {
238 vpninfo->vpn_domain = new_option->value;
239 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
240 vpninfo->vpn_proxy_pac = new_option->value;
241 } else if (!strcmp(buf + 7, "Split-Include")) {
242 struct split_include *inc = malloc(sizeof(*inc));
245 inc->route = new_option->value;
246 inc->next = vpninfo->split_includes;
247 vpninfo->split_includes = inc;
248 } else if (!strcmp(buf + 7, "Split-Exclude")) {
249 struct split_include *exc = malloc(sizeof(*exc));
252 exc->route = new_option->value;
253 exc->next = vpninfo->split_excludes;
254 vpninfo->split_excludes = exc;
258 if (!vpninfo->vpn_addr) {
259 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
262 if (!vpninfo->vpn_netmask)
263 vpninfo->vpn_netmask = "255.255.255.255";
265 if (strcmp(old_addr, vpninfo->vpn_addr)) {
266 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IP address (%s != %s)\n",
267 vpninfo->vpn_addr, old_addr);
272 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
273 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different netmask (%s != %s)\n",
274 vpninfo->vpn_netmask, old_netmask);
279 free(vpninfo->dtls_cipher);
280 vpninfo->dtls_cipher = NULL;
282 while (old_dtls_opts) {
283 struct vpn_option *tmp = old_dtls_opts;
284 old_dtls_opts = old_dtls_opts->next;
289 while (old_cstp_opts) {
290 struct vpn_option *tmp = old_cstp_opts;
291 old_cstp_opts = old_cstp_opts->next;
296 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
297 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
299 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
300 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
302 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
303 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
304 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
306 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
307 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
309 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
314 int make_cstp_connection(struct openconnect_info *vpninfo)
318 if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
321 if (vpninfo->deflate) {
322 vpninfo->deflate_adler32 = 1;
323 vpninfo->inflate_adler32 = 1;
325 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
326 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
327 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
328 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
329 vpninfo->deflate = 0;
332 if (!vpninfo->deflate_pkt) {
333 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
334 if (!vpninfo->deflate_pkt) {
335 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
336 vpninfo->deflate = 0;
338 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
339 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
340 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
344 return start_cstp_connection(vpninfo);
347 static int cstp_reconnect(struct openconnect_info *vpninfo)
353 timeout = vpninfo->reconnect_timeout;
354 interval = vpninfo->reconnect_interval;
356 while ((ret = make_cstp_connection(vpninfo))) {
359 vpninfo->progress(vpninfo, PRG_INFO,
360 "sleep %ds, remaining timeout %ds\n",
366 interval += vpninfo->reconnect_interval;
367 if (interval > RECONNECT_INTERVAL_MAX)
368 interval = RECONNECT_INTERVAL_MAX;
373 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
375 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
383 vpninfo->inflate_strm.next_in = buf;
384 vpninfo->inflate_strm.avail_in = len - 4;
386 vpninfo->inflate_strm.next_out = new->data;
387 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
388 vpninfo->inflate_strm.total_out = 0;
390 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
391 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
396 new->len = vpninfo->inflate_strm.total_out;
398 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
399 new->data, new->len);
401 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
402 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
405 vpninfo->progress(vpninfo, PRG_TRACE,
406 "Received compressed data packet of %ld bytes\n",
407 vpninfo->inflate_strm.total_out);
409 queue_packet(&vpninfo->incoming_queue, new);
413 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
415 unsigned char buf[16384];
419 /* FIXME: The poll() handling here is fairly simplistic. Actually,
420 if the SSL connection stalls it could return a WANT_WRITE error
421 on _either_ of the SSL_read() or SSL_write() calls. In that case,
422 we should probably remove POLLIN from the events we're looking for,
423 and add POLLOUT. As it is, though, it'll just chew CPU time in that
424 fairly unlikely situation, until the write backlog clears. */
425 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
428 if (buf[0] != 'S' || buf[1] != 'T' ||
429 buf[2] != 'F' || buf[3] != 1 || buf[7])
432 payload_len = (buf[4] << 8) + buf[5];
433 if (len != 8 + payload_len) {
434 vpninfo->progress(vpninfo, PRG_ERR,
435 "Unexpected packet length. SSL_read returned %d but packet is\n",
437 vpninfo->progress(vpninfo, PRG_ERR,
438 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
439 buf[0], buf[1], buf[2], buf[3],
440 buf[4], buf[5], buf[6], buf[7]);
443 vpninfo->ssl_times.last_rx = time(NULL);
446 vpninfo->progress(vpninfo, PRG_TRACE,
447 "Got CSTP DPD request\n");
448 vpninfo->owe_ssl_dpd_response = 1;
451 case AC_PKT_DPD_RESP:
452 vpninfo->progress(vpninfo, PRG_TRACE,
453 "Got CSTP DPD response\n");
456 case AC_PKT_KEEPALIVE:
457 vpninfo->progress(vpninfo, PRG_TRACE,
458 "Got CSTP Keepalive\n");
462 vpninfo->progress(vpninfo, PRG_TRACE,
463 "Received uncompressed data packet of %d bytes\n",
465 queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
470 case AC_PKT_DISCONN: {
472 for (i = 0; i < payload_len; i++) {
473 if (!isprint(buf[payload_len + 8 + i]))
474 buf[payload_len + 8 + i] = '.';
476 buf[payload_len + 8] = 0;
477 vpninfo->progress(vpninfo, PRG_ERR,
478 "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
479 vpninfo->quit_reason = "Server request";
482 case AC_PKT_COMPRESSED:
483 if (!vpninfo->deflate) {
484 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
487 inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
491 case AC_PKT_TERM_SERVER:
492 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
493 vpninfo->quit_reason = "Server request";
498 vpninfo->progress(vpninfo, PRG_ERR,
499 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
500 buf[0], buf[1], buf[2], buf[3],
501 buf[4], buf[5], buf[6], buf[7]);
502 vpninfo->quit_reason = "Unknown packet received";
507 /* If SSL_write() fails we are expected to try again. With exactly
508 the same data, at exactly the same location. So we keep the
509 packet we had before.... */
510 if (vpninfo->current_ssl_pkt) {
512 vpninfo->ssl_times.last_tx = time(NULL);
513 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
514 ret = SSL_write(vpninfo->https_ssl,
515 vpninfo->current_ssl_pkt->hdr,
516 vpninfo->current_ssl_pkt->len + 8);
518 ret = SSL_get_error(vpninfo->https_ssl, ret);
520 case SSL_ERROR_WANT_WRITE:
521 /* Waiting for the socket to become writable -- it's
522 probably stalled, and/or the buffers are full */
523 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
525 case SSL_ERROR_WANT_READ:
526 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
530 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
531 ERR_print_errors_fp(stderr);
532 vpninfo->quit_reason = "SSL write error";
536 if (ret != vpninfo->current_ssl_pkt->len + 8) {
537 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
538 vpninfo->current_ssl_pkt->len + 8, ret);
539 vpninfo->quit_reason = "Internal error";
542 /* Don't free the 'special' packets */
543 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
544 vpninfo->current_ssl_pkt != &dpd_pkt &&
545 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
546 vpninfo->current_ssl_pkt != &keepalive_pkt)
547 free(vpninfo->current_ssl_pkt);
549 vpninfo->current_ssl_pkt = NULL;
552 if (vpninfo->owe_ssl_dpd_response) {
553 vpninfo->owe_ssl_dpd_response = 0;
554 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
555 goto handle_outgoing;
558 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
560 /* Not that this will ever happen; we don't even process
561 the setting when we're asked for it. */
562 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
563 time(&vpninfo->ssl_times.last_rekey);
569 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
570 openconnect_close_https(vpninfo);
572 /* It's already deflated in the old stream. Extremely
573 non-trivial to reconstitute it; just throw it away */
574 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
575 vpninfo->current_ssl_pkt = NULL;
577 if (cstp_reconnect(vpninfo)) {
578 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
579 vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
582 /* I think we can leave DTLS to its own devices; when we reconnect
583 with the same master secret, we do seem to get the same sessid */
587 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
589 vpninfo->current_ssl_pkt = &dpd_pkt;
590 goto handle_outgoing;
593 /* No need to send an explicit keepalive
594 if we have real data to send */
595 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
598 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
600 vpninfo->current_ssl_pkt = &keepalive_pkt;
601 goto handle_outgoing;
607 /* Service outgoing packet queue, if no DTLS */
608 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
609 struct pkt *this = vpninfo->outgoing_queue;
610 vpninfo->outgoing_queue = this->next;
611 vpninfo->outgoing_qlen--;
613 if (vpninfo->deflate) {
614 unsigned char *adler;
617 vpninfo->deflate_strm.next_in = this->data;
618 vpninfo->deflate_strm.avail_in = this->len;
619 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
620 vpninfo->deflate_strm.avail_out = 2040;
621 vpninfo->deflate_strm.total_out = 0;
623 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
625 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
629 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
630 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
632 /* Add ongoing adler32 to tail of compressed packet */
633 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
634 this->data, this->len);
636 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
637 *(adler++) = vpninfo->deflate_adler32 >> 24;
638 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
639 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
640 *(adler) = vpninfo->deflate_adler32 & 0xff;
642 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
644 vpninfo->progress(vpninfo, PRG_TRACE,
645 "Sending compressed data packet of %d bytes\n",
648 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
651 memcpy(this->hdr, data_hdr, 8);
652 this->hdr[4] = this->len >> 8;
653 this->hdr[5] = this->len & 0xff;
655 vpninfo->progress(vpninfo, PRG_TRACE,
656 "Sending uncompressed data packet of %d bytes\n",
659 vpninfo->current_ssl_pkt = this;
661 goto handle_outgoing;
664 /* Work is not done if we just got rid of packets off the queue */
668 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
670 unsigned char *bye_pkt;
673 /* already lost connection? */
674 if (!vpninfo->https_ssl)
677 reason_len = strlen(reason);
678 bye_pkt = malloc(reason_len + 8);
682 memcpy(bye_pkt, data_hdr, 8);
683 memcpy(bye_pkt + 8, reason, reason_len);
685 bye_pkt[4] = reason_len >> 8;
686 bye_pkt[5] = reason_len & 0xff;
687 bye_pkt[6] = AC_PKT_DISCONN;
689 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
692 vpninfo->progress(vpninfo, PRG_INFO,
693 "Send BYE packet: %s\n", reason);