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