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
);