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 #else /* !__APPLE__ */
36 #include <linux/if_tun.h>
37 #endif /* !__APPLE__ */
39 #include "tun_device.h"
43 #include <threading/thread.h>
45 #define TUN_DEFAULT_MTU 1500
47 typedef struct private_tun_device_t private_tun_device_t
;
49 struct private_tun_device_t
{
57 * The TUN device's file descriptor
62 * Name of the TUN device
64 char if_name
[IFNAMSIZ
];
67 * Socket used for ioctl() to set interface addr, ...
78 * Set the sockaddr_t from the given netmask
80 static void set_netmask(struct ifreq
*ifr
, int family
, u_int8_t netmask
)
89 struct sockaddr_in
*addr
= (struct sockaddr_in
*)&ifr
->ifr_addr
;
90 addr
->sin_family
= AF_INET
;
91 target
= (char*)&addr
->sin_addr
;
97 struct sockaddr_in6
*addr
= (struct sockaddr_in6
*)&ifr
->ifr_addr
;
98 addr
->sin6_family
= AF_INET6
;
99 target
= (char*)&addr
->sin6_addr
;
107 bytes
= (netmask
+ 7) / 8;
108 bits
= (bytes
* 8) - netmask
;
110 memset(target
, 0xff, bytes
);
111 memset(target
+ bytes
, 0x00, len
- bytes
);
112 target
[bytes
- 1] = bits ?
(u_int8_t
)(0xff << bits
) : 0xff;
115 METHOD(tun_device_t
, set_address
, bool,
116 private_tun_device_t
*this, host_t
*addr
, u_int8_t netmask
)
121 family
= addr
->get_family(addr
);
122 if ((netmask
> 32 && family
== AF_INET
) || netmask
> 128)
124 DBG1(DBG_LIB
, "failed to set address on %s: invalid netmask",
129 memset(&ifr
, 0, sizeof(ifr
));
130 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
131 memcpy(&ifr
.ifr_addr
, addr
->get_sockaddr(addr
), sizeof(sockaddr_t
));
133 if (ioctl(this->sock
, SIOCSIFADDR
, &ifr
) < 0)
135 DBG1(DBG_LIB
, "failed to set address on %s: %s",
136 this->if_name
, strerror(errno
));
140 if (ioctl(this->sock
, SIOCSIFDSTADDR
, &ifr
) < 0)
142 DBG1(DBG_LIB
, "failed to set dest address on %s: %s",
143 this->if_name
, strerror(errno
));
146 #endif /* __APPLE__ */
148 set_netmask(&ifr
, family
, netmask
);
150 if (ioctl(this->sock
, SIOCSIFNETMASK
, &ifr
) < 0)
152 DBG1(DBG_LIB
, "failed to set netmask on %s: %s",
153 this->if_name
, strerror(errno
));
159 METHOD(tun_device_t
, up
, bool,
160 private_tun_device_t
*this)
164 memset(&ifr
, 0, sizeof(ifr
));
165 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
167 if (ioctl(this->sock
, SIOCGIFFLAGS
, &ifr
) < 0)
169 DBG1(DBG_LIB
, "failed to get interface flags for %s: %s", this->if_name
,
174 ifr
.ifr_flags
|= IFF_RUNNING
| IFF_UP
;
176 if (ioctl(this->sock
, SIOCSIFFLAGS
, &ifr
) < 0)
178 DBG1(DBG_LIB
, "failed to set interface flags on %s: %s", this->if_name
,
185 METHOD(tun_device_t
, set_mtu
, bool,
186 private_tun_device_t
*this, int mtu
)
190 memset(&ifr
, 0, sizeof(ifr
));
191 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
194 if (ioctl(this->sock
, SIOCSIFMTU
, &ifr
) < 0)
202 METHOD(tun_device_t
, get_mtu
, int,
203 private_tun_device_t
*this)
212 memset(&ifr
, 0, sizeof(ifr
));
213 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
214 this->mtu
= TUN_DEFAULT_MTU
;
216 if (ioctl(this->sock
, SIOCGIFMTU
, &ifr
) == 0)
218 this->mtu
= ifr
.ifr_mtu
;
223 METHOD(tun_device_t
, get_name
, char*,
224 private_tun_device_t
*this)
226 return this->if_name
;
229 METHOD(tun_device_t
, write_packet
, bool,
230 private_tun_device_t
*this, chunk_t 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
,
283 METHOD(tun_device_t
, destroy
, void,
284 private_tun_device_t
*this)
298 * Initialize the tun device
300 static bool init_tun(private_tun_device_t
*this, const char *name_tmpl
)
304 struct ctl_info info
;
305 struct sockaddr_ctl addr
;
306 socklen_t size
= IFNAMSIZ
;
308 memset(&info
, 0, sizeof(info
));
309 memset(&addr
, 0, sizeof(addr
));
311 this->tunfd
= socket(PF_SYSTEM
, SOCK_DGRAM
, SYSPROTO_CONTROL
);
314 DBG1(DBG_LIB
, "failed to open tundevice PF_SYSTEM socket: %s",
319 /* get a control identifier for the utun kernel extension */
320 strncpy(info
.ctl_name
, UTUN_CONTROL_NAME
, strlen(UTUN_CONTROL_NAME
));
321 if (ioctl(this->tunfd
, CTLIOCGINFO
, &info
) < 0)
323 DBG1(DBG_LIB
, "failed to ioctl tundevice: %s", strerror(errno
));
328 addr
.sc_id
= info
.ctl_id
;
329 addr
.sc_len
= sizeof(addr
);
330 addr
.sc_family
= AF_SYSTEM
;
331 addr
.ss_sysaddr
= AF_SYS_CONTROL
;
332 /* allocate identifier dynamically */
335 if (connect(this->tunfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
337 DBG1(DBG_LIB
, "failed to connect tundevice: %s", strerror(errno
));
341 if (getsockopt(this->tunfd
, SYSPROTO_CONTROL
, UTUN_OPT_IFNAME
,
342 this->if_name
, &size
) < 0)
344 DBG1(DBG_LIB
, "getting tundevice name failed: %s", strerror(errno
));
350 #else /* !__APPLE__ */
354 strncpy(this->if_name
, name_tmpl ?
: "tun%d", IFNAMSIZ
);
355 this->if_name
[IFNAMSIZ
-1] = '\0';
357 this->tunfd
= open("/dev/net/tun", O_RDWR
);
360 DBG1(DBG_LIB
, "failed to open /dev/net/tun: %s", strerror(errno
));
364 memset(&ifr
, 0, sizeof(ifr
));
366 /* TUN device, no packet info */
367 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
;
369 strncpy(ifr
.ifr_name
, this->if_name
, IFNAMSIZ
);
370 if (ioctl(this->tunfd
, TUNSETIFF
, (void*)&ifr
) < 0)
372 DBG1(DBG_LIB
, "failed to configure TUN device: %s", strerror(errno
));
376 strncpy(this->if_name
, ifr
.ifr_name
, IFNAMSIZ
);
379 #endif /* !__APPLE__ */
383 * Described in header
385 tun_device_t
*tun_device_create(const char *name_tmpl
)
387 private_tun_device_t
*this;
391 .read_packet
= _read_packet
,
392 .write_packet
= _write_packet
,
395 .get_name
= _get_name
,
396 .set_address
= _set_address
,
404 if (!init_tun(this, name_tmpl
))
409 DBG1(DBG_LIB
, "created TUN device: %s", this->if_name
);
411 this->sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
414 DBG1(DBG_LIB
, "failed to open socket to configure TUN device");
418 return &this->public;