netlink: Avoid crash with clientless netlink
[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>
090dbeef 6#include <errno.h>
9d3a4132
SE
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/ioctl.h>
ff05a229
SE
10#include <sys/utsname.h>
11#include <sys/socket.h>
9d3a4132 12
ff05a229
SE
13#ifdef HAVE_NET_IF_H
14#include <net/if.h>
9d3a4132 15#ifdef HAVE_LINUX_IF_H
9d3a4132 16#include <linux/if_tun.h>
ff05a229 17#define LINUX_TUN_SUPPORTED
9d3a4132 18#endif
ff05a229
SE
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) && \
26defined(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
41static 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};
9d3a4132 50
ff05a229
SE
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
57static 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};
9d3a4132
SE
66
67/* Connection to the kernel through the universal TUN/TAP driver */
68
69struct tun {
70 struct netlink nl;
71 int fd;
fe5e9cc4
SE
72 cstring_t device_path;
73 cstring_t ip_path;
9d3a4132 74 string_t interface_name;
fe5e9cc4 75 cstring_t ifconfig_path;
ff05a229 76 uint32_t ifconfig_type;
fe5e9cc4 77 cstring_t route_path;
ff05a229
SE
78 uint32_t route_type;
79 uint32_t tun_flavour;
80 bool_t search_for_if; /* Applies to tun-BSD only */
9d3a4132
SE
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;
b2a56f7c 84 uint32_t local_address; /* host interface address */
9d3a4132
SE
85};
86
fe5e9cc4 87static cstring_t tun_flavour_str(uint32_t flavour)
ff05a229
SE
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
9d3a4132 98static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
90a39563 99 int *timeout_io)
9d3a4132
SE
100{
101 struct tun *st=sst;
102 *nfds_io=1;
103 fds[0].fd=st->fd;
fe5e9cc4 104 fds[0].events=POLLIN;
9d3a4132
SE
105 return 0;
106}
107
90a39563 108static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds)
9d3a4132
SE
109{
110 struct tun *st=sst;
111 int l;
112
7138d0c5 113 if (nfds==0) return;
9d3a4132
SE
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");
3abd18e8
IJ
119 buffer_init(st->buff,calculate_max_start_pad());
120 l=read(st->fd,st->buff->start,st->buff->len-calculate_max_start_pad());
9d3a4132
SE
121 if (l<0) {
122 fatal_perror("tun_afterpoll: read()");
123 }
124 if (l==0) {
4f5e39ec 125 fatal("tun_afterpoll: read()=0; device gone away?");
9d3a4132
SE
126 }
127 if (l>0) {
128 st->buff->size=l;
469fd1d9 129 st->netlink_to_tunnel(&st->nl,st->buff);
9d3a4132
SE
130 BUF_ASSERT_FREE(st->buff);
131 }
132 }
133}
134
469fd1d9 135static void tun_deliver_to_kernel(void *sst, struct buffer_if *buf)
9d3a4132
SE
136{
137 struct tun *st=sst;
090dbeef 138 ssize_t rc;
9d3a4132
SE
139
140 BUF_ASSERT_USED(buf);
090dbeef
RK
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 }
9d3a4132
SE
159 BUF_FREE(buf);
160}
161
d3fe100d 162static bool_t tun_set_route(void *sst, struct netlink_client *routes)
9d3a4132
SE
163{
164 struct tun *st=sst;
165 string_t network, mask, secnetaddr;
d3fe100d 166 struct subnet_list *nets;
1caa23ff 167 int32_t i;
ff05a229 168 int fd=-1;
efacf9e0 169 bool_t up;
ff05a229 170
efacf9e0
ST
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;
ff05a229
SE
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",
efacf9e0
ST
196 st->nl.name,up?"adding":"deleting",network,
197 nets->list[i].len,up?"to":"from");
ff05a229
SE
198 switch (st->route_type) {
199 case TUN_CONFIG_LINUX:
efacf9e0 200 sys_cmd(st->route_path,"route",up?"add":"del",
ff05a229
SE
201 "-net",network,"netmask",mask,
202 "gw",secnetaddr,(char *)0);
203 break;
204 case TUN_CONFIG_BSD:
efacf9e0 205 sys_cmd(st->route_path,"route",up?"add":"del",
ff05a229
SE
206 "-net",network,secnetaddr,mask,(char *)0);
207 break;
208 case TUN_CONFIG_SOLARIS25:
efacf9e0 209 sys_cmd(st->route_path,"route",up?"add":"del",
ff05a229
SE
210 network,secnetaddr,(char *)0);
211 break;
212 case TUN_CONFIG_IOCTL:
213 {
ea7ec970
SE
214 /* darwin rtentry has a different format, use /sbin/route instead */
215#if HAVE_NET_ROUTE_H && ! __APPLE__
ff05a229
SE
216 struct rtentry rt;
217 struct sockaddr_in *sa;
218 int action;
219
076bb54e 220 FILLZERO(rt);
ff05a229
SE
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;
efacf9e0 231 action=up?SIOCADDRT:SIOCDELRT;
ff05a229
SE
232 if (ioctl(fd,action,&rt)<0) {
233 fatal_perror("tun_set_route: ioctl()");
234 }
235#else
4f5e39ec 236 fatal("tun_set_route: ioctl method not supported");
ff05a229 237#endif
d3fe100d 238 }
ff05a229
SE
239 break;
240 default:
4f5e39ec 241 fatal("tun_set_route: unsupported route command type");
ff05a229
SE
242 break;
243 }
244 free(network); free(mask);
245 }
246 free(secnetaddr);
247 if (st->route_type==TUN_CONFIG_IOCTL) {
248 close(fd);
9d3a4132 249 }
efacf9e0 250 routes->kup=up;
ff05a229 251 return True;
9d3a4132
SE
252}
253
254static void tun_phase_hook(void *sst, uint32_t newphase)
255{
256 struct tun *st=sst;
257 string_t hostaddr,secnetaddr;
7c006408 258 char mtu[6];
d3fe100d 259 struct netlink_client *r;
9d3a4132 260
ff05a229 261 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
9d3a4132
SE
262 if (st->search_for_if) {
263 string_t dname;
264 int i;
265
9d3a4132
SE
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) {
4f5e39ec 280 fatal("%s: unable to open any TUN device (%s...)",
9d3a4132
SE
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 }
ff05a229
SE
290 } else if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
291#ifdef LINUX_TUN_SUPPORTED
9d3a4132
SE
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 }
076bb54e 301 FILLZERO(ifr);
9d3a4132
SE
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);
9d3a4132
SE
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
4f5e39ec 316 fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected");
ff05a229
SE
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
4f5e39ec 347 fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
ff05a229
SE
348#endif /* HAVE_TUN_STREAMS */
349 } else {
4f5e39ec 350 fatal("tun_phase_hook: unknown flavour of TUN");
9d3a4132
SE
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
b2a56f7c 356 hostaddr=ipaddr_to_string(st->local_address);
9d3a4132 357 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
c1d2109a 358 snprintf(mtu,sizeof(mtu),"%d",st->nl.mtu);
9d3a4132
SE
359 mtu[5]=0;
360
fe5e9cc4 361 switch (st->ifconfig_type) {
ff05a229
SE
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:
ea7ec970 378#if HAVE_NET_IF_H && ! __APPLE__
ff05a229
SE
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;
076bb54e 388 FILLZERO(*sa);
ff05a229
SE
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;
076bb54e 398 FILLZERO(*sa);
ff05a229
SE
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;
076bb54e 408 FILLZERO(*sa);
ff05a229
SE
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 }
9d3a4132 426
ff05a229
SE
427 close(fd);
428 }
429#else
4f5e39ec 430 fatal("tun_apply: ifconfig by ioctl() not supported");
ff05a229
SE
431#endif /* HAVE_NET_IF_H */
432 break;
433 default:
4f5e39ec 434 fatal("tun_apply: unsupported ifconfig method");
ff05a229
SE
435 break;
436 }
437
d3fe100d
SE
438 for (r=st->nl.clients; r; r=r->next) {
439 tun_set_route(st,r);
9d3a4132
SE
440 }
441
442 /* Register for poll() */
443 register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
444}
445
ff05a229
SE
446static list_t *tun_create(closure_t *self, struct cloc loc, dict_t *context,
447 list_t *args,uint32_t default_flavour)
9d3a4132
SE
448{
449 struct tun *st;
450 item_t *item;
451 dict_t *dict;
ff05a229 452 string_t flavour,type;
9d3a4132
SE
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
ff05a229
SE
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
9d3a4132 473 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
ff05a229 474 st->ip_path=dict_read_string(dict,"ip-path",False,"tun-netlink",loc);
9d3a4132
SE
475 st->interface_name=dict_read_string(dict,"interface",False,
476 "tun-netlink",loc);
ff05a229
SE
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);
9d3a4132 492
9d3a4132 493 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
794f2398 494 st->local_address=string_item_to_ipaddr(
b2a56f7c 495 dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
9d3a4132 496
ff05a229
SE
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) {
621c2861 505 st->tun_flavour=TUN_FLAVOUR_LINUX;
ff05a229
SE
506 } else if (strcmp(u.sysname,"SunOS")==0) {
507 st->tun_flavour=TUN_FLAVOUR_STREAMS;
ea7ec970
SE
508 } else if (strcmp(u.sysname,"FreeBSD")==0
509 || strcmp(u.sysname,"Darwin")==0) {
ff05a229
SE
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 }
9d3a4132 517
ff05a229
SE
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:
ea7ec970 524#if __linux__
4f5e39ec
SE
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;
ea7ec970
SE
528#else
529 st->ifconfig_type=TUN_CONFIG_BSD;
530#endif
ff05a229
SE
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;
9d3a4132 539
ff05a229
SE
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 }
9d3a4132 546
ff05a229
SE
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 }
9d3a4132 555
ff05a229
SE
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 }
9d3a4132 571
ff05a229 572 if (!st->ip_path) st->ip_path="/dev/ip";
9d3a4132
SE
573 if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
574 if (!st->route_path) st->route_path="route";
ff05a229
SE
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
9d3a4132
SE
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. */
ff05a229
SE
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 }
9d3a4132
SE
603 }
604
9d3a4132
SE
605 add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
606
607 return new_closure(&st->nl.cl);
608}
609
ff05a229
SE
610static 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
616static 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
9d3a4132
SE
624void tun_module(dict_t *dict)
625{
9d3a4132 626 add_closure(dict,"tun",tun_apply);
ff05a229 627 add_closure(dict,"tun-old",tun_bsd_apply);
9d3a4132 628}