Enable IPv6
[platform/upstream/openconnect.git] / cstp.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008 Intel Corporation.
5  * Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
6  *
7  * Author: David Woodhouse <dwmw2@infradead.org>
8  *
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.
12  *
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.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to:
20  *
21  *   Free Software Foundation, Inc.
22  *   51 Franklin Street, Fifth Floor,
23  *   Boston, MA 02110-1301 USA
24  */
25 #include <netdb.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <arpa/inet.h>
32
33 #include <openssl/ssl.h>
34 #include <openssl/err.h>
35
36 #include "openconnect.h"
37
38 /*
39  * Data packets are encapsulated in the SSL stream as follows:
40  *
41  * 0000: Magic "STF\x1"
42  * 0004: Big-endian 16-bit length (not including 8-byte header)
43  * 0006: Byte packet type (see openconnect.h)
44  * 0008: data payload
45  */
46
47 static char data_hdr[8] = {
48         'S', 'T', 'F', 1,
49         0, 0,           /* Length */
50         AC_PKT_DATA,    /* Type */
51         0               /* Unknown */
52 };
53
54 static struct pkt keepalive_pkt = {
55         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
56 };
57
58 static struct pkt dpd_pkt = {
59         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
60 };
61
62 static struct pkt dpd_resp_pkt = {
63         .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
64 };
65
66
67 static int start_cstp_connection(struct openconnect_info *vpninfo)
68 {
69         char buf[65536];
70         int i;
71         int retried = 0;
72         struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
73         struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
74         struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
75         struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
76         const char *old_addr = vpninfo->vpn_addr;
77         const char *old_netmask = vpninfo->vpn_netmask;
78         const char *old_addr6 = vpninfo->vpn_addr6;
79         const char *old_netmask6 = vpninfo->vpn_netmask6;
80         struct split_include *inc;
81
82         /* Clear old options which will be overwritten */
83         vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
84         vpninfo->vpn_addr6 = vpninfo->vpn_netmask6 = NULL;
85         vpninfo->cstp_options = vpninfo->dtls_options = NULL;
86         vpninfo->vpn_domain = vpninfo->vpn_proxy_pac = NULL;
87
88         for (i=0; i<3; i++)
89                 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
90
91         for (inc = vpninfo->split_includes; inc; ) {
92                 struct split_include *next = inc->next;
93                 free(inc);
94                 inc = next;
95         }
96         for (inc = vpninfo->split_excludes; inc; ) {
97                 struct split_include *next = inc->next;
98                 free(inc);
99                 inc = next;
100         }
101         vpninfo->split_includes = vpninfo->split_excludes = NULL;
102  retry:
103         openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
104         openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
105         openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
106         openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
107         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
108         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
109         if (vpninfo->deflate)
110                 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
111         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
112         openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: %s\r\n",
113                                vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4");
114         openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
115         for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
116                 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
117         openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: %s\r\n\r\n",
118                                vpninfo->dtls_ciphers?:"AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA");
119
120         if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
121                 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
122                 if (!retried) {
123                         retried = 1;
124                         openconnect_close_https(vpninfo);
125
126                         if (openconnect_open_https(vpninfo)) {
127                                 vpninfo->progress(vpninfo, PRG_ERR,
128                                                   "Failed to open HTTPS connection to %s\n",
129                                                   vpninfo->hostname);
130                                 exit(1);
131                         }
132                         goto retry;
133                 }
134                 return -EINVAL;
135         }
136
137         if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
138                 if (!strncmp(buf, "HTTP/1.1 503 ", 13)) {
139                         /* "Service Unavailable. Why? */
140                         char *reason = "<unknown>";
141                         while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
142                                 if (!strncmp(buf, "X-Reason: ", 10)) {
143                                         reason = buf + 10;
144                                         break;
145                                 }
146                         }
147                         vpninfo->progress(vpninfo, PRG_ERR, "VPN service unavailable; reason: %s\n",
148                                           reason);
149                         return -EINVAL;
150                 }
151                 vpninfo->progress(vpninfo, PRG_ERR,
152                                   "Got inappropriate HTTP CONNECT response: %s\n",
153                                   buf);
154                 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
155                         exit(2);
156                 return -EINVAL;
157         }
158
159         vpninfo->progress(vpninfo, PRG_INFO,
160                           "Got CONNECT response: %s\n", buf);
161
162         /* We may have advertised it, but we only do it if the server agrees */
163         vpninfo->deflate = 0;
164
165         while ((i = openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
166                 struct vpn_option *new_option;
167                 char *colon = strchr(buf, ':');
168                 if (!colon)
169                         continue;
170
171                 *colon = 0;
172                 colon++;
173                 if (*colon == ' ')
174                         colon++;
175
176                 if (strncmp(buf, "X-DTLS-", 7) &&
177                     strncmp(buf, "X-CSTP-", 7))
178                         continue;
179
180                 new_option = malloc(sizeof(*new_option));
181                 if (!new_option) {
182                         vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
183                         return -ENOMEM;
184                 }
185                 new_option->option = strdup(buf);
186                 new_option->value = strdup(colon);
187                 new_option->next = NULL;
188
189                 if (!new_option->option || !new_option->value) {
190                         vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
191                         return -ENOMEM;
192                 }
193
194                 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
195
196                 if (!strncmp(buf, "X-DTLS-", 7)) {
197                         *next_dtls_option = new_option;
198                         next_dtls_option = &new_option->next;
199                         continue;
200                 }
201                 /* CSTP options... */
202                 *next_cstp_option = new_option;
203                 next_cstp_option = &new_option->next;
204
205
206                 if (!strcmp(buf + 7, "Keepalive")) {
207                         vpninfo->ssl_times.keepalive = atol(colon);
208                 } else if (!strcmp(buf + 7, "DPD")) {
209                         vpninfo->ssl_times.dpd = atol(colon);
210                 } else if (!strcmp(buf + 7, "Content-Encoding")) {
211                         if (!strcmp(colon, "deflate"))
212                                 vpninfo->deflate = 1;
213                         else {
214                                 vpninfo->progress(vpninfo, PRG_ERR,
215                                         "Unknown CSTP-Content-Encoding %s\n",
216                                         colon);
217                                 return -EINVAL;
218                         }
219                 } else if (!strcmp(buf + 7, "MTU")) {
220                         vpninfo->mtu = atol(colon);
221                 } else if (!strcmp(buf + 7, "Address")) {
222                         if (strchr(new_option->value, ':'))
223                                 vpninfo->vpn_addr6 = new_option->value;
224                         else
225                                 vpninfo->vpn_addr = new_option->value;
226                 } else if (!strcmp(buf + 7, "Netmask")) {
227                         if (strchr(new_option->value, ':'))
228                                 vpninfo->vpn_netmask6 = new_option->value;
229                         else
230                                 vpninfo->vpn_netmask = new_option->value;
231                 } else if (!strcmp(buf + 7, "DNS")) {
232                         int j;
233                         for (j = 0; j < 3; j++) {
234                                 if (!vpninfo->vpn_dns[j]) {
235                                         vpninfo->vpn_dns[j] = new_option->value;
236                                         break;
237                                 }
238                         }
239                 } else if (!strcmp(buf + 7, "NBNS")) {
240                         int j;
241                         for (j = 0; j < 3; j++) {
242                                 if (!vpninfo->vpn_nbns[j]) {
243                                         vpninfo->vpn_nbns[j] = new_option->value;
244                                         break;
245                                 }
246                         }
247                 } else if (!strcmp(buf + 7, "Default-Domain")) {
248                         vpninfo->vpn_domain = new_option->value;
249                 } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
250                         vpninfo->vpn_proxy_pac = new_option->value;
251                 } else if (!strcmp(buf + 7, "Split-Include")) {
252                         struct split_include *inc = malloc(sizeof(*inc));
253                         if (!inc)
254                                 continue;
255                         inc->route = new_option->value;
256                         inc->next = vpninfo->split_includes;
257                         vpninfo->split_includes = inc;
258                 } else if (!strcmp(buf + 7, "Split-Exclude")) {
259                         struct split_include *exc = malloc(sizeof(*exc));
260                         if (!exc)
261                                 continue;
262                         exc->route = new_option->value;
263                         exc->next = vpninfo->split_excludes;
264                         vpninfo->split_excludes = exc;
265                 }
266         }
267
268         if (!vpninfo->vpn_addr && !vpninfo->vpn_addr6) {
269                 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
270                 return -EINVAL;
271         }
272         if (vpninfo->vpn_addr && !vpninfo->vpn_netmask)
273                 vpninfo->vpn_netmask = "255.255.255.255";
274         if (old_addr) {
275                 if (strcmp(old_addr, vpninfo->vpn_addr)) {
276                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP address (%s != %s)\n",
277                                 vpninfo->vpn_addr, old_addr);
278                         return -EINVAL;
279                 }
280         }
281         if (old_netmask) {
282                 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
283                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different Legacy IP netmask (%s != %s)\n",
284                                 vpninfo->vpn_netmask, old_netmask);
285                         return -EINVAL;
286                 }
287         }
288         if (old_addr6) {
289                 if (strcmp(old_addr6, vpninfo->vpn_addr6)) {
290                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 address (%s != %s)\n",
291                                 vpninfo->vpn_addr6, old_addr6);
292                         return -EINVAL;
293                 }
294         }
295         if (old_netmask6) {
296                 if (strcmp(old_netmask6, vpninfo->vpn_netmask6)) {
297                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IPv6 netmask (%s != %s)\n",
298                                 vpninfo->vpn_netmask6, old_netmask6);
299                         return -EINVAL;
300                 }
301         }
302
303         while (old_dtls_opts) {
304                 struct vpn_option *tmp = old_dtls_opts;
305                 old_dtls_opts = old_dtls_opts->next;
306                 free(tmp->value);
307                 free(tmp->option);
308                 free(tmp);
309         }
310         while (old_cstp_opts) {
311                 struct vpn_option *tmp = old_cstp_opts;
312                 old_cstp_opts = old_cstp_opts->next;
313                 free(tmp->value);
314                 free(tmp->option);
315                 free(tmp);
316         }
317         vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
318                           vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
319
320         BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl), 1);
321         BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl), 1);
322
323         fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
324         if (vpninfo->select_nfds <= vpninfo->ssl_fd)
325                 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
326
327         FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
328         FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
329
330         vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
331         return 0;
332 }
333
334
335 int make_cstp_connection(struct openconnect_info *vpninfo)
336 {
337         int ret;
338
339         if (!vpninfo->https_ssl && (ret = openconnect_open_https(vpninfo)))
340                 return ret;
341
342         if (vpninfo->deflate) {
343                 vpninfo->deflate_adler32 = 1;
344                 vpninfo->inflate_adler32 = 1;
345
346                 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
347                     deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
348                                  Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
349                         vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
350                         vpninfo->deflate = 0;
351                 }
352
353                 if (!vpninfo->deflate_pkt) {
354                         vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
355                         if (!vpninfo->deflate_pkt) {
356                                 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
357                                 vpninfo->deflate = 0;
358                         }
359                         memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
360                         memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
361                         vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
362                 }
363         }
364
365         return start_cstp_connection(vpninfo);
366 }
367
368 static int cstp_reconnect(struct openconnect_info *vpninfo)
369 {
370         int ret;
371         int timeout;
372         int interval;
373
374         timeout = vpninfo->reconnect_timeout;
375         interval = vpninfo->reconnect_interval;
376
377         while ((ret = make_cstp_connection(vpninfo))) {
378                 if (timeout <= 0)
379                         return ret;
380                 vpninfo->progress(vpninfo, PRG_INFO,
381                                   "sleep %ds, remaining timeout %ds\n",
382                                   interval, timeout);
383                 sleep(interval);
384                 if (killed)
385                         return 1;
386                 timeout -= interval;
387                 interval += vpninfo->reconnect_interval;
388                 if (interval > RECONNECT_INTERVAL_MAX)
389                         interval = RECONNECT_INTERVAL_MAX;
390         }
391         return 0;
392 }
393
394 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, void *buf, int len)
395 {
396         struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
397
398         if (!new)
399                 return -ENOMEM;
400
401         new->next = NULL;
402
403         vpninfo->inflate_strm.next_in = buf;
404         vpninfo->inflate_strm.avail_in = len - 4;
405
406         vpninfo->inflate_strm.next_out = new->data;
407         vpninfo->inflate_strm.avail_out = vpninfo->mtu;
408         vpninfo->inflate_strm.total_out = 0;
409
410         if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
411                 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
412                 free(new);
413                 return -EINVAL;
414         }
415
416         new->len = vpninfo->inflate_strm.total_out;
417
418         vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
419                                            new->data, new->len);
420
421         if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *) (buf + len - 4) )) {
422                 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
423         }
424
425         vpninfo->progress(vpninfo, PRG_TRACE,
426                           "Received compressed data packet of %ld bytes\n",
427                           vpninfo->inflate_strm.total_out);
428
429         queue_packet(&vpninfo->incoming_queue, new);
430         return 0;
431 }
432
433 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
434 {
435         unsigned char buf[16384];
436         int len, ret;
437         int work_done = 0;
438
439         /* FIXME: The poll() handling here is fairly simplistic. Actually,
440            if the SSL connection stalls it could return a WANT_WRITE error
441            on _either_ of the SSL_read() or SSL_write() calls. In that case,
442            we should probably remove POLLIN from the events we're looking for,
443            and add POLLOUT. As it is, though, it'll just chew CPU time in that
444            fairly unlikely situation, until the write backlog clears. */
445         while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
446                 int payload_len;
447
448                 if (buf[0] != 'S' || buf[1] != 'T' ||
449                     buf[2] != 'F' || buf[3] != 1 || buf[7])
450                         goto unknown_pkt;
451
452                 payload_len = (buf[4] << 8) + buf[5];
453                 if (len != 8 + payload_len) {
454                         vpninfo->progress(vpninfo, PRG_ERR,
455                                           "Unexpected packet length. SSL_read returned %d but packet is\n",
456                                           len);
457                         vpninfo->progress(vpninfo, PRG_ERR,
458                                           "%02x %02x %02x %02x %02x %02x %02x %02x\n",
459                                           buf[0], buf[1], buf[2], buf[3],
460                                           buf[4], buf[5], buf[6], buf[7]);
461                         continue;
462                 }
463                 vpninfo->ssl_times.last_rx = time(NULL);
464                 switch(buf[6]) {
465                 case AC_PKT_DPD_OUT:
466                         vpninfo->progress(vpninfo, PRG_TRACE,
467                                           "Got CSTP DPD request\n");
468                         vpninfo->owe_ssl_dpd_response = 1;
469                         continue;
470
471                 case AC_PKT_DPD_RESP:
472                         vpninfo->progress(vpninfo, PRG_TRACE,
473                                           "Got CSTP DPD response\n");
474                         continue;
475
476                 case AC_PKT_KEEPALIVE:
477                         vpninfo->progress(vpninfo, PRG_TRACE,
478                                           "Got CSTP Keepalive\n");
479                         continue;
480
481                 case AC_PKT_DATA:
482                         vpninfo->progress(vpninfo, PRG_TRACE,
483                                           "Received uncompressed data packet of %d bytes\n",
484                                           payload_len);
485                         queue_new_packet(&vpninfo->incoming_queue, buf + 8,
486                                          payload_len);
487                         work_done = 1;
488                         continue;
489
490                 case AC_PKT_DISCONN: {
491                         int i;
492                         for (i = 0; i < payload_len; i++) {
493                                 if (!isprint(buf[payload_len + 8 + i]))
494                                         buf[payload_len + 8 + i] = '.';
495                         }
496                         buf[payload_len + 8] = 0;
497                         vpninfo->progress(vpninfo, PRG_ERR,
498                                           "Received server disconnect: %02x '%s'\n", buf[8], buf + 9);
499                         vpninfo->quit_reason = "Server request";
500                         return 1;
501                 }
502                 case AC_PKT_COMPRESSED:
503                         if (!vpninfo->deflate) {
504                                 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
505                                 goto unknown_pkt;
506                         }
507                         inflate_and_queue_packet(vpninfo, buf + 8, payload_len);
508                         work_done = 1;
509                         continue;
510
511                 case AC_PKT_TERM_SERVER:
512                         vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
513                         vpninfo->quit_reason = "Server request";
514                         return 1;
515                 }
516
517         unknown_pkt:
518                 vpninfo->progress(vpninfo, PRG_ERR,
519                                   "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
520                                   buf[0], buf[1], buf[2], buf[3],
521                                   buf[4], buf[5], buf[6], buf[7]);
522                 vpninfo->quit_reason = "Unknown packet received";
523                 return 1;
524         }
525
526         ret = SSL_get_error(vpninfo->https_ssl, len);
527         if (ret == SSL_ERROR_SYSCALL || ret == SSL_ERROR_ZERO_RETURN) {
528                 vpninfo->progress(vpninfo, PRG_ERR,
529                                   "SSL read error %d (server probably closed connection); reconnecting.\n",
530                                   ret);
531                         goto do_reconnect;
532         }
533
534
535         /* If SSL_write() fails we are expected to try again. With exactly
536            the same data, at exactly the same location. So we keep the
537            packet we had before.... */
538         if (vpninfo->current_ssl_pkt) {
539         handle_outgoing:
540                 vpninfo->ssl_times.last_tx = time(NULL);
541                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
542                 ret = SSL_write(vpninfo->https_ssl,
543                                 vpninfo->current_ssl_pkt->hdr,
544                                 vpninfo->current_ssl_pkt->len + 8);
545                 if (ret <= 0) {
546                         ret = SSL_get_error(vpninfo->https_ssl, ret);
547                         switch (ret) {
548                         case SSL_ERROR_WANT_WRITE:
549                                 /* Waiting for the socket to become writable -- it's
550                                    probably stalled, and/or the buffers are full */
551                                 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
552
553                         case SSL_ERROR_WANT_READ:
554                                 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
555                                         goto peer_dead;
556                                 return work_done;
557                         default:
558                                 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d\n", ret);
559                                 report_ssl_errors(vpninfo);
560                                 goto do_reconnect;
561                         }
562                 }
563                 if (ret != vpninfo->current_ssl_pkt->len + 8) {
564                         vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
565                                 vpninfo->current_ssl_pkt->len + 8, ret);
566                         vpninfo->quit_reason = "Internal error";
567                         return 1;
568                 }
569                 /* Don't free the 'special' packets */
570                 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
571                     vpninfo->current_ssl_pkt != &dpd_pkt &&
572                     vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
573                     vpninfo->current_ssl_pkt != &keepalive_pkt)
574                         free(vpninfo->current_ssl_pkt);
575
576                 vpninfo->current_ssl_pkt = NULL;
577         }
578
579         if (vpninfo->owe_ssl_dpd_response) {
580                 vpninfo->owe_ssl_dpd_response = 0;
581                 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
582                 goto handle_outgoing;
583         }
584
585         switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
586         case KA_REKEY:
587                 /* Not that this will ever happen; we don't even process
588                    the setting when we're asked for it. */
589                 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
590                 time(&vpninfo->ssl_times.last_rekey);
591                 work_done = 1;
592                 break;
593
594         case KA_DPD_DEAD:
595         peer_dead:
596                 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
597         do_reconnect:
598                 openconnect_close_https(vpninfo);
599
600                 /* It's already deflated in the old stream. Extremely
601                    non-trivial to reconstitute it; just throw it away */
602                 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
603                         vpninfo->current_ssl_pkt = NULL;
604
605                 if (cstp_reconnect(vpninfo)) {
606                         vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
607                         vpninfo->quit_reason = "CSTP reconnect failed";
608                         return 1;
609                 }
610                 /* I think we can leave DTLS to its own devices; when we reconnect
611                    with the same master secret, we do seem to get the same sessid */
612                 return 1;
613
614         case KA_DPD:
615                 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
616
617                 vpninfo->current_ssl_pkt = &dpd_pkt;
618                 goto handle_outgoing;
619
620         case KA_KEEPALIVE:
621                 /* No need to send an explicit keepalive
622                    if we have real data to send */
623                 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
624                         break;
625
626                 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
627
628                 vpninfo->current_ssl_pkt = &keepalive_pkt;
629                 goto handle_outgoing;
630
631         case KA_NONE:
632                 ;
633         }
634
635         /* Service outgoing packet queue, if no DTLS */
636         while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
637                 struct pkt *this = vpninfo->outgoing_queue;
638                 vpninfo->outgoing_queue = this->next;
639                 vpninfo->outgoing_qlen--;
640
641                 if (vpninfo->deflate) {
642                         unsigned char *adler;
643                         int ret;
644
645                         vpninfo->deflate_strm.next_in = this->data;
646                         vpninfo->deflate_strm.avail_in = this->len;
647                         vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
648                         vpninfo->deflate_strm.avail_out = 2040;
649                         vpninfo->deflate_strm.total_out = 0;
650
651                         ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
652                         if (ret) {
653                                 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
654                                 goto uncompr;
655                         }
656
657                         vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
658                         vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
659
660                         /* Add ongoing adler32 to tail of compressed packet */
661                         vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
662                                                            this->data, this->len);
663
664                         adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
665                         *(adler++) =  vpninfo->deflate_adler32 >> 24;
666                         *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
667                         *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
668                         *(adler)   =  vpninfo->deflate_adler32 & 0xff;
669
670                         vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
671
672                         vpninfo->progress(vpninfo, PRG_TRACE,
673                                           "Sending compressed data packet of %d bytes\n",
674                                           this->len);
675
676                         vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
677                 } else {
678                 uncompr:
679                         memcpy(this->hdr, data_hdr, 8);
680                         this->hdr[4] = this->len >> 8;
681                         this->hdr[5] = this->len & 0xff;
682
683                         vpninfo->progress(vpninfo, PRG_TRACE,
684                                           "Sending uncompressed data packet of %d bytes\n",
685                                           this->len);
686
687                         vpninfo->current_ssl_pkt = this;
688                 }
689                 goto handle_outgoing;
690         }
691
692         /* Work is not done if we just got rid of packets off the queue */
693         return work_done;
694 }
695
696 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
697 {
698         unsigned char *bye_pkt;
699         int reason_len;
700
701         /* already lost connection? */
702         if (!vpninfo->https_ssl)
703                 return 0;
704
705         reason_len = strlen(reason);
706         bye_pkt = malloc(reason_len + 9);
707         if (!bye_pkt)
708                 return -ENOMEM;
709
710         memcpy(bye_pkt, data_hdr, 8);
711         memcpy(bye_pkt + 9, reason, reason_len);
712
713         bye_pkt[4] = (reason_len + 1) >> 8;
714         bye_pkt[5] = (reason_len + 1) & 0xff;
715         bye_pkt[6] = AC_PKT_DISCONN;
716         bye_pkt[8] = 0xb0;
717
718         SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 9);
719         free(bye_pkt);
720
721         vpninfo->progress(vpninfo, PRG_INFO,
722                           "Send BYE packet: %s\n", reason);
723
724         return 0;
725 }