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, ...
88 METHOD(tun_device_t
, set_address
, bool,
89 private_tun_device_t
*this, host_t
*addr
, u_int8_t netmask
)
94 memset(&ifr
, 0, sizeof(ifr
));
95 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
96 memcpy(&ifr
.ifr_addr
, addr
->get_sockaddr(addr
),
97 *addr
->get_sockaddr_len(addr
));
99 if (ioctl(this->sock
, SIOCSIFADDR
, &ifr
) < 0)
101 DBG1(DBG_LIB
, "failed to set address on %s: %s",
102 this->if_name
, strerror(errno
));
106 if (ioctl(this->sock
, SIOCSIFDSTADDR
, &ifr
) < 0)
108 DBG1(DBG_LIB
, "failed to set dest address on %s: %s",
109 this->if_name
, strerror(errno
));
112 #endif /* __APPLE__ */
114 mask
= host_create_netmask(addr
->get_family(addr
), netmask
);
117 DBG1(DBG_LIB
, "invalid netmask: %d", netmask
);
120 memcpy(&ifr
.ifr_addr
, mask
->get_sockaddr(mask
),
121 *mask
->get_sockaddr_len(mask
));
124 if (ioctl(this->sock
, SIOCSIFNETMASK
, &ifr
) < 0)
126 DBG1(DBG_LIB
, "failed to set netmask on %s: %s",
127 this->if_name
, strerror(errno
));
130 this->address
= addr
->clone(addr
);
131 this->netmask
= netmask
;
135 METHOD(tun_device_t
, get_address
, host_t
*,
136 private_tun_device_t
*this, u_int8_t
*netmask
)
138 if (netmask
&& this->address
)
140 *netmask
= this->netmask
;
142 return this->address
;
145 METHOD(tun_device_t
, up
, bool,
146 private_tun_device_t
*this)
150 memset(&ifr
, 0, sizeof(ifr
));
151 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
153 if (ioctl(this->sock
, SIOCGIFFLAGS
, &ifr
) < 0)
155 DBG1(DBG_LIB
, "failed to get interface flags for %s: %s", this->if_name
,
160 ifr
.ifr_flags
|= IFF_RUNNING
| IFF_UP
;
162 if (ioctl(this->sock
, SIOCSIFFLAGS
, &ifr
) < 0)
164 DBG1(DBG_LIB
, "failed to set interface flags on %s: %s", this->if_name
,
171 METHOD(tun_device_t
, set_mtu
, bool,
172 private_tun_device_t
*this, int mtu
)
176 memset(&ifr
, 0, sizeof(ifr
));
177 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
180 if (ioctl(this->sock
, SIOCSIFMTU
, &ifr
) < 0)
182 DBG1(DBG_LIB
, "failed to set MTU on %s: %s", this->if_name
,
190 METHOD(tun_device_t
, get_mtu
, int,
191 private_tun_device_t
*this)
200 memset(&ifr
, 0, sizeof(ifr
));
201 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
202 this->mtu
= TUN_DEFAULT_MTU
;
204 if (ioctl(this->sock
, SIOCGIFMTU
, &ifr
) == 0)
206 this->mtu
= ifr
.ifr_mtu
;
211 METHOD(tun_device_t
, get_name
, char*,
212 private_tun_device_t
*this)
214 return this->if_name
;
217 METHOD(tun_device_t
, get_fd
, int,
218 private_tun_device_t
*this)
223 METHOD(tun_device_t
, write_packet
, bool,
224 private_tun_device_t
*this, chunk_t packet
)
229 /* UTUN's expect the packets to be prepended by a 32-bit protocol number
230 * instead of parsing the packet again, we assume IPv4 for now */
231 u_int32_t proto
= htonl(AF_INET
);
232 packet
= chunk_cata("cc", chunk_from_thing(proto
), packet
);
234 s
= write(this->tunfd
, packet
.ptr
, packet
.len
);
237 DBG1(DBG_LIB
, "failed to write packet to TUN device %s: %s",
238 this->if_name
, strerror(errno
));
241 else if (s
!= packet
.len
)
248 METHOD(tun_device_t
, read_packet
, bool,
249 private_tun_device_t
*this, chunk_t
*packet
)
256 FD_SET(this->tunfd
, &set
);
258 old
= thread_cancelability(TRUE
);
259 len
= select(this->tunfd
+ 1, &set
, NULL
, NULL
, NULL
);
260 thread_cancelability(old
);
264 DBG1(DBG_LIB
, "select on TUN device %s failed: %s", this->if_name
,
268 /* FIXME: this is quite expensive for lots of small packets, copy from
269 * local buffer instead? */
270 *packet
= chunk_alloc(get_mtu(this));
271 len
= read(this->tunfd
, packet
->ptr
, packet
->len
);
274 DBG1(DBG_LIB
, "reading from TUN device %s failed: %s", this->if_name
,
281 /* UTUN's prepend packets with a 32-bit protocol number */
282 packet
->len
-= sizeof(u_int32_t
);
283 memmove(packet
->ptr
, packet
->ptr
+ sizeof(u_int32_t
), packet
->len
);
288 METHOD(tun_device_t
, destroy
, void,
289 private_tun_device_t
*this)
295 /* tun(4) says the following: "These network interfaces persist until
296 * the if_tun.ko module is unloaded, or until removed with the
297 * ifconfig(8) command." So simply closing the FD is not enough. */
300 memset(&ifr
, 0, sizeof(ifr
));
301 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
302 if (ioctl(this->sock
, SIOCIFDESTROY
, &ifr
) < 0)
304 DBG1(DBG_LIB
, "failed to destroy %s: %s", this->if_name
,
307 #endif /* __FreeBSD__ */
313 DESTROY_IF(this->address
);
318 * Initialize the tun device
320 static bool init_tun(private_tun_device_t
*this, const char *name_tmpl
)
324 struct ctl_info info
;
325 struct sockaddr_ctl addr
;
326 socklen_t size
= IFNAMSIZ
;
328 memset(&info
, 0, sizeof(info
));
329 memset(&addr
, 0, sizeof(addr
));
331 this->tunfd
= socket(PF_SYSTEM
, SOCK_DGRAM
, SYSPROTO_CONTROL
);
334 DBG1(DBG_LIB
, "failed to open tundevice PF_SYSTEM socket: %s",
339 /* get a control identifier for the utun kernel extension */
340 strncpy(info
.ctl_name
, UTUN_CONTROL_NAME
, strlen(UTUN_CONTROL_NAME
));
341 if (ioctl(this->tunfd
, CTLIOCGINFO
, &info
) < 0)
343 DBG1(DBG_LIB
, "failed to ioctl tundevice: %s", strerror(errno
));
348 addr
.sc_id
= info
.ctl_id
;
349 addr
.sc_len
= sizeof(addr
);
350 addr
.sc_family
= AF_SYSTEM
;
351 addr
.ss_sysaddr
= AF_SYS_CONTROL
;
352 /* allocate identifier dynamically */
355 if (connect(this->tunfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
357 DBG1(DBG_LIB
, "failed to connect tundevice: %s", strerror(errno
));
361 if (getsockopt(this->tunfd
, SYSPROTO_CONTROL
, UTUN_OPT_IFNAME
,
362 this->if_name
, &size
) < 0)
364 DBG1(DBG_LIB
, "getting tundevice name failed: %s", strerror(errno
));
370 #elif defined(IFF_TUN)
374 strncpy(this->if_name
, name_tmpl ?
: "tun%d", IFNAMSIZ
);
375 this->if_name
[IFNAMSIZ
-1] = '\0';
377 this->tunfd
= open("/dev/net/tun", O_RDWR
);
380 DBG1(DBG_LIB
, "failed to open /dev/net/tun: %s", strerror(errno
));
384 memset(&ifr
, 0, sizeof(ifr
));
386 /* TUN device, no packet info */
387 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
;
389 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
390 if (ioctl(this->tunfd
, TUNSETIFF
, (void*)&ifr
) < 0)
392 DBG1(DBG_LIB
, "failed to configure TUN device: %s", strerror(errno
));
396 strncpy(this->if_name
, ifr
.ifr_name
, IFNAMSIZ
);
401 /* this works on FreeBSD and might also work on Linux with older TUN
402 * driver versions (no IFF_TUN) */
403 char devname
[IFNAMSIZ
];
404 /* the same process is allowed to open a device again, but that's not what
405 * we want (unless we previously closed a device, which we don't know at
406 * this point). therefore, this counter is static so we don't accidentally
407 * open a device twice */
412 DBG1(DBG_LIB
, "arbitrary naming of TUN devices is not supported");
417 snprintf(devname
, IFNAMSIZ
, "/dev/tun%d", i
);
418 this->tunfd
= open(devname
, O_RDWR
);
420 { /* for ioctl(2) calls only the interface name is used */
421 snprintf(this->if_name
, IFNAMSIZ
, "tun%d", i
);
424 DBG1(DBG_LIB
, "failed to open %s: %s", this->if_name
, strerror(errno
));
426 return this->tunfd
> 0;
428 #endif /* !__APPLE__ */
432 * Described in header
434 tun_device_t
*tun_device_create(const char *name_tmpl
)
436 private_tun_device_t
*this;
440 .read_packet
= _read_packet
,
441 .write_packet
= _write_packet
,
444 .get_name
= _get_name
,
446 .set_address
= _set_address
,
447 .get_address
= _get_address
,
455 if (!init_tun(this, name_tmpl
))
460 DBG1(DBG_LIB
, "created TUN device: %s", this->if_name
);
462 this->sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
465 DBG1(DBG_LIB
, "failed to open socket to configure TUN device");
469 return &this->public;