1 /*
2 * OpenConnect (SSL + DTLS) VPN client
3 *
4 * Copyright © 2008-2015 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
18 #include <config.h>
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #ifndef _WIN32
26 /* for setgroups() */
27 # include <sys/types.h>
28 # include <grp.h>
29 #endif
30
31 #include "openconnect-internal.h"
32
queue_new_packet(struct pkt_q * q,void * buf,int len)33 int queue_new_packet(struct pkt_q *q, void *buf, int len)
34 {
35 struct pkt *new = malloc(sizeof(struct pkt) + len);
36 if (!new)
37 return -ENOMEM;
38
39 new->len = len;
40 new->next = NULL;
41 memcpy(new->data, buf, len);
42 queue_packet(q, new);
43 return 0;
44 }
45
46 /* This is here because it's generic and hence can't live in either of the
47 tun*.c files for specific platforms */
tun_mainloop(struct openconnect_info * vpninfo,int * timeout,int readable)48 int tun_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
49 {
50 struct pkt *this;
51 int work_done = 0;
52
53 if (!tun_is_up(vpninfo)) {
54 /* no tun yet; clear any queued packets */
55 while ((this = dequeue_packet(&vpninfo->incoming_queue)))
56 free(this);
57
58 return 0;
59 }
60
61 if (readable && read_fd_monitored(vpninfo, tun)) {
62 struct pkt *out_pkt = vpninfo->tun_pkt;
63 while (1) {
64 int len = vpninfo->ip_info.mtu;
65
66 if (!out_pkt) {
67 out_pkt = malloc(sizeof(struct pkt) + len + vpninfo->pkt_trailer);
68 if (!out_pkt) {
69 vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
70 break;
71 }
72 out_pkt->len = len;
73 }
74
75 if (os_read_tun(vpninfo, out_pkt))
76 break;
77
78 vpninfo->stats.tx_pkts++;
79 vpninfo->stats.tx_bytes += out_pkt->len;
80 work_done = 1;
81
82 if (queue_packet(&vpninfo->outgoing_queue, out_pkt) +
83 vpninfo->oncp_control_queue.count >= vpninfo->max_qlen) {
84 out_pkt = NULL;
85 unmonitor_read_fd(vpninfo, tun);
86 break;
87 }
88 out_pkt = NULL;
89 }
90 vpninfo->tun_pkt = out_pkt;
91 } else if (vpninfo->outgoing_queue.count + vpninfo->oncp_control_queue.count < vpninfo->max_qlen) {
92 monitor_read_fd(vpninfo, tun);
93 }
94
95 while ((this = dequeue_packet(&vpninfo->incoming_queue))) {
96
97 unmonitor_write_fd(vpninfo, tun);
98
99 if (os_write_tun(vpninfo, this)) {
100 requeue_packet(&vpninfo->incoming_queue, this);
101 break;
102 }
103
104 vpninfo->stats.rx_pkts++;
105 vpninfo->stats.rx_bytes += this->len;
106
107 free(this);
108 }
109 /* Work is not done if we just got rid of packets off the queue */
110 return work_done;
111 }
112
setup_tun_device(struct openconnect_info * vpninfo)113 static int setup_tun_device(struct openconnect_info *vpninfo)
114 {
115 int ret;
116
117 if (vpninfo->setup_tun) {
118 vpninfo->setup_tun(vpninfo->cbdata);
119 if (tun_is_up(vpninfo))
120 return 0;
121 }
122
123 #ifndef _WIN32
124 if (vpninfo->use_tun_script) {
125 ret = openconnect_setup_tun_script(vpninfo, vpninfo->vpnc_script);
126 if (ret) {
127 fprintf(stderr, _("Set up tun script failed\n"));
128 return ret;
129 }
130 } else
131 #endif
132 ret = openconnect_setup_tun_device(vpninfo, vpninfo->vpnc_script, vpninfo->ifname);
133 if (ret) {
134 fprintf(stderr, _("Set up tun device failed\n"));
135 return ret;
136 }
137
138 #if !defined(_WIN32) && !defined(__native_client__)
139 if (vpninfo->uid != getuid()) {
140 int e;
141
142 if (setgid(vpninfo->gid)) {
143 e = errno;
144 fprintf(stderr, _("Failed to set gid %ld: %s\n"),
145 (long)vpninfo->gid, strerror(e));
146 return -EPERM;
147 }
148
149 if (setgroups(1, &vpninfo->gid)) {
150 e = errno;
151 fprintf(stderr, _("Failed to set groups to %ld: %s\n"),
152 (long)vpninfo->gid, strerror(e));
153 return -EPERM;
154 }
155
156 if (setuid(vpninfo->uid)) {
157 e = errno;
158 fprintf(stderr, _("Failed to set uid %ld: %s\n"),
159 (long)vpninfo->uid, strerror(e));
160 return -EPERM;
161 }
162 }
163 #endif
164 return 0;
165 }
166
167 /* Return value:
168 * = 0, when successfully paused (may call again)
169 * = -EINTR, if aborted locally via OC_CMD_CANCEL
170 * = -ECONNABORTED, if aborted locally via OC_CMD_DETACH
171 * = -EPIPE, if the remote end explicitly terminated the session
172 * = -EPERM, if the gateway sent 401 Unauthorized (cookie expired)
173 * < 0, for any other error
174 */
openconnect_mainloop(struct openconnect_info * vpninfo,int reconnect_timeout,int reconnect_interval)175 int openconnect_mainloop(struct openconnect_info *vpninfo,
176 int reconnect_timeout,
177 int reconnect_interval)
178 {
179 int ret = 0;
180 int tun_r = 1, udp_r = 1, tcp_r = 1;
181 vpninfo->reconnect_timeout = reconnect_timeout;
182 vpninfo->reconnect_interval = reconnect_interval;
183
184 if (vpninfo->cmd_fd != -1) {
185 monitor_fd_new(vpninfo, cmd);
186 monitor_read_fd(vpninfo, cmd);
187 }
188
189 while (!vpninfo->quit_reason) {
190 int did_work = 0;
191 int timeout;
192 #ifdef _WIN32
193 HANDLE events[4];
194 int nr_events = 0;
195 #else
196 struct timeval tv;
197 fd_set rfds, wfds, efds;
198 #endif
199
200 /* If tun is not up, loop more often to detect
201 * a DTLS timeout (due to a firewall block) as soon. */
202 if (tun_is_up(vpninfo))
203 timeout = INT_MAX;
204 else
205 timeout = 1000;
206
207 if (vpninfo->dtls_state > DTLS_DISABLED) {
208 /* Postpone tun device creation after DTLS is connected so
209 * we have a better knowledge of the link MTU. We also
210 * force the creation if DTLS enters sleeping mode - i.e.,
211 * we failed to connect on time. */
212 if (!tun_is_up(vpninfo) && (vpninfo->dtls_state == DTLS_CONNECTED ||
213 vpninfo->dtls_state == DTLS_SLEEPING)) {
214 ret = setup_tun_device(vpninfo);
215 if (ret) {
216 break;
217 }
218 }
219
220 ret = vpninfo->proto->udp_mainloop(vpninfo, &timeout, udp_r);
221 if (vpninfo->quit_reason)
222 break;
223 did_work += ret;
224
225 } else if (!tun_is_up(vpninfo)) {
226 /* No DTLS - setup TUN device unconditionally */
227 ret = setup_tun_device(vpninfo);
228 if (ret)
229 break;
230 }
231
232 ret = vpninfo->proto->tcp_mainloop(vpninfo, &timeout, tcp_r);
233 if (vpninfo->quit_reason)
234 break;
235 did_work += ret;
236
237 /* Tun must be last because it will set/clear its bit
238 in the select_rfds according to the queue length */
239 did_work += tun_mainloop(vpninfo, &timeout, tun_r);
240 if (vpninfo->quit_reason)
241 break;
242
243 poll_cmd_fd(vpninfo, 0);
244 if (vpninfo->got_cancel_cmd) {
245 if (vpninfo->cancel_type == OC_CMD_CANCEL) {
246 vpninfo->quit_reason = "Aborted by caller";
247 ret = -EINTR;
248 } else {
249 ret = -ECONNABORTED;
250 }
251 vpninfo->got_cancel_cmd = 0;
252 break;
253 }
254
255 if (vpninfo->got_pause_cmd) {
256 /* close all connections and wait for the user to call
257 openconnect_mainloop() again */
258 openconnect_close_https(vpninfo, 0);
259 if (vpninfo->dtls_state > DTLS_DISABLED) {
260 vpninfo->proto->udp_close(vpninfo);
261 vpninfo->new_dtls_started = 0;
262 }
263
264 vpninfo->got_pause_cmd = 0;
265 vpn_progress(vpninfo, PRG_INFO, _("Caller paused the connection\n"));
266 return 0;
267 }
268
269 if (did_work)
270 continue;
271
272 vpn_progress(vpninfo, PRG_TRACE,
273 _("No work to do; sleeping for %d ms...\n"), timeout);
274
275 #ifdef _WIN32
276 if (vpninfo->dtls_monitored) {
277 WSAEventSelect(vpninfo->dtls_fd, vpninfo->dtls_event, vpninfo->dtls_monitored);
278 events[nr_events++] = vpninfo->dtls_event;
279 }
280 if (vpninfo->ssl_monitored) {
281 WSAEventSelect(vpninfo->ssl_fd, vpninfo->ssl_event, vpninfo->ssl_monitored);
282 events[nr_events++] = vpninfo->ssl_event;
283 }
284 if (vpninfo->cmd_monitored) {
285 WSAEventSelect(vpninfo->cmd_fd, vpninfo->cmd_event, vpninfo->cmd_monitored);
286 events[nr_events++] = vpninfo->cmd_event;
287 }
288 if (vpninfo->tun_monitored) {
289 events[nr_events++] = vpninfo->tun_rd_overlap.hEvent;
290 }
291 if (WaitForMultipleObjects(nr_events, events, FALSE, timeout) == WAIT_FAILED) {
292 char *errstr = openconnect__win32_strerror(GetLastError());
293 vpn_progress(vpninfo, PRG_ERR,
294 _("WaitForMultipleObjects failed: %s\n"),
295 errstr);
296 free(errstr);
297 }
298 #else
299 memcpy(&rfds, &vpninfo->_select_rfds, sizeof(rfds));
300 memcpy(&wfds, &vpninfo->_select_wfds, sizeof(wfds));
301 memcpy(&efds, &vpninfo->_select_efds, sizeof(efds));
302
303 tv.tv_sec = timeout / 1000;
304 tv.tv_usec = (timeout % 1000) * 1000;
305
306 if (select(vpninfo->_select_nfds, &rfds, &wfds, &efds, &tv) < 0 &&
307 errno != EINTR) {
308 ret = -errno;
309 vpn_perror(vpninfo, _("Failed select() in mainloop"));
310 break;
311 }
312
313 if (vpninfo->tun_fd >= 0)
314 tun_r = FD_ISSET(vpninfo->tun_fd, &rfds);
315 if (vpninfo->dtls_fd >= 0)
316 udp_r = FD_ISSET(vpninfo->dtls_fd, &rfds);
317 if (vpninfo->ssl_fd >= 0)
318 tcp_r = FD_ISSET(vpninfo->ssl_fd, &rfds);
319 #endif
320 }
321
322 if (vpninfo->quit_reason && vpninfo->proto->vpn_close_session)
323 vpninfo->proto->vpn_close_session(vpninfo, vpninfo->quit_reason);
324
325 if (tun_is_up(vpninfo))
326 os_shutdown_tun(vpninfo);
327 return ret < 0 ? ret : -EIO;
328 }
329
ka_check_deadline(int * timeout,time_t now,time_t due)330 int ka_check_deadline(int *timeout, time_t now, time_t due)
331 {
332 if (now >= due)
333 return 1;
334 if (*timeout > (due - now) * 1000)
335 *timeout = (due - now) * 1000;
336 return 0;
337 }
338
339 /* Called when the socket is unwritable, to get the deadline for DPD.
340 Returns 1 if DPD deadline has already arrived. */
ka_stalled_action(struct keepalive_info * ka,int * timeout)341 int ka_stalled_action(struct keepalive_info *ka, int *timeout)
342 {
343 time_t now = time(NULL);
344
345 /* We only support the new-tunnel rekey method for now. */
346 if (ka->rekey_method != REKEY_NONE &&
347 ka_check_deadline(timeout, now, ka->last_rekey + ka->rekey)) {
348 ka->last_rekey = now;
349 return KA_REKEY;
350 }
351
352 if (ka->dpd &&
353 ka_check_deadline(timeout, now, ka->last_rx + (2 * ka->dpd)))
354 return KA_DPD_DEAD;
355
356 return KA_NONE;
357 }
358
359
keepalive_action(struct keepalive_info * ka,int * timeout)360 int keepalive_action(struct keepalive_info *ka, int *timeout)
361 {
362 time_t now = time(NULL);
363
364 if (ka->rekey_method != REKEY_NONE &&
365 ka_check_deadline(timeout, now, ka->last_rekey + ka->rekey)) {
366 ka->last_rekey = now;
367 return KA_REKEY;
368 }
369
370 /* DPD is bidirectional -- PKT 3 out, PKT 4 back */
371 if (ka->dpd) {
372 time_t due = ka->last_rx + ka->dpd;
373 time_t overdue = ka->last_rx + (2 * ka->dpd);
374
375 /* Peer didn't respond */
376 if (now > overdue)
377 return KA_DPD_DEAD;
378
379 /* If we already have DPD outstanding, don't flood. Repeat by
380 all means, but only after half the DPD period. */
381 if (ka->last_dpd > ka->last_rx)
382 due = ka->last_dpd + ka->dpd / 2;
383
384 /* We haven't seen a packet from this host for $DPD seconds.
385 Prod it to see if it's still alive */
386 if (ka_check_deadline(timeout, now, due)) {
387 ka->last_dpd = now;
388 return KA_DPD;
389 }
390 }
391
392 /* Keepalive is just client -> server.
393 If we haven't sent anything for $KEEPALIVE seconds, send a
394 dummy packet (which the server will discard) */
395 if (ka->keepalive &&
396 ka_check_deadline(timeout, now, ka->last_tx + ka->keepalive))
397 return KA_KEEPALIVE;
398
399 return KA_NONE;
400 }
401
trojan_check_deadline(struct openconnect_info * vpninfo,int * timeout)402 int trojan_check_deadline(struct openconnect_info *vpninfo, int *timeout)
403 {
404 time_t now = time(NULL);
405
406 if (vpninfo->trojan_interval &&
407 ka_check_deadline(timeout, now,
408 vpninfo->last_trojan + vpninfo->trojan_interval)) {
409 vpninfo->last_trojan = now;
410 return 1;
411 } else {
412 return 0;
413 }
414 }
415