chiark / gitweb /
transform: Do not look at any bytes of PKCS#5 padding other than the last
[secnet.git] / tun.c
1 #include "secnet.h"
2 #include "util.h"
3 #include "netlink.h"
4 #include <stdio.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <sys/utsname.h>
11 #include <sys/socket.h>
12
13 #ifdef HAVE_NET_IF_H
14 #include <net/if.h>
15 #ifdef HAVE_LINUX_IF_H
16 #include <linux/if_tun.h>
17 #define LINUX_TUN_SUPPORTED
18 #endif
19 #endif
20
21 #ifdef HAVE_NET_ROUTE_H
22 #include <net/route.h>
23 #endif
24
25 #if defined(HAVE_STROPTS_H) && defined(HAVE_SYS_SOCKIO_H) && \
26 defined(HAVE_NET_IF_TUN_H)
27 #define HAVE_TUN_STREAMS
28 #endif
29
30 #ifdef HAVE_TUN_STREAMS
31 #include <stropts.h>
32 #include <sys/sockio.h>
33 #include <net/if_tun.h>
34 #endif
35
36 #define TUN_FLAVOUR_GUESS   0
37 #define TUN_FLAVOUR_BSD     1
38 #define TUN_FLAVOUR_LINUX   2
39 #define TUN_FLAVOUR_STREAMS 3
40
41 static struct flagstr flavours[]={
42     {"guess", TUN_FLAVOUR_GUESS},
43     {"bsd", TUN_FLAVOUR_BSD},
44     {"BSD", TUN_FLAVOUR_BSD},
45     {"linux", TUN_FLAVOUR_LINUX},
46     {"streams", TUN_FLAVOUR_STREAMS},
47     {"STREAMS", TUN_FLAVOUR_STREAMS},
48     {NULL, 0}
49 };
50
51 #define TUN_CONFIG_GUESS      0
52 #define TUN_CONFIG_IOCTL      1
53 #define TUN_CONFIG_BSD        2
54 #define TUN_CONFIG_LINUX      3
55 #define TUN_CONFIG_SOLARIS25  4
56
57 static struct flagstr config_types[]={
58     {"guess", TUN_CONFIG_GUESS},
59     {"ioctl", TUN_CONFIG_IOCTL},
60     {"bsd", TUN_CONFIG_BSD},
61     {"BSD", TUN_CONFIG_BSD},
62     {"linux", TUN_CONFIG_LINUX},
63     {"solaris-2.5", TUN_CONFIG_SOLARIS25},
64     {NULL, 0}
65 };
66
67 /* Connection to the kernel through the universal TUN/TAP driver */
68
69 struct tun {
70     struct netlink nl;
71     int fd;
72     cstring_t device_path;
73     cstring_t ip_path;
74     string_t interface_name;
75     cstring_t ifconfig_path;
76     uint32_t ifconfig_type;
77     cstring_t route_path;
78     uint32_t route_type;
79     uint32_t tun_flavour;
80     bool_t search_for_if; /* Applies to tun-BSD only */
81     struct buffer_if *buff; /* We receive packets into here
82                                and send them to the netlink code. */
83     netlink_deliver_fn *netlink_to_tunnel;
84     uint32_t local_address; /* host interface address */
85 };
86
87 static cstring_t tun_flavour_str(uint32_t flavour)
88 {
89     switch (flavour) {
90     case TUN_FLAVOUR_GUESS: return "guess";
91     case TUN_FLAVOUR_BSD: return "BSD";
92     case TUN_FLAVOUR_LINUX: return "linux";
93     case TUN_FLAVOUR_STREAMS: return "STREAMS";
94     default: return "unknown";
95     }
96 }
97
98 static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
99                           int *timeout_io)
100 {
101     struct tun *st=sst;
102     *nfds_io=1;
103     fds[0].fd=st->fd;
104     fds[0].events=POLLIN;
105     return 0;
106 }
107
108 static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds)
109 {
110     struct tun *st=sst;
111     int l;
112
113     if (nfds==0) return;
114     if (fds[0].revents&POLLERR) {
115         printf("tun_afterpoll: hup!\n");
116     }
117     if (fds[0].revents&POLLIN) {
118         BUF_ALLOC(st->buff,"tun_afterpoll");
119         buffer_init(st->buff,st->nl.max_start_pad);
120         l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad);
121         if (l<0) {
122             fatal_perror("tun_afterpoll: read()");
123         }
124         if (l==0) {
125             fatal("tun_afterpoll: read()=0; device gone away?");
126         }
127         if (l>0) {
128             st->buff->size=l;
129             st->netlink_to_tunnel(&st->nl,st->buff);
130             BUF_ASSERT_FREE(st->buff);
131         }
132     }
133 }
134
135 static void tun_deliver_to_kernel(void *sst, struct buffer_if *buf)
136 {
137     struct tun *st=sst;
138     ssize_t rc;
139
140     BUF_ASSERT_USED(buf);
141     
142     /* Log errors, so we can tell what's going on, but only once a
143        minute, so we don't flood the logs.  Short writes count as
144        errors. */
145     rc = write(st->fd,buf->start,buf->size);
146     if(rc != buf->size) {
147         static struct timeval last_report;
148         if(tv_now_global.tv_sec >= last_report.tv_sec + 60) {
149             if(rc < 0)
150                 Message(M_WARNING,
151                         "failed to deliver packet to tun device: %s\n",
152                         strerror(errno));
153             else
154                 Message(M_WARNING,
155                         "truncated packet delivered to tun device\n");
156             last_report = tv_now_global;
157         }
158     }
159     BUF_FREE(buf);
160 }
161
162 static bool_t tun_set_route(void *sst, struct netlink_client *routes)
163 {
164     struct tun *st=sst;
165     string_t network, mask, secnetaddr;
166     struct subnet_list *nets;
167     int32_t i;
168     int fd=-1;
169     bool_t up;
170
171     if (routes->options & OPT_SOFTROUTE)
172         up = routes->up;
173     else
174         up = routes->link_quality > LINK_QUALITY_UNUSED;
175
176     if (up == routes->kup) return False;
177     if (st->route_type==TUN_CONFIG_IOCTL) {
178         if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
179             fd=open(st->ip_path,O_RDWR);
180             if (fd<0) {
181                 fatal_perror("tun_set_route: can't open %s",st->ip_path);
182             }
183         } else {
184             fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
185             if (fd<0) {
186                 fatal_perror("tun_set_route: socket()");
187             }
188         }
189     }
190     nets=routes->subnets;
191     secnetaddr=ipaddr_to_string(st->nl.secnet_address);
192     for (i=0; i<nets->entries; i++) {
193         network=ipaddr_to_string(nets->list[i].prefix);
194         mask=ipaddr_to_string(nets->list[i].mask);
195         Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
196                 st->nl.name,up?"adding":"deleting",network,
197                 nets->list[i].len,up?"to":"from");
198         switch (st->route_type) {
199         case TUN_CONFIG_LINUX:
200             sys_cmd(st->route_path,"route",up?"add":"del",
201                     "-net",network,"netmask",mask,
202                     "gw",secnetaddr,(char *)0);
203             break;
204         case TUN_CONFIG_BSD:
205             sys_cmd(st->route_path,"route",up?"add":"del",
206                     "-net",network,secnetaddr,mask,(char *)0);
207             break;
208         case TUN_CONFIG_SOLARIS25:
209             sys_cmd(st->route_path,"route",up?"add":"del",
210                     network,secnetaddr,(char *)0);
211             break;
212         case TUN_CONFIG_IOCTL:
213         {
214           /* darwin rtentry has a different format, use /sbin/route instead */
215 #if HAVE_NET_ROUTE_H && ! __APPLE__
216             struct rtentry rt;
217             struct sockaddr_in *sa;
218             int action;
219             
220             FILLZERO(rt);
221             sa=(struct sockaddr_in *)&rt.rt_dst;
222             sa->sin_family=AF_INET;
223             sa->sin_addr.s_addr=htonl(nets->list[i].prefix);
224             sa=(struct sockaddr_in *)&rt.rt_genmask;
225             sa->sin_family=AF_INET;
226             sa->sin_addr.s_addr=htonl(nets->list[i].mask);
227             sa=(struct sockaddr_in *)&rt.rt_gateway;
228             sa->sin_family=AF_INET;
229             sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
230             rt.rt_flags=RTF_UP|RTF_GATEWAY;
231             action=up?SIOCADDRT:SIOCDELRT;
232             if (ioctl(fd,action,&rt)<0) {
233                 fatal_perror("tun_set_route: ioctl()");
234             }
235 #else
236             fatal("tun_set_route: ioctl method not supported");
237 #endif
238         }
239         break;
240         default:
241             fatal("tun_set_route: unsupported route command type");
242             break;
243         }
244         free(network); free(mask);
245     }
246     free(secnetaddr);
247     if (st->route_type==TUN_CONFIG_IOCTL) {
248         close(fd);
249     }
250     routes->kup=up;
251     return True;
252 }
253
254 static void tun_phase_hook(void *sst, uint32_t newphase)
255 {
256     struct tun *st=sst;
257     string_t hostaddr,secnetaddr;
258     char mtu[6];
259     struct netlink_client *r;
260
261     if (st->tun_flavour==TUN_FLAVOUR_BSD) {
262         if (st->search_for_if) {
263             string_t dname;
264             int i;
265
266             dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
267             st->interface_name=safe_malloc(8,"tun_phase_hook");
268         
269             for (i=0; i<255; i++) {
270                 sprintf(dname,"%s%d",st->device_path,i);
271                 if ((st->fd=open(dname,O_RDWR))>0) {
272                     sprintf(st->interface_name,"tun%d",i);
273                     Message(M_INFO,"%s: allocated network interface %s "
274                             "through %s\n",st->nl.name,st->interface_name,
275                             dname);
276                     break;
277                 }
278             }
279             if (st->fd==-1) {
280                 fatal("%s: unable to open any TUN device (%s...)",
281                       st->nl.name,st->device_path);
282             }
283         } else {
284             st->fd=open(st->device_path,O_RDWR);
285             if (st->fd==-1) {
286                 fatal_perror("%s: unable to open TUN device file %s",
287                              st->nl.name,st->device_path);
288             }
289         }
290     } else if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
291 #ifdef LINUX_TUN_SUPPORTED
292         struct ifreq ifr;
293
294         /* New TUN interface: open the device, then do ioctl TUNSETIFF
295            to set or find out the network interface name. */
296         st->fd=open(st->device_path,O_RDWR);
297         if (st->fd==-1) {
298             fatal_perror("%s: can't open device file %s",st->nl.name,
299                          st->device_path);
300         }
301         FILLZERO(ifr);
302         ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
303                                                 no extra headers */
304         if (st->interface_name)
305             strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
306         if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
307             fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
308         }
309         if (!st->interface_name) {
310             st->interface_name=safe_malloc(strlen(ifr.ifr_name)+1,"tun_apply");
311             strcpy(st->interface_name,ifr.ifr_name);
312             Message(M_INFO,"%s: allocated network interface %s\n",st->nl.name,
313                     st->interface_name);
314         }
315 #else
316         fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected");
317 #endif /* LINUX_TUN_SUPPORTED */
318     } else if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
319 #ifdef HAVE_TUN_STREAMS
320         int tun_fd, if_fd, ppa=-1, ip_fd;
321
322         if ((ip_fd=open(st->ip_path, O_RDWR)) < 0) {
323             fatal_perror("%s: can't open %s",st->nl.name,st->ip_path);
324         }
325         if ((tun_fd=open(st->device_path,O_RDWR)) < 0) {
326             fatal_perror("%s: can't open %s",st->nl.name,st->device_path);
327         }
328         if ((ppa=ioctl(tun_fd,TUNNEWPPA,ppa)) < 0) {
329             fatal_perror("%s: can't assign new interface");
330         }
331         if ((if_fd=open(st->device_path,O_RDWR)) < 0) {
332             fatal_perror("%s: can't open %s (2)",st->nl.name,st->device_path);
333         }
334         if (ioctl(if_fd,I_PUSH,"ip") < 0) {
335             fatal_perror("%s: can't push IP module",st->nl.name);
336         }
337         if (ioctl(if_fd,IF_UNITSEL,(char *)&ppa) < 0) {
338             fatal_perror("%s: can't set ppa %d",st->nl.name,ppa);
339         }
340         if (ioctl(ip_fd, I_LINK, if_fd) < 0) {
341             fatal_perror("%s: can't link TUN device to IP",st->nl.name);
342         }
343         st->interface_name=safe_malloc(10,"tun_apply");
344         sprintf(st->interface_name,"tun%d",ppa);
345         st->fd=tun_fd;
346 #else
347         fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
348 #endif /* HAVE_TUN_STREAMS */
349     } else {
350         fatal("tun_phase_hook: unknown flavour of TUN");
351     }
352     /* All the networks we'll be using have been registered. Invoke ifconfig
353        to set the TUN device's address, and route to add routes to all
354        our networks. */
355
356     hostaddr=ipaddr_to_string(st->local_address);
357     secnetaddr=ipaddr_to_string(st->nl.secnet_address);
358     snprintf(mtu,sizeof(mtu),"%d",st->nl.mtu);
359     mtu[5]=0;
360
361     switch (st->ifconfig_type) {
362     case TUN_CONFIG_LINUX:
363         sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
364                 hostaddr,"netmask","255.255.255.255","-broadcast",
365                 "-multicast",
366                 "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
367         break;
368     case TUN_CONFIG_BSD:
369         sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
370                 hostaddr,"netmask","255.255.255.255",
371                 secnetaddr,"mtu",mtu,"up",(char *)0);
372         break;
373     case TUN_CONFIG_SOLARIS25:
374         sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
375                 hostaddr,secnetaddr,"mtu",mtu,"up",(char *)0);
376         break;
377     case TUN_CONFIG_IOCTL:
378 #if HAVE_NET_IF_H && ! __APPLE__
379     {
380         int fd;
381         struct ifreq ifr;
382         struct sockaddr_in *sa;
383         fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
384
385         /* Interface address */
386         strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
387         sa=(struct sockaddr_in *)&ifr.ifr_addr;
388         FILLZERO(*sa);
389         sa->sin_family=AF_INET;
390         sa->sin_addr.s_addr=htonl(st->local_address);
391         if (ioctl(fd,SIOCSIFADDR, &ifr)!=0) {
392             fatal_perror("tun_apply: SIOCSIFADDR");
393         }
394 #ifdef SIOCSIFNETMASK
395         /* Netmask */
396         strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
397         sa=(struct sockaddr_in *)&ifr.ifr_netmask;
398         FILLZERO(*sa);
399         sa->sin_family=AF_INET;
400         sa->sin_addr.s_addr=htonl(0xffffffff);
401         if (ioctl(fd,SIOCSIFNETMASK, &ifr)!=0) {
402             fatal_perror("tun_apply: SIOCSIFNETMASK");
403         }
404 #endif
405         /* Destination address (point-to-point) */
406         strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
407         sa=(struct sockaddr_in *)&ifr.ifr_dstaddr;
408         FILLZERO(*sa);
409         sa->sin_family=AF_INET;
410         sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
411         if (ioctl(fd,SIOCSIFDSTADDR, &ifr)!=0) {
412             fatal_perror("tun_apply: SIOCSIFDSTADDR");
413         }
414         /* MTU */
415         strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
416         ifr.ifr_mtu=st->nl.mtu;
417         if (ioctl(fd,SIOCSIFMTU, &ifr)!=0) {
418             fatal_perror("tun_apply: SIOCSIFMTU");
419         }
420         /* Flags */
421         strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
422         ifr.ifr_flags=IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP;
423         if (ioctl(fd,SIOCSIFFLAGS, &ifr)!=0) {
424             fatal_perror("tun_apply: SIOCSIFFLAGS");
425         }
426
427         close(fd);
428     }
429 #else
430     fatal("tun_apply: ifconfig by ioctl() not supported");
431 #endif /* HAVE_NET_IF_H */
432     break;
433     default:
434         fatal("tun_apply: unsupported ifconfig method");
435         break;
436     }
437         
438     for (r=st->nl.clients; r; r=r->next) {
439         tun_set_route(st,r);
440     }
441
442     /* Register for poll() */
443     register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
444 }
445
446 static list_t *tun_create(closure_t *self, struct cloc loc, dict_t *context,
447                           list_t *args,uint32_t default_flavour)
448 {
449     struct tun *st;
450     item_t *item;
451     dict_t *dict;
452     string_t flavour,type;
453
454     st=safe_malloc(sizeof(*st),"tun_apply");
455
456     /* First parameter must be a dict */
457     item=list_elem(args,0);
458     if (!item || item->type!=t_dict)
459         cfgfatal(loc,"tun","parameter must be a dictionary\n");
460     
461     dict=item->data.dict;
462
463     st->netlink_to_tunnel=
464         netlink_init(&st->nl,st,loc,dict,
465                      "netlink-tun",tun_set_route,tun_deliver_to_kernel);
466
467     flavour=dict_read_string(dict,"flavour",False,"tun-netlink",loc);
468     if (flavour)
469         st->tun_flavour=string_to_word(flavour,loc,flavours,"tun-flavour");
470     else
471         st->tun_flavour=default_flavour;
472
473     st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
474     st->ip_path=dict_read_string(dict,"ip-path",False,"tun-netlink",loc);
475     st->interface_name=dict_read_string(dict,"interface",False,
476                                         "tun-netlink",loc);
477     st->search_for_if=dict_read_bool(dict,"interface-search",False,
478                                      "tun-netlink",loc,st->device_path==NULL);
479
480     type=dict_read_string(dict,"ifconfig-type",False,"tun-netlink",loc);
481     if (type) st->ifconfig_type=string_to_word(type,loc,config_types,
482                                                "ifconfig-type");
483     else st->ifconfig_type=TUN_CONFIG_GUESS;
484     st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
485                                        "tun-netlink",loc);
486
487     type=dict_read_string(dict,"route-type",False,"tun-netlink",loc);
488     if (type) st->route_type=string_to_word(type,loc,config_types,
489                                             "route-type");
490     else st->route_type=TUN_CONFIG_GUESS;
491     st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
492
493     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
494     st->local_address=string_item_to_ipaddr(
495         dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
496
497     if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
498         /* If we haven't been told what type of TUN we're using, take
499            a guess based on the system details. */
500         struct utsname u;
501         if (uname(&u)<0) {
502             fatal_perror("tun_create: uname");
503         }
504         if (strcmp(u.sysname,"Linux")==0) {
505             st->tun_flavour=TUN_FLAVOUR_LINUX;
506         } else if (strcmp(u.sysname,"SunOS")==0) {
507             st->tun_flavour=TUN_FLAVOUR_STREAMS;
508         } else if (strcmp(u.sysname,"FreeBSD")==0
509                    || strcmp(u.sysname,"Darwin")==0) {
510             st->tun_flavour=TUN_FLAVOUR_BSD;
511         }
512     }
513     if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
514         cfgfatal(loc,"tun","cannot guess which type of TUN is in use; "
515                  "specify the flavour explicitly\n");
516     }
517
518     if (st->ifconfig_type==TUN_CONFIG_GUESS) {
519         switch (st->tun_flavour) {
520         case TUN_FLAVOUR_LINUX:
521             st->ifconfig_type=TUN_CONFIG_IOCTL;
522             break;
523         case TUN_FLAVOUR_BSD:
524 #if __linux__
525             /* XXX on Linux we still want TUN_CONFIG_IOCTL.  Perhaps we can
526                use this on BSD too. */
527             st->ifconfig_type=TUN_CONFIG_IOCTL;
528 #else     
529             st->ifconfig_type=TUN_CONFIG_BSD;
530 #endif
531             break;
532         case TUN_FLAVOUR_STREAMS:
533             st->ifconfig_type=TUN_CONFIG_BSD;
534             break;
535         }
536     }
537     if (st->route_type==TUN_CONFIG_GUESS)
538         st->route_type=st->ifconfig_type;
539
540     if (st->ifconfig_type==TUN_CONFIG_GUESS) {
541         cfgfatal(loc,"tun","cannot guess which ifconfig method to use\n");
542     }
543     if (st->route_type==TUN_CONFIG_GUESS) {
544         cfgfatal(loc,"tun","cannot guess which route method to use\n");
545     }
546
547     if (st->ifconfig_type==TUN_CONFIG_IOCTL && st->ifconfig_path) {
548         cfgfatal(loc,"tun","ifconfig-type \"ioctl\" is incompatible with "
549                  "ifconfig-path\n");
550     }
551     if (st->route_type==TUN_CONFIG_IOCTL && st->route_path) {
552         cfgfatal(loc,"tun","route-type \"ioctl\" is incompatible with "
553                  "route-path\n");
554     }
555
556     Message(M_DEBUG_CONFIG,"%s: tun flavour %s\n",st->nl.name,
557             tun_flavour_str(st->tun_flavour));
558     switch (st->tun_flavour) {
559     case TUN_FLAVOUR_BSD:
560         if (!st->device_path) st->device_path="/dev/tun";
561         break;
562     case TUN_FLAVOUR_LINUX:
563         if (!st->device_path) st->device_path="/dev/net/tun";
564         break;
565     case TUN_FLAVOUR_STREAMS:
566         if (!st->device_path) st->device_path="/dev/tun";
567         if (st->interface_name) cfgfatal(loc,"tun","interface name cannot "
568                                          "be specified with STREAMS TUN\n");
569         break;
570     }
571     
572     if (!st->ip_path) st->ip_path="/dev/ip";
573     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
574     if (!st->route_path) st->route_path="route";
575
576 #ifndef HAVE_TUN_STREAMS
577     if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
578         cfgfatal(loc,"tun","TUN flavour STREAMS unsupported in this build "
579                  "of secnet\n");
580     }
581 #endif
582 #ifndef LINUX_TUN_SUPPORTED
583     if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
584         cfgfatal(loc,"tun","TUN flavour LINUX unsupported in this build "
585                  "of secnet\n");
586     }
587 #endif
588
589     /* Old TUN interface: the network interface name depends on which
590        /dev/tunX file we open. If 'interface-search' is set to true, treat
591        'device' as the prefix and try numbers from 0--255. If it's set
592        to false, treat 'device' as the whole name, and require than an
593        appropriate interface name be specified. */
594     if (st->tun_flavour==TUN_FLAVOUR_BSD) {
595         if (st->search_for_if && st->interface_name) {
596             cfgfatal(loc,"tun","you may not specify an interface name "
597                      "in interface-search mode\n");
598         }
599         if (!st->search_for_if && !st->interface_name) {
600             cfgfatal(loc,"tun","you must specify an interface name "
601                      "when you explicitly specify a TUN device file\n");
602         }
603     }
604
605     add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
606
607     return new_closure(&st->nl.cl);
608 }
609
610 static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
611                          list_t *args)
612 {
613     return tun_create(self,loc,context,args,TUN_FLAVOUR_GUESS);
614 }
615
616 static list_t *tun_bsd_apply(closure_t *self, struct cloc loc, dict_t *context,
617                              list_t *args)
618 {
619     Message(M_WARNING,"(%s,%d): obsolete use of tun-old; replace with tun "
620             "and specify flavour \"bsd\".\n",loc.file,loc.line);
621     return tun_create(self,loc,context,args,TUN_FLAVOUR_BSD);
622 }
623
624 void tun_module(dict_t *dict)
625 {
626     add_closure(dict,"tun",tun_apply);
627     add_closure(dict,"tun-old",tun_bsd_apply);
628 }