BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file BTap.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <string.h>
31 #include <stdio.h>
32  
33 #ifdef BADVPN_USE_WINAPI
34 #include <windows.h>
35 #include <winioctl.h>
36 #include <objbase.h>
37 #include <wtypes.h>
38 #include "wintap-common.h"
39 #include <tuntap/tapwin32-funcs.h>
40 #else
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <errno.h>
44 #include <sys/ioctl.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49 #include <net/if_arp.h>
50 #ifdef BADVPN_LINUX
51 #include <linux/if_tun.h>
52 #endif
53 #ifdef BADVPN_FREEBSD
54 #include <net/if_tun.h>
55 #include <net/if_tap.h>
56 #endif
57 #endif
58  
59 #include <base/BLog.h>
60  
61 #include <tuntap/BTap.h>
62  
63 #include <generated/blog_channel_BTap.h>
64  
65 static void report_error (BTap *o);
66 static void output_handler_recv (BTap *o, uint8_t *data);
67  
68 #ifdef BADVPN_USE_WINAPI
69  
70 static void recv_olap_handler (BTap *o, int event, DWORD bytes)
71 {
72 DebugObject_Access(&o->d_obj);
73 ASSERT(o->output_packet)
74 ASSERT(event == BREACTOR_IOCP_EVENT_SUCCEEDED || event == BREACTOR_IOCP_EVENT_FAILED)
75  
76 // set no output packet
77 o->output_packet = NULL;
78  
79 if (event == BREACTOR_IOCP_EVENT_FAILED) {
80 BLog(BLOG_ERROR, "read operation failed");
81 report_error(o);
82 return;
83 }
84  
85 ASSERT(bytes >= 0)
86 ASSERT(bytes <= o->frame_mtu)
87  
88 // done
89 PacketRecvInterface_Done(&o->output, bytes);
90 }
91  
92 #else
93  
94 static void fd_handler (BTap *o, int events)
95 {
96 DebugObject_Access(&o->d_obj);
97 DebugError_AssertNoError(&o->d_err);
98  
99 if (events&(BREACTOR_ERROR|BREACTOR_HUP)) {
100 BLog(BLOG_WARNING, "device fd reports error?");
101 }
102  
103 if (events&BREACTOR_READ) do {
104 ASSERT(o->output_packet)
105  
106 // try reading into the buffer
107 int bytes = read(o->fd, o->output_packet, o->frame_mtu);
108 if (bytes <= 0) {
109 // Treat zero return value the same as EAGAIN.
110 // See: https://bugzilla.kernel.org/show_bug.cgi?id=96381
111 if (bytes == 0 || errno == EAGAIN || errno == EWOULDBLOCK) {
112 // retry later
113 break;
114 }
115 // report fatal error
116 report_error(o);
117 return;
118 }
119  
120 ASSERT_FORCE(bytes <= o->frame_mtu)
121  
122 // set no output packet
123 o->output_packet = NULL;
124  
125 // update events
126 o->poll_events &= ~BREACTOR_READ;
127 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->poll_events);
128  
129 // inform receiver we finished the packet
130 PacketRecvInterface_Done(&o->output, bytes);
131 } while (0);
132 }
133  
134 #endif
135  
136 void report_error (BTap *o)
137 {
138 DEBUGERROR(&o->d_err, o->handler_error(o->handler_error_user));
139 }
140  
141 void output_handler_recv (BTap *o, uint8_t *data)
142 {
143 DebugObject_Access(&o->d_obj);
144 DebugError_AssertNoError(&o->d_err);
145 ASSERT(data)
146 ASSERT(!o->output_packet)
147  
148 #ifdef BADVPN_USE_WINAPI
149  
150 memset(&o->recv_olap.olap, 0, sizeof(o->recv_olap.olap));
151  
152 // read
153 BOOL res = ReadFile(o->device, data, o->frame_mtu, NULL, &o->recv_olap.olap);
154 if (res == FALSE && GetLastError() != ERROR_IO_PENDING) {
155 BLog(BLOG_ERROR, "ReadFile failed (%u)", GetLastError());
156 report_error(o);
157 return;
158 }
159  
160 o->output_packet = data;
161  
162 #else
163  
164 // attempt read
165 int bytes = read(o->fd, data, o->frame_mtu);
166 if (bytes <= 0) {
167 if (bytes == 0 || errno == EAGAIN || errno == EWOULDBLOCK) {
168 // See note about zero return in fd_handler.
169 // retry later in fd_handler
170 // remember packet
171 o->output_packet = data;
172 // update events
173 o->poll_events |= BREACTOR_READ;
174 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->poll_events);
175 return;
176 }
177 // report fatal error
178 report_error(o);
179 return;
180 }
181  
182 ASSERT_FORCE(bytes <= o->frame_mtu)
183  
184 PacketRecvInterface_Done(&o->output, bytes);
185  
186 #endif
187 }
188  
189 int BTap_Init (BTap *o, BReactor *reactor, char *devname, BTap_handler_error handler_error, void *handler_error_user, int tun)
190 {
191 ASSERT(tun == 0 || tun == 1)
192  
193 struct BTap_init_data init_data;
194 init_data.dev_type = tun ? BTAP_DEV_TUN : BTAP_DEV_TAP;
195 init_data.init_type = BTAP_INIT_STRING;
196 init_data.init.string = devname;
197  
198 return BTap_Init2(o, reactor, init_data, handler_error, handler_error_user);
199 }
200  
201 int BTap_Init2 (BTap *o, BReactor *reactor, struct BTap_init_data init_data, BTap_handler_error handler_error, void *handler_error_user)
202 {
203 ASSERT(init_data.dev_type == BTAP_DEV_TUN || init_data.dev_type == BTAP_DEV_TAP)
204  
205 // init arguments
206 o->reactor = reactor;
207 o->handler_error = handler_error;
208 o->handler_error_user = handler_error_user;
209  
210 #ifdef BADVPN_USE_WINAPI
211  
212 ASSERT(init_data.init_type == BTAP_INIT_STRING)
213  
214 // parse device specification
215  
216 if (!init_data.init.string) {
217 BLog(BLOG_ERROR, "no device specification provided");
218 goto fail0;
219 }
220  
221 char *device_component_id;
222 char *device_name;
223 uint32_t tun_addrs[3];
224  
225 if (init_data.dev_type == BTAP_DEV_TUN) {
226 if (!tapwin32_parse_tun_spec(init_data.init.string, &device_component_id, &device_name, tun_addrs)) {
227 BLog(BLOG_ERROR, "failed to parse TUN device specification");
228 goto fail0;
229 }
230 } else {
231 if (!tapwin32_parse_tap_spec(init_data.init.string, &device_component_id, &device_name)) {
232 BLog(BLOG_ERROR, "failed to parse TAP device specification");
233 goto fail0;
234 }
235 }
236  
237 // locate device path
238  
239 char device_path[TAPWIN32_MAX_REG_SIZE];
240  
241 BLog(BLOG_INFO, "Looking for TAP-Win32 with component ID %s, name %s", device_component_id, device_name);
242  
243 if (!tapwin32_find_device(device_component_id, device_name, &device_path)) {
244 BLog(BLOG_ERROR, "Could not find device");
245 goto fail1;
246 }
247  
248 // open device
249  
250 BLog(BLOG_INFO, "Opening device %s", device_path);
251  
252 o->device = CreateFile(device_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED, 0);
253 if (o->device == INVALID_HANDLE_VALUE) {
254 BLog(BLOG_ERROR, "CreateFile failed");
255 goto fail1;
256 }
257  
258 // set TUN if needed
259  
260 DWORD len;
261  
262 if (init_data.dev_type == BTAP_DEV_TUN) {
263 if (!DeviceIoControl(o->device, TAP_IOCTL_CONFIG_TUN, tun_addrs, sizeof(tun_addrs), tun_addrs, sizeof(tun_addrs), &len, NULL)) {
264 BLog(BLOG_ERROR, "DeviceIoControl(TAP_IOCTL_CONFIG_TUN) failed");
265 goto fail2;
266 }
267 }
268  
269 // get MTU
270  
271 ULONG umtu = 0;
272  
273 if (!DeviceIoControl(o->device, TAP_IOCTL_GET_MTU, &umtu, sizeof(umtu), &umtu, sizeof(umtu), &len, NULL)) {
274 BLog(BLOG_ERROR, "DeviceIoControl(TAP_IOCTL_GET_MTU) failed");
275 goto fail2;
276 }
277  
278 if (init_data.dev_type == BTAP_DEV_TUN) {
279 o->frame_mtu = umtu;
280 } else {
281 o->frame_mtu = umtu + BTAP_ETHERNET_HEADER_LENGTH;
282 }
283  
284 // set connected
285  
286 ULONG upstatus = TRUE;
287 if (!DeviceIoControl(o->device, TAP_IOCTL_SET_MEDIA_STATUS, &upstatus, sizeof(upstatus), &upstatus, sizeof(upstatus), &len, NULL)) {
288 BLog(BLOG_ERROR, "DeviceIoControl(TAP_IOCTL_SET_MEDIA_STATUS) failed");
289 goto fail2;
290 }
291  
292 BLog(BLOG_INFO, "Device opened");
293  
294 // associate device with IOCP
295  
296 if (!CreateIoCompletionPort(o->device, BReactor_GetIOCPHandle(o->reactor), 0, 0)) {
297 BLog(BLOG_ERROR, "CreateIoCompletionPort failed");
298 goto fail2;
299 }
300  
301 // init send olap
302 BReactorIOCPOverlapped_Init(&o->send_olap, o->reactor, o, NULL);
303  
304 // init recv olap
305 BReactorIOCPOverlapped_Init(&o->recv_olap, o->reactor, o, (BReactorIOCPOverlapped_handler)recv_olap_handler);
306  
307 free(device_name);
308 free(device_component_id);
309  
310 goto success;
311  
312 fail2:
313 ASSERT_FORCE(CloseHandle(o->device))
314 fail1:
315 free(device_name);
316 free(device_component_id);
317 fail0:
318 return 0;
319  
320 #endif
321  
322 #if defined(BADVPN_LINUX) || defined(BADVPN_FREEBSD)
323  
324 o->close_fd = (init_data.init_type != BTAP_INIT_FD);
325  
326 switch (init_data.init_type) {
327 case BTAP_INIT_FD: {
328 ASSERT(init_data.init.fd.fd >= 0)
329 ASSERT(init_data.init.fd.mtu >= 0)
330 ASSERT(init_data.dev_type != BTAP_DEV_TAP || init_data.init.fd.mtu >= BTAP_ETHERNET_HEADER_LENGTH)
331  
332 o->fd = init_data.init.fd.fd;
333 o->frame_mtu = init_data.init.fd.mtu;
334 } break;
335  
336 case BTAP_INIT_STRING: {
337 char devname_real[IFNAMSIZ];
338  
339 #ifdef BADVPN_LINUX
340  
341 // open device
342  
343 if ((o->fd = open("/dev/net/tun", O_RDWR)) < 0) {
344 BLog(BLOG_ERROR, "error opening device");
345 goto fail0;
346 }
347  
348 // configure device
349  
350 struct ifreq ifr;
351 memset(&ifr, 0, sizeof(ifr));
352 ifr.ifr_flags |= IFF_NO_PI;
353 if (init_data.dev_type == BTAP_DEV_TUN) {
354 ifr.ifr_flags |= IFF_TUN;
355 } else {
356 ifr.ifr_flags |= IFF_TAP;
357 }
358 if (init_data.init.string) {
359 snprintf(ifr.ifr_name, IFNAMSIZ, "%s", init_data.init.string);
360 }
361  
362 if (ioctl(o->fd, TUNSETIFF, (void *)&ifr) < 0) {
363 BLog(BLOG_ERROR, "error configuring device");
364 goto fail1;
365 }
366  
367 strcpy(devname_real, ifr.ifr_name);
368  
369 #endif
370  
371 #ifdef BADVPN_FREEBSD
372  
373 if (init_data.dev_type == BTAP_DEV_TUN) {
374 BLog(BLOG_ERROR, "TUN not supported on FreeBSD");
375 goto fail0;
376 }
377  
378 if (!init_data.init.string) {
379 BLog(BLOG_ERROR, "no device specified");
380 goto fail0;
381 }
382  
383 // open device
384  
385 char devnode[10 + IFNAMSIZ];
386 snprintf(devnode, sizeof(devnode), "/dev/%s", init_data.init.string);
387  
388 if ((o->fd = open(devnode, O_RDWR)) < 0) {
389 BLog(BLOG_ERROR, "error opening device");
390 goto fail0;
391 }
392  
393 // get name
394  
395 struct ifreq ifr;
396 memset(&ifr, 0, sizeof(ifr));
397 if (ioctl(o->fd, TAPGIFNAME, (void *)&ifr) < 0) {
398 BLog(BLOG_ERROR, "error configuring device");
399 goto fail1;
400 }
401  
402 strcpy(devname_real, ifr.ifr_name);
403  
404 #endif
405  
406 // get MTU
407  
408 // open dummy socket for ioctls
409 int sock = socket(AF_INET, SOCK_DGRAM, 0);
410 if (sock < 0) {
411 BLog(BLOG_ERROR, "socket failed");
412 goto fail1;
413 }
414  
415 memset(&ifr, 0, sizeof(ifr));
416 strcpy(ifr.ifr_name, devname_real);
417  
418 if (ioctl(sock, SIOCGIFMTU, (void *)&ifr) < 0) {
419 BLog(BLOG_ERROR, "error getting MTU");
420 close(sock);
421 goto fail1;
422 }
423  
424 if (init_data.dev_type == BTAP_DEV_TUN) {
425 o->frame_mtu = ifr.ifr_mtu;
426 } else {
427 o->frame_mtu = ifr.ifr_mtu + BTAP_ETHERNET_HEADER_LENGTH;
428 }
429  
430 close(sock);
431 } break;
432  
433 default: ASSERT(0);
434 }
435  
436 // set non-blocking
437 if (fcntl(o->fd, F_SETFL, O_NONBLOCK) < 0) {
438 BLog(BLOG_ERROR, "cannot set non-blocking");
439 goto fail1;
440 }
441  
442 // init file descriptor object
443 BFileDescriptor_Init(&o->bfd, o->fd, (BFileDescriptor_handler)fd_handler, o);
444 if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) {
445 BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
446 goto fail1;
447 }
448 o->poll_events = 0;
449  
450 goto success;
451  
452 fail1:
453 if (o->close_fd) {
454 ASSERT_FORCE(close(o->fd) == 0)
455 }
456 fail0:
457 return 0;
458  
459 #endif
460  
461 success:
462 // init output
463 PacketRecvInterface_Init(&o->output, o->frame_mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, BReactor_PendingGroup(o->reactor));
464  
465 // set no output packet
466 o->output_packet = NULL;
467  
468 DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor));
469 DebugObject_Init(&o->d_obj);
470 return 1;
471 }
472  
473 void BTap_Free (BTap *o)
474 {
475 DebugObject_Free(&o->d_obj);
476 DebugError_Free(&o->d_err);
477  
478 // free output
479 PacketRecvInterface_Free(&o->output);
480  
481 #ifdef BADVPN_USE_WINAPI
482  
483 // cancel I/O
484 ASSERT_FORCE(CancelIo(o->device))
485  
486 // wait receiving to finish
487 if (o->output_packet) {
488 BLog(BLOG_DEBUG, "waiting for receiving to finish");
489 BReactorIOCPOverlapped_Wait(&o->recv_olap, NULL, NULL);
490 }
491  
492 // free recv olap
493 BReactorIOCPOverlapped_Free(&o->recv_olap);
494  
495 // free send olap
496 BReactorIOCPOverlapped_Free(&o->send_olap);
497  
498 // close device
499 ASSERT_FORCE(CloseHandle(o->device))
500  
501 #else
502  
503 // free BFileDescriptor
504 BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
505  
506 if (o->close_fd) {
507 // close file descriptor
508 ASSERT_FORCE(close(o->fd) == 0)
509 }
510  
511 #endif
512 }
513  
514 int BTap_GetMTU (BTap *o)
515 {
516 DebugObject_Access(&o->d_obj);
517  
518 return o->frame_mtu;
519 }
520  
521 void BTap_Send (BTap *o, uint8_t *data, int data_len)
522 {
523 DebugObject_Access(&o->d_obj);
524 DebugError_AssertNoError(&o->d_err);
525 ASSERT(data_len >= 0)
526 ASSERT(data_len <= o->frame_mtu)
527  
528 #ifdef BADVPN_USE_WINAPI
529  
530 // ignore frames without an Ethernet header, or we get errors in WriteFile
531 if (data_len < 14) {
532 return;
533 }
534  
535 memset(&o->send_olap.olap, 0, sizeof(o->send_olap.olap));
536  
537 // write
538 BOOL res = WriteFile(o->device, data, data_len, NULL, &o->send_olap.olap);
539 if (res == FALSE && GetLastError() != ERROR_IO_PENDING) {
540 BLog(BLOG_ERROR, "WriteFile failed (%u)", GetLastError());
541 return;
542 }
543  
544 // wait
545 int succeeded;
546 DWORD bytes;
547 BReactorIOCPOverlapped_Wait(&o->send_olap, &succeeded, &bytes);
548  
549 if (!succeeded) {
550 BLog(BLOG_ERROR, "write operation failed");
551 } else {
552 ASSERT(bytes >= 0)
553 ASSERT(bytes <= data_len)
554  
555 if (bytes < data_len) {
556 BLog(BLOG_ERROR, "write operation didn't write everything");
557 }
558 }
559  
560 #else
561  
562 int bytes = write(o->fd, data, data_len);
563 if (bytes < 0) {
564 // malformed packets will cause errors, ignore them and act like
565 // the packet was accepeted
566 } else {
567 if (bytes != data_len) {
568 BLog(BLOG_WARNING, "written %d expected %d", bytes, data_len);
569 }
570 }
571  
572 #endif
573 }
574  
575 PacketRecvInterface * BTap_GetOutput (BTap *o)
576 {
577 DebugObject_Access(&o->d_obj);
578  
579 return &o->output;
580 }