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