Log write failures on tun device.
[secnet] / 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
170 if (routes->up == routes->kup) return False;
171 if (st->route_type==TUN_CONFIG_IOCTL) {
172 if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
173 fd=open(st->ip_path,O_RDWR);
174 if (fd<0) {
175 fatal_perror("tun_set_route: can't open %s",st->ip_path);
176 }
177 } else {
178 fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
179 if (fd<0) {
180 fatal_perror("tun_set_route: socket()");
181 }
182 }
183 }
184 nets=routes->subnets;
185 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
186 for (i=0; i<nets->entries; i++) {
187 network=ipaddr_to_string(nets->list[i].prefix);
188 mask=ipaddr_to_string(nets->list[i].mask);
189 Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
190 st->nl.name,routes->up?"adding":"deleting",network,
191 nets->list[i].len,routes->up?"to":"from");
192 switch (st->route_type) {
193 case TUN_CONFIG_LINUX:
194 sys_cmd(st->route_path,"route",routes->up?"add":"del",
195 "-net",network,"netmask",mask,
196 "gw",secnetaddr,(char *)0);
197 break;
198 case TUN_CONFIG_BSD:
199 sys_cmd(st->route_path,"route",routes->up?"add":"del",
200 "-net",network,secnetaddr,mask,(char *)0);
201 break;
202 case TUN_CONFIG_SOLARIS25:
203 sys_cmd(st->route_path,"route",routes->up?"add":"del",
204 network,secnetaddr,(char *)0);
205 break;
206 case TUN_CONFIG_IOCTL:
207 {
208 /* darwin rtentry has a different format, use /sbin/route instead */
209 #if HAVE_NET_ROUTE_H && ! __APPLE__
210 struct rtentry rt;
211 struct sockaddr_in *sa;
212 int action;
213
214 memset(&rt,0,sizeof(rt));
215 sa=(struct sockaddr_in *)&rt.rt_dst;
216 sa->sin_family=AF_INET;
217 sa->sin_addr.s_addr=htonl(nets->list[i].prefix);
218 sa=(struct sockaddr_in *)&rt.rt_genmask;
219 sa->sin_family=AF_INET;
220 sa->sin_addr.s_addr=htonl(nets->list[i].mask);
221 sa=(struct sockaddr_in *)&rt.rt_gateway;
222 sa->sin_family=AF_INET;
223 sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
224 rt.rt_flags=RTF_UP|RTF_GATEWAY;
225 action=routes->up?SIOCADDRT:SIOCDELRT;
226 if (ioctl(fd,action,&rt)<0) {
227 fatal_perror("tun_set_route: ioctl()");
228 }
229 #else
230 fatal("tun_set_route: ioctl method not supported");
231 #endif
232 }
233 break;
234 default:
235 fatal("tun_set_route: unsupported route command type");
236 break;
237 }
238 free(network); free(mask);
239 }
240 free(secnetaddr);
241 if (st->route_type==TUN_CONFIG_IOCTL) {
242 close(fd);
243 }
244 routes->kup=routes->up;
245 return True;
246 }
247
248 static void tun_phase_hook(void *sst, uint32_t newphase)
249 {
250 struct tun *st=sst;
251 string_t hostaddr,secnetaddr;
252 char mtu[6];
253 struct netlink_client *r;
254
255 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
256 if (st->search_for_if) {
257 string_t dname;
258 int i;
259
260 dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
261 st->interface_name=safe_malloc(8,"tun_phase_hook");
262
263 for (i=0; i<255; i++) {
264 sprintf(dname,"%s%d",st->device_path,i);
265 if ((st->fd=open(dname,O_RDWR))>0) {
266 sprintf(st->interface_name,"tun%d",i);
267 Message(M_INFO,"%s: allocated network interface %s "
268 "through %s\n",st->nl.name,st->interface_name,
269 dname);
270 break;
271 }
272 }
273 if (st->fd==-1) {
274 fatal("%s: unable to open any TUN device (%s...)",
275 st->nl.name,st->device_path);
276 }
277 } else {
278 st->fd=open(st->device_path,O_RDWR);
279 if (st->fd==-1) {
280 fatal_perror("%s: unable to open TUN device file %s",
281 st->nl.name,st->device_path);
282 }
283 }
284 } else if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
285 #ifdef LINUX_TUN_SUPPORTED
286 struct ifreq ifr;
287
288 /* New TUN interface: open the device, then do ioctl TUNSETIFF
289 to set or find out the network interface name. */
290 st->fd=open(st->device_path,O_RDWR);
291 if (st->fd==-1) {
292 fatal_perror("%s: can't open device file %s",st->nl.name,
293 st->device_path);
294 }
295 memset(&ifr,0,sizeof(ifr));
296 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
297 no extra headers */
298 if (st->interface_name)
299 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
300 if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
301 fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
302 }
303 if (!st->interface_name) {
304 st->interface_name=safe_malloc(strlen(ifr.ifr_name)+1,"tun_apply");
305 strcpy(st->interface_name,ifr.ifr_name);
306 Message(M_INFO,"%s: allocated network interface %s\n",st->nl.name,
307 st->interface_name);
308 }
309 #else
310 fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected");
311 #endif /* LINUX_TUN_SUPPORTED */
312 } else if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
313 #ifdef HAVE_TUN_STREAMS
314 int tun_fd, if_fd, ppa=-1, ip_fd;
315
316 if ((ip_fd=open(st->ip_path, O_RDWR)) < 0) {
317 fatal_perror("%s: can't open %s",st->nl.name,st->ip_path);
318 }
319 if ((tun_fd=open(st->device_path,O_RDWR)) < 0) {
320 fatal_perror("%s: can't open %s",st->nl.name,st->device_path);
321 }
322 if ((ppa=ioctl(tun_fd,TUNNEWPPA,ppa)) < 0) {
323 fatal_perror("%s: can't assign new interface");
324 }
325 if ((if_fd=open(st->device_path,O_RDWR)) < 0) {
326 fatal_perror("%s: can't open %s (2)",st->nl.name,st->device_path);
327 }
328 if (ioctl(if_fd,I_PUSH,"ip") < 0) {
329 fatal_perror("%s: can't push IP module",st->nl.name);
330 }
331 if (ioctl(if_fd,IF_UNITSEL,(char *)&ppa) < 0) {
332 fatal_perror("%s: can't set ppa %d",st->nl.name,ppa);
333 }
334 if (ioctl(ip_fd, I_LINK, if_fd) < 0) {
335 fatal_perror("%s: can't link TUN device to IP",st->nl.name);
336 }
337 st->interface_name=safe_malloc(10,"tun_apply");
338 sprintf(st->interface_name,"tun%d",ppa);
339 st->fd=tun_fd;
340 #else
341 fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
342 #endif /* HAVE_TUN_STREAMS */
343 } else {
344 fatal("tun_phase_hook: unknown flavour of TUN");
345 }
346 /* All the networks we'll be using have been registered. Invoke ifconfig
347 to set the TUN device's address, and route to add routes to all
348 our networks. */
349
350 hostaddr=ipaddr_to_string(st->local_address);
351 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
352 snprintf(mtu,sizeof(mtu),"%d",st->nl.mtu);
353 mtu[5]=0;
354
355 switch (st->ifconfig_type) {
356 case TUN_CONFIG_LINUX:
357 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
358 hostaddr,"netmask","255.255.255.255","-broadcast",
359 "-multicast",
360 "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
361 break;
362 case TUN_CONFIG_BSD:
363 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
364 hostaddr,"netmask","255.255.255.255",
365 secnetaddr,"mtu",mtu,"up",(char *)0);
366 break;
367 case TUN_CONFIG_SOLARIS25:
368 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
369 hostaddr,secnetaddr,"mtu",mtu,"up",(char *)0);
370 break;
371 case TUN_CONFIG_IOCTL:
372 #if HAVE_NET_IF_H && ! __APPLE__
373 {
374 int fd;
375 struct ifreq ifr;
376 struct sockaddr_in *sa;
377 fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
378
379 /* Interface address */
380 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
381 sa=(struct sockaddr_in *)&ifr.ifr_addr;
382 memset(sa,0,sizeof(*sa));
383 sa->sin_family=AF_INET;
384 sa->sin_addr.s_addr=htonl(st->local_address);
385 if (ioctl(fd,SIOCSIFADDR, &ifr)!=0) {
386 fatal_perror("tun_apply: SIOCSIFADDR");
387 }
388 #ifdef SIOCSIFNETMASK
389 /* Netmask */
390 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
391 sa=(struct sockaddr_in *)&ifr.ifr_netmask;
392 memset(sa,0,sizeof(*sa));
393 sa->sin_family=AF_INET;
394 sa->sin_addr.s_addr=htonl(0xffffffff);
395 if (ioctl(fd,SIOCSIFNETMASK, &ifr)!=0) {
396 fatal_perror("tun_apply: SIOCSIFNETMASK");
397 }
398 #endif
399 /* Destination address (point-to-point) */
400 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
401 sa=(struct sockaddr_in *)&ifr.ifr_dstaddr;
402 memset(sa,0,sizeof(*sa));
403 sa->sin_family=AF_INET;
404 sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
405 if (ioctl(fd,SIOCSIFDSTADDR, &ifr)!=0) {
406 fatal_perror("tun_apply: SIOCSIFDSTADDR");
407 }
408 /* MTU */
409 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
410 ifr.ifr_mtu=st->nl.mtu;
411 if (ioctl(fd,SIOCSIFMTU, &ifr)!=0) {
412 fatal_perror("tun_apply: SIOCSIFMTU");
413 }
414 /* Flags */
415 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
416 ifr.ifr_flags=IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP;
417 if (ioctl(fd,SIOCSIFFLAGS, &ifr)!=0) {
418 fatal_perror("tun_apply: SIOCSIFFLAGS");
419 }
420
421 close(fd);
422 }
423 #else
424 fatal("tun_apply: ifconfig by ioctl() not supported");
425 #endif /* HAVE_NET_IF_H */
426 break;
427 default:
428 fatal("tun_apply: unsupported ifconfig method");
429 break;
430 }
431
432 for (r=st->nl.clients; r; r=r->next) {
433 tun_set_route(st,r);
434 }
435
436 /* Register for poll() */
437 register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
438 }
439
440 static list_t *tun_create(closure_t *self, struct cloc loc, dict_t *context,
441 list_t *args,uint32_t default_flavour)
442 {
443 struct tun *st;
444 item_t *item;
445 dict_t *dict;
446 string_t flavour,type;
447
448 st=safe_malloc(sizeof(*st),"tun_apply");
449
450 /* First parameter must be a dict */
451 item=list_elem(args,0);
452 if (!item || item->type!=t_dict)
453 cfgfatal(loc,"tun","parameter must be a dictionary\n");
454
455 dict=item->data.dict;
456
457 st->netlink_to_tunnel=
458 netlink_init(&st->nl,st,loc,dict,
459 "netlink-tun",tun_set_route,tun_deliver_to_kernel);
460
461 flavour=dict_read_string(dict,"flavour",False,"tun-netlink",loc);
462 if (flavour)
463 st->tun_flavour=string_to_word(flavour,loc,flavours,"tun-flavour");
464 else
465 st->tun_flavour=default_flavour;
466
467 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
468 st->ip_path=dict_read_string(dict,"ip-path",False,"tun-netlink",loc);
469 st->interface_name=dict_read_string(dict,"interface",False,
470 "tun-netlink",loc);
471 st->search_for_if=dict_read_bool(dict,"interface-search",False,
472 "tun-netlink",loc,st->device_path==NULL);
473
474 type=dict_read_string(dict,"ifconfig-type",False,"tun-netlink",loc);
475 if (type) st->ifconfig_type=string_to_word(type,loc,config_types,
476 "ifconfig-type");
477 else st->ifconfig_type=TUN_CONFIG_GUESS;
478 st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
479 "tun-netlink",loc);
480
481 type=dict_read_string(dict,"route-type",False,"tun-netlink",loc);
482 if (type) st->route_type=string_to_word(type,loc,config_types,
483 "route-type");
484 else st->route_type=TUN_CONFIG_GUESS;
485 st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
486
487 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
488 st->local_address=string_item_to_ipaddr(
489 dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
490
491 if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
492 /* If we haven't been told what type of TUN we're using, take
493 a guess based on the system details. */
494 struct utsname u;
495 if (uname(&u)<0) {
496 fatal_perror("tun_create: uname");
497 }
498 if (strcmp(u.sysname,"Linux")==0) {
499 st->tun_flavour=TUN_FLAVOUR_LINUX;
500 } else if (strcmp(u.sysname,"SunOS")==0) {
501 st->tun_flavour=TUN_FLAVOUR_STREAMS;
502 } else if (strcmp(u.sysname,"FreeBSD")==0
503 || strcmp(u.sysname,"Darwin")==0) {
504 st->tun_flavour=TUN_FLAVOUR_BSD;
505 }
506 }
507 if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
508 cfgfatal(loc,"tun","cannot guess which type of TUN is in use; "
509 "specify the flavour explicitly\n");
510 }
511
512 if (st->ifconfig_type==TUN_CONFIG_GUESS) {
513 switch (st->tun_flavour) {
514 case TUN_FLAVOUR_LINUX:
515 st->ifconfig_type=TUN_CONFIG_IOCTL;
516 break;
517 case TUN_FLAVOUR_BSD:
518 #if __linux__
519 /* XXX on Linux we still want TUN_CONFIG_IOCTL. Perhaps we can
520 use this on BSD too. */
521 st->ifconfig_type=TUN_CONFIG_IOCTL;
522 #else
523 st->ifconfig_type=TUN_CONFIG_BSD;
524 #endif
525 break;
526 case TUN_FLAVOUR_STREAMS:
527 st->ifconfig_type=TUN_CONFIG_BSD;
528 break;
529 }
530 }
531 if (st->route_type==TUN_CONFIG_GUESS)
532 st->route_type=st->ifconfig_type;
533
534 if (st->ifconfig_type==TUN_CONFIG_GUESS) {
535 cfgfatal(loc,"tun","cannot guess which ifconfig method to use\n");
536 }
537 if (st->route_type==TUN_CONFIG_GUESS) {
538 cfgfatal(loc,"tun","cannot guess which route method to use\n");
539 }
540
541 if (st->ifconfig_type==TUN_CONFIG_IOCTL && st->ifconfig_path) {
542 cfgfatal(loc,"tun","ifconfig-type \"ioctl\" is incompatible with "
543 "ifconfig-path\n");
544 }
545 if (st->route_type==TUN_CONFIG_IOCTL && st->route_path) {
546 cfgfatal(loc,"tun","route-type \"ioctl\" is incompatible with "
547 "route-path\n");
548 }
549
550 Message(M_DEBUG_CONFIG,"%s: tun flavour %s\n",st->nl.name,
551 tun_flavour_str(st->tun_flavour));
552 switch (st->tun_flavour) {
553 case TUN_FLAVOUR_BSD:
554 if (!st->device_path) st->device_path="/dev/tun";
555 break;
556 case TUN_FLAVOUR_LINUX:
557 if (!st->device_path) st->device_path="/dev/net/tun";
558 break;
559 case TUN_FLAVOUR_STREAMS:
560 if (!st->device_path) st->device_path="/dev/tun";
561 if (st->interface_name) cfgfatal(loc,"tun","interface name cannot "
562 "be specified with STREAMS TUN\n");
563 break;
564 }
565
566 if (!st->ip_path) st->ip_path="/dev/ip";
567 if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
568 if (!st->route_path) st->route_path="route";
569
570 #ifndef HAVE_TUN_STREAMS
571 if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
572 cfgfatal(loc,"tun","TUN flavour STREAMS unsupported in this build "
573 "of secnet\n");
574 }
575 #endif
576 #ifndef LINUX_TUN_SUPPORTED
577 if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
578 cfgfatal(loc,"tun","TUN flavour LINUX unsupported in this build "
579 "of secnet\n");
580 }
581 #endif
582
583 /* Old TUN interface: the network interface name depends on which
584 /dev/tunX file we open. If 'interface-search' is set to true, treat
585 'device' as the prefix and try numbers from 0--255. If it's set
586 to false, treat 'device' as the whole name, and require than an
587 appropriate interface name be specified. */
588 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
589 if (st->search_for_if && st->interface_name) {
590 cfgfatal(loc,"tun","you may not specify an interface name "
591 "in interface-search mode\n");
592 }
593 if (!st->search_for_if && !st->interface_name) {
594 cfgfatal(loc,"tun","you must specify an interface name "
595 "when you explicitly specify a TUN device file\n");
596 }
597 }
598
599 add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
600
601 return new_closure(&st->nl.cl);
602 }
603
604 static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
605 list_t *args)
606 {
607 return tun_create(self,loc,context,args,TUN_FLAVOUR_GUESS);
608 }
609
610 static list_t *tun_bsd_apply(closure_t *self, struct cloc loc, dict_t *context,
611 list_t *args)
612 {
613 Message(M_WARNING,"(%s,%d): obsolete use of tun-old; replace with tun "
614 "and specify flavour \"bsd\".\n",loc.file,loc.line);
615 return tun_create(self,loc,context,args,TUN_FLAVOUR_BSD);
616 }
617
618 void tun_module(dict_t *dict)
619 {
620 add_closure(dict,"tun",tun_apply);
621 add_closure(dict,"tun-old",tun_bsd_apply);
622 }