Ported tun_device de-/initialization to FreeBSD
[strongswan.git] / src / libstrongswan / utils / 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 <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 /**
79 * Set the sockaddr_t from the given netmask
80 */
81 static void set_netmask(struct ifreq *ifr, int family, u_int8_t netmask)
82 {
83 int len, bytes, bits;
84 char *target;
85
86 switch (family)
87 {
88 case AF_INET:
89 {
90 struct sockaddr_in *addr = (struct sockaddr_in*)&ifr->ifr_addr;
91 addr->sin_family = AF_INET;
92 target = (char*)&addr->sin_addr;
93 len = 4;
94 break;
95 }
96 case AF_INET6:
97 {
98 struct sockaddr_in6 *addr = (struct sockaddr_in6*)&ifr->ifr_addr;
99 addr->sin6_family = AF_INET6;
100 target = (char*)&addr->sin6_addr;
101 len = 16;
102 break;
103 }
104 default:
105 return;
106 }
107
108 bytes = (netmask + 7) / 8;
109 bits = (bytes * 8) - netmask;
110
111 memset(target, 0xff, bytes);
112 memset(target + bytes, 0x00, len - bytes);
113 target[bytes - 1] = bits ? (u_int8_t)(0xff << bits) : 0xff;
114 }
115
116 METHOD(tun_device_t, set_address, bool,
117 private_tun_device_t *this, host_t *addr, u_int8_t netmask)
118 {
119 struct ifreq ifr;
120 int family;
121
122 family = addr->get_family(addr);
123 if ((netmask > 32 && family == AF_INET) || netmask > 128)
124 {
125 DBG1(DBG_LIB, "failed to set address on %s: invalid netmask",
126 this->if_name);
127 return FALSE;
128 }
129
130 memset(&ifr, 0, sizeof(ifr));
131 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
132 memcpy(&ifr.ifr_addr, addr->get_sockaddr(addr), sizeof(sockaddr_t));
133
134 if (ioctl(this->sock, SIOCSIFADDR, &ifr) < 0)
135 {
136 DBG1(DBG_LIB, "failed to set address on %s: %s",
137 this->if_name, strerror(errno));
138 return FALSE;
139 }
140 #ifdef __APPLE__
141 if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0)
142 {
143 DBG1(DBG_LIB, "failed to set dest address on %s: %s",
144 this->if_name, strerror(errno));
145 return FALSE;
146 }
147 #endif /* __APPLE__ */
148
149 set_netmask(&ifr, family, netmask);
150
151 if (ioctl(this->sock, SIOCSIFNETMASK, &ifr) < 0)
152 {
153 DBG1(DBG_LIB, "failed to set netmask on %s: %s",
154 this->if_name, strerror(errno));
155 return FALSE;
156 }
157 return TRUE;
158 }
159
160 METHOD(tun_device_t, up, bool,
161 private_tun_device_t *this)
162 {
163 struct ifreq ifr;
164
165 memset(&ifr, 0, sizeof(ifr));
166 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
167
168 if (ioctl(this->sock, SIOCGIFFLAGS, &ifr) < 0)
169 {
170 DBG1(DBG_LIB, "failed to get interface flags for %s: %s", this->if_name,
171 strerror(errno));
172 return FALSE;
173 }
174
175 ifr.ifr_flags |= IFF_RUNNING | IFF_UP;
176
177 if (ioctl(this->sock, SIOCSIFFLAGS, &ifr) < 0)
178 {
179 DBG1(DBG_LIB, "failed to set interface flags on %s: %s", this->if_name,
180 strerror(errno));
181 return FALSE;
182 }
183 return TRUE;
184 }
185
186 METHOD(tun_device_t, set_mtu, bool,
187 private_tun_device_t *this, int mtu)
188 {
189 struct ifreq ifr;
190
191 memset(&ifr, 0, sizeof(ifr));
192 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
193 ifr.ifr_mtu = mtu;
194
195 if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0)
196 {
197 DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name,
198 strerror(errno));
199 return FALSE;
200 }
201 this->mtu = mtu;
202 return TRUE;
203 }
204
205 METHOD(tun_device_t, get_mtu, int,
206 private_tun_device_t *this)
207 {
208 struct ifreq ifr;
209
210 if (this->mtu > 0)
211 {
212 return this->mtu;
213 }
214
215 memset(&ifr, 0, sizeof(ifr));
216 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
217 this->mtu = TUN_DEFAULT_MTU;
218
219 if (ioctl(this->sock, SIOCGIFMTU, &ifr) == 0)
220 {
221 this->mtu = ifr.ifr_mtu;
222 }
223 return this->mtu;
224 }
225
226 METHOD(tun_device_t, get_name, char*,
227 private_tun_device_t *this)
228 {
229 return this->if_name;
230 }
231
232 METHOD(tun_device_t, write_packet, bool,
233 private_tun_device_t *this, chunk_t packet)
234 {
235 ssize_t s;
236
237 s = write(this->tunfd, packet.ptr, packet.len);
238 if (s < 0)
239 {
240 DBG1(DBG_LIB, "failed to write packet to TUN device %s: %s",
241 this->if_name, strerror(errno));
242 return FALSE;
243 }
244 else if (s != packet.len)
245 {
246 return FALSE;
247 }
248 return TRUE;
249 }
250
251 METHOD(tun_device_t, read_packet, bool,
252 private_tun_device_t *this, chunk_t *packet)
253 {
254 ssize_t len;
255 fd_set set;
256 bool old;
257
258 FD_ZERO(&set);
259 FD_SET(this->tunfd, &set);
260
261 old = thread_cancelability(TRUE);
262 len = select(this->tunfd + 1, &set, NULL, NULL, NULL);
263 thread_cancelability(old);
264
265 if (len < 0)
266 {
267 DBG1(DBG_LIB, "select on TUN device %s failed: %s", this->if_name,
268 strerror(errno));
269 return FALSE;
270 }
271 /* FIXME: this is quite expensive for lots of small packets, copy from
272 * local buffer instead? */
273 *packet = chunk_alloc(get_mtu(this));
274 len = read(this->tunfd, packet->ptr, packet->len);
275 if (len < 0)
276 {
277 DBG1(DBG_LIB, "reading from TUN device %s failed: %s", this->if_name,
278 strerror(errno));
279 chunk_free(packet);
280 return FALSE;
281 }
282 packet->len = len;
283 return TRUE;
284 }
285
286 METHOD(tun_device_t, destroy, void,
287 private_tun_device_t *this)
288 {
289 if (this->tunfd > 0)
290 {
291 close(this->tunfd);
292 #ifdef __FreeBSD__
293 /* tun(4) says the following: "These network interfaces persist until
294 * the if_tun.ko module is unloaded, or until removed with the
295 * ifconfig(8) command." So simply closing the FD is not enough. */
296 struct ifreq ifr;
297
298 memset(&ifr, 0, sizeof(ifr));
299 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
300 if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0)
301 {
302 DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name,
303 strerror(errno));
304 }
305 #endif /* __FreeBSD__ */
306 }
307 if (this->sock > 0)
308 {
309 close(this->sock);
310 }
311 free(this);
312 }
313
314 /**
315 * Initialize the tun device
316 */
317 static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
318 {
319 #ifdef __APPLE__
320
321 struct ctl_info info;
322 struct sockaddr_ctl addr;
323 socklen_t size = IFNAMSIZ;
324
325 memset(&info, 0, sizeof(info));
326 memset(&addr, 0, sizeof(addr));
327
328 this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
329 if (this->tunfd < 0)
330 {
331 DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s",
332 strerror(errno));
333 return FALSE;
334 }
335
336 /* get a control identifier for the utun kernel extension */
337 strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
338 if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0)
339 {
340 DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno));
341 close(this->tunfd);
342 return FALSE;
343 }
344
345 addr.sc_id = info.ctl_id;
346 addr.sc_len = sizeof(addr);
347 addr.sc_family = AF_SYSTEM;
348 addr.ss_sysaddr = AF_SYS_CONTROL;
349 /* allocate identifier dynamically */
350 addr.sc_unit = 0;
351
352 if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
353 {
354 DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno));
355 close(this->tunfd);
356 return FALSE;
357 }
358 if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
359 this->if_name, &size) < 0)
360 {
361 DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno));
362 close(this->tunfd);
363 return FALSE;
364 }
365 return TRUE;
366
367 #elif defined(IFF_TUN)
368
369 struct ifreq ifr;
370
371 strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
372 this->if_name[IFNAMSIZ-1] = '\0';
373
374 this->tunfd = open("/dev/net/tun", O_RDWR);
375 if (this->tunfd < 0)
376 {
377 DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno));
378 return FALSE;
379 }
380
381 memset(&ifr, 0, sizeof(ifr));
382
383 /* TUN device, no packet info */
384 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
385
386 strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
387 if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0)
388 {
389 DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno));
390 close(this->tunfd);
391 return FALSE;
392 }
393 strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ);
394 return TRUE;
395
396 #else /* !IFF_TUN */
397
398 /* this works on FreeBSD and might also work on Linux with older TUN
399 * driver versions (no IFF_TUN) */
400 char devname[IFNAMSIZ];
401 int i;
402
403 if (name_tmpl)
404 {
405 DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
406 }
407
408 for (i = 0; i < 256; i++)
409 {
410 snprintf(devname, IFNAMSIZ, "/dev/tun%d", i);
411 this->tunfd = open(devname, O_RDWR);
412 if (this->tunfd > 0)
413 { /* for ioctl(2) calls only the interface name is used */
414 snprintf(this->if_name, IFNAMSIZ, "tun%d", i);
415 break;
416 }
417 DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno));
418 }
419 return this->tunfd > 0;
420
421 #endif /* !__APPLE__ */
422 }
423
424 /*
425 * Described in header
426 */
427 tun_device_t *tun_device_create(const char *name_tmpl)
428 {
429 private_tun_device_t *this;
430
431 INIT(this,
432 .public = {
433 .read_packet = _read_packet,
434 .write_packet = _write_packet,
435 .get_mtu = _get_mtu,
436 .set_mtu = _set_mtu,
437 .get_name = _get_name,
438 .set_address = _set_address,
439 .up = _up,
440 .destroy = _destroy,
441 },
442 .tunfd = -1,
443 .sock = -1,
444 );
445
446 if (!init_tun(this, name_tmpl))
447 {
448 free(this);
449 return NULL;
450 }
451 DBG1(DBG_LIB, "created TUN device: %s", this->if_name);
452
453 this->sock = socket(AF_INET, SOCK_DGRAM, 0);
454 if (this->sock < 0)
455 {
456 DBG1(DBG_LIB, "failed to open socket to configure TUN device");
457 destroy(this);
458 return NULL;
459 }
460 return &this->public;
461 }