10 #ifdef HAVE_LINUX_IF_H
12 #include <linux/if_tun.h>
15 /* Where do we find if_tun on other platforms? */
17 /* Connection to the kernel through the universal TUN/TAP driver */
23 string_t interface_name
;
24 string_t ifconfig_path
;
27 bool_t search_for_if
; /* Applies to tun-old only */
28 struct buffer_if
*buff
; /* We receive packets into here
29 and send them to the netlink code. */
30 netlink_deliver_fn
*netlink_to_tunnel
;
31 uint32_t local_address
; /* host interface address */
34 static int tun_beforepoll(void *sst
, struct pollfd
*fds
, int *nfds_io
,
35 int *timeout_io
, const struct timeval
*tv_now
,
41 fds
[0].events
=POLLIN
|POLLERR
|POLLHUP
;
45 static void tun_afterpoll(void *sst
, struct pollfd
*fds
, int nfds
,
46 const struct timeval
*tv_now
, uint64_t *now
)
52 if (fds
[0].revents
&POLLERR
) {
53 printf("tun_afterpoll: hup!\n");
55 if (fds
[0].revents
&POLLIN
) {
56 BUF_ALLOC(st
->buff
,"tun_afterpoll");
57 buffer_init(st
->buff
,st
->nl
.max_start_pad
);
58 l
=read(st
->fd
,st
->buff
->start
,st
->buff
->len
-st
->nl
.max_start_pad
);
60 fatal_perror("tun_afterpoll: read()");
63 fatal("tun_afterpoll: read()=0; device gone away?\n");
67 st
->netlink_to_tunnel(&st
->nl
,st
->buff
);
68 BUF_ASSERT_FREE(st
->buff
);
73 static void tun_deliver_to_kernel(void *sst
, struct buffer_if
*buf
)
78 /* No error checking, because we'd just throw the packet away
79 anyway if it didn't work. */
80 write(st
->fd
,buf
->start
,buf
->size
);
84 static bool_t
tun_set_route(void *sst
, struct netlink_client
*routes
)
87 string_t network
, mask
, secnetaddr
;
88 struct subnet_list
*nets
;
91 if (routes
->up
!= routes
->kup
) {
93 for (i
=0; i
<nets
->entries
; i
++) {
94 network
=ipaddr_to_string(nets
->list
[i
].prefix
);
95 mask
=ipaddr_to_string(nets
->list
[i
].mask
);
96 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
97 Message(M_INFO
,"%s: %s route %s/%d %s kernel routing table\n",
98 st
->nl
.name
,routes
->up?
"adding":"deleting",network
,
99 nets
->list
[i
].len
,routes
->up?
"to":"from");
100 sys_cmd(st
->route_path
,"route",routes
->up?
"add":"del",
101 "-net",network
,"netmask",mask
,"gw",secnetaddr
,(char *)0);
102 free(network
); free(mask
); free(secnetaddr
);
104 routes
->kup
=routes
->up
;
110 static void tun_phase_hook(void *sst
, uint32_t newphase
)
113 string_t hostaddr
,secnetaddr
;
115 struct netlink_client
*r
;
118 if (st
->search_for_if
) {
122 /* ASSERT st->interface_name */
123 dname
=safe_malloc(strlen(st
->device_path
)+4,"tun_old_apply");
124 st
->interface_name
=safe_malloc(8,"tun_phase_hook");
126 for (i
=0; i
<255; i
++) {
127 sprintf(dname
,"%s%d",st
->device_path
,i
);
128 if ((st
->fd
=open(dname
,O_RDWR
))>0) {
129 sprintf(st
->interface_name
,"tun%d",i
);
130 Message(M_INFO
,"%s: allocated network interface %s "
131 "through %s\n",st
->nl
.name
,st
->interface_name
,
137 fatal("%s: unable to open any TUN device (%s...)\n",
138 st
->nl
.name
,st
->device_path
);
141 st
->fd
=open(st
->device_path
,O_RDWR
);
143 fatal_perror("%s: unable to open TUN device file %s",
144 st
->nl
.name
,st
->device_path
);
148 #ifdef HAVE_LINUX_IF_H
151 /* New TUN interface: open the device, then do ioctl TUNSETIFF
152 to set or find out the network interface name. */
153 st
->fd
=open(st
->device_path
,O_RDWR
);
155 fatal_perror("%s: can't open device file %s",st
->nl
.name
,
158 memset(&ifr
,0,sizeof(ifr
));
159 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Just send/receive IP packets,
161 if (st
->interface_name
)
162 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
163 Message(M_DEBUG
,"%s: about to ioctl(TUNSETIFF)...\n",st
->nl
.name
);
164 if (ioctl(st
->fd
,TUNSETIFF
,&ifr
)<0) {
165 fatal_perror("%s: ioctl(TUNSETIFF)",st
->nl
.name
);
167 if (!st
->interface_name
) {
168 st
->interface_name
=safe_malloc(strlen(ifr
.ifr_name
)+1,"tun_apply");
169 strcpy(st
->interface_name
,ifr
.ifr_name
);
170 Message(M_INFO
,"%s: allocated network interface %s\n",st
->nl
.name
,
174 fatal("netlink.c:tun_phase_hook:!tun_old unexpected\n");
175 #endif /* HAVE_LINUX_IF_H */
177 /* All the networks we'll be using have been registered. Invoke ifconfig
178 to set the TUN device's address, and route to add routes to all
181 hostaddr
=ipaddr_to_string(st
->local_address
);
182 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
183 snprintf(mtu
,6,"%d",st
->nl
.mtu
);
186 /* XXX on FreeBSD the "-broadcast" and "pointopoint" must be left
187 out. It assumes a point-to-point interface if two IP addresses
189 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
190 hostaddr
,"netmask","255.255.255.255","-broadcast",
191 "pointopoint",secnetaddr
,"mtu",mtu
,"up",(char *)0);
193 for (r
=st
->nl
.clients
; r
; r
=r
->next
) {
197 /* Register for poll() */
198 register_for_poll(st
, tun_beforepoll
, tun_afterpoll
, 1, st
->nl
.name
);
201 #ifdef HAVE_LINUX_IF_H
202 static list_t
*tun_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
209 st
=safe_malloc(sizeof(*st
),"tun_apply");
211 /* First parameter must be a dict */
212 item
=list_elem(args
,0);
213 if (!item
|| item
->type
!=t_dict
)
214 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
216 dict
=item
->data
.dict
;
218 st
->netlink_to_tunnel
=
219 netlink_init(&st
->nl
,st
,loc
,dict
,
220 "netlink-tun",tun_set_route
,tun_deliver_to_kernel
);
223 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
224 st
->interface_name
=dict_read_string(dict
,"interface",False
,
226 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",
227 False
,"tun-netlink",loc
);
228 st
->route_path
=dict_read_string(dict
,"route-path",
229 False
,"tun-netlink",loc
);
231 if (!st
->device_path
) st
->device_path
="/dev/net/tun";
232 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
233 if (!st
->route_path
) st
->route_path
="route";
234 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
235 st
->local_address
=string_item_to_ipaddr(
236 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
238 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
240 return new_closure(&st
->nl
.cl
);
242 #endif /* HAVE_LINUX_IF_H */
244 static list_t
*tun_old_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
251 st
=safe_malloc(sizeof(*st
),"tun_old_apply");
253 /* First parameter must be a dict */
254 item
=list_elem(args
,0);
255 if (!item
|| item
->type
!=t_dict
)
256 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
258 dict
=item
->data
.dict
;
260 st
->netlink_to_tunnel
=
261 netlink_init(&st
->nl
,st
,loc
,dict
,
262 "netlink-tun",tun_set_route
,tun_deliver_to_kernel
);
265 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
266 st
->interface_name
=dict_read_string(dict
,"interface",False
,
268 st
->search_for_if
=dict_read_bool(dict
,"interface-search",False
,
269 "tun-netlink",loc
,st
->device_path
==NULL
);
270 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",False
,
272 st
->route_path
=dict_read_string(dict
,"route-path",False
,"tun-netlink",loc
);
274 if (!st
->device_path
) st
->device_path
="/dev/tun";
275 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
276 if (!st
->route_path
) st
->route_path
="route";
277 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
278 st
->local_address
=string_item_to_ipaddr(
279 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
281 /* Old TUN interface: the network interface name depends on which
282 /dev/tunX file we open. If 'interface-search' is set to true, treat
283 'device' as the prefix and try numbers from 0--255. If it's set
284 to false, treat 'device' as the whole name, and require than an
285 appropriate interface name be specified. */
286 if (st
->search_for_if
&& st
->interface_name
) {
287 cfgfatal(loc
,"tun-old","you may not specify an interface name "
288 "in interface-search mode\n");
290 if (!st
->search_for_if
&& !st
->interface_name
) {
291 cfgfatal(loc
,"tun-old","you must specify an interface name "
292 "when you explicitly specify a TUN device file\n");
296 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
298 return new_closure(&st
->nl
.cl
);
301 init_module tun_module
;
302 void tun_module(dict_t
*dict
)
304 #ifdef HAVE_LINUX_IF_H
305 add_closure(dict
,"tun",tun_apply
);
307 add_closure(dict
,"tun-old",tun_old_apply
);