9 #include <sys/utsname.h>
10 #include <sys/socket.h>
14 #ifdef HAVE_LINUX_IF_H
15 #include <linux/if_tun.h>
16 #define LINUX_TUN_SUPPORTED
20 #ifdef HAVE_NET_ROUTE_H
21 #include <net/route.h>
24 #if defined(HAVE_STROPTS_H) && defined(HAVE_SYS_SOCKIO_H) && \
25 defined(HAVE_NET_IF_TUN_H)
26 #define HAVE_TUN_STREAMS
29 #ifdef HAVE_TUN_STREAMS
31 #include <sys/sockio.h>
32 #include <net/if_tun.h>
35 #define TUN_FLAVOUR_GUESS 0
36 #define TUN_FLAVOUR_BSD 1
37 #define TUN_FLAVOUR_LINUX 2
38 #define TUN_FLAVOUR_STREAMS 3
40 static 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},
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
56 static 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},
66 /* Connection to the kernel through the universal TUN/TAP driver */
71 cstring_t device_path;
73 string_t interface_name;
74 cstring_t ifconfig_path;
75 uint32_t ifconfig_type;
79 bool_t search_for_if; /* Applies to tun-BSD only */
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;
83 uint32_t local_address; /* host interface address */
86 static cstring_t tun_flavour_str(uint32_t 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";
97 static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
98 int *timeout_io, const struct timeval *tv_now,
104 fds[0].events=POLLIN;
108 static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
109 const struct timeval *tv_now, uint64_t *now)
115 if (fds[0].revents&POLLERR) {
116 printf("tun_afterpoll: hup!\n");
118 if (fds[0].revents&POLLIN) {
119 BUF_ALLOC(st->buff,"tun_afterpoll");
120 buffer_init(st->buff,st->nl.max_start_pad);
121 l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad);
123 fatal_perror("tun_afterpoll: read()");
126 fatal("tun_afterpoll: read()=0; device gone away?");
130 st->netlink_to_tunnel(&st->nl,st->buff);
131 BUF_ASSERT_FREE(st->buff);
136 static void tun_deliver_to_kernel(void *sst, struct buffer_if *buf)
140 BUF_ASSERT_USED(buf);
141 /* No error checking, because we'd just throw the packet away
142 anyway if it didn't work. */
143 write(st->fd,buf->start,buf->size);
147 static bool_t tun_set_route(void *sst, struct netlink_client *routes)
150 string_t network, mask, secnetaddr;
151 struct subnet_list *nets;
155 if (routes->up == routes->kup) return False;
156 if (st->route_type==TUN_CONFIG_IOCTL) {
157 if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
158 fd=open(st->ip_path,O_RDWR);
160 fatal_perror("tun_set_route: can't open %s",st->ip_path);
163 fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
165 fatal_perror("tun_set_route: socket()");
169 nets=routes->subnets;
170 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
171 for (i=0; i<nets->entries; i++) {
172 network=ipaddr_to_string(nets->list[i].prefix);
173 mask=ipaddr_to_string(nets->list[i].mask);
174 Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
175 st->nl.name,routes->up?"adding":"deleting",network,
176 nets->list[i].len,routes->up?"to":"from");
177 switch (st->route_type) {
178 case TUN_CONFIG_LINUX:
179 sys_cmd(st->route_path,"route",routes->up?"add":"del",
180 "-net",network,"netmask",mask,
181 "gw",secnetaddr,(char *)0);
184 sys_cmd(st->route_path,"route",routes->up?"add":"del",
185 "-net",network,secnetaddr,mask,(char *)0);
187 case TUN_CONFIG_SOLARIS25:
188 sys_cmd(st->route_path,"route",routes->up?"add":"del",
189 network,secnetaddr,(char *)0);
191 case TUN_CONFIG_IOCTL:
193 /* darwin rtentry has a different format, use /sbin/route instead */
194 #if HAVE_NET_ROUTE_H && ! __APPLE__
196 struct sockaddr_in *sa;
199 memset(&rt,0,sizeof(rt));
200 sa=(struct sockaddr_in *)&rt.rt_dst;
201 sa->sin_family=AF_INET;
202 sa->sin_addr.s_addr=htonl(nets->list[i].prefix);
203 sa=(struct sockaddr_in *)&rt.rt_genmask;
204 sa->sin_family=AF_INET;
205 sa->sin_addr.s_addr=htonl(nets->list[i].mask);
206 sa=(struct sockaddr_in *)&rt.rt_gateway;
207 sa->sin_family=AF_INET;
208 sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
209 rt.rt_flags=RTF_UP|RTF_GATEWAY;
210 action=routes->up?SIOCADDRT:SIOCDELRT;
211 if (ioctl(fd,action,&rt)<0) {
212 fatal_perror("tun_set_route: ioctl()");
215 fatal("tun_set_route: ioctl method not supported");
220 fatal("tun_set_route: unsupported route command type");
223 free(network); free(mask);
226 if (st->route_type==TUN_CONFIG_IOCTL) {
229 routes->kup=routes->up;
233 static void tun_phase_hook(void *sst, uint32_t newphase)
236 string_t hostaddr,secnetaddr;
238 struct netlink_client *r;
240 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
241 if (st->search_for_if) {
245 dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
246 st->interface_name=safe_malloc(8,"tun_phase_hook");
248 for (i=0; i<255; i++) {
249 sprintf(dname,"%s%d",st->device_path,i);
250 if ((st->fd=open(dname,O_RDWR))>0) {
251 sprintf(st->interface_name,"tun%d",i);
252 Message(M_INFO,"%s: allocated network interface %s "
253 "through %s\n",st->nl.name,st->interface_name,
259 fatal("%s: unable to open any TUN device (%s...)",
260 st->nl.name,st->device_path);
263 st->fd=open(st->device_path,O_RDWR);
265 fatal_perror("%s: unable to open TUN device file %s",
266 st->nl.name,st->device_path);
269 } else if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
270 #ifdef LINUX_TUN_SUPPORTED
273 /* New TUN interface: open the device, then do ioctl TUNSETIFF
274 to set or find out the network interface name. */
275 st->fd=open(st->device_path,O_RDWR);
277 fatal_perror("%s: can't open device file %s",st->nl.name,
280 memset(&ifr,0,sizeof(ifr));
281 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
283 if (st->interface_name)
284 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
285 if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
286 fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
288 if (!st->interface_name) {
289 st->interface_name=safe_malloc(strlen(ifr.ifr_name)+1,"tun_apply");
290 strcpy(st->interface_name,ifr.ifr_name);
291 Message(M_INFO,"%s: allocated network interface %s\n",st->nl.name,
295 fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected");
296 #endif /* LINUX_TUN_SUPPORTED */
297 } else if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
298 #ifdef HAVE_TUN_STREAMS
299 int tun_fd, if_fd, ppa=-1, ip_fd;
301 if ((ip_fd=open(st->ip_path, O_RDWR)) < 0) {
302 fatal_perror("%s: can't open %s",st->nl.name,st->ip_path);
304 if ((tun_fd=open(st->device_path,O_RDWR)) < 0) {
305 fatal_perror("%s: can't open %s",st->nl.name,st->device_path);
307 if ((ppa=ioctl(tun_fd,TUNNEWPPA,ppa)) < 0) {
308 fatal_perror("%s: can't assign new interface");
310 if ((if_fd=open(st->device_path,O_RDWR)) < 0) {
311 fatal_perror("%s: can't open %s (2)",st->nl.name,st->device_path);
313 if (ioctl(if_fd,I_PUSH,"ip") < 0) {
314 fatal_perror("%s: can't push IP module",st->nl.name);
316 if (ioctl(if_fd,IF_UNITSEL,(char *)&ppa) < 0) {
317 fatal_perror("%s: can't set ppa %d",st->nl.name,ppa);
319 if (ioctl(ip_fd, I_LINK, if_fd) < 0) {
320 fatal_perror("%s: can't link TUN device to IP",st->nl.name);
322 st->interface_name=safe_malloc(10,"tun_apply");
323 sprintf(st->interface_name,"tun%d",ppa);
326 fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
327 #endif /* HAVE_TUN_STREAMS */
329 fatal("tun_phase_hook: unknown flavour of TUN");
331 /* All the networks we'll be using have been registered. Invoke ifconfig
332 to set the TUN device's address, and route to add routes to all
335 hostaddr=ipaddr_to_string(st->local_address);
336 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
337 snprintf(mtu,6,"%d",st->nl.mtu);
340 switch (st->ifconfig_type) {
341 case TUN_CONFIG_LINUX:
342 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
343 hostaddr,"netmask","255.255.255.255","-broadcast",
345 "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
348 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
349 hostaddr,"netmask","255.255.255.255",
350 secnetaddr,"mtu",mtu,"up",(char *)0);
352 case TUN_CONFIG_SOLARIS25:
353 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
354 hostaddr,secnetaddr,"mtu",mtu,"up",(char *)0);
356 case TUN_CONFIG_IOCTL:
357 #if HAVE_NET_IF_H && ! __APPLE__
361 struct sockaddr_in *sa;
362 fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
364 /* Interface address */
365 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
366 sa=(struct sockaddr_in *)&ifr.ifr_addr;
367 memset(sa,0,sizeof(*sa));
368 sa->sin_family=AF_INET;
369 sa->sin_addr.s_addr=htonl(st->local_address);
370 if (ioctl(fd,SIOCSIFADDR, &ifr)!=0) {
371 fatal_perror("tun_apply: SIOCSIFADDR");
373 #ifdef SIOCSIFNETMASK
375 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
376 sa=(struct sockaddr_in *)&ifr.ifr_netmask;
377 memset(sa,0,sizeof(*sa));
378 sa->sin_family=AF_INET;
379 sa->sin_addr.s_addr=htonl(0xffffffff);
380 if (ioctl(fd,SIOCSIFNETMASK, &ifr)!=0) {
381 fatal_perror("tun_apply: SIOCSIFNETMASK");
384 /* Destination address (point-to-point) */
385 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
386 sa=(struct sockaddr_in *)&ifr.ifr_dstaddr;
387 memset(sa,0,sizeof(*sa));
388 sa->sin_family=AF_INET;
389 sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
390 if (ioctl(fd,SIOCSIFDSTADDR, &ifr)!=0) {
391 fatal_perror("tun_apply: SIOCSIFDSTADDR");
394 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
395 ifr.ifr_mtu=st->nl.mtu;
396 if (ioctl(fd,SIOCSIFMTU, &ifr)!=0) {
397 fatal_perror("tun_apply: SIOCSIFMTU");
400 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
401 ifr.ifr_flags=IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP;
402 if (ioctl(fd,SIOCSIFFLAGS, &ifr)!=0) {
403 fatal_perror("tun_apply: SIOCSIFFLAGS");
409 fatal("tun_apply: ifconfig by ioctl() not supported");
410 #endif /* HAVE_NET_IF_H */
413 fatal("tun_apply: unsupported ifconfig method");
417 for (r=st->nl.clients; r; r=r->next) {
421 /* Register for poll() */
422 register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
425 static list_t *tun_create(closure_t *self, struct cloc loc, dict_t *context,
426 list_t *args,uint32_t default_flavour)
431 string_t flavour,type;
433 st=safe_malloc(sizeof(*st),"tun_apply");
435 /* First parameter must be a dict */
436 item=list_elem(args,0);
437 if (!item || item->type!=t_dict)
438 cfgfatal(loc,"tun","parameter must be a dictionary\n");
440 dict=item->data.dict;
442 st->netlink_to_tunnel=
443 netlink_init(&st->nl,st,loc,dict,
444 "netlink-tun",tun_set_route,tun_deliver_to_kernel);
446 flavour=dict_read_string(dict,"flavour",False,"tun-netlink",loc);
448 st->tun_flavour=string_to_word(flavour,loc,flavours,"tun-flavour");
450 st->tun_flavour=default_flavour;
452 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
453 st->ip_path=dict_read_string(dict,"ip-path",False,"tun-netlink",loc);
454 st->interface_name=dict_read_string(dict,"interface",False,
456 st->search_for_if=dict_read_bool(dict,"interface-search",False,
457 "tun-netlink",loc,st->device_path==NULL);
459 type=dict_read_string(dict,"ifconfig-type",False,"tun-netlink",loc);
460 if (type) st->ifconfig_type=string_to_word(type,loc,config_types,
462 else st->ifconfig_type=TUN_CONFIG_GUESS;
463 st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
466 type=dict_read_string(dict,"route-type",False,"tun-netlink",loc);
467 if (type) st->route_type=string_to_word(type,loc,config_types,
469 else st->route_type=TUN_CONFIG_GUESS;
470 st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
472 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
473 st->local_address=string_item_to_ipaddr(
474 dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
476 if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
477 /* If we haven't been told what type of TUN we're using, take
478 a guess based on the system details. */
481 fatal_perror("tun_create: uname");
483 if (strcmp(u.sysname,"Linux")==0) {
484 if (u.release[0]=='2' && u.release[1]=='.' && u.release[3]=='.') {
485 if (u.release[2]=='2') st->tun_flavour=TUN_FLAVOUR_BSD;
486 else if (u.release[2]=='4') st->tun_flavour=TUN_FLAVOUR_LINUX;
488 } else if (strcmp(u.sysname,"SunOS")==0) {
489 st->tun_flavour=TUN_FLAVOUR_STREAMS;
490 } else if (strcmp(u.sysname,"FreeBSD")==0
491 || strcmp(u.sysname,"Darwin")==0) {
492 st->tun_flavour=TUN_FLAVOUR_BSD;
495 if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
496 cfgfatal(loc,"tun","cannot guess which type of TUN is in use; "
497 "specify the flavour explicitly\n");
500 if (st->ifconfig_type==TUN_CONFIG_GUESS) {
501 switch (st->tun_flavour) {
502 case TUN_FLAVOUR_LINUX:
503 st->ifconfig_type=TUN_CONFIG_IOCTL;
505 case TUN_FLAVOUR_BSD:
507 /* XXX on Linux we still want TUN_CONFIG_IOCTL. Perhaps we can
508 use this on BSD too. */
509 st->ifconfig_type=TUN_CONFIG_IOCTL;
511 st->ifconfig_type=TUN_CONFIG_BSD;
514 case TUN_FLAVOUR_STREAMS:
515 st->ifconfig_type=TUN_CONFIG_BSD;
519 if (st->route_type==TUN_CONFIG_GUESS)
520 st->route_type=st->ifconfig_type;
522 if (st->ifconfig_type==TUN_CONFIG_GUESS) {
523 cfgfatal(loc,"tun","cannot guess which ifconfig method to use\n");
525 if (st->route_type==TUN_CONFIG_GUESS) {
526 cfgfatal(loc,"tun","cannot guess which route method to use\n");
529 if (st->ifconfig_type==TUN_CONFIG_IOCTL && st->ifconfig_path) {
530 cfgfatal(loc,"tun","ifconfig-type \"ioctl\" is incompatible with "
533 if (st->route_type==TUN_CONFIG_IOCTL && st->route_path) {
534 cfgfatal(loc,"tun","route-type \"ioctl\" is incompatible with "
538 Message(M_DEBUG_CONFIG,"%s: tun flavour %s\n",st->nl.name,
539 tun_flavour_str(st->tun_flavour));
540 switch (st->tun_flavour) {
541 case TUN_FLAVOUR_BSD:
542 if (!st->device_path) st->device_path="/dev/tun";
544 case TUN_FLAVOUR_LINUX:
545 if (!st->device_path) st->device_path="/dev/net/tun";
547 case TUN_FLAVOUR_STREAMS:
548 if (!st->device_path) st->device_path="/dev/tun";
549 if (st->interface_name) cfgfatal(loc,"tun","interface name cannot "
550 "be specified with STREAMS TUN\n");
554 if (!st->ip_path) st->ip_path="/dev/ip";
555 if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
556 if (!st->route_path) st->route_path="route";
558 #ifndef HAVE_TUN_STREAMS
559 if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
560 cfgfatal(loc,"tun","TUN flavour STREAMS unsupported in this build "
564 #ifndef LINUX_TUN_SUPPORTED
565 if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
566 cfgfatal(loc,"tun","TUN flavour LINUX unsupported in this build "
571 /* Old TUN interface: the network interface name depends on which
572 /dev/tunX file we open. If 'interface-search' is set to true, treat
573 'device' as the prefix and try numbers from 0--255. If it's set
574 to false, treat 'device' as the whole name, and require than an
575 appropriate interface name be specified. */
576 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
577 if (st->search_for_if && st->interface_name) {
578 cfgfatal(loc,"tun","you may not specify an interface name "
579 "in interface-search mode\n");
581 if (!st->search_for_if && !st->interface_name) {
582 cfgfatal(loc,"tun","you must specify an interface name "
583 "when you explicitly specify a TUN device file\n");
587 add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
589 return new_closure(&st->nl.cl);
592 static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
595 return tun_create(self,loc,context,args,TUN_FLAVOUR_GUESS);
598 static list_t *tun_bsd_apply(closure_t *self, struct cloc loc, dict_t *context,
601 Message(M_WARNING,"(%s,%d): obsolete use of tun-old; replace with tun "
602 "and specify flavour \"bsd\".\n",loc.file,loc.line);
603 return tun_create(self,loc,context,args,TUN_FLAVOUR_BSD);
606 void tun_module(dict_t *dict)
608 add_closure(dict,"tun",tun_apply);
609 add_closure(dict,"tun-old",tun_bsd_apply);