10 #ifdef HAVE_LINUX_IF_H
12 #include <linux/if_tun.h>
15 /* XXX 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
)
51 if (fds
[0].revents
&POLLERR
) {
52 printf("tun_afterpoll: hup!\n");
54 if (fds
[0].revents
&POLLIN
) {
55 BUF_ALLOC(st
->buff
,"tun_afterpoll");
56 buffer_init(st
->buff
,st
->nl
.max_start_pad
);
57 l
=read(st
->fd
,st
->buff
->start
,st
->buff
->len
-st
->nl
.max_start_pad
);
59 fatal_perror("tun_afterpoll: read()");
62 fatal("tun_afterpoll: read()=0; device gone away?\n");
66 st
->netlink_to_tunnel(&st
->nl
,NULL
,st
->buff
);
67 BUF_ASSERT_FREE(st
->buff
);
72 static void tun_deliver_to_kernel(void *sst
, void *cid
,
73 struct buffer_if
*buf
)
79 /* No error checking, because we'd just throw the packet away anyway */
80 write(st
->fd
,buf
->start
,buf
->size
);
84 static bool_t
tun_set_route(void *sst
, struct netlink_route
*route
)
87 string_t network
, mask
, secnetaddr
;
89 if (route
->up
!= route
->kup
) {
90 network
=ipaddr_to_string(route
->net
.prefix
);
91 mask
=ipaddr_to_string(route
->net
.mask
);
92 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
93 Message(M_INFO
,"%s: %s route %s/%d %s kernel routing table\n",
94 st
->nl
.name
,route
->up?
"adding":"deleting",network
,
95 route
->net
.len
,route
->up?
"to":"from");
96 sys_cmd(st
->route_path
,"route",route
->up?
"add":"del","-net",network
,
97 "netmask",mask
,"gw",secnetaddr
,(char *)0);
98 free(network
); free(mask
); free(secnetaddr
);
105 static void tun_phase_hook(void *sst
, uint32_t newphase
)
108 string_t hostaddr
,secnetaddr
;
110 string_t network
,mask
;
111 struct netlink_route
*r
;
115 if (st
->search_for_if
) {
119 /* ASSERT st->interface_name */
120 dname
=safe_malloc(strlen(st
->device_path
)+4,"tun_old_apply");
121 st
->interface_name
=safe_malloc(8,"tun_phase_hook");
123 for (i
=0; i
<255; i
++) {
124 sprintf(dname
,"%s%d",st
->device_path
,i
);
125 if ((st
->fd
=open(dname
,O_RDWR
))>0) {
126 sprintf(st
->interface_name
,"tun%d",i
);
127 Message(M_INFO
,"%s: allocated network interface %s "
128 "through %s\n",st
->nl
.name
,st
->interface_name
,
134 fatal("%s: unable to open any TUN device (%s...)\n",
135 st
->nl
.name
,st
->device_path
);
138 st
->fd
=open(st
->device_path
,O_RDWR
);
140 fatal_perror("%s: unable to open TUN device file %s",
141 st
->nl
.name
,st
->device_path
);
145 #ifdef HAVE_LINUX_IF_H
148 /* New TUN interface: open the device, then do ioctl TUNSETIFF
149 to set or find out the network interface name. */
150 st
->fd
=open(st
->device_path
,O_RDWR
);
152 fatal_perror("%s: can't open device file %s",st
->nl
.name
,
155 memset(&ifr
,0,sizeof(ifr
));
156 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Just send/receive IP packets,
158 if (st
->interface_name
)
159 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
160 Message(M_DEBUG
,"%s: about to ioctl(TUNSETIFF)...\n",st
->nl
.name
);
161 if (ioctl(st
->fd
,TUNSETIFF
,&ifr
)<0) {
162 fatal_perror("%s: ioctl(TUNSETIFF)",st
->nl
.name
);
164 if (!st
->interface_name
) {
165 st
->interface_name
=safe_malloc(strlen(ifr
.ifr_name
)+1,"tun_apply");
166 strcpy(st
->interface_name
,ifr
.ifr_name
);
167 Message(M_INFO
,"%s: allocated network interface %s\n",st
->nl
.name
,
171 fatal("netlink.c:tun_phase_hook:!tun_old unexpected\n");
172 #endif /* HAVE_LINUX_IF_H */
174 /* All the networks we'll be using have been registered. Invoke ifconfig
175 to set the TUN device's address, and route to add routes to all
178 hostaddr
=ipaddr_to_string(st
->local_address
);
179 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
180 snprintf(mtu
,6,"%d",st
->nl
.mtu
);
183 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
184 hostaddr
,"netmask","255.255.255.255","-broadcast",
185 "pointopoint",secnetaddr
,"mtu",mtu
,"up",(char *)0);
188 for (i
=0; i
<st
->nl
.n_routes
; i
++) {
189 if (r
[i
].up
&& !r
[i
].kup
) {
190 network
=ipaddr_to_string(r
[i
].net
.prefix
);
191 mask
=ipaddr_to_string(r
[i
].net
.mask
);
192 sys_cmd(st
->route_path
,"route","add","-net",network
,
193 "netmask",mask
,"gw",secnetaddr
,(char *)0);
198 /* Register for poll() */
199 register_for_poll(st
, tun_beforepoll
, tun_afterpoll
, 1, st
->nl
.name
);
202 #ifdef HAVE_LINUX_IF_H
203 static list_t
*tun_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
210 st
=safe_malloc(sizeof(*st
),"tun_apply");
212 /* First parameter must be a dict */
213 item
=list_elem(args
,0);
214 if (!item
|| item
->type
!=t_dict
)
215 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
217 dict
=item
->data
.dict
;
219 st
->netlink_to_tunnel
=
220 netlink_init(&st
->nl
,st
,loc
,dict
,
221 "netlink-tun",tun_set_route
,tun_deliver_to_kernel
);
224 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
225 st
->interface_name
=dict_read_string(dict
,"interface",False
,
227 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",
228 False
,"tun-netlink",loc
);
229 st
->route_path
=dict_read_string(dict
,"route-path",
230 False
,"tun-netlink",loc
);
232 if (!st
->device_path
) st
->device_path
="/dev/net/tun";
233 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
234 if (!st
->route_path
) st
->route_path
="route";
235 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
236 st
->local_address
=string_to_ipaddr(
237 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
239 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
241 return new_closure(&st
->nl
.cl
);
243 #endif /* HAVE_LINUX_IF_H */
245 static list_t
*tun_old_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
252 st
=safe_malloc(sizeof(*st
),"tun_old_apply");
254 Message(M_WARNING
,"the tun-old code has never been tested. Please report "
255 "success or failure to steve@greenend.org.uk\n");
257 /* First parameter must be a dict */
258 item
=list_elem(args
,0);
259 if (!item
|| item
->type
!=t_dict
)
260 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
262 dict
=item
->data
.dict
;
264 st
->netlink_to_tunnel
=
265 netlink_init(&st
->nl
,st
,loc
,dict
,
266 "netlink-tun",NULL
,tun_deliver_to_kernel
);
269 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
270 st
->interface_name
=dict_read_string(dict
,"interface",False
,
272 st
->search_for_if
=dict_read_bool(dict
,"interface-search",False
,
273 "tun-netlink",loc
,st
->device_path
==NULL
);
274 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",False
,
276 st
->route_path
=dict_read_string(dict
,"route-path",False
,"tun-netlink",loc
);
278 if (!st
->device_path
) st
->device_path
="/dev/tun";
279 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
280 if (!st
->route_path
) st
->route_path
="route";
281 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
282 st
->local_address
=string_to_ipaddr(
283 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
285 /* Old TUN interface: the network interface name depends on which
286 /dev/tunX file we open. If 'interface-search' is set to true, treat
287 'device' as the prefix and try numbers from 0--255. If it's set
288 to false, treat 'device' as the whole name, and require than an
289 appropriate interface name be specified. */
290 if (st
->search_for_if
&& st
->interface_name
) {
291 cfgfatal(loc
,"tun-old","you may not specify an interface name "
292 "in interface-search mode\n");
294 if (!st
->search_for_if
&& !st
->interface_name
) {
295 cfgfatal(loc
,"tun-old","you must specify an interface name "
296 "when you explicitly specify a TUN device file\n");
300 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
302 return new_closure(&st
->nl
.cl
);
305 init_module tun_module
;
306 void tun_module(dict_t
*dict
)
308 #ifdef HAVE_LINUX_IF_H
309 add_closure(dict
,"tun",tun_apply
);
311 add_closure(dict
,"tun-old",tun_old_apply
);