After DPD, keep retrying to connect for longer.
[platform/upstream/openconnect.git] / cstp.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008 Intel Corporation.
5  *
6  * Author: David Woodhouse <dwmw2@infradead.org>
7  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24 #include <netdb.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <time.h>
28 #include <ctype.h>
29
30 #include <openssl/ssl.h>
31 #include <openssl/err.h>
32
33 #include "openconnect.h"
34
35 /*
36  * Data packets are encapsulated in the SSL stream as follows:
37  * 
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)
41  * 0008: data payload
42  */
43
44 static char data_hdr[8] = {
45         'S', 'T', 'F', 1,
46         0, 0,           /* Length */
47         AC_PKT_DATA,    /* Type */
48         0               /* Unknown */
49 };
50
51 static struct pkt keepalive_pkt = {
52         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
53 };
54
55 static struct pkt dpd_pkt = {
56         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
57 };
58
59 static struct pkt dpd_resp_pkt = {
60         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
61 };
62
63
64 static int start_cstp_connection(struct openconnect_info *vpninfo)
65 {
66         char buf[65536];
67         int i;
68         int retried = 0;
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;
76
77         /* Clear old options which will be overwritten */
78         vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
79         vpninfo->cstp_options = vpninfo->dtls_options = NULL;
80         for (i=0; i<3; i++)
81                 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
82
83         for (inc = vpninfo->split_includes; inc; inc = inc->next) {
84                 struct split_include *next = inc->next;
85                 free(inc);
86                 inc = next;
87         }
88  retry:
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);
95         if (vpninfo->deflate)
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");
105
106         if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
107                 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
108                 if (!retried) {
109                         retried = 1;
110                         openconnect_close_https(vpninfo);
111                 
112                         if (openconnect_open_https(vpninfo)) {
113                                 vpninfo->progress(vpninfo, PRG_ERR,
114                                                   "Failed to open HTTPS connection to %s\n",
115                                                   vpninfo->hostname);
116                                 exit(1);
117                         }
118                         goto retry;
119                 }
120                 return -EINVAL;
121         }
122
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)) {
129                                         reason = buf + 10;
130                                         break;
131                                 }
132                         }
133                         vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
134                                           reason);
135                         return -EINVAL;
136                 }
137                 vpninfo->progress(vpninfo, PRG_ERR, 
138                                   "Got inappropriate HTTP CONNECT response: %s\n",
139                                   buf);
140                 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
141                         exit(2);
142                 return -EINVAL;
143         }
144
145         vpninfo->progress(vpninfo, PRG_INFO,
146                           "Got CONNECT response: %s\n", buf);
147
148         /* We may have advertised it, but we only do it if the server agrees */
149         vpninfo->deflate = 0;
150
151         while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
152                 struct vpn_option *new_option;
153                 char *colon = strchr(buf, ':');
154                 if (!colon)
155                         continue;
156
157                 *colon = 0;
158                 colon++;
159                 if (*colon == ' ')
160                         colon++;
161
162                 if (strncmp(buf, "X-DTLS-", 7) &&
163                     strncmp(buf, "X-CSTP-", 7))
164                         continue;
165
166                 new_option = malloc(sizeof(*new_option));
167                 if (!new_option) {
168                         vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
169                         return -ENOMEM;
170                 }
171                 new_option->option = strdup(buf);
172                 new_option->value = strdup(colon);
173                 new_option->next = NULL;
174
175                 if (!new_option->option || !new_option->value) {
176                         vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
177                         return -ENOMEM;
178                 }
179
180                 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
181
182                 if (!strncmp(buf, "X-DTLS-", 7)) {
183                         *next_dtls_option = new_option;
184                         next_dtls_option = &new_option->next;
185                         continue;
186                 }
187                 /* CSTP options... */
188                 *next_cstp_option = new_option;
189                 next_cstp_option = &new_option->next;
190
191
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;
199                         else {
200                                 vpninfo->progress(vpninfo, PRG_ERR, 
201                                         "Unknown CSTP-Content-Encoding %s\n",
202                                         colon);
203                                 return -EINVAL;
204                         }
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")) {
212                         int j;
213                         for (j = 0; j < 3; j++) {
214                                 if (!vpninfo->vpn_dns[j]) {
215                                         vpninfo->vpn_dns[j] = new_option->value;
216                                         break;
217                                 }
218                         }
219                 } else if (!strcmp(buf + 7, "NBNS")) {
220                         int j;
221                         for (j = 0; j < 3; j++) {
222                                 if (!vpninfo->vpn_nbns[j]) {
223                                         vpninfo->vpn_nbns[j] = new_option->value;
224                                         break;
225                                 }
226                         }
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));
231                         if (!inc)
232                                 continue;
233                         inc->route = new_option->value;
234                         inc->next = vpninfo->split_includes;
235                         vpninfo->split_includes = inc;
236                 }
237         }
238
239         if (!vpninfo->vpn_addr) {
240                 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
241                 return -EINVAL;
242         }
243         if (!vpninfo->vpn_netmask)
244                 vpninfo->vpn_netmask = "255.255.255.255";
245         if (old_addr) {
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);
249                         return -EINVAL;
250                 }
251         }
252         if (old_netmask) {
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);
256                         return -EINVAL;
257                 }
258         }
259
260         while (old_dtls_opts) {
261                 struct vpn_option *tmp = old_dtls_opts;
262                 old_dtls_opts = old_dtls_opts->next;
263                 free(tmp->value);
264                 free(tmp->option);
265                 free(tmp);
266         }
267         while (old_cstp_opts) {
268                 struct vpn_option *tmp = old_cstp_opts;
269                 old_cstp_opts = old_cstp_opts->next;
270                 free(tmp->value);
271                 free(tmp->option);
272                 free(tmp);
273         }
274         vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
275                           vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
276
277         BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
278         BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);
279
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;
283
284         FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
285         FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
286
287         vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
288         return 0;
289 }
290
291
292 int make_cstp_connection(struct openconnect_info *vpninfo)
293 {
294         int ret;
295
296         if (!vpninfo->https_ssl && (ret=openconnect_open_https(vpninfo)))
297                 return ret;
298
299         if (vpninfo->deflate) {
300                 vpninfo->deflate_adler32 = 1;
301                 vpninfo->inflate_adler32 = 1;
302
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;
308                 }
309
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;
315                         }
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;
319                 }
320         }
321
322         return start_cstp_connection(vpninfo);
323 }
324
325 static int cstp_reconnect(struct openconnect_info *vpninfo)
326 {
327         int retries, nr_retries, ret;
328         
329         nr_retries = vpninfo->reconnect_timeout / vpninfo->reconnect_interval;
330
331         while ((ret = make_cstp_connection(vpninfo))) {
332                 retries++;
333                 if (retries >= nr_retries)
334                         return ret;
335                 sleep(vpninfo->reconnect_interval);
336         }
337         return 0;
338 }
339
340 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
341 {
342         struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
343
344         if (!new)
345                 return -ENOMEM;
346
347         new->type = type;
348         new->next = NULL;
349
350         vpninfo->inflate_strm.next_in = buf;
351         vpninfo->inflate_strm.avail_in = len - 4;
352
353         vpninfo->inflate_strm.next_out = new->data;
354         vpninfo->inflate_strm.avail_out = vpninfo->mtu;
355         vpninfo->inflate_strm.total_out = 0;
356
357         if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
358                 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
359                 free(new);
360                 return -EINVAL;
361         }
362
363         new->len = vpninfo->inflate_strm.total_out;
364
365         vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
366                                            new->data, new->len);
367
368         if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
369                 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
370         }
371
372         vpninfo->progress(vpninfo, PRG_TRACE,
373                           "Received compressed data packet of %ld bytes\n",
374                           vpninfo->inflate_strm.total_out);
375
376         queue_packet(&vpninfo->incoming_queue, new);
377         return 0;
378 }
379
380 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
381 {
382         unsigned char buf[16384];
383         int len, ret;
384         int work_done = 0;
385
386         /* FIXME: The poll() handling here is fairly simplistic. Actually,
387            if the SSL connection stalls it could return a WANT_WRITE error
388            on _either_ of the SSL_read() or SSL_write() calls. In that case,
389            we should probably remove POLLIN from the events we're looking for,
390            and add POLLOUT. As it is, though, it'll just chew CPU time in that
391            fairly unlikely situation, until the write backlog clears. */
392         while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
393                 int payload_len;
394
395                 if (buf[0] != 'S' || buf[1] != 'T' ||
396                     buf[2] != 'F' || buf[3] != 1 || buf[7])
397                         goto unknown_pkt;
398
399                 payload_len = (buf[4] << 8) + buf[5];
400                 if (len != 8 + payload_len) {
401                         vpninfo->progress(vpninfo, PRG_ERR,
402                                           "Unexpected packet length. SSL_read returned %d but packet is\n",
403                                           len);
404                         vpninfo->progress(vpninfo, PRG_ERR,
405                                           "%02x %02x %02x %02x %02x %02x %02x %02x\n",
406                                           buf[0], buf[1], buf[2], buf[3],
407                                           buf[4], buf[5], buf[6], buf[7]);
408                         continue;
409                 }
410                 vpninfo->ssl_times.last_rx = time(NULL);
411                 switch(buf[6]) {
412                 case AC_PKT_DPD_OUT:
413                         vpninfo->progress(vpninfo, PRG_TRACE,
414                                           "Got CSTP DPD request\n");
415                         vpninfo->owe_ssl_dpd_response = 1;
416                         continue;
417
418                 case AC_PKT_DPD_RESP:
419                         vpninfo->progress(vpninfo, PRG_TRACE,
420                                           "Got CSTP DPD response\n");
421                         continue;
422
423                 case AC_PKT_KEEPALIVE:
424                         vpninfo->progress(vpninfo, PRG_TRACE,
425                                           "Got CSTP Keepalive\n");
426                         continue;
427
428                 case AC_PKT_DATA:
429                         vpninfo->progress(vpninfo, PRG_TRACE,
430                                           "Received uncompressed data packet of %d bytes\n",
431                                           payload_len);
432                         queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
433                                          payload_len);
434                         work_done = 1;
435                         continue;
436
437                 case AC_PKT_DISCONN: {
438                         int i;
439                         for (i = 0; i < payload_len; i++) {
440                                 if (!isprint(buf[payload_len + 8 + i]))
441                                         buf[payload_len + 8 + i] = '.';
442                         }
443                         buf[payload_len + 8] = 0;
444                         vpninfo->progress(vpninfo, PRG_ERR,
445                                           "Received server disconnect: '%s'\n", buf + 8);
446                         vpninfo->quit_reason = "Server request";
447                         return 1;
448                 }
449                 case AC_PKT_COMPRESSED:
450                         if (!vpninfo->deflate) {
451                                 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
452                                 goto unknown_pkt;
453                         }
454                         inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
455                         work_done = 1;
456                         continue;
457
458                 case AC_PKT_TERM_SERVER:
459                         vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
460                         vpninfo->quit_reason = "Server request";
461                         return 1;
462                 }
463
464         unknown_pkt:
465                 vpninfo->progress(vpninfo, PRG_ERR,
466                                   "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
467                                   buf[0], buf[1], buf[2], buf[3],
468                                   buf[4], buf[5], buf[6], buf[7]);
469                 vpninfo->quit_reason = "Unknown packet received";
470                 return 1;
471         }
472
473
474         /* If SSL_write() fails we are expected to try again. With exactly
475            the same data, at exactly the same location. So we keep the 
476            packet we had before.... */
477         if (vpninfo->current_ssl_pkt) {
478         handle_outgoing:
479                 vpninfo->ssl_times.last_tx = time(NULL);
480                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
481                 ret = SSL_write(vpninfo->https_ssl,
482                                 vpninfo->current_ssl_pkt->hdr,
483                                 vpninfo->current_ssl_pkt->len + 8);
484                 if (ret <= 0) {
485                         ret = SSL_get_error(vpninfo->https_ssl, ret);
486                         switch (ret) {
487                         case SSL_ERROR_WANT_WRITE:
488                                 /* Waiting for the socket to become writable -- it's
489                                    probably stalled, and/or the buffers are full */
490                                 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
491
492                         case SSL_ERROR_WANT_READ:
493                                 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
494                                         goto peer_dead;
495                                 return work_done;
496                         default:
497                                 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
498                                 ERR_print_errors_fp(stderr);
499                                 vpninfo->quit_reason = "SSL write error";
500                                 return 1;
501                         }
502                 }
503                 if (ret != vpninfo->current_ssl_pkt->len + 8) {
504                         vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
505                                 vpninfo->current_ssl_pkt->len + 8, ret);
506                         vpninfo->quit_reason = "Internal error";
507                         return 1;
508                 }
509                 /* Don't free the 'special' packets */
510                 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
511                     vpninfo->current_ssl_pkt != &dpd_pkt &&
512                     vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
513                     vpninfo->current_ssl_pkt != &keepalive_pkt)
514                         free(vpninfo->current_ssl_pkt);
515
516                 vpninfo->current_ssl_pkt = NULL;
517         }
518
519         if (vpninfo->owe_ssl_dpd_response) {
520                 vpninfo->owe_ssl_dpd_response = 0;
521                 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
522                 goto handle_outgoing;
523         }
524
525         switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
526         case KA_REKEY:
527                 /* Not that this will ever happen; we don't even process
528                    the setting when we're asked for it. */
529                 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
530                 time(&vpninfo->ssl_times.last_rekey);
531                 work_done = 1;
532                 break;
533
534         case KA_DPD_DEAD:
535         peer_dead:
536                 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
537                 openconnect_close_https(vpninfo);
538
539                 /* It's already deflated in the old stream. Extremely 
540                    non-trivial to reconstitute it; just throw it away */
541                 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
542                         vpninfo->current_ssl_pkt = NULL;
543
544                 if (cstp_reconnect(vpninfo)) {
545                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
546                         vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
547                         return 1;
548                 }
549                 /* I think we can leave DTLS to its own devices; when we reconnect
550                    with the same master secret, we do seem to get the same sessid */
551                 return 1;
552
553         case KA_DPD:
554                 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
555
556                 vpninfo->current_ssl_pkt = &dpd_pkt;
557                 goto handle_outgoing;
558
559         case KA_KEEPALIVE:
560                 /* No need to send an explicit keepalive
561                    if we have real data to send */
562                 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
563                         break;
564
565                 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
566
567                 vpninfo->current_ssl_pkt = &keepalive_pkt;
568                 goto handle_outgoing;
569
570         case KA_NONE:
571                 ;
572         }
573
574         /* Service outgoing packet queue, if no DTLS */
575         while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
576                 struct pkt *this = vpninfo->outgoing_queue;
577                 vpninfo->outgoing_queue = this->next;
578                 vpninfo->outgoing_qlen--;
579
580                 if (vpninfo->deflate) {
581                         unsigned char *adler;
582                         int ret;
583
584                         vpninfo->deflate_strm.next_in = this->data;
585                         vpninfo->deflate_strm.avail_in = this->len;
586                         vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
587                         vpninfo->deflate_strm.avail_out = 2040;
588                         vpninfo->deflate_strm.total_out = 0;
589
590                         ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
591                         if (ret) {
592                                 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
593                                 goto uncompr;
594                         }
595
596                         vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
597                         vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
598
599                         /* Add ongoing adler32 to tail of compressed packet */
600                         vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
601                                                            this->data, this->len);
602
603                         adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
604                         *(adler++) =  vpninfo->deflate_adler32 >> 24;
605                         *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
606                         *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
607                         *(adler)   =  vpninfo->deflate_adler32 & 0xff;
608
609                         vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
610
611                         vpninfo->progress(vpninfo, PRG_TRACE,
612                                           "Sending compressed data packet of %d bytes\n",
613                                           this->len);
614
615                         vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
616                 } else {
617                 uncompr:
618                         memcpy(this->hdr, data_hdr, 8);
619                         this->hdr[4] = this->len >> 8;
620                         this->hdr[5] = this->len & 0xff;
621
622                         vpninfo->progress(vpninfo, PRG_TRACE,
623                                           "Sending uncompressed data packet of %d bytes\n",
624                                           this->len);
625
626                         vpninfo->current_ssl_pkt = this;
627                 }
628                 goto handle_outgoing;
629         }
630
631         /* Work is not done if we just got rid of packets off the queue */
632         return work_done;
633 }
634
635 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
636 {
637         unsigned char *bye_pkt;
638         int reason_len = strlen(reason);
639         bye_pkt = malloc(reason_len + 8);
640         if (!bye_pkt)
641                 return -ENOMEM;
642         
643         memcpy(bye_pkt, data_hdr, 8);
644         memcpy(bye_pkt + 8, reason, strlen(reason));
645
646         bye_pkt[4] = reason_len >> 8;
647         bye_pkt[5] = reason_len & 0xff;
648         bye_pkt[6] = AC_PKT_DISCONN;
649
650         SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
651         free(bye_pkt);
652
653         vpninfo->progress(vpninfo, PRG_INFO,
654                           "Send BYE packet: %s\n", reason);
655
656         return 0;
657 }