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