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
;
33 static int tun_beforepoll(void *sst
, struct pollfd
*fds
, int *nfds_io
,
34 int *timeout_io
, const struct timeval
*tv_now
,
40 fds
[0].events
=POLLIN
|POLLERR
|POLLHUP
;
44 static void tun_afterpoll(void *sst
, struct pollfd
*fds
, int nfds
,
45 const struct timeval
*tv_now
, uint64_t *now
)
50 if (fds
[0].revents
&POLLERR
) {
51 printf("tun_afterpoll: hup!\n");
53 if (fds
[0].revents
&POLLIN
) {
54 BUF_ALLOC(st
->buff
,"tun_afterpoll");
55 buffer_init(st
->buff
,st
->nl
.max_start_pad
);
56 l
=read(st
->fd
,st
->buff
->start
,st
->buff
->len
-st
->nl
.max_start_pad
);
58 fatal_perror("tun_afterpoll: read()");
61 fatal("tun_afterpoll: read()=0; device gone away?\n");
65 st
->netlink_to_tunnel(&st
->nl
,NULL
,st
->buff
);
66 BUF_ASSERT_FREE(st
->buff
);
71 static void tun_deliver_to_kernel(void *sst
, void *cid
,
72 struct buffer_if
*buf
)
78 /* No error checking, because we'd just throw the packet away anyway */
79 write(st
->fd
,buf
->start
,buf
->size
);
83 static bool_t
tun_set_route(void *sst
, struct netlink_route
*route
)
86 string_t network
, mask
, secnetaddr
;
88 if (route
->up
!= route
->kup
) {
89 network
=ipaddr_to_string(route
->net
.prefix
);
90 mask
=ipaddr_to_string(route
->net
.mask
);
91 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
92 Message(M_INFO
,"%s: %s route %s/%d %s kernel routing table\n",
93 st
->nl
.name
,route
->up?
"adding":"deleting",network
,
94 route
->net
.len
,route
->up?
"to":"from");
95 sys_cmd(st
->route_path
,"route",route
->up?
"add":"del","-net",network
,
96 "netmask",mask
,"gw",secnetaddr
,(char *)0);
97 free(network
); free(mask
); free(secnetaddr
);
104 static void tun_phase_hook(void *sst
, uint32_t newphase
)
107 string_t hostaddr
,secnetaddr
;
109 string_t network
,mask
;
110 struct netlink_route
*r
;
114 if (st
->search_for_if
) {
118 /* ASSERT st->interface_name */
119 dname
=safe_malloc(strlen(st
->device_path
)+4,"tun_old_apply");
120 st
->interface_name
=safe_malloc(8,"tun_phase_hook");
122 for (i
=0; i
<255; i
++) {
123 sprintf(dname
,"%s%d",st
->device_path
,i
);
124 if ((st
->fd
=open(dname
,O_RDWR
))>0) {
125 sprintf(st
->interface_name
,"tun%d",i
);
126 Message(M_INFO
,"%s: allocated network interface %s "
127 "through %s\n",st
->nl
.name
,st
->interface_name
,
133 fatal("%s: unable to open any TUN device (%s...)\n",
134 st
->nl
.name
,st
->device_path
);
137 st
->fd
=open(st
->device_path
,O_RDWR
);
139 fatal_perror("%s: unable to open TUN device file %s",
140 st
->nl
.name
,st
->device_path
);
144 #ifdef HAVE_LINUX_IF_H
147 /* New TUN interface: open the device, then do ioctl TUNSETIFF
148 to set or find out the network interface name. */
149 st
->fd
=open(st
->device_path
,O_RDWR
);
151 fatal_perror("%s: can't open device file %s",st
->nl
.name
,
154 memset(&ifr
,0,sizeof(ifr
));
155 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Just send/receive IP packets,
157 if (st
->interface_name
)
158 strncpy(ifr
.ifr_name
,st
->interface_name
,IFNAMSIZ
);
159 Message(M_INFO
,"%s: about to ioctl(TUNSETIFF)...\n",st
->nl
.name
);
160 if (ioctl(st
->fd
,TUNSETIFF
,&ifr
)<0) {
161 fatal_perror("%s: ioctl(TUNSETIFF)",st
->nl
.name
);
163 if (!st
->interface_name
) {
164 st
->interface_name
=safe_malloc(strlen(ifr
.ifr_name
)+1,"tun_apply");
165 strcpy(st
->interface_name
,ifr
.ifr_name
);
166 Message(M_INFO
,"%s: allocated network interface %s\n",st
->nl
.name
,
170 fatal("netlink.c:tun_phase_hook:!tun_old unexpected\n");
171 #endif /* HAVE_LINUX_IF_H */
173 /* All the networks we'll be using have been registered. Invoke ifconfig
174 to set the TUN device's address, and route to add routes to all
177 hostaddr
=ipaddr_to_string(st
->nl
.local_address
);
178 secnetaddr
=ipaddr_to_string(st
->nl
.secnet_address
);
179 snprintf(mtu
,6,"%d",st
->nl
.mtu
);
182 sys_cmd(st
->ifconfig_path
,"ifconfig",st
->interface_name
,
183 hostaddr
,"netmask","255.255.255.255","-broadcast",
184 "pointopoint",secnetaddr
,"mtu",mtu
,"up",(char *)0);
187 for (i
=0; i
<st
->nl
.n_routes
; i
++) {
188 if (r
[i
].up
&& !r
[i
].kup
) {
189 network
=ipaddr_to_string(r
[i
].net
.prefix
);
190 mask
=ipaddr_to_string(r
[i
].net
.mask
);
191 sys_cmd(st
->route_path
,"route","add","-net",network
,
192 "netmask",mask
,"gw",secnetaddr
,(char *)0);
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
);
236 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
238 return new_closure(&st
->nl
.cl
);
240 #endif /* HAVE_LINUX_IF_H */
242 static list_t
*tun_old_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
249 st
=safe_malloc(sizeof(*st
),"tun_old_apply");
251 Message(M_WARNING
,"the tun-old code has never been tested. Please report "
252 "success or failure to steve@greenend.org.uk\n");
254 /* First parameter must be a dict */
255 item
=list_elem(args
,0);
256 if (!item
|| item
->type
!=t_dict
)
257 cfgfatal(loc
,"tun","parameter must be a dictionary\n");
259 dict
=item
->data
.dict
;
261 st
->netlink_to_tunnel
=
262 netlink_init(&st
->nl
,st
,loc
,dict
,
263 "netlink-tun",NULL
,tun_deliver_to_kernel
);
266 st
->device_path
=dict_read_string(dict
,"device",False
,"tun-netlink",loc
);
267 st
->interface_name
=dict_read_string(dict
,"interface",False
,
269 st
->search_for_if
=dict_read_bool(dict
,"interface-search",False
,
270 "tun-netlink",loc
,st
->device_path
==NULL
);
271 st
->ifconfig_path
=dict_read_string(dict
,"ifconfig-path",False
,
273 st
->route_path
=dict_read_string(dict
,"route-path",False
,"tun-netlink",loc
);
275 if (!st
->device_path
) st
->device_path
="/dev/tun";
276 if (!st
->ifconfig_path
) st
->ifconfig_path
="ifconfig";
277 if (!st
->route_path
) st
->route_path
="route";
278 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"tun-netlink",loc
);
280 /* Old TUN interface: the network interface name depends on which
281 /dev/tunX file we open. If 'interface-search' is set to true, treat
282 'device' as the prefix and try numbers from 0--255. If it's set
283 to false, treat 'device' as the whole name, and require than an
284 appropriate interface name be specified. */
285 if (st
->search_for_if
&& st
->interface_name
) {
286 cfgfatal(loc
,"tun-old","you may not specify an interface name "
287 "in interface-search mode\n");
289 if (!st
->search_for_if
&& !st
->interface_name
) {
290 cfgfatal(loc
,"tun-old","you must specify an interface name "
291 "when you explicitly specify a TUN device file\n");
295 add_hook(PHASE_GETRESOURCES
,tun_phase_hook
,st
);
297 return new_closure(&st
->nl
.cl
);
300 init_module tun_module
;
301 void tun_module(dict_t
*dict
)
303 #ifdef HAVE_LINUX_IF_H
304 add_closure(dict
,"tun",tun_apply
);
306 add_closure(dict
,"tun-old",tun_old_apply
);