10 #include <sys/utsname.h>
11 #include <sys/socket.h>
15 #ifdef HAVE_LINUX_IF_H
16 #include <linux/if_tun.h>
17 #define LINUX_TUN_SUPPORTED
21 #ifdef HAVE_NET_ROUTE_H
22 #include <net/route.h>
25 #if defined(HAVE_STROPTS_H) && defined(HAVE_SYS_SOCKIO_H) && \
26 defined(HAVE_NET_IF_TUN_H)
27 #define HAVE_TUN_STREAMS
30 #ifdef HAVE_TUN_STREAMS
32 #include <sys/sockio.h>
33 #include <net/if_tun.h>
36 #define TUN_FLAVOUR_GUESS 0
37 #define TUN_FLAVOUR_BSD 1
38 #define TUN_FLAVOUR_LINUX 2
39 #define TUN_FLAVOUR_STREAMS 3
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},
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
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},
67 /* Connection to the kernel through the universal TUN/TAP driver */
72 cstring_t device_path;
74 string_t interface_name;
75 cstring_t ifconfig_path;
76 uint32_t ifconfig_type;
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;
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,
103 fds[0].events=POLLIN;
107 static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds)
113 if (fds[0].revents&POLLERR) {
114 printf("tun_afterpoll: hup!\n");
116 if (fds[0].revents&POLLIN) {
117 BUF_ALLOC(st->buff,"tun_afterpoll");
118 buffer_init(st->buff,calculate_max_start_pad());
119 l=read(st->fd,st->buff->start,st->buff->len-calculate_max_start_pad());
121 fatal_perror("tun_afterpoll: read()");
124 fatal("tun_afterpoll: read()=0; device gone away?");
128 st->netlink_to_tunnel(&st->nl,st->buff);
129 BUF_ASSERT_FREE(st->buff);
134 static void tun_deliver_to_kernel(void *sst, struct buffer_if *buf)
139 BUF_ASSERT_USED(buf);
141 /* Log errors, so we can tell what's going on, but only once a
142 minute, so we don't flood the logs. Short writes count as
144 rc = write(st->fd,buf->start,buf->size);
145 if(rc != buf->size) {
146 static struct timeval last_report;
147 if(tv_now_global.tv_sec >= last_report.tv_sec + 60) {
150 "failed to deliver packet to tun device: %s\n",
154 "truncated packet delivered to tun device\n");
155 last_report = tv_now_global;
161 static bool_t tun_set_route(void *sst, struct netlink_client *routes)
164 string_t network, mask, secnetaddr;
165 struct subnet_list *nets;
170 if (routes->options & OPT_SOFTROUTE)
173 up = routes->link_quality > LINK_QUALITY_UNUSED;
175 if (up == routes->kup) return False;
176 if (st->route_type==TUN_CONFIG_IOCTL) {
177 if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
178 fd=open(st->ip_path,O_RDWR);
180 fatal_perror("tun_set_route: can't open %s",st->ip_path);
183 fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
185 fatal_perror("tun_set_route: socket()");
189 nets=routes->subnets;
190 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
191 for (i=0; i<nets->entries; i++) {
192 network=ipaddr_to_string(nets->list[i].prefix);
193 mask=ipaddr_to_string(nets->list[i].mask);
194 Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
195 st->nl.name,up?"adding":"deleting",network,
196 nets->list[i].len,up?"to":"from");
197 switch (st->route_type) {
198 case TUN_CONFIG_LINUX:
199 sys_cmd(st->route_path,"route",up?"add":"del",
200 "-net",network,"netmask",mask,
201 "gw",secnetaddr,(char *)0);
204 sys_cmd(st->route_path,"route",up?"add":"del",
205 "-net",network,secnetaddr,mask,(char *)0);
207 case TUN_CONFIG_SOLARIS25:
208 sys_cmd(st->route_path,"route",up?"add":"del",
209 network,secnetaddr,(char *)0);
211 case TUN_CONFIG_IOCTL:
213 /* darwin rtentry has a different format, use /sbin/route instead */
214 #if HAVE_NET_ROUTE_H && ! __APPLE__
216 struct sockaddr_in *sa;
220 sa=(struct sockaddr_in *)&rt.rt_dst;
221 sa->sin_family=AF_INET;
222 sa->sin_addr.s_addr=htonl(nets->list[i].prefix);
223 sa=(struct sockaddr_in *)&rt.rt_genmask;
224 sa->sin_family=AF_INET;
225 sa->sin_addr.s_addr=htonl(nets->list[i].mask);
226 sa=(struct sockaddr_in *)&rt.rt_gateway;
227 sa->sin_family=AF_INET;
228 sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
229 rt.rt_flags=RTF_UP|RTF_GATEWAY;
230 action=up?SIOCADDRT:SIOCDELRT;
231 if (ioctl(fd,action,&rt)<0) {
232 fatal_perror("tun_set_route: ioctl()");
235 fatal("tun_set_route: ioctl method not supported");
240 fatal("tun_set_route: unsupported route command type");
243 free(network); free(mask);
246 if (st->route_type==TUN_CONFIG_IOCTL) {
253 static void tun_phase_hook(void *sst, uint32_t newphase)
256 string_t hostaddr,secnetaddr;
258 struct netlink_client *r;
260 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
261 if (st->search_for_if) {
265 dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
266 st->interface_name=safe_malloc(8,"tun_phase_hook");
268 for (i=0; i<255; i++) {
269 sprintf(dname,"%s%d",st->device_path,i);
270 if ((st->fd=open(dname,O_RDWR))>0) {
271 sprintf(st->interface_name,"tun%d",i);
272 Message(M_INFO,"%s: allocated network interface %s "
273 "through %s\n",st->nl.name,st->interface_name,
279 fatal("%s: unable to open any TUN device (%s...)",
280 st->nl.name,st->device_path);
283 st->fd=open(st->device_path,O_RDWR);
285 fatal_perror("%s: unable to open TUN device file %s",
286 st->nl.name,st->device_path);
289 } else if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
290 #ifdef LINUX_TUN_SUPPORTED
293 /* New TUN interface: open the device, then do ioctl TUNSETIFF
294 to set or find out the network interface name. */
295 st->fd=open(st->device_path,O_RDWR);
297 fatal_perror("%s: can't open device file %s",st->nl.name,
301 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
303 if (st->interface_name)
304 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
305 if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
306 fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
308 if (!st->interface_name) {
309 st->interface_name=safe_malloc(strlen(ifr.ifr_name)+1,"tun_apply");
310 strcpy(st->interface_name,ifr.ifr_name);
311 Message(M_INFO,"%s: allocated network interface %s\n",st->nl.name,
315 fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected");
316 #endif /* LINUX_TUN_SUPPORTED */
317 } else if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
318 #ifdef HAVE_TUN_STREAMS
319 int tun_fd, if_fd, ppa=-1, ip_fd;
321 if ((ip_fd=open(st->ip_path, O_RDWR)) < 0) {
322 fatal_perror("%s: can't open %s",st->nl.name,st->ip_path);
324 if ((tun_fd=open(st->device_path,O_RDWR)) < 0) {
325 fatal_perror("%s: can't open %s",st->nl.name,st->device_path);
327 if ((ppa=ioctl(tun_fd,TUNNEWPPA,ppa)) < 0) {
328 fatal_perror("%s: can't assign new interface");
330 if ((if_fd=open(st->device_path,O_RDWR)) < 0) {
331 fatal_perror("%s: can't open %s (2)",st->nl.name,st->device_path);
333 if (ioctl(if_fd,I_PUSH,"ip") < 0) {
334 fatal_perror("%s: can't push IP module",st->nl.name);
336 if (ioctl(if_fd,IF_UNITSEL,(char *)&ppa) < 0) {
337 fatal_perror("%s: can't set ppa %d",st->nl.name,ppa);
339 if (ioctl(ip_fd, I_LINK, if_fd) < 0) {
340 fatal_perror("%s: can't link TUN device to IP",st->nl.name);
342 st->interface_name=safe_malloc(10,"tun_apply");
343 sprintf(st->interface_name,"tun%d",ppa);
346 fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
347 #endif /* HAVE_TUN_STREAMS */
349 fatal("tun_phase_hook: unknown flavour of TUN");
351 /* All the networks we'll be using have been registered. Invoke ifconfig
352 to set the TUN device's address, and route to add routes to all
355 hostaddr=ipaddr_to_string(st->nl.local_address);
356 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
357 snprintf(mtu,sizeof(mtu),"%d",st->nl.mtu);
360 switch (st->ifconfig_type) {
361 case TUN_CONFIG_LINUX:
362 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
363 hostaddr,"netmask","255.255.255.255","-broadcast",
365 "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
368 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
369 hostaddr,"netmask","255.255.255.255",
370 secnetaddr,"mtu",mtu,"up",(char *)0);
372 case TUN_CONFIG_SOLARIS25:
373 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
374 hostaddr,secnetaddr,"mtu",mtu,"up",(char *)0);
376 case TUN_CONFIG_IOCTL:
377 #if HAVE_NET_IF_H && ! __APPLE__
381 struct sockaddr_in *sa;
382 fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
384 /* Interface address */
385 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
386 sa=(struct sockaddr_in *)&ifr.ifr_addr;
388 sa->sin_family=AF_INET;
389 sa->sin_addr.s_addr=htonl(st->nl.local_address);
390 if (ioctl(fd,SIOCSIFADDR, &ifr)!=0) {
391 fatal_perror("tun_apply: SIOCSIFADDR");
393 #ifdef SIOCSIFNETMASK
395 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
396 sa=(struct sockaddr_in *)&ifr.ifr_netmask;
398 sa->sin_family=AF_INET;
399 sa->sin_addr.s_addr=htonl(0xffffffff);
400 if (ioctl(fd,SIOCSIFNETMASK, &ifr)!=0) {
401 fatal_perror("tun_apply: SIOCSIFNETMASK");
404 /* Destination address (point-to-point) */
405 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
406 sa=(struct sockaddr_in *)&ifr.ifr_dstaddr;
408 sa->sin_family=AF_INET;
409 sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
410 if (ioctl(fd,SIOCSIFDSTADDR, &ifr)!=0) {
411 fatal_perror("tun_apply: SIOCSIFDSTADDR");
414 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
415 ifr.ifr_mtu=st->nl.mtu;
416 if (ioctl(fd,SIOCSIFMTU, &ifr)!=0) {
417 fatal_perror("tun_apply: SIOCSIFMTU");
420 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
421 ifr.ifr_flags=IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP;
422 if (ioctl(fd,SIOCSIFFLAGS, &ifr)!=0) {
423 fatal_perror("tun_apply: SIOCSIFFLAGS");
429 fatal("tun_apply: ifconfig by ioctl() not supported");
430 #endif /* HAVE_NET_IF_H */
433 fatal("tun_apply: unsupported ifconfig method");
437 for (r=st->nl.clients; r; r=r->next) {
441 /* Register for poll() */
442 register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
445 static list_t *tun_create(closure_t *self, struct cloc loc, dict_t *context,
446 list_t *args,uint32_t default_flavour)
451 string_t flavour,type;
453 st=safe_malloc(sizeof(*st),"tun_apply");
455 /* First parameter must be a dict */
456 item=list_elem(args,0);
457 if (!item || item->type!=t_dict)
458 cfgfatal(loc,"tun","parameter must be a dictionary\n");
460 dict=item->data.dict;
462 st->netlink_to_tunnel=
463 netlink_init(&st->nl,st,loc,dict,
464 "netlink-tun",tun_set_route,tun_deliver_to_kernel);
466 flavour=dict_read_string(dict,"flavour",False,"tun-netlink",loc);
468 st->tun_flavour=string_to_word(flavour,loc,flavours,"tun-flavour");
470 st->tun_flavour=default_flavour;
472 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
473 st->ip_path=dict_read_string(dict,"ip-path",False,"tun-netlink",loc);
474 st->interface_name=dict_read_string(dict,"interface",False,
476 st->search_for_if=dict_read_bool(dict,"interface-search",False,
477 "tun-netlink",loc,st->device_path==NULL);
479 type=dict_read_string(dict,"ifconfig-type",False,"tun-netlink",loc);
480 if (type) st->ifconfig_type=string_to_word(type,loc,config_types,
482 else st->ifconfig_type=TUN_CONFIG_GUESS;
483 st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
486 type=dict_read_string(dict,"route-type",False,"tun-netlink",loc);
487 if (type) st->route_type=string_to_word(type,loc,config_types,
489 else st->route_type=TUN_CONFIG_GUESS;
490 st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
492 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
494 if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
495 /* If we haven't been told what type of TUN we're using, take
496 a guess based on the system details. */
499 fatal_perror("tun_create: uname");
501 if (strcmp(u.sysname,"Linux")==0) {
502 st->tun_flavour=TUN_FLAVOUR_LINUX;
503 } else if (strcmp(u.sysname,"SunOS")==0) {
504 st->tun_flavour=TUN_FLAVOUR_STREAMS;
505 } else if (strcmp(u.sysname,"FreeBSD")==0
506 || strcmp(u.sysname,"Darwin")==0) {
507 st->tun_flavour=TUN_FLAVOUR_BSD;
510 if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
511 cfgfatal(loc,"tun","cannot guess which type of TUN is in use; "
512 "specify the flavour explicitly\n");
515 if (st->ifconfig_type==TUN_CONFIG_GUESS) {
516 switch (st->tun_flavour) {
517 case TUN_FLAVOUR_LINUX:
518 st->ifconfig_type=TUN_CONFIG_IOCTL;
520 case TUN_FLAVOUR_BSD:
522 /* XXX on Linux we still want TUN_CONFIG_IOCTL. Perhaps we can
523 use this on BSD too. */
524 st->ifconfig_type=TUN_CONFIG_IOCTL;
526 st->ifconfig_type=TUN_CONFIG_BSD;
529 case TUN_FLAVOUR_STREAMS:
530 st->ifconfig_type=TUN_CONFIG_BSD;
534 if (st->route_type==TUN_CONFIG_GUESS)
535 st->route_type=st->ifconfig_type;
537 if (st->ifconfig_type==TUN_CONFIG_GUESS) {
538 cfgfatal(loc,"tun","cannot guess which ifconfig method to use\n");
540 if (st->route_type==TUN_CONFIG_GUESS) {
541 cfgfatal(loc,"tun","cannot guess which route method to use\n");
544 if (st->ifconfig_type==TUN_CONFIG_IOCTL && st->ifconfig_path) {
545 cfgfatal(loc,"tun","ifconfig-type \"ioctl\" is incompatible with "
548 if (st->route_type==TUN_CONFIG_IOCTL && st->route_path) {
549 cfgfatal(loc,"tun","route-type \"ioctl\" is incompatible with "
553 Message(M_DEBUG_CONFIG,"%s: tun flavour %s\n",st->nl.name,
554 tun_flavour_str(st->tun_flavour));
555 switch (st->tun_flavour) {
556 case TUN_FLAVOUR_BSD:
557 if (!st->device_path) st->device_path="/dev/tun";
559 case TUN_FLAVOUR_LINUX:
560 if (!st->device_path) st->device_path="/dev/net/tun";
562 case TUN_FLAVOUR_STREAMS:
563 if (!st->device_path) st->device_path="/dev/tun";
564 if (st->interface_name) cfgfatal(loc,"tun","interface name cannot "
565 "be specified with STREAMS TUN\n");
569 if (!st->ip_path) st->ip_path="/dev/ip";
570 if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
571 if (!st->route_path) st->route_path="route";
573 #ifndef HAVE_TUN_STREAMS
574 if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
575 cfgfatal(loc,"tun","TUN flavour STREAMS unsupported in this build "
579 #ifndef LINUX_TUN_SUPPORTED
580 if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
581 cfgfatal(loc,"tun","TUN flavour LINUX unsupported in this build "
586 /* Old TUN interface: the network interface name depends on which
587 /dev/tunX file we open. If 'interface-search' is set to true, treat
588 'device' as the prefix and try numbers from 0--255. If it's set
589 to false, treat 'device' as the whole name, and require than an
590 appropriate interface name be specified. */
591 if (st->tun_flavour==TUN_FLAVOUR_BSD) {
592 if (st->search_for_if && st->interface_name) {
593 cfgfatal(loc,"tun","you may not specify an interface name "
594 "in interface-search mode\n");
596 if (!st->search_for_if && !st->interface_name) {
597 cfgfatal(loc,"tun","you must specify an interface name "
598 "when you explicitly specify a TUN device file\n");
602 add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
604 return new_closure(&st->nl.cl);
607 static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
610 return tun_create(self,loc,context,args,TUN_FLAVOUR_GUESS);
613 static list_t *tun_bsd_apply(closure_t *self, struct cloc loc, dict_t *context,
616 Message(M_WARNING,"(%s,%d): obsolete use of tun-old; replace with tun "
617 "and specify flavour \"bsd\".\n",loc.file,loc.line);
618 return tun_create(self,loc,context,args,TUN_FLAVOUR_BSD);
621 void tun_module(dict_t *dict)
623 add_closure(dict,"tun",tun_apply);
624 add_closure(dict,"tun-old",tun_bsd_apply);