Skip to content

Latest commit

 

History

History
787 lines (677 loc) · 17.9 KB

tun.c

File metadata and controls

787 lines (677 loc) · 17.9 KB
 
Sep 22, 2008
Sep 22, 2008
1
/*
Nov 20, 2008
Nov 20, 2008
2
* OpenConnect (SSL + DTLS) VPN client
Sep 22, 2008
Sep 22, 2008
3
*
May 13, 2012
May 13, 2012
4
* Copyright © 2008-2012 Intel Corporation.
Sep 22, 2008
Sep 22, 2008
5
*
Nov 20, 2008
Nov 20, 2008
6
7
8
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
Oct 4, 2008
Oct 4, 2008
9
* modify it under the terms of the GNU Lesser General Public License
Nov 20, 2008
Nov 20, 2008
10
* version 2.1, as published by the Free Software Foundation.
Sep 22, 2008
Sep 22, 2008
11
*
Nov 20, 2008
Nov 20, 2008
12
* This program is distributed in the hope that it will be useful, but
Oct 4, 2008
Oct 4, 2008
13
14
15
16
17
18
19
20
21
22
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to:
*
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
Sep 22, 2008
Sep 22, 2008
23
24
*/
Jun 1, 2009
Jun 1, 2009
25
26
#include <sys/types.h>
#include <sys/stat.h>
Oct 15, 2008
Oct 15, 2008
27
#include <sys/socket.h>
Sep 22, 2008
Sep 22, 2008
28
#include <sys/ioctl.h>
Jun 1, 2009
Jun 1, 2009
29
#include <string.h>
Nov 3, 2009
Nov 3, 2009
30
#include <signal.h>
Sep 22, 2008
Sep 22, 2008
31
#include <fcntl.h>
Sep 22, 2008
Sep 22, 2008
32
#include <unistd.h>
Jan 1, 2010
Jan 1, 2010
33
#include <netdb.h>
Jun 1, 2009
Jun 1, 2009
34
#include <netinet/in_systm.h>
Sep 26, 2008
Sep 26, 2008
35
#include <netinet/in.h>
Jun 1, 2009
Jun 1, 2009
36
#include <netinet/ip.h>
Dec 5, 2008
Dec 5, 2008
37
#include <net/if.h>
Sep 26, 2008
Sep 26, 2008
38
#include <arpa/inet.h>
Sep 29, 2008
Sep 29, 2008
39
#include <errno.h>
Apr 14, 2010
Apr 14, 2010
40
#include <ctype.h>
May 29, 2012
May 29, 2012
41
42
#include <stdio.h>
#include <stdlib.h>
Nov 18, 2009
Nov 18, 2009
43
44
45
#if defined(__sun__)
#include <stropts.h>
#include <sys/sockio.h>
May 8, 2010
May 8, 2010
46
47
48
49
#include <net/if_tun.h>
#ifndef TUNNEWPPA
#error "Install TAP driver from http://www.whiteboard.ne.jp/~admin2/tuntap/"
#endif
Nov 18, 2009
Nov 18, 2009
50
#endif
Sep 22, 2008
Sep 22, 2008
51
Mar 9, 2011
Mar 9, 2011
52
#include "openconnect-internal.h"
Sep 22, 2008
Sep 22, 2008
53
Nov 18, 2009
Nov 18, 2009
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
* If an if_tun.h include file was found anywhere (by the Makefile), it's
* included. Else, we end up assuming that we have BSD-style devices such
* as /dev/tun0 etc.
*/
#ifdef IF_TUN_HDR
#include IF_TUN_HDR
#endif
/*
* The OS X tun/tap driver doesn't provide a header file; you're expected
* to define this for yourself.
*/
#ifdef __APPLE__
#define TUNSIFHEAD _IOW('t', 96, int)
#endif
/*
* OpenBSD always puts the protocol family prefix onto packets. Other
* systems let us enable that with the TUNSIFHEAD ioctl, and some of them
* (e.g. FreeBSD) _need_ it otherwise they'll interpret IPv6 packets as IPv4.
*/
#if defined(__OpenBSD__) || defined(TUNSIFHEAD)
Nov 13, 2009
Nov 13, 2009
77
#define TUN_HAS_AF_PREFIX 1
Jun 1, 2009
Jun 1, 2009
78
79
#endif
Apr 16, 2012
Apr 16, 2012
80
static int set_tun_mtu(struct openconnect_info *vpninfo)
Sep 22, 2008
Sep 22, 2008
81
{
Apr 16, 2012
Apr 16, 2012
82
#ifndef __sun__ /* We don't know how to do this on Solaris */
Sep 22, 2008
Sep 22, 2008
83
struct ifreq ifr;
Sep 29, 2008
Sep 29, 2008
84
int net_fd;
Sep 29, 2008
Sep 29, 2008
85
Sep 26, 2008
Sep 26, 2008
86
87
net_fd = socket(PF_INET, SOCK_DGRAM, 0);
if (net_fd < 0) {
Sep 22, 2011
Sep 22, 2011
88
perror(_("open net"));
Sep 29, 2008
Sep 29, 2008
89
return -EINVAL;
Sep 26, 2008
Sep 26, 2008
90
}
Apr 16, 2012
Apr 16, 2012
91
Sep 26, 2008
Sep 26, 2008
92
memset(&ifr, 0, sizeof(ifr));
Sep 27, 2008
Sep 27, 2008
93
strncpy(ifr.ifr_name, vpninfo->ifname, sizeof(ifr.ifr_name) - 1);
Sep 30, 2008
Sep 30, 2008
94
ifr.ifr_mtu = vpninfo->mtu;
Apr 16, 2012
Apr 16, 2012
95
Sep 30, 2008
Sep 30, 2008
96
if (ioctl(net_fd, SIOCSIFMTU, &ifr) < 0)
Sep 22, 2011
Sep 22, 2011
97
perror(_("SIOCSIFMTU"));
Sep 30, 2008
Sep 30, 2008
98
Sep 26, 2008
Sep 26, 2008
99
close(net_fd);
Apr 16, 2012
Apr 16, 2012
100
#endif
Sep 29, 2008
Sep 29, 2008
101
102
return 0;
}
Apr 16, 2012
Apr 16, 2012
103
Sep 29, 2008
Sep 29, 2008
104
Sep 30, 2008
Sep 30, 2008
105
106
107
108
109
110
111
static int setenv_int(const char *opt, int value)
{
char buf[16];
sprintf(buf, "%d", value);
return setenv(opt, buf, 1);
}
Nov 3, 2009
Nov 3, 2009
112
113
114
115
116
117
118
119
120
121
122
static int netmasklen(struct in_addr addr)
{
int masklen;
for (masklen = 0; masklen < 32; masklen++) {
if (ntohl(addr.s_addr) >= (0xffffffff << masklen))
break;
}
return 32 - masklen;
}
Apr 29, 2009
Apr 29, 2009
123
static int process_split_xxclude(struct openconnect_info *vpninfo,
Sep 27, 2011
Sep 27, 2011
124
int include, const char *route, int *v4_incs,
Nov 11, 2009
Nov 11, 2009
125
int *v6_incs)
Oct 24, 2008
Oct 24, 2008
126
127
{
struct in_addr addr;
Sep 27, 2011
Sep 27, 2011
128
const char *in_ex = include?"IN":"EX";
Oct 24, 2008
Oct 24, 2008
129
130
131
132
133
134
char envname[80];
char *slash;
slash = strchr(route, '/');
if (!slash) {
badinc:
Sep 27, 2011
Sep 27, 2011
135
136
137
138
139
140
141
142
if (include)
vpn_progress(vpninfo, PRG_ERR,
_("Discard bad split include: \"%s\"\n"),
route);
else
vpn_progress(vpninfo, PRG_ERR,
_("Discard bad split exclude: \"%s\"\n"),
route);
Oct 24, 2008
Oct 24, 2008
143
144
145
146
return -EINVAL;
}
*slash = 0;
Nov 11, 2009
Nov 11, 2009
147
148
149
150
151
152
153
154
155
156
157
158
159
160
if (strchr(route, ':')) {
snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_ADDR", in_ex,
*v6_incs);
setenv(envname, route, 1);
snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_MASKLEN", in_ex,
*v6_incs);
setenv(envname, slash+1, 1);
(*v6_incs)++;
return 0;
}
Oct 24, 2008
Oct 24, 2008
161
162
163
164
165
166
if (!inet_aton(route, &addr)) {
*slash = '/';
goto badinc;
}
envname[79] = 0;
Nov 11, 2009
Nov 11, 2009
167
snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_ADDR", in_ex, *v4_incs);
Oct 24, 2008
Oct 24, 2008
168
169
170
171
172
173
174
175
setenv(envname, route, 1);
/* Put it back how we found it */
*slash = '/';
if (!inet_aton(slash+1, &addr))
goto badinc;
Nov 11, 2009
Nov 11, 2009
176
snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASK", in_ex, *v4_incs);
Oct 24, 2008
Oct 24, 2008
177
178
setenv(envname, slash+1, 1);
Nov 11, 2009
Nov 11, 2009
179
snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASKLEN", in_ex, *v4_incs);
Nov 3, 2009
Nov 3, 2009
180
setenv_int(envname, netmasklen(addr));
Oct 24, 2008
Oct 24, 2008
181
Nov 11, 2009
Nov 11, 2009
182
(*v4_incs)++;
Oct 24, 2008
Oct 24, 2008
183
184
185
return 0;
}
Sep 30, 2008
Sep 30, 2008
186
static int appendenv(const char *opt, const char *new)
Sep 29, 2008
Sep 29, 2008
187
188
189
190
191
192
193
194
195
196
197
198
199
{
char buf[1024];
char *old = getenv(opt);
buf[1023] = 0;
if (old)
snprintf(buf, 1023, "%s %s", old, new);
else
snprintf(buf, 1023, "%s", new);
return setenv(opt, buf, 1);
}
Apr 29, 2009
Apr 29, 2009
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
static void setenv_cstp_opts(struct openconnect_info *vpninfo)
{
char *env_buf;
int buflen = 0;
int bufofs = 0;
struct vpn_option *opt;
for (opt = vpninfo->cstp_options; opt; opt = opt->next)
buflen += 2 + strlen(opt->option) + strlen(opt->value);
env_buf = malloc(buflen + 1);
if (!env_buf)
return;
env_buf[buflen] = 0;
for (opt = vpninfo->cstp_options; opt; opt = opt->next)
bufofs += snprintf(env_buf + bufofs, buflen - bufofs,
"%s=%s\n", opt->option, opt->value);
setenv("CISCO_CSTP_OPTIONS", env_buf, 1);
free(env_buf);
}
Apr 11, 2010
Apr 11, 2010
224
225
226
227
228
static void set_banner(struct openconnect_info *vpninfo)
{
char *banner, *q;
const char *p;
Apr 23, 2012
Apr 23, 2012
229
if (!vpninfo->banner || !(banner = malloc(strlen(vpninfo->banner)+1))) {
Apr 11, 2010
Apr 11, 2010
230
231
232
233
234
235
236
unsetenv("CISCO_BANNER");
return;
}
p = vpninfo->banner;
q = banner;
while (*p) {
Nov 4, 2011
Nov 4, 2011
237
238
if (*p == '%' && isxdigit((int)(unsigned char)p[1]) &&
isxdigit((int)(unsigned char)p[2])) {
Apr 11, 2010
Apr 11, 2010
239
240
241
242
243
244
245
246
247
248
249
*(q++) = unhex(p + 1);
p += 3;
} else
*(q++) = *(p++);
}
*q = 0;
setenv("CISCO_BANNER", banner, 1);
free(banner);
}
Oct 6, 2008
Oct 6, 2008
250
static void set_script_env(struct openconnect_info *vpninfo)
Sep 29, 2008
Sep 29, 2008
251
{
Jan 1, 2010
Jan 1, 2010
252
253
254
255
256
char host[80];
int ret = getnameinfo(vpninfo->peer_addr, vpninfo->peer_addrlen, host,
sizeof(host), NULL, 0, NI_NUMERICHOST);
if (!ret)
setenv("VPNGATEWAY", host, 1);
Feb 27, 2010
Feb 27, 2010
257
Apr 11, 2010
Apr 11, 2010
258
set_banner(vpninfo);
Sep 30, 2008
Sep 30, 2008
259
unsetenv("CISCO_SPLIT_INC");
Apr 29, 2009
Apr 29, 2009
260
unsetenv("CISCO_SPLIT_EXC");
Sep 30, 2008
Sep 30, 2008
261
Sep 30, 2008
Sep 30, 2008
262
setenv_int("INTERNAL_IP4_MTU", vpninfo->mtu);
Sep 30, 2008
Sep 30, 2008
263
Nov 2, 2009
Nov 2, 2009
264
265
if (vpninfo->vpn_addr) {
setenv("INTERNAL_IP4_ADDRESS", vpninfo->vpn_addr, 1);
Nov 3, 2009
Nov 3, 2009
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
if (vpninfo->vpn_netmask) {
struct in_addr addr;
struct in_addr mask;
if (inet_aton(vpninfo->vpn_addr, &addr) &&
inet_aton(vpninfo->vpn_netmask, &mask)) {
char *netaddr;
addr.s_addr &= mask.s_addr;
netaddr = inet_ntoa(addr);
setenv("INTERNAL_IP4_NETADDR", netaddr, 1);
setenv("INTERNAL_IP4_NETMASK", vpninfo->vpn_netmask, 1);
setenv_int("INTERNAL_IP4_NETMASKLEN", netmasklen(mask));
}
}
Nov 2, 2009
Nov 2, 2009
282
283
284
285
286
}
if (vpninfo->vpn_addr6) {
setenv("INTERNAL_IP6_ADDRESS", vpninfo->vpn_addr6, 1);
setenv("INTERNAL_IP6_NETMASK", vpninfo->vpn_netmask6, 1);
}
Apr 9, 2009
Apr 9, 2009
287
Sep 30, 2008
Sep 30, 2008
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
if (vpninfo->vpn_dns[0])
setenv("INTERNAL_IP4_DNS", vpninfo->vpn_dns[0], 1);
else
unsetenv("INTERNAL_IP4_DNS");
if (vpninfo->vpn_dns[1])
appendenv("INTERNAL_IP4_DNS", vpninfo->vpn_dns[1]);
if (vpninfo->vpn_dns[2])
appendenv("INTERNAL_IP4_DNS", vpninfo->vpn_dns[2]);
if (vpninfo->vpn_nbns[0])
setenv("INTERNAL_IP4_NBNS", vpninfo->vpn_nbns[0], 1);
else
unsetenv("INTERNAL_IP4_NBNS");
if (vpninfo->vpn_nbns[1])
appendenv("INTERNAL_IP4_NBNS", vpninfo->vpn_nbns[1]);
if (vpninfo->vpn_nbns[2])
appendenv("INTERNAL_IP4_NBNS", vpninfo->vpn_nbns[2]);
if (vpninfo->vpn_domain)
setenv("CISCO_DEF_DOMAIN", vpninfo->vpn_domain, 1);
else unsetenv ("CISCO_DEF_DOMAIN");
Oct 24, 2008
Oct 24, 2008
309
Apr 29, 2009
Apr 29, 2009
310
311
312
if (vpninfo->vpn_proxy_pac)
setenv("CISCO_PROXY_PAC", vpninfo->vpn_proxy_pac, 1);
Jun 8, 2012
Jun 8, 2012
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
if (vpninfo->split_dns) {
char *list;
int len = 0;
struct split_include *dns = vpninfo->split_dns;
while (dns) {
len += strlen(dns->route) + 1;
dns = dns->next;
}
list = malloc(len);
if (list) {
char *p = list;
dns = vpninfo->split_dns;
while (1) {
strcpy(p, dns->route);
p += strlen(p);
dns = dns->next;
if (!dns)
break;
Jun 13, 2012
Jun 13, 2012
333
*(p++) = ',';
Jun 8, 2012
Jun 8, 2012
334
335
336
337
338
}
setenv("CISCO_SPLIT_DNS", list, 1);
free(list);
}
}
Oct 24, 2008
Oct 24, 2008
339
340
341
if (vpninfo->split_includes) {
struct split_include *this = vpninfo->split_includes;
int nr_split_includes = 0;
Nov 11, 2009
Nov 11, 2009
342
int nr_v6_split_includes = 0;
Oct 24, 2008
Oct 24, 2008
343
344
while (this) {
Sep 27, 2011
Sep 27, 2011
345
process_split_xxclude(vpninfo, 1, this->route,
Nov 11, 2009
Nov 11, 2009
346
347
&nr_split_includes,
&nr_v6_split_includes);
Oct 24, 2008
Oct 24, 2008
348
349
this = this->next;
}
Nov 11, 2009
Nov 11, 2009
350
351
352
353
if (nr_split_includes)
setenv_int("CISCO_SPLIT_INC", nr_split_includes);
if (nr_v6_split_includes)
setenv_int("CISCO_IPV6_SPLIT_INC", nr_v6_split_includes);
Apr 9, 2009
Apr 9, 2009
354
}
Apr 29, 2009
Apr 29, 2009
355
356
357
if (vpninfo->split_excludes) {
struct split_include *this = vpninfo->split_excludes;
int nr_split_excludes = 0;
Nov 11, 2009
Nov 11, 2009
358
int nr_v6_split_excludes = 0;
Apr 9, 2009
Apr 9, 2009
359
Apr 29, 2009
Apr 29, 2009
360
while (this) {
Sep 27, 2011
Sep 27, 2011
361
process_split_xxclude(vpninfo, 0, this->route,
Nov 11, 2009
Nov 11, 2009
362
363
&nr_split_excludes,
&nr_v6_split_excludes);
Apr 29, 2009
Apr 29, 2009
364
365
this = this->next;
}
Nov 11, 2009
Nov 11, 2009
366
367
368
369
if (nr_split_excludes)
setenv_int("CISCO_SPLIT_EXC", nr_split_excludes);
if (nr_v6_split_excludes)
setenv_int("CISCO_IPV6_SPLIT_EXC", nr_v6_split_excludes);
Apr 29, 2009
Apr 29, 2009
370
}
Apr 29, 2009
Apr 29, 2009
371
setenv_cstp_opts(vpninfo);
Oct 6, 2008
Oct 6, 2008
372
373
}
Apr 10, 2012
Apr 10, 2012
374
int script_config_tun(struct openconnect_info *vpninfo, const char *reason)
Oct 6, 2008
Oct 6, 2008
375
{
Apr 10, 2012
Apr 10, 2012
376
377
378
379
if (!vpninfo->vpnc_script)
return 0;
setenv("reason", reason, 1);
Jan 5, 2010
Jan 5, 2010
380
381
if (system(vpninfo->vpnc_script)) {
int e = errno;
Jun 27, 2011
Jun 27, 2011
382
vpn_progress(vpninfo, PRG_ERR,
Apr 10, 2012
Apr 10, 2012
383
384
_("Failed to spawn script '%s' for %s: %s\n"),
vpninfo->vpnc_script, reason, strerror(e));
Jan 5, 2010
Jan 5, 2010
385
386
return -e;
}
Sep 29, 2008
Sep 29, 2008
387
return 0;
Sep 29, 2008
Sep 29, 2008
388
389
}
Dec 12, 2011
Dec 12, 2011
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
#ifdef __sun__
static int link_proto(int unit_nr, const char *devname, uint64_t flags)
{
int ip_fd, mux_id, tun2_fd;
struct lifreq ifr;
tun2_fd = open("/dev/tun", O_RDWR);
if (tun2_fd < 0) {
perror(_("Could not /dev/tun for plumbing"));
return -EIO;
}
if (ioctl(tun2_fd, I_PUSH, "ip") < 0) {
perror(_("Can't push IP"));
close(tun2_fd);
return -EIO;
}
sprintf(ifr.lifr_name, "tun%d", unit_nr);
ifr.lifr_ppa = unit_nr;
ifr.lifr_flags = flags;
if (ioctl(tun2_fd, SIOCSLIFNAME, &ifr) < 0) {
perror(_("Can't set ifname"));
close(tun2_fd);
return -1;
}
ip_fd = open(devname, O_RDWR);
if (ip_fd < 0) {
fprintf(stderr, _("Can't open %s: %s"), devname,
strerror(errno));
close(tun2_fd);
return -1;
}
mux_id = ioctl(ip_fd, I_LINK, tun2_fd);
if (mux_id < 0) {
fprintf(stderr, _("Can't plumb %s for IPv%d: %s\n"),
ifr.lifr_name, (flags == IFF_IPV4) ? 4 : 6,
strerror(errno));
close(tun2_fd);
close(ip_fd);
return -1;
}
close(tun2_fd);
return ip_fd;
}
#endif
Apr 10, 2012
Apr 10, 2012
440
Jun 1, 2012
Jun 1, 2012
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
#ifdef SIOCIFCREATE
static int bsd_open_tun(char *tun_name)
{
int fd;
int s;
struct ifreq ifr;
fd = open(tun_name, O_RDWR);
if (fd >= 0) {
return fd;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return -1;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name + 5, sizeof(ifr.ifr_name) - 1);
if (!ioctl(s, SIOCIFCREATE, &ifr))
fd = open(tun_name, O_RDWR);
close(s);
}
return fd;
}
#else
#define bsd_open_tun(tun_name) open(tun_name, O_RDWR)
#endif
Apr 10, 2012
Apr 10, 2012
469
470
static int os_setup_tun(struct openconnect_info *vpninfo)
{
Jun 1, 2012
Jun 1, 2012
471
int tun_fd = -1;
Apr 10, 2012
Apr 10, 2012
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
#ifdef IFF_TUN /* Linux */
struct ifreq ifr;
int tunerr;
tun_fd = open("/dev/net/tun", O_RDWR);
if (tun_fd < 0) {
/* Android has /dev/tun instead of /dev/net/tun
Since other systems might have too, just try it
as a fallback instead of using ifdef __ANDROID__ */
tunerr = errno;
tun_fd = open("/dev/tun", O_RDWR);
}
if (tun_fd < 0) {
/* If the error on /dev/tun is ENOENT, that's boring.
Use the error we got on /dev/net/tun instead */
if (errno != -ENOENT)
tunerr = errno;
vpn_progress(vpninfo, PRG_ERR,
_("Failed to open tun device: %s\n"),
strerror(tunerr));
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
if (vpninfo->ifname)
strncpy(ifr.ifr_name, vpninfo->ifname,
sizeof(ifr.ifr_name) - 1);
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("TUNSETIFF failed: %s\n"),
strerror(errno));
exit(1);
}
if (!vpninfo->ifname)
vpninfo->ifname = strdup(ifr.ifr_name);
#elif defined (__sun__)
static char tun_name[80];
int unit_nr;
tun_fd = open("/dev/tun", O_RDWR);
if (tun_fd < 0) {
perror(_("open /dev/tun"));
return -EIO;
}
unit_nr = ioctl(tun_fd, TUNNEWPPA, -1);
if (unit_nr < 0) {
perror(_("Failed to create new tun"));
close(tun_fd);
return -EIO;
}
if (ioctl(tun_fd, I_SRDOPT, RMSGD) < 0) {
perror(_("Failed to put tun file descriptor into message-discard mode"));
close(tun_fd);
return -EIO;
}
sprintf(tun_name, "tun%d", unit_nr);
vpninfo->ifname = strdup(tun_name);
vpninfo->ip_fd = link_proto(unit_nr, "/dev/udp", IFF_IPV4);
if (vpninfo->ip_fd < 0) {
close(tun_fd);
return -EIO;
}
if (vpninfo->vpn_addr6) {
vpninfo->ip6_fd = link_proto(unit_nr, "/dev/udp6", IFF_IPV6);
if (vpninfo->ip6_fd < 0) {
close(tun_fd);
close(vpninfo->ip_fd);
vpninfo->ip_fd = -1;
return -EIO;
}
} else
vpninfo->ip6_fd = -1;
#else /* BSD et al have /dev/tun$x devices */
static char tun_name[80];
int i;
Jun 1, 2012
Jun 1, 2012
555
556
557
558
559
560
561
562
563
564
565
566
567
if (vpninfo->ifname) {
char *endp = NULL;
if (strncmp(vpninfo->ifname, "tun", 3) ||
((void)strtol(vpninfo->ifname + 3, &endp, 10), !endp) ||
*endp) {
vpn_progress(vpninfo, PRG_ERR,
_("Invalid interface name '%s'; must match 'tun%%d'\n"),
vpninfo->ifname);
return -EINVAL;
}
snprintf(tun_name, sizeof(tun_name),
"/dev/%s", vpninfo->ifname);
Jun 1, 2012
Jun 1, 2012
568
tun_fd = bsd_open_tun(tun_name);
Jun 1, 2012
Jun 1, 2012
569
570
571
572
573
574
575
if (tun_fd < 0) {
int err = errno;
vpn_progress(vpninfo, PRG_ERR,
_("Cannot open '%s': %s\n"),
tun_name, strerror(err));
return -EINVAL;
}
Jun 1, 2012
Jun 1, 2012
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
}
#ifdef HAVE_FDEVNAME_R
/* We don't have to iterate over the possible devices; on FreeBSD
at least, opening /dev/tun will give us the next available
device. */
if (tun_fd < 0) {
tun_fd = open("/dev/tun", O_RDWR);
if (tun_fd >= 0) {
if (!fdevname_r(tun_fd, tun_name, sizeof(tun_name)) ||
strncmp(tun_name, "tun", 3)) {
close(tun_fd);
tun_fd = -1;
} else
vpninfo->ifname = strdup(tun_name);
}
}
#endif
if (tun_fd < 0) {
Jun 1, 2012
Jun 1, 2012
594
595
for (i = 0; i < 255; i++) {
sprintf(tun_name, "/dev/tun%d", i);
Jun 1, 2012
Jun 1, 2012
596
tun_fd = bsd_open_tun(tun_name);
Jun 1, 2012
Jun 1, 2012
597
598
599
600
601
602
603
604
if (tun_fd >= 0)
break;
}
if (tun_fd < 0) {
perror(_("open tun"));
exit(1);
}
vpninfo->ifname = strdup(tun_name + 5);
Apr 10, 2012
Apr 10, 2012
605
606
607
608
609
610
611
612
613
614
615
616
}
#ifdef TUNSIFHEAD
i = 1;
if (ioctl(tun_fd, TUNSIFHEAD, &i) < 0) {
perror(_("TUNSIFHEAD"));
exit(1);
}
#endif
#endif
return tun_fd;
}
Sep 29, 2008
Sep 29, 2008
617
/* Set up a tuntap device. */
Oct 5, 2008
Oct 5, 2008
618
int setup_tun(struct openconnect_info *vpninfo)
Sep 29, 2008
Sep 29, 2008
619
620
621
{
int tun_fd;
Feb 24, 2010
Feb 24, 2010
622
623
set_script_env(vpninfo);
Oct 6, 2008
Oct 6, 2008
624
625
626
627
628
if (vpninfo->script_tun) {
pid_t child;
int fds[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds)) {
Sep 22, 2011
Sep 22, 2011
629
perror(_("socketpair"));
Oct 6, 2008
Oct 6, 2008
630
631
632
633
634
exit(1);
}
tun_fd = fds[0];
child = fork();
if (child < 0) {
Sep 22, 2011
Sep 22, 2011
635
perror(_("fork"));
Oct 6, 2008
Oct 6, 2008
636
637
638
639
640
exit(1);
} else if (!child) {
close(tun_fd);
setenv_int("VPNFD", fds[1]);
execl("/bin/sh", "/bin/sh", "-c", vpninfo->vpnc_script, NULL);
Sep 22, 2011
Sep 22, 2011
641
perror(_("execl"));
Oct 6, 2008
Oct 6, 2008
642
643
exit(1);
}
Oct 6, 2008
Oct 6, 2008
644
close(fds[1]);
Oct 6, 2008
Oct 6, 2008
645
vpninfo->script_tun = child;
Sep 22, 2011
Sep 22, 2011
646
vpninfo->ifname = strdup(_("(script)"));
Oct 6, 2008
Oct 6, 2008
647
} else {
Apr 10, 2012
Apr 10, 2012
648
script_config_tun(vpninfo, "pre-init");
Nov 3, 2009
Nov 3, 2009
649
Apr 10, 2012
Apr 10, 2012
650
651
652
tun_fd = os_setup_tun(vpninfo);
if (tun_fd < 0)
return tun_fd;
Nov 3, 2009
Nov 3, 2009
653
Apr 16, 2012
Apr 16, 2012
654
655
656
657
658
setenv("TUNDEV", vpninfo->ifname, 1);
script_config_tun(vpninfo, "connect");
/* Ancient vpnc-scripts might not get this right */
set_tun_mtu(vpninfo);
Oct 6, 2008
Oct 6, 2008
659
}
Sep 29, 2008
Sep 29, 2008
660
Oct 14, 2008
Oct 14, 2008
661
662
fcntl(tun_fd, F_SETFD, FD_CLOEXEC);
Sep 22, 2008
Sep 22, 2008
663
vpninfo->tun_fd = tun_fd;
Apr 9, 2009
Apr 9, 2009
664
Oct 15, 2008
Oct 15, 2008
665
666
667
668
if (vpninfo->select_nfds <= tun_fd)
vpninfo->select_nfds = tun_fd + 1;
FD_SET(tun_fd, &vpninfo->select_rfds);
Sep 26, 2008
Sep 26, 2008
669
Sep 22, 2008
Sep 22, 2008
670
671
fcntl(vpninfo->tun_fd, F_SETFL, fcntl(vpninfo->tun_fd, F_GETFL) | O_NONBLOCK);
Sep 22, 2008
Sep 22, 2008
672
673
674
return 0;
}
Dec 12, 2011
Dec 12, 2011
675
676
static struct pkt *out_pkt;
Oct 5, 2008
Oct 5, 2008
677
int tun_mainloop(struct openconnect_info *vpninfo, int *timeout)
Sep 22, 2008
Sep 22, 2008
678
679
{
int work_done = 0;
Dec 13, 2011
Dec 13, 2011
680
681
682
683
684
685
int prefix_size = 0;
#ifdef TUN_HAS_AF_PREFIX
if (!vpninfo->script_tun)
prefix_size = sizeof(int);
#endif
Sep 22, 2008
Sep 22, 2008
686
Oct 26, 2008
Oct 26, 2008
687
if (FD_ISSET(vpninfo->tun_fd, &vpninfo->select_rfds)) {
Dec 13, 2011
Dec 13, 2011
688
while (1) {
Dec 12, 2011
Dec 12, 2011
689
690
691
692
693
694
695
696
697
698
int len = vpninfo->mtu;
if (!out_pkt) {
out_pkt = malloc(sizeof(struct pkt) + len);
if (!out_pkt) {
vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
break;
}
}
Dec 13, 2011
Dec 13, 2011
699
700
701
702
len = read(vpninfo->tun_fd, out_pkt->data - prefix_size, len + prefix_size);
if (len <= prefix_size)
break;
out_pkt->len = len - prefix_size;
Dec 12, 2011
Dec 12, 2011
703
704
705
queue_packet(&vpninfo->outgoing_queue, out_pkt);
out_pkt = NULL;
Oct 26, 2008
Oct 26, 2008
706
707
708
work_done = 1;
vpninfo->outgoing_qlen++;
Oct 26, 2008
Oct 26, 2008
709
if (vpninfo->outgoing_qlen == vpninfo->max_qlen) {
Oct 26, 2008
Oct 26, 2008
710
711
712
713
FD_CLR(vpninfo->tun_fd, &vpninfo->select_rfds);
break;
}
}
Oct 26, 2008
Oct 26, 2008
714
} else if (vpninfo->outgoing_qlen < vpninfo->max_qlen) {
Oct 26, 2008
Oct 26, 2008
715
FD_SET(vpninfo->tun_fd, &vpninfo->select_rfds);
Sep 22, 2008
Sep 22, 2008
716
717
}
Sep 22, 2008
Sep 22, 2008
718
719
720
/* The kernel returns -ENOMEM when the queue is full, so theoretically
we could handle that and retry... but it doesn't let us poll() for
the no-longer-full situation, so let's not bother. */
Sep 22, 2008
Sep 22, 2008
721
722
while (vpninfo->incoming_queue) {
struct pkt *this = vpninfo->incoming_queue;
Jun 1, 2009
Jun 1, 2009
723
724
725
unsigned char *data = this->data;
int len = this->len;
Nov 2, 2009
Nov 2, 2009
726
#ifdef TUN_HAS_AF_PREFIX
Aug 20, 2010
Aug 20, 2010
727
728
729
730
731
732
733
734
735
736
737
738
if (!vpninfo->script_tun) {
struct ip *iph = (void *)data;
int type;
if (iph->ip_v == 6)
type = AF_INET6;
else if (iph->ip_v == 4)
type = AF_INET;
else {
static int complained = 0;
if (!complained) {
complained = 1;
Jun 27, 2011
Jun 27, 2011
739
vpn_progress(vpninfo, PRG_ERR,
Sep 22, 2011
Sep 22, 2011
740
741
_("Unknown packet (len %d) received: %02x %02x %02x %02x...\n"),
len, data[0], data[1], data[2], data[3]);
Aug 20, 2010
Aug 20, 2010
742
743
744
}
free(this);
continue;
Nov 2, 2009
Nov 2, 2009
745
}
Aug 20, 2010
Aug 20, 2010
746
747
748
data -= 4;
len += 4;
*(int *)data = htonl(type);
Nov 2, 2009
Nov 2, 2009
749
}
Jun 1, 2009
Jun 1, 2009
750
#endif
Nov 2, 2009
Nov 2, 2009
751
vpninfo->incoming_queue = this->next;
Jun 1, 2009
Jun 1, 2009
752
Dec 7, 2011
Dec 7, 2011
753
754
755
756
757
758
759
760
761
if (write(vpninfo->tun_fd, data, len) < 0) {
/* Handle death of "script" socket */
if (vpninfo->script_tun && errno == ENOTCONN) {
vpninfo->quit_reason = "Client connection terminated";
return 1;
}
vpn_progress(vpninfo, PRG_ERR,
_("Failed to write incoming packet: %s\n"),
strerror(errno));
Oct 6, 2008
Oct 6, 2008
762
}
Jan 28, 2009
Jan 28, 2009
763
free(this);
Sep 22, 2008
Sep 22, 2008
764
765
766
767
}
/* Work is not done if we just got rid of packets off the queue */
return work_done;
}
Nov 3, 2009
Nov 3, 2009
768
769
770
771
772
void shutdown_tun(struct openconnect_info *vpninfo)
{
if (vpninfo->script_tun) {
kill(vpninfo->script_tun, SIGHUP);
Nov 3, 2009
Nov 3, 2009
773
} else {
Apr 10, 2012
Apr 10, 2012
774
script_config_tun(vpninfo, "disconnect");
Nov 3, 2009
Nov 3, 2009
775
776
777
#ifdef __sun__
close(vpninfo->ip_fd);
vpninfo->ip_fd = -1;
Dec 12, 2011
Dec 12, 2011
778
779
780
781
if (vpninfo->ip6_fd != -1) {
close(vpninfo->ip6_fd);
vpninfo->ip6_fd = -1;
}
Nov 3, 2009
Nov 3, 2009
782
#endif
Nov 3, 2009
Nov 3, 2009
783
784
785
786
787
}
close(vpninfo->tun_fd);
vpninfo->tun_fd = -1;
}