2 * This file is part of secnet.
3 * See README for full list of copyright holders.
5 * secnet is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * secnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * version 3 along with secnet; if not, see
17 * https://www.gnu.org/licenses/gpl.html.
28 #include <sys/ioctl.h>
29 #include <sys/utsname.h>
30 #include <sys/socket.h>
34 #ifdef HAVE_LINUX_IF_TUN_H
35 #include <linux/if_tun.h>
36 #define LINUX_TUN_SUPPORTED
40 #ifdef HAVE_NET_ROUTE_H
41 #include <net/route.h>
44 #if defined(HAVE_STROPTS_H) && defined(HAVE_SYS_SOCKIO_H) && \
45 defined(HAVE_NET_IF_TUN_H)
46 #define HAVE_TUN_STREAMS
49 #ifdef HAVE_TUN_STREAMS
51 #include <sys/sockio.h>
52 #include <net/if_tun.h>
55 #define TUN_FLAVOUR_GUESS 0
56 #define TUN_FLAVOUR_BSD 1
57 #define TUN_FLAVOUR_LINUX 2
58 #define TUN_FLAVOUR_STREAMS 3
60 static struct flagstr flavours
[]={
61 {"guess", TUN_FLAVOUR_GUESS
},
62 {"bsd", TUN_FLAVOUR_BSD
},
63 {"BSD", TUN_FLAVOUR_BSD
},
64 {"linux", TUN_FLAVOUR_LINUX
},
65 {"streams", TUN_FLAVOUR_STREAMS
},
66 {"STREAMS", TUN_FLAVOUR_STREAMS
},
70 #define TUN_CONFIG_GUESS 0
71 #define TUN_CONFIG_IOCTL 1
72 #define TUN_CONFIG_BSD 2
73 #define TUN_CONFIG_LINUX 3
74 #define TUN_CONFIG_SOLARIS25 4
76 static struct flagstr config_types
[]={
77 {"guess", TUN_CONFIG_GUESS
},
78 {"ioctl", TUN_CONFIG_IOCTL
},
79 {"bsd", TUN_CONFIG_BSD
},
80 {"BSD", TUN_CONFIG_BSD
},
81 {"linux", TUN_CONFIG_LINUX
},
82 {"solaris-2.5", TUN_CONFIG_SOLARIS25
},
86 /* Connection to the kernel through the universal TUN/TAP driver */
91 cstring_t device_path
;
93 string_t interface_name
;
94 cstring_t ifconfig_path
;
95 uint32_t ifconfig_type
;
99 bool_t search_for_if
; /* Applies to tun-BSD only */
100 struct buffer_if
*buff
; /* We receive packets into here
101 and send them to the netlink code. */
102 netlink_deliver_fn
*netlink_to_tunnel
;
105 static cstring_t
tun_flavour_str(uint32_t flavour
)
108 case TUN_FLAVOUR_GUESS
: return "guess";
109 case TUN_FLAVOUR_BSD
: return "BSD";
110 case TUN_FLAVOUR_LINUX
: return "linux";
111 case TUN_FLAVOUR_STREAMS
: return "STREAMS";
112 default: return "unknown";
116 static int tun_beforepoll(void *sst
, struct pollfd
*fds
, int *nfds_io
,
120 BEFOREPOLL_WANT_FDS(1);
122 fds
[0].events
=POLLIN
;
126 static void tun_afterpoll(void *sst
, struct pollfd
*fds
, int nfds
)
132 if (fds
[0].revents
&POLLERR
) {
133 printf("tun_afterpoll: hup!\n");
135 if (fds
[0].revents
&POLLIN
) {
136 BUF_ALLOC(st
->buff
,"tun_afterpoll");
137 buffer_init(st
->buff
,calculate_max_start_pad());
138 l
=read(st
->fd
, st
->buff
->start
, buf_remaining_space(st
->buff
));
140 if (errno
==EINTR
|| iswouldblock(errno
)) return;
141 fatal_perror("tun_afterpoll: read()");
144 fatal("tun_afterpoll: read()=0; device gone away?");
148 st
->netlink_to_tunnel(&st
->nl
,st
->buff
);
149 BUF_ASSERT_FREE(st
->buff
);
154 static void tun_deliver_to_kernel(void *sst
, struct buffer_if
*buf
)
159 BUF_ASSERT_USED(buf
);
161 /* Log errors, so we can tell what's going on, but only once a
162 minute, so we don't flood the logs. Short writes count as
164 rc
= write(st
->fd
,buf
->start
,buf
->size
);
165 if(rc
!= buf
->size
) {
166 static struct timeval last_report
;
167 if(tv_now_global
.tv_sec
>= last_report
.tv_sec
+ 60) {
170 "failed to deliver packet to tun device: %s\n",
174 "truncated packet delivered to tun device\n");
175 last_report
= tv_now_global
;
181 static bool_t
tun_set_route(void *sst
, struct netlink_client
*routes
)
184 string_t network
, mask
, secnetaddr
;
185 struct subnet_list
*nets
;
190 if (routes
->options
& OPT_SOFTROUTE
)
193 up
= routes
->link_quality
> LINK_QUALITY_UNUSED
;
195 if (up
== routes
->kup
) return False
;
196 if (st
->route_type
==TUN_CONFIG_IOCTL
) {
197 if (st
->tun_flavour
==TUN_FLAVOUR_STREAMS
) {
198 fd
=open(st
->ip_path
,O_RDWR
);
200 fatal_perror("tun_set_route: can't open %s",st
->ip_path
);
203 fd
=socket(PF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
205 fatal_perror("tun_set_route: socket()");
209 nets
=routes
->subnets
;
210 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
211 for (i
=0; i
<nets
->entries
; i
++) {
212 network
=ipaddr_to_string(nets
->list
[i
].prefix
);
213 mask
=ipaddr_to_string(nets
->list
[i
].mask
);
214 Message(M_INFO
,"%s: %s route %s/%d %s kernel routing table\n",
215 st
->nl
.name
,up?
"adding":"deleting",network
,
216 nets
->list
[i
].len
,up?
"to":"from");
217 switch (st
->route_type
) {
218 case TUN_CONFIG_LINUX
:
219 sys_cmd(st
->route_path
,"route",up?
"add":"del",
220 "-net",network
,"netmask",mask
,
221 "gw",secnetaddr
,(char *)0);
224 sys_cmd(st
->route_path
,"route",up?
"add":"del",
225 "-net",network
,secnetaddr
,mask
,(char *)0);
227 case TUN_CONFIG_SOLARIS25
:
228 sys_cmd(st
->route_path
,"route",up?
"add":"del",
229 network
,secnetaddr
,(char *)0);
231 case TUN_CONFIG_IOCTL
:
233 /* darwin rtentry has a different format, use /sbin/route instead */
234 #if HAVE_NET_ROUTE_H && ! __APPLE__
236 struct sockaddr_in
*sa
;
240 sa
=(struct sockaddr_in
*)&rt
.rt_dst
;
241 sa
->sin_family
=AF_INET
;
242 sa
->sin_addr
.s_addr
=htonl(nets
->list
[i
].prefix
);
243 sa
=(struct sockaddr_in
*)&rt
.rt_genmask
;
244 sa
->sin_family
=AF_INET
;
245 sa
->sin_addr
.s_addr
=htonl(nets
->list
[i
].mask
);
246 sa
=(struct sockaddr_in
*)&rt
.rt_gateway
;
247 sa
->sin_family
=AF_INET
;
248 sa
->sin_addr
.s_addr
=htonl(st
->nl
.secnet_address
);
249 rt
.rt_flags
=RTF_UP
|RTF_GATEWAY
;
250 action
=up?SIOCADDRT
:SIOCDELRT
;
251 if (ioctl(fd
,action
,&rt
)<0) {
252 fatal_perror("tun_set_route: ioctl()");
255 fatal("tun_set_route: ioctl method not supported");
260 fatal("tun_set_route: unsupported route command type");
271 static void tun_phase_hook(void *sst
, uint32_t newphase
)
274 string_t hostaddr
,secnetaddr
;
276 struct netlink_client
*r
;
278 if (st
->tun_flavour
==TUN_FLAVOUR_BSD
) {
279 if (st
->search_for_if
) {
283 dname
=safe_malloc(strlen(st
->device_path
)+4,"tun_old_apply");
284 st
->interface_name
=safe_malloc(8,"tun_phase_hook");
286 for (i
=0; i
<255; i
++) {
287 sprintf(dname
,"%s%d",st
->device_path
,i
);
288 if ((st
->fd
=open(dname
,O_RDWR
))>0) {
289 sprintf(st
->interface_name
,"tun%d",i
);
290 Message(M_INFO
,"%s: allocated network interface %s "
291 "through %s\n",st
->nl
.name
,st
->interface_name
,
297 fatal("%s: unable to open any TUN device (%s...)",
298 st
->nl
.name
,st
->device_path
);
301 st
->fd
=open(st
->device_path
,O_RDWR
);
303 fatal_perror("%s: unable to open TUN device file %s",
304 st
->nl
.name
,st
->device_path
);
307 } else if (st
->tun_flavour
==TUN_FLAVOUR_LINUX
) {
308 #ifdef LINUX_TUN_SUPPORTED
311 /* New TUN interface: open the device, then do ioctl TUNSETIFF
312 to set or find out the network interface name. */
313 st
->fd
=open(st
->device_path
,O_RDWR
);
315 fatal_perror("%s: can't open device file %s",st
->nl
.name
,
319 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Just send/receive IP packets,
321 if (st
->interface_name
)
322 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
323 if (ioctl(st
->fd
,TUNSETIFF
,&ifr
)<0) {
324 fatal_perror("%s: ioctl(TUNSETIFF)",st
->nl
.name
);
326 if (!st
->interface_name
) {
327 st
->interface_name
=safe_malloc(strlen(ifr
.ifr_name
)+1,"tun_apply");
328 strcpy(st
->interface_name
,ifr
.ifr_name
);
329 Message(M_INFO
,"%s: allocated network interface %s\n",st
->nl
.name
,
333 fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected");
334 #endif /* LINUX_TUN_SUPPORTED */
335 } else if (st
->tun_flavour
==TUN_FLAVOUR_STREAMS
) {
336 #ifdef HAVE_TUN_STREAMS
337 int tun_fd
, if_fd
, ppa
=-1, ip_fd
;
339 if ((ip_fd
=open(st
->ip_path
, O_RDWR
)) < 0) {
340 fatal_perror("%s: can't open %s",st
->nl
.name
,st
->ip_path
);
342 if ((tun_fd
=open(st
->device_path
,O_RDWR
)) < 0) {
343 fatal_perror("%s: can't open %s",st
->nl
.name
,st
->device_path
);
345 if ((ppa
=ioctl(tun_fd
,TUNNEWPPA
,ppa
)) < 0) {
346 fatal_perror("%s: can't assign new interface");
348 if ((if_fd
=open(st
->device_path
,O_RDWR
)) < 0) {
349 fatal_perror("%s: can't open %s (2)",st
->nl
.name
,st
->device_path
);
351 if (ioctl(if_fd
,I_PUSH
,"ip") < 0) {
352 fatal_perror("%s: can't push IP module",st
->nl
.name
);
354 if (ioctl(if_fd
,IF_UNITSEL
,(char *)&ppa
) < 0) {
355 fatal_perror("%s: can't set ppa %d",st
->nl
.name
,ppa
);
357 if (ioctl(ip_fd
, I_LINK
, if_fd
) < 0) {
358 fatal_perror("%s: can't link TUN device to IP",st
->nl
.name
);
360 st
->interface_name
=safe_malloc(10,"tun_apply");
361 sprintf(st
->interface_name
,"tun%d",ppa
);
366 fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
367 #endif /* HAVE_TUN_STREAMS */
369 fatal("tun_phase_hook: unknown flavour of TUN");
371 /* All the networks we'll be using have been registered. Invoke ifconfig
372 to set the TUN device's address, and route to add routes to all
378 hostaddr
=ipaddr_to_string(st
->nl
.local_address
);
379 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
380 snprintf(mtu
,sizeof(mtu
),"%d",st
->nl
.mtu
);
383 switch (st
->ifconfig_type
) {
384 case TUN_CONFIG_LINUX
:
385 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
386 hostaddr
,"netmask","255.255.255.255","-broadcast",
388 "pointopoint",secnetaddr
,"mtu",mtu
,"up",(char *)0);
391 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
392 hostaddr
,"netmask","255.255.255.255",
393 secnetaddr
,"mtu",mtu
,"up",(char *)0);
395 case TUN_CONFIG_SOLARIS25
:
396 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
397 hostaddr
,secnetaddr
,"mtu",mtu
,"up",(char *)0);
399 case TUN_CONFIG_IOCTL
:
400 #if HAVE_NET_IF_H && ! __APPLE__
404 struct sockaddr_in
*sa
;
405 fd
=socket(PF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
407 /* Interface address */
408 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
409 sa
=(struct sockaddr_in
*)&ifr
.ifr_addr
;
411 sa
->sin_family
=AF_INET
;
412 sa
->sin_addr
.s_addr
=htonl(st
->nl
.local_address
);
413 if (ioctl(fd
,SIOCSIFADDR
, &ifr
)!=0) {
414 fatal_perror("tun_apply: SIOCSIFADDR");
416 #ifdef SIOCSIFNETMASK
418 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
419 sa
=(struct sockaddr_in
*)&ifr
.ifr_netmask
;
421 sa
->sin_family
=AF_INET
;
422 sa
->sin_addr
.s_addr
=htonl(0xffffffff);
423 if (ioctl(fd
,SIOCSIFNETMASK
, &ifr
)!=0) {
424 fatal_perror("tun_apply: SIOCSIFNETMASK");
427 /* Destination address (point-to-point) */
428 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
429 sa
=(struct sockaddr_in
*)&ifr
.ifr_dstaddr
;
431 sa
->sin_family
=AF_INET
;
432 sa
->sin_addr
.s_addr
=htonl(st
->nl
.secnet_address
);
433 if (ioctl(fd
,SIOCSIFDSTADDR
, &ifr
)!=0) {
434 fatal_perror("tun_apply: SIOCSIFDSTADDR");
437 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
438 ifr
.ifr_mtu
=st
->nl
.mtu
;
439 if (ioctl(fd
,SIOCSIFMTU
, &ifr
)!=0) {
440 fatal_perror("tun_apply: SIOCSIFMTU");
443 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
444 ifr
.ifr_flags
=IFF_UP
|IFF_POINTOPOINT
|IFF_RUNNING
|IFF_NOARP
;
445 if (ioctl(fd
,SIOCSIFFLAGS
, &ifr
)!=0) {
446 fatal_perror("tun_apply: SIOCSIFFLAGS");
452 fatal("tun_apply: ifconfig by ioctl() not supported");
453 #endif /* HAVE_NET_IF_H */
456 fatal("tun_apply: unsupported ifconfig method");
460 for (r
=st
->nl
.clients
; r
; r
=r
->next
) {
464 add_hook(PHASE_CHILDPERSIST
,childpersist_closefd_hook
,&st
->fd
);
466 /* Register for poll() */
467 register_for_poll(st
, tun_beforepoll
, tun_afterpoll
, st
->nl
.name
);
470 static list_t
*tun_create(closure_t
*self
, struct cloc loc
, dict_t
*context
,
471 list_t
*args
,uint32_t default_flavour
)
476 string_t flavour
,type
;
480 /* First parameter must be a dict */
481 item
=list_elem(args
,0);
482 if (!item
|| item
->type
!=t_dict
)
483 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
485 dict
=item
->data
.dict
;
487 st
->netlink_to_tunnel
=
488 netlink_init(&st
->nl
,st
,loc
,dict
,
489 "netlink-tun",tun_set_route
,tun_deliver_to_kernel
);
491 flavour
=dict_read_string(dict
,"flavour",False
,"tun-netlink",loc
);
493 st
->tun_flavour
=string_to_word(flavour
,loc
,flavours
,"tun-flavour");
495 st
->tun_flavour
=default_flavour
;
497 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
498 st
->ip_path
=dict_read_string(dict
,"ip-path",False
,"tun-netlink",loc
);
499 st
->interface_name
=dict_read_string(dict
,"interface",False
,
501 st
->search_for_if
=dict_read_bool(dict
,"interface-search",False
,
502 "tun-netlink",loc
,st
->device_path
==NULL
);
504 type
=dict_read_string(dict
,"ifconfig-type",False
,"tun-netlink",loc
);
505 if (type
) st
->ifconfig_type
=string_to_word(type
,loc
,config_types
,
507 else st
->ifconfig_type
=TUN_CONFIG_GUESS
;
508 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",False
,
511 type
=dict_read_string(dict
,"route-type",False
,"tun-netlink",loc
);
512 if (type
) st
->route_type
=string_to_word(type
,loc
,config_types
,
514 else st
->route_type
=TUN_CONFIG_GUESS
;
515 st
->route_path
=dict_read_string(dict
,"route-path",False
,"tun-netlink",loc
);
517 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
519 if (st
->tun_flavour
==TUN_FLAVOUR_GUESS
) {
520 /* If we haven't been told what type of TUN we're using, take
521 a guess based on the system details. */
524 fatal_perror("tun_create: uname");
526 if (strcmp(u
.sysname
,"Linux")==0) {
527 st
->tun_flavour
=TUN_FLAVOUR_LINUX
;
528 } else if (strcmp(u
.sysname
,"SunOS")==0) {
529 st
->tun_flavour
=TUN_FLAVOUR_STREAMS
;
530 } else if (strcmp(u
.sysname
,"FreeBSD")==0
531 || strcmp(u
.sysname
,"Darwin")==0) {
532 st
->tun_flavour
=TUN_FLAVOUR_BSD
;
535 if (st
->tun_flavour
==TUN_FLAVOUR_GUESS
) {
536 cfgfatal(loc
,"tun","cannot guess which type of TUN is in use; "
537 "specify the flavour explicitly\n");
540 if (st
->ifconfig_type
==TUN_CONFIG_GUESS
) {
541 switch (st
->tun_flavour
) {
542 case TUN_FLAVOUR_LINUX
:
543 st
->ifconfig_type
=TUN_CONFIG_IOCTL
;
545 case TUN_FLAVOUR_BSD
:
547 /* XXX on Linux we still want TUN_CONFIG_IOCTL. Perhaps we can
548 use this on BSD too. */
549 st
->ifconfig_type
=TUN_CONFIG_IOCTL
;
551 st
->ifconfig_type
=TUN_CONFIG_BSD
;
554 case TUN_FLAVOUR_STREAMS
:
555 st
->ifconfig_type
=TUN_CONFIG_BSD
;
559 if (st
->route_type
==TUN_CONFIG_GUESS
)
560 st
->route_type
=st
->ifconfig_type
;
562 if (st
->ifconfig_type
==TUN_CONFIG_GUESS
) {
563 cfgfatal(loc
,"tun","cannot guess which ifconfig method to use\n");
565 if (st
->route_type
==TUN_CONFIG_GUESS
) {
566 cfgfatal(loc
,"tun","cannot guess which route method to use\n");
569 if (st
->ifconfig_type
==TUN_CONFIG_IOCTL
&& st
->ifconfig_path
) {
570 cfgfatal(loc
,"tun","ifconfig-type \"ioctl\" is incompatible with "
573 if (st
->route_type
==TUN_CONFIG_IOCTL
&& st
->route_path
) {
574 cfgfatal(loc
,"tun","route-type \"ioctl\" is incompatible with "
578 Message(M_DEBUG_CONFIG
,"%s: tun flavour %s\n",st
->nl
.name
,
579 tun_flavour_str(st
->tun_flavour
));
580 switch (st
->tun_flavour
) {
581 case TUN_FLAVOUR_BSD
:
582 if (!st
->device_path
) st
->device_path
="/dev/tun";
584 case TUN_FLAVOUR_LINUX
:
585 if (!st
->device_path
) st
->device_path
="/dev/net/tun";
587 case TUN_FLAVOUR_STREAMS
:
588 if (!st
->device_path
) st
->device_path
="/dev/tun";
589 if (st
->interface_name
) cfgfatal(loc
,"tun","interface name cannot "
590 "be specified with STREAMS TUN\n");
594 if (!st
->ip_path
) st
->ip_path
="/dev/ip";
595 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
596 if (!st
->route_path
) st
->route_path
="route";
598 #ifndef HAVE_TUN_STREAMS
599 if (st
->tun_flavour
==TUN_FLAVOUR_STREAMS
) {
600 cfgfatal(loc
,"tun","TUN flavour STREAMS unsupported in this build "
604 #ifndef LINUX_TUN_SUPPORTED
605 if (st
->tun_flavour
==TUN_FLAVOUR_LINUX
) {
606 cfgfatal(loc
,"tun","TUN flavour LINUX unsupported in this build "
611 /* Old TUN interface: the network interface name depends on which
612 /dev/tunX file we open. If 'interface-search' is set to true, treat
613 'device' as the prefix and try numbers from 0--255. If it's set
614 to false, treat 'device' as the whole name, and require than an
615 appropriate interface name be specified. */
616 if (st
->tun_flavour
==TUN_FLAVOUR_BSD
) {
617 if (st
->search_for_if
&& st
->interface_name
) {
618 cfgfatal(loc
,"tun","you may not specify an interface name "
619 "in interface-search mode\n");
621 if (!st
->search_for_if
&& !st
->interface_name
) {
622 cfgfatal(loc
,"tun","you must specify an interface name "
623 "when you explicitly specify a TUN device file\n");
627 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
629 return new_closure(&st
->nl
.cl
);
632 static list_t
*tun_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
635 return tun_create(self
,loc
,context
,args
,TUN_FLAVOUR_GUESS
);
638 static list_t
*tun_bsd_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
641 Message(M_WARNING
,"(%s,%d): obsolete use of tun-old; replace with tun "
642 "and specify flavour \"bsd\".\n",loc
.file
,loc
.line
);
643 return tun_create(self
,loc
,context
,args
,TUN_FLAVOUR_BSD
);
646 void tun_module(dict_t
*dict
)
648 add_closure(dict
,"tun",tun_apply
);
649 add_closure(dict
,"tun-old",tun_bsd_apply
);