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
,NULL
,st
->buff
);
68 BUF_ASSERT_FREE(st
->buff
);
73 static void tun_deliver_to_kernel(void *sst
, void *cid
,
74 struct buffer_if
*buf
)
79 /* No error checking, because we'd just throw the packet away
80 anyway if it didn't work. */
81 write(st
->fd
,buf
->start
,buf
->size
);
85 static bool_t
tun_set_route(void *sst
, struct netlink_route
*route
)
88 string_t network
, mask
, secnetaddr
;
90 if (route
->up
!= route
->kup
) {
91 network
=ipaddr_to_string(route
->net
.prefix
);
92 mask
=ipaddr_to_string(route
->net
.mask
);
93 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
94 Message(M_INFO
,"%s: %s route %s/%d %s kernel routing table\n",
95 st
->nl
.name
,route
->up?
"adding":"deleting",network
,
96 route
->net
.len
,route
->up?
"to":"from");
97 sys_cmd(st
->route_path
,"route",route
->up?
"add":"del","-net",network
,
98 "netmask",mask
,"gw",secnetaddr
,(char *)0);
99 free(network
); free(mask
); free(secnetaddr
);
100 route
->kup
=route
->up
;
106 static void tun_phase_hook(void *sst
, uint32_t newphase
)
109 string_t hostaddr
,secnetaddr
;
111 string_t network
,mask
;
112 struct netlink_route
*r
;
116 if (st
->search_for_if
) {
120 /* ASSERT st->interface_name */
121 dname
=safe_malloc(strlen(st
->device_path
)+4,"tun_old_apply");
122 st
->interface_name
=safe_malloc(8,"tun_phase_hook");
124 for (i
=0; i
<255; i
++) {
125 sprintf(dname
,"%s%d",st
->device_path
,i
);
126 if ((st
->fd
=open(dname
,O_RDWR
))>0) {
127 sprintf(st
->interface_name
,"tun%d",i
);
128 Message(M_INFO
,"%s: allocated network interface %s "
129 "through %s\n",st
->nl
.name
,st
->interface_name
,
135 fatal("%s: unable to open any TUN device (%s...)\n",
136 st
->nl
.name
,st
->device_path
);
139 st
->fd
=open(st
->device_path
,O_RDWR
);
141 fatal_perror("%s: unable to open TUN device file %s",
142 st
->nl
.name
,st
->device_path
);
146 #ifdef HAVE_LINUX_IF_H
149 /* New TUN interface: open the device, then do ioctl TUNSETIFF
150 to set or find out the network interface name. */
151 st
->fd
=open(st
->device_path
,O_RDWR
);
153 fatal_perror("%s: can't open device file %s",st
->nl
.name
,
156 memset(&ifr
,0,sizeof(ifr
));
157 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Just send/receive IP packets,
159 if (st
->interface_name
)
160 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
161 Message(M_DEBUG
,"%s: about to ioctl(TUNSETIFF)...\n",st
->nl
.name
);
162 if (ioctl(st
->fd
,TUNSETIFF
,&ifr
)<0) {
163 fatal_perror("%s: ioctl(TUNSETIFF)",st
->nl
.name
);
165 if (!st
->interface_name
) {
166 st
->interface_name
=safe_malloc(strlen(ifr
.ifr_name
)+1,"tun_apply");
167 strcpy(st
->interface_name
,ifr
.ifr_name
);
168 Message(M_INFO
,"%s: allocated network interface %s\n",st
->nl
.name
,
172 fatal("netlink.c:tun_phase_hook:!tun_old unexpected\n");
173 #endif /* HAVE_LINUX_IF_H */
175 /* All the networks we'll be using have been registered. Invoke ifconfig
176 to set the TUN device's address, and route to add routes to all
179 hostaddr
=ipaddr_to_string(st
->local_address
);
180 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
181 snprintf(mtu
,6,"%d",st
->nl
.mtu
);
184 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
185 hostaddr
,"netmask","255.255.255.255","-broadcast",
186 "pointopoint",secnetaddr
,"mtu",mtu
,"up",(char *)0);
189 for (i
=0; i
<st
->nl
.n_routes
; i
++) {
190 if (r
[i
].up
&& !r
[i
].kup
) {
191 network
=ipaddr_to_string(r
[i
].net
.prefix
);
192 mask
=ipaddr_to_string(r
[i
].net
.mask
);
193 sys_cmd(st
->route_path
,"route","add","-net",network
,
194 "netmask",mask
,"gw",secnetaddr
,(char *)0);
199 /* Register for poll() */
200 register_for_poll(st
, tun_beforepoll
, tun_afterpoll
, 1, st
->nl
.name
);
203 #ifdef HAVE_LINUX_IF_H
204 static list_t
*tun_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
211 st
=safe_malloc(sizeof(*st
),"tun_apply");
213 /* First parameter must be a dict */
214 item
=list_elem(args
,0);
215 if (!item
|| item
->type
!=t_dict
)
216 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
218 dict
=item
->data
.dict
;
220 st
->netlink_to_tunnel
=
221 netlink_init(&st
->nl
,st
,loc
,dict
,
222 "netlink-tun",tun_set_route
,tun_deliver_to_kernel
);
225 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
226 st
->interface_name
=dict_read_string(dict
,"interface",False
,
228 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",
229 False
,"tun-netlink",loc
);
230 st
->route_path
=dict_read_string(dict
,"route-path",
231 False
,"tun-netlink",loc
);
233 if (!st
->device_path
) st
->device_path
="/dev/net/tun";
234 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
235 if (!st
->route_path
) st
->route_path
="route";
236 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
237 st
->local_address
=string_to_ipaddr(
238 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
240 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
242 return new_closure(&st
->nl
.cl
);
244 #endif /* HAVE_LINUX_IF_H */
246 static list_t
*tun_old_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
253 st
=safe_malloc(sizeof(*st
),"tun_old_apply");
255 Message(M_WARNING
,"the tun-old code has never been tested. Please report "
256 "success or failure to steve@greenend.org.uk\n");
258 /* First parameter must be a dict */
259 item
=list_elem(args
,0);
260 if (!item
|| item
->type
!=t_dict
)
261 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
263 dict
=item
->data
.dict
;
265 st
->netlink_to_tunnel
=
266 netlink_init(&st
->nl
,st
,loc
,dict
,
267 "netlink-tun",NULL
,tun_deliver_to_kernel
);
270 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
271 st
->interface_name
=dict_read_string(dict
,"interface",False
,
273 st
->search_for_if
=dict_read_bool(dict
,"interface-search",False
,
274 "tun-netlink",loc
,st
->device_path
==NULL
);
275 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",False
,
277 st
->route_path
=dict_read_string(dict
,"route-path",False
,"tun-netlink",loc
);
279 if (!st
->device_path
) st
->device_path
="/dev/tun";
280 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
281 if (!st
->route_path
) st
->route_path
="route";
282 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
283 st
->local_address
=string_to_ipaddr(
284 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
286 /* Old TUN interface: the network interface name depends on which
287 /dev/tunX file we open. If 'interface-search' is set to true, treat
288 'device' as the prefix and try numbers from 0--255. If it's set
289 to false, treat 'device' as the whole name, and require than an
290 appropriate interface name be specified. */
291 if (st
->search_for_if
&& st
->interface_name
) {
292 cfgfatal(loc
,"tun-old","you may not specify an interface name "
293 "in interface-search mode\n");
295 if (!st
->search_for_if
&& !st
->interface_name
) {
296 cfgfatal(loc
,"tun-old","you must specify an interface name "
297 "when you explicitly specify a TUN device file\n");
301 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
303 return new_closure(&st
->nl
.cl
);
306 init_module tun_module
;
307 void tun_module(dict_t
*dict
)
309 #ifdef HAVE_LINUX_IF_H
310 add_closure(dict
,"tun",tun_apply
);
312 add_closure(dict
,"tun-old",tun_old_apply
);