tun_device: add a getter for the underlying file descriptor
[strongswan.git] / src / libstrongswan / networking / tun_device.c
1 /*
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
7 *
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>.
12 *
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
16 * for more details.
17 */
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <netinet/in.h>
22 #include <string.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <net/if.h>
29
30 #ifdef __APPLE__
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>
36 #else
37 #include <net/if_tun.h>
38 #endif
39
40 #include "tun_device.h"
41
42 #include <library.h>
43 #include <utils/debug.h>
44 #include <threading/thread.h>
45
46 #define TUN_DEFAULT_MTU 1500
47
48 typedef struct private_tun_device_t private_tun_device_t;
49
50 struct private_tun_device_t {
51
52 /**
53 * Public interface
54 */
55 tun_device_t public;
56
57 /**
58 * The TUN device's file descriptor
59 */
60 int tunfd;
61
62 /**
63 * Name of the TUN device
64 */
65 char if_name[IFNAMSIZ];
66
67 /**
68 * Socket used for ioctl() to set interface addr, ...
69 */
70 int sock;
71
72 /**
73 * The current MTU
74 */
75 int mtu;
76 };
77
78 METHOD(tun_device_t, set_address, bool,
79 private_tun_device_t *this, host_t *addr, u_int8_t netmask)
80 {
81 struct ifreq ifr;
82 host_t *mask;
83
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));
88
89 if (ioctl(this->sock, SIOCSIFADDR, &ifr) < 0)
90 {
91 DBG1(DBG_LIB, "failed to set address on %s: %s",
92 this->if_name, strerror(errno));
93 return FALSE;
94 }
95 #ifdef __APPLE__
96 if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0)
97 {
98 DBG1(DBG_LIB, "failed to set dest address on %s: %s",
99 this->if_name, strerror(errno));
100 return FALSE;
101 }
102 #endif /* __APPLE__ */
103
104 mask = host_create_netmask(addr->get_family(addr), netmask);
105 if (!mask)
106 {
107 DBG1(DBG_LIB, "invalid netmask: %d", netmask);
108 return FALSE;
109 }
110 memcpy(&ifr.ifr_addr, mask->get_sockaddr(mask),
111 *mask->get_sockaddr_len(mask));
112 mask->destroy(mask);
113
114 if (ioctl(this->sock, SIOCSIFNETMASK, &ifr) < 0)
115 {
116 DBG1(DBG_LIB, "failed to set netmask on %s: %s",
117 this->if_name, strerror(errno));
118 return FALSE;
119 }
120 return TRUE;
121 }
122
123 METHOD(tun_device_t, up, bool,
124 private_tun_device_t *this)
125 {
126 struct ifreq ifr;
127
128 memset(&ifr, 0, sizeof(ifr));
129 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
130
131 if (ioctl(this->sock, SIOCGIFFLAGS, &ifr) < 0)
132 {
133 DBG1(DBG_LIB, "failed to get interface flags for %s: %s", this->if_name,
134 strerror(errno));
135 return FALSE;
136 }
137
138 ifr.ifr_flags |= IFF_RUNNING | IFF_UP;
139
140 if (ioctl(this->sock, SIOCSIFFLAGS, &ifr) < 0)
141 {
142 DBG1(DBG_LIB, "failed to set interface flags on %s: %s", this->if_name,
143 strerror(errno));
144 return FALSE;
145 }
146 return TRUE;
147 }
148
149 METHOD(tun_device_t, set_mtu, bool,
150 private_tun_device_t *this, int mtu)
151 {
152 struct ifreq ifr;
153
154 memset(&ifr, 0, sizeof(ifr));
155 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
156 ifr.ifr_mtu = mtu;
157
158 if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0)
159 {
160 DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name,
161 strerror(errno));
162 return FALSE;
163 }
164 this->mtu = mtu;
165 return TRUE;
166 }
167
168 METHOD(tun_device_t, get_mtu, int,
169 private_tun_device_t *this)
170 {
171 struct ifreq ifr;
172
173 if (this->mtu > 0)
174 {
175 return this->mtu;
176 }
177
178 memset(&ifr, 0, sizeof(ifr));
179 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
180 this->mtu = TUN_DEFAULT_MTU;
181
182 if (ioctl(this->sock, SIOCGIFMTU, &ifr) == 0)
183 {
184 this->mtu = ifr.ifr_mtu;
185 }
186 return this->mtu;
187 }
188
189 METHOD(tun_device_t, get_name, char*,
190 private_tun_device_t *this)
191 {
192 return this->if_name;
193 }
194
195 METHOD(tun_device_t, get_fd, int,
196 private_tun_device_t *this)
197 {
198 return this->tunfd;
199 }
200
201 METHOD(tun_device_t, write_packet, bool,
202 private_tun_device_t *this, chunk_t packet)
203 {
204 ssize_t s;
205
206 s = write(this->tunfd, packet.ptr, packet.len);
207 if (s < 0)
208 {
209 DBG1(DBG_LIB, "failed to write packet to TUN device %s: %s",
210 this->if_name, strerror(errno));
211 return FALSE;
212 }
213 else if (s != packet.len)
214 {
215 return FALSE;
216 }
217 return TRUE;
218 }
219
220 METHOD(tun_device_t, read_packet, bool,
221 private_tun_device_t *this, chunk_t *packet)
222 {
223 ssize_t len;
224 fd_set set;
225 bool old;
226
227 FD_ZERO(&set);
228 FD_SET(this->tunfd, &set);
229
230 old = thread_cancelability(TRUE);
231 len = select(this->tunfd + 1, &set, NULL, NULL, NULL);
232 thread_cancelability(old);
233
234 if (len < 0)
235 {
236 DBG1(DBG_LIB, "select on TUN device %s failed: %s", this->if_name,
237 strerror(errno));
238 return FALSE;
239 }
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);
244 if (len < 0)
245 {
246 DBG1(DBG_LIB, "reading from TUN device %s failed: %s", this->if_name,
247 strerror(errno));
248 chunk_free(packet);
249 return FALSE;
250 }
251 packet->len = len;
252 return TRUE;
253 }
254
255 METHOD(tun_device_t, destroy, void,
256 private_tun_device_t *this)
257 {
258 if (this->tunfd > 0)
259 {
260 close(this->tunfd);
261 #ifdef __FreeBSD__
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. */
265 struct ifreq ifr;
266
267 memset(&ifr, 0, sizeof(ifr));
268 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
269 if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0)
270 {
271 DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name,
272 strerror(errno));
273 }
274 #endif /* __FreeBSD__ */
275 }
276 if (this->sock > 0)
277 {
278 close(this->sock);
279 }
280 free(this);
281 }
282
283 /**
284 * Initialize the tun device
285 */
286 static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
287 {
288 #ifdef __APPLE__
289
290 struct ctl_info info;
291 struct sockaddr_ctl addr;
292 socklen_t size = IFNAMSIZ;
293
294 memset(&info, 0, sizeof(info));
295 memset(&addr, 0, sizeof(addr));
296
297 this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
298 if (this->tunfd < 0)
299 {
300 DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s",
301 strerror(errno));
302 return FALSE;
303 }
304
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)
308 {
309 DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno));
310 close(this->tunfd);
311 return FALSE;
312 }
313
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 */
319 addr.sc_unit = 0;
320
321 if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
322 {
323 DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno));
324 close(this->tunfd);
325 return FALSE;
326 }
327 if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
328 this->if_name, &size) < 0)
329 {
330 DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno));
331 close(this->tunfd);
332 return FALSE;
333 }
334 return TRUE;
335
336 #elif defined(IFF_TUN)
337
338 struct ifreq ifr;
339
340 strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
341 this->if_name[IFNAMSIZ-1] = '\0';
342
343 this->tunfd = open("/dev/net/tun", O_RDWR);
344 if (this->tunfd < 0)
345 {
346 DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno));
347 return FALSE;
348 }
349
350 memset(&ifr, 0, sizeof(ifr));
351
352 /* TUN device, no packet info */
353 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
354
355 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
356 if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0)
357 {
358 DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno));
359 close(this->tunfd);
360 return FALSE;
361 }
362 strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ);
363 return TRUE;
364
365 #else /* !IFF_TUN */
366
367 /* this works on FreeBSD and might also work on Linux with older TUN
368 * driver versions (no IFF_TUN) */
369 char devname[IFNAMSIZ];
370 int i;
371
372 if (name_tmpl)
373 {
374 DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
375 }
376
377 for (i = 0; i < 256; i++)
378 {
379 snprintf(devname, IFNAMSIZ, "/dev/tun%d", i);
380 this->tunfd = open(devname, O_RDWR);
381 if (this->tunfd > 0)
382 { /* for ioctl(2) calls only the interface name is used */
383 snprintf(this->if_name, IFNAMSIZ, "tun%d", i);
384 break;
385 }
386 DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno));
387 }
388 return this->tunfd > 0;
389
390 #endif /* !__APPLE__ */
391 }
392
393 /*
394 * Described in header
395 */
396 tun_device_t *tun_device_create(const char *name_tmpl)
397 {
398 private_tun_device_t *this;
399
400 INIT(this,
401 .public = {
402 .read_packet = _read_packet,
403 .write_packet = _write_packet,
404 .get_mtu = _get_mtu,
405 .set_mtu = _set_mtu,
406 .get_name = _get_name,
407 .get_fd = _get_fd,
408 .set_address = _set_address,
409 .up = _up,
410 .destroy = _destroy,
411 },
412 .tunfd = -1,
413 .sock = -1,
414 );
415
416 if (!init_tun(this, name_tmpl))
417 {
418 free(this);
419 return NULL;
420 }
421 DBG1(DBG_LIB, "created TUN device: %s", this->if_name);
422
423 this->sock = socket(AF_INET, SOCK_DGRAM, 0);
424 if (this->sock < 0)
425 {
426 DBG1(DBG_LIB, "failed to open socket to configure TUN device");
427 destroy(this);
428 return NULL;
429 }
430 return &this->public;
431 }