2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
6 * Copyright (C) 2012 Martin Willi
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
31 #include <net/if_utun.h>
32 #include <netinet/in_var.h>
33 #include <sys/kern_control.h>
34 #elif defined(__linux__)
35 #include <linux/if_tun.h>
37 #include <net/if_tun.h>
40 #include "tun_device.h"
43 #include <utils/debug.h>
44 #include <threading/thread.h>
46 #define TUN_DEFAULT_MTU 1500
48 typedef struct private_tun_device_t private_tun_device_t
;
50 struct private_tun_device_t
{
58 * The TUN device's file descriptor
63 * Name of the TUN device
65 char if_name
[IFNAMSIZ
];
68 * Socket used for ioctl() to set interface addr, ...
78 METHOD(tun_device_t
, set_address
, bool,
79 private_tun_device_t
*this, host_t
*addr
, u_int8_t netmask
)
84 memset(&ifr
, 0, sizeof(ifr
));
85 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
86 memcpy(&ifr
.ifr_addr
, addr
->get_sockaddr(addr
),
87 *addr
->get_sockaddr_len(addr
));
89 if (ioctl(this->sock
, SIOCSIFADDR
, &ifr
) < 0)
91 DBG1(DBG_LIB
, "failed to set address on %s: %s",
92 this->if_name
, strerror(errno
));
96 if (ioctl(this->sock
, SIOCSIFDSTADDR
, &ifr
) < 0)
98 DBG1(DBG_LIB
, "failed to set dest address on %s: %s",
99 this->if_name
, strerror(errno
));
102 #endif /* __APPLE__ */
104 mask
= host_create_netmask(addr
->get_family(addr
), netmask
);
107 DBG1(DBG_LIB
, "invalid netmask: %d", netmask
);
110 memcpy(&ifr
.ifr_addr
, mask
->get_sockaddr(mask
),
111 *mask
->get_sockaddr_len(mask
));
114 if (ioctl(this->sock
, SIOCSIFNETMASK
, &ifr
) < 0)
116 DBG1(DBG_LIB
, "failed to set netmask on %s: %s",
117 this->if_name
, strerror(errno
));
123 METHOD(tun_device_t
, up
, bool,
124 private_tun_device_t
*this)
128 memset(&ifr
, 0, sizeof(ifr
));
129 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
131 if (ioctl(this->sock
, SIOCGIFFLAGS
, &ifr
) < 0)
133 DBG1(DBG_LIB
, "failed to get interface flags for %s: %s", this->if_name
,
138 ifr
.ifr_flags
|= IFF_RUNNING
| IFF_UP
;
140 if (ioctl(this->sock
, SIOCSIFFLAGS
, &ifr
) < 0)
142 DBG1(DBG_LIB
, "failed to set interface flags on %s: %s", this->if_name
,
149 METHOD(tun_device_t
, set_mtu
, bool,
150 private_tun_device_t
*this, int mtu
)
154 memset(&ifr
, 0, sizeof(ifr
));
155 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
158 if (ioctl(this->sock
, SIOCSIFMTU
, &ifr
) < 0)
160 DBG1(DBG_LIB
, "failed to set MTU on %s: %s", this->if_name
,
168 METHOD(tun_device_t
, get_mtu
, int,
169 private_tun_device_t
*this)
178 memset(&ifr
, 0, sizeof(ifr
));
179 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
180 this->mtu
= TUN_DEFAULT_MTU
;
182 if (ioctl(this->sock
, SIOCGIFMTU
, &ifr
) == 0)
184 this->mtu
= ifr
.ifr_mtu
;
189 METHOD(tun_device_t
, get_name
, char*,
190 private_tun_device_t
*this)
192 return this->if_name
;
195 METHOD(tun_device_t
, get_fd
, int,
196 private_tun_device_t
*this)
201 METHOD(tun_device_t
, write_packet
, bool,
202 private_tun_device_t
*this, chunk_t packet
)
206 s
= write(this->tunfd
, packet
.ptr
, packet
.len
);
209 DBG1(DBG_LIB
, "failed to write packet to TUN device %s: %s",
210 this->if_name
, strerror(errno
));
213 else if (s
!= packet
.len
)
220 METHOD(tun_device_t
, read_packet
, bool,
221 private_tun_device_t
*this, chunk_t
*packet
)
228 FD_SET(this->tunfd
, &set
);
230 old
= thread_cancelability(TRUE
);
231 len
= select(this->tunfd
+ 1, &set
, NULL
, NULL
, NULL
);
232 thread_cancelability(old
);
236 DBG1(DBG_LIB
, "select on TUN device %s failed: %s", this->if_name
,
240 /* FIXME: this is quite expensive for lots of small packets, copy from
241 * local buffer instead? */
242 *packet
= chunk_alloc(get_mtu(this));
243 len
= read(this->tunfd
, packet
->ptr
, packet
->len
);
246 DBG1(DBG_LIB
, "reading from TUN device %s failed: %s", this->if_name
,
255 METHOD(tun_device_t
, destroy
, void,
256 private_tun_device_t
*this)
262 /* tun(4) says the following: "These network interfaces persist until
263 * the if_tun.ko module is unloaded, or until removed with the
264 * ifconfig(8) command." So simply closing the FD is not enough. */
267 memset(&ifr
, 0, sizeof(ifr
));
268 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
269 if (ioctl(this->sock
, SIOCIFDESTROY
, &ifr
) < 0)
271 DBG1(DBG_LIB
, "failed to destroy %s: %s", this->if_name
,
274 #endif /* __FreeBSD__ */
284 * Initialize the tun device
286 static bool init_tun(private_tun_device_t
*this, const char *name_tmpl
)
290 struct ctl_info info
;
291 struct sockaddr_ctl addr
;
292 socklen_t size
= IFNAMSIZ
;
294 memset(&info
, 0, sizeof(info
));
295 memset(&addr
, 0, sizeof(addr
));
297 this->tunfd
= socket(PF_SYSTEM
, SOCK_DGRAM
, SYSPROTO_CONTROL
);
300 DBG1(DBG_LIB
, "failed to open tundevice PF_SYSTEM socket: %s",
305 /* get a control identifier for the utun kernel extension */
306 strncpy(info
.ctl_name
, UTUN_CONTROL_NAME
, strlen(UTUN_CONTROL_NAME
));
307 if (ioctl(this->tunfd
, CTLIOCGINFO
, &info
) < 0)
309 DBG1(DBG_LIB
, "failed to ioctl tundevice: %s", strerror(errno
));
314 addr
.sc_id
= info
.ctl_id
;
315 addr
.sc_len
= sizeof(addr
);
316 addr
.sc_family
= AF_SYSTEM
;
317 addr
.ss_sysaddr
= AF_SYS_CONTROL
;
318 /* allocate identifier dynamically */
321 if (connect(this->tunfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
323 DBG1(DBG_LIB
, "failed to connect tundevice: %s", strerror(errno
));
327 if (getsockopt(this->tunfd
, SYSPROTO_CONTROL
, UTUN_OPT_IFNAME
,
328 this->if_name
, &size
) < 0)
330 DBG1(DBG_LIB
, "getting tundevice name failed: %s", strerror(errno
));
336 #elif defined(IFF_TUN)
340 strncpy(this->if_name
, name_tmpl ?
: "tun%d", IFNAMSIZ
);
341 this->if_name
[IFNAMSIZ
-1] = '\0';
343 this->tunfd
= open("/dev/net/tun", O_RDWR
);
346 DBG1(DBG_LIB
, "failed to open /dev/net/tun: %s", strerror(errno
));
350 memset(&ifr
, 0, sizeof(ifr
));
352 /* TUN device, no packet info */
353 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
;
355 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
356 if (ioctl(this->tunfd
, TUNSETIFF
, (void*)&ifr
) < 0)
358 DBG1(DBG_LIB
, "failed to configure TUN device: %s", strerror(errno
));
362 strncpy(this->if_name
, ifr
.ifr_name
, IFNAMSIZ
);
367 /* this works on FreeBSD and might also work on Linux with older TUN
368 * driver versions (no IFF_TUN) */
369 char devname
[IFNAMSIZ
];
374 DBG1(DBG_LIB
, "arbitrary naming of TUN devices is not supported");
377 for (i
= 0; i
< 256; i
++)
379 snprintf(devname
, IFNAMSIZ
, "/dev/tun%d", i
);
380 this->tunfd
= open(devname
, O_RDWR
);
382 { /* for ioctl(2) calls only the interface name is used */
383 snprintf(this->if_name
, IFNAMSIZ
, "tun%d", i
);
386 DBG1(DBG_LIB
, "failed to open %s: %s", this->if_name
, strerror(errno
));
388 return this->tunfd
> 0;
390 #endif /* !__APPLE__ */
394 * Described in header
396 tun_device_t
*tun_device_create(const char *name_tmpl
)
398 private_tun_device_t
*this;
402 .read_packet
= _read_packet
,
403 .write_packet
= _write_packet
,
406 .get_name
= _get_name
,
408 .set_address
= _set_address
,
416 if (!init_tun(this, name_tmpl
))
421 DBG1(DBG_LIB
, "created TUN device: %s", this->if_name
);
423 this->sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
426 DBG1(DBG_LIB
, "failed to open socket to configure TUN device");
430 return &this->public;