]> git.ipfire.org Git - people/stevee/aiccu.git/blob - common/tun.c
spelling error
[people/stevee/aiccu.git] / common / tun.c
1 /**********************************************************
2 SixXS - Automatic IPv6 Connectivity Configuration Utility
3 ***********************************************************
4 Copyright 2003-2005 SixXS - http://www.sixxs.net
5 ***********************************************************
6 common/tun.c - Tunnel Device Handling
7 ***********************************************************
8 $Author: jeroen $
9 $Id: tun.c,v 1.14 2007-01-11 00:29:18 jeroen Exp $
10 $Date: 2007-01-11 00:29:18 $
11 **********************************************************/
12
13 #include "tun.h"
14 #include "aiccu.h"
15
16 /* The tun/tap device HANDLE */
17 #ifndef _WIN32
18 int tun_fd;
19
20 /*
21 * HAS_IFHEAD -> Tunnel Device produces packets with a tun_pi in the front
22 * NEED_IFHEAD -> Tunnel Device produces packets with a tun_pi in the front, but it is not active per default
23 */
24
25 #else
26 HANDLE device_handle = INVALID_HANDLE_VALUE;
27 #define ETH_P_IPV6 0x86dd
28 #define ETH_ALEN 6
29 struct ether_header
30 {
31 uint8_t ether_dhost[ETH_ALEN]; /* destination eth addr */
32 uint8_t ether_shost[ETH_ALEN]; /* source ether addr */
33 uint16_t ether_type; /* packet type ID field */
34 };
35
36 /* Tap device constants which we use */
37 #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
38 #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE(2, METHOD_BUFFERED)
39 #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE(5, METHOD_BUFFERED)
40 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
41 #define TAP_REGISTRY_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
42 #define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
43 #define TAP_DEVICE_DIR "\\\\.\\Global\\"
44 #define TAP_WIN32_MIN_MAJOR 8
45 #define TAP_WIN32_MIN_MINOR 1
46 #define TAP_COMPONENT_ID1 "tap0801" /* Original Tun/Tap driver ID */
47 #define TAP_COMPONENT_ID2 "tap0802" /* Windows Vista marked 801 as broken, thus use another ID */
48
49 #endif
50
51 void tun_log(int level, const char *what, const char *fmt, ...);
52 void tun_log(int level, const char *what, const char *fmt, ...)
53 {
54 char buf[1024];
55 va_list ap;
56
57 /* Clear them just in case */
58 memset(buf, 0, sizeof(buf));
59
60 snprintf(buf, sizeof(buf), "[tun-%s] ", what);
61
62 /* Print the log message behind it */
63 va_start(ap, fmt);
64 vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, ap);
65 va_end(ap);
66
67 /* Actually Log it */
68 dolog(level, buf);
69 }
70
71 static const char reader_name[] = "tundev->tun";
72 static const char writer_name[] = "tun->tundev";
73
74 #ifdef _WIN32
75 /* Windows doesn't have writev() but does have WSASend */
76 int writev(SOCKET sock, const struct iovec *vector, DWORD count)
77 {
78 DWORD sent;
79 WSASend(sock, (LPWSABUF)vector, count, &sent, 0, NULL, NULL);
80 return sent;
81 }
82
83 uint16_t inchksum(const void *data, uint32_t length);
84 uint16_t inchksum(const void *data, uint32_t length)
85 {
86 register long sum = 0;
87 register const uint16_t *wrd = (const uint16_t *)data;
88 register long slen = (long)length;
89
90 while (slen >= 2)
91 {
92 sum += *wrd++;
93 slen-=2;
94 }
95
96 if (slen > 0) sum+=*(const uint8_t *)wrd;
97
98 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
99
100 return (uint16_t)sum;
101 }
102
103 uint16_t ipv6_checksum(const struct ip6_hdr *ip6, uint8_t protocol, const void *data, const uint16_t length);
104 uint16_t ipv6_checksum(const struct ip6_hdr *ip6, uint8_t protocol, const void *data, const uint16_t length)
105 {
106 struct
107 {
108 uint16_t length;
109 uint16_t zero1;
110 uint8_t zero2;
111 uint8_t next;
112 } pseudo;
113 register uint32_t chksum = 0;
114
115 pseudo.length = htons(length);
116 pseudo.zero1 = 0;
117 pseudo.zero2 = 0;
118 pseudo.next = protocol;
119
120 /* IPv6 Source + Dest */
121 chksum = inchksum(&ip6->ip6_src, sizeof(ip6->ip6_src) + sizeof(ip6->ip6_dst));
122 chksum += inchksum(&pseudo, sizeof(pseudo));
123 chksum += inchksum(data, length);
124
125 /* Wrap in the carries to reduce chksum to 16 bits. */
126 chksum = (chksum >> 16) + (chksum & 0xffff);
127 chksum += (chksum >> 16);
128
129 /* Take ones-complement and replace 0 with 0xFFFF. */
130 chksum = (uint16_t) ~chksum;
131 if (chksum == 0UL) chksum = 0xffffUL;
132 return (uint16_t)chksum;
133 }
134 #endif
135
136 /*
137 * Tun -> Socket
138 *
139 * Needs to be started in a separate thread
140 * This gets done by tun_start()
141 *
142 */
143 #ifndef _WIN32
144 void *tun_reader(void *arg);
145 void *tun_reader(void *arg)
146 #else
147 DWORD WINAPI tun_reader(LPVOID arg);
148 DWORD WINAPI tun_reader(LPVOID arg)
149 #endif
150 {
151 unsigned char buf[2048];
152
153 /* The function that actually does something with the buffer */
154 struct tun_reader *tun = (struct tun_reader *)arg;
155
156 #ifdef _WIN32
157 DWORD n, lenin;
158 OVERLAPPED overlapped;
159 unsigned int errcount = 0;
160
161 struct nd_sol
162 {
163 struct ip6_hdr ip;
164 struct icmp6_hdr icmp;
165 struct nd_neighbor_solicit sol;
166 } *solic = (struct nd_sol *)&buf[sizeof(struct ether)];
167
168 struct nd_adv
169 {
170 struct ip6_hdr ip;
171 struct icmp6_hdr icmp;
172 struct nd_neighbor_advert adv;
173 } advert;
174
175 /* Create an event for overlapped results */
176 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
177 #else
178 ssize_t n;
179 #endif
180
181 /* Forever */
182 while (true)
183 {
184 #ifndef _WIN32
185 n = read(tun_fd, buf, sizeof(buf));
186 if (n <= 0)
187 {
188 /* Only report issues when the tunnel is actually up and running */
189 if (g_aiccu->tunrunning) tun_log(LOG_ERR, reader_name, "Read error on Tun Device: %s (%d)\n", strerror(errno), errno);
190 continue;
191 }
192
193 #if defined(NEED_IFHEAD) || defined(HAS_IFHEAD)
194 /* get the tun_pi struct out of there */
195 memmove(&buf, &buf[4], n-4);
196 n-=4;
197 #endif
198
199 tun->function((char *)buf, (unsigned int)n);
200 #else /* Windows */
201 overlapped.Offset = 0;
202 overlapped.OffsetHigh = 0;
203
204 memset(buf,0,sizeof(buf));
205 n = ReadFile(device_handle, buf, sizeof(buf), &lenin, &overlapped);
206 if (!n)
207 {
208 while (!n && GetLastError() == ERROR_IO_PENDING)
209 {
210 if (WaitForSingleObject(overlapped.hEvent, 20000) == WAIT_OBJECT_0)
211 {
212 n = GetOverlappedResult(device_handle, &overlapped, &lenin, FALSE);
213 }
214 }
215
216 if (!n)
217 {
218 tun_log(LOG_ERR, reader_name, "Error reading from device: %u, %s (%d)\n", GetLastError(), strerror(errno), errno);
219 errcount++;
220 if (errcount > 10) break;
221 continue;
222 }
223 }
224
225 /* Check for neighbour discovery packets (ICMPv6, ND_SOL, hop=255)
226 * (XXX: doesn't check for a chain, but ND is usually without)
227 */
228 if ( solic->ip.ip6_ctlun.ip6_un1.ip6_un1_nxt == IPPROTO_ICMPV6 &&
229 solic->icmp.icmp6_type == ND_NEIGHBOR_SOLICIT &&
230 solic->ip.ip6_ctlun.ip6_un1.ip6_un1_hlim == 255)
231 {
232 /* Ignore unspecified ND's as they are used for DAD */
233 if (IN6_IS_ADDR_UNSPECIFIED(&solic->ip.ip6_src)) continue;
234
235 /* Create our reply */
236 memset(&advert, 0, sizeof(advert));
237 advert.ip.ip6_ctlun.ip6_un2_vfc = 6 << 4;
238 advert.ip.ip6_ctlun.ip6_un1.ip6_un1_flow = solic->ip.ip6_ctlun.ip6_un1.ip6_un1_flow;
239 advert.ip.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(sizeof(advert.icmp) + sizeof(advert.adv));
240 advert.ip.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_ICMPV6;
241 advert.ip.ip6_ctlun.ip6_un1.ip6_un1_hlim = 255;
242
243 /* Swap src/dst */
244 memcpy(&advert.ip.ip6_src, &solic->sol.nd_ns_target, sizeof(advert.ip.ip6_src));
245 memcpy(&advert.ip.ip6_dst, &solic->ip.ip6_src, sizeof(advert.ip.ip6_dst));
246
247 /* ICMP Neighbour Advertisement */
248 advert.icmp.icmp6_type = ND_NEIGHBOR_ADVERT;
249 advert.icmp.icmp6_code = 0;
250 advert.icmp.icmp6_dataun.icmp6_un_data8[0] = 0xe0;
251 memcpy(&advert.adv.nd_na_target, &solic->sol.nd_ns_target, sizeof(advert.adv.nd_na_target));
252 /* Fake MAC address */
253 advert.adv.nd_no_type = 2;
254 advert.adv.nd_no_len = 1;
255 advert.adv.nd_no_mac[0] = 0x00;
256 advert.adv.nd_no_mac[1] = 0xff;
257 advert.adv.nd_no_mac[2] = 0x25;
258 advert.adv.nd_no_mac[3] = 0x02;
259 advert.adv.nd_no_mac[4] = 0x19;
260 advert.adv.nd_no_mac[5] = 0x78;
261
262 /* ICMP has a checksum */
263 advert.icmp.icmp6_cksum = ipv6_checksum(&advert.ip, IPPROTO_ICMPV6, (uint8_t *)&advert.icmp, sizeof(advert.icmp) + sizeof(advert.adv));
264
265 /* We'll need to answer this back to the TAP device */
266 tun_write((char *)&advert, (unsigned int)sizeof(advert));
267 continue;
268 }
269 tun->function((char *)&buf[sizeof(struct ether)], (unsigned int)lenin - sizeof(struct ether));
270 #endif
271 }
272
273 D(dolog(LOG_DEBUG, "TUN Reader stopping\n"));
274 #ifndef _WIN32
275 return NULL;
276 #else
277 return 0;
278 #endif
279 }
280
281 /* Socket -> Tun */
282 void tun_write(char *buf, unsigned int length)
283 {
284 unsigned int c = 0;
285 #ifndef _WIN32
286 #ifdef linux
287 struct iovec dat[2];
288 struct tun_pi pi;
289 memset(&pi, 0, sizeof(pi));
290
291 pi.proto = htons(ETH_P_IPV6);
292
293 dat[0].iov_base = &pi;
294 dat[0].iov_len = sizeof(pi);
295 dat[1].iov_base = buf;
296 dat[1].iov_len = length;
297
298 length += sizeof(pi);
299
300 /* Forward the packet to the kernel */
301 c = writev(tun_fd, dat, 2);
302
303 #else /* *BSD/Darwin */
304
305 uint32_t type = htonl(AF_INET6);
306 struct iovec dat[2];
307
308 dat[0].iov_base = (void *)&type;
309 dat[0].iov_len = sizeof(type);
310 dat[1].iov_base = buf;
311 dat[1].iov_len = length;
312
313 length += sizeof(type);
314
315 /* Forward the packet to the kernel */
316 c = writev(tun_fd, dat, 2);
317
318 #endif
319
320 if (c != length)
321 {
322 tun_log(LOG_ERR, writer_name, "Error while writing to TUN: %u != %u\n", c, length);
323 }
324
325 #else /* Windows */
326 DWORD n, lenout;
327 OVERLAPPED overlapped;
328 unsigned char mbuf[4096];
329
330 struct ether *eth = (struct ether *)mbuf;
331
332 /* Sent the packet outbound */
333 overlapped.Offset = 0;
334 overlapped.OffsetHigh = 0;
335 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
336
337 memset(mbuf,0,sizeof(mbuf));
338 eth->ether_dhost[0] = htons(0x3333);
339 eth->ether_dhost[1] = htons(0xff00);
340 eth->ether_dhost[2] = htons(0x0002);
341 eth->ether_shost[0] = htons(0x00ff);
342 eth->ether_shost[1] = htons(0x5342);
343 eth->ether_shost[2] = htons(0x2768);
344 eth->ether_type = htons(ETH_P_IPV6);
345 memcpy(&mbuf[sizeof(*eth)],buf,length);
346
347 n = WriteFile(device_handle, mbuf, sizeof(*eth)+length, &lenout, &overlapped);
348 if (!n && GetLastError() == ERROR_IO_PENDING)
349 {
350 WaitForSingleObject(overlapped.hEvent, INFINITE);
351 n = GetOverlappedResult(device_handle, &overlapped, &lenout, FALSE);
352 }
353
354 if (!n)
355 {
356 tun_log(LOG_ERR, writer_name, "Error writing to device: %u, %s (%d)\n", GetLastError(), strerror(errno), errno);
357 }
358 #endif
359 }
360
361 #ifdef _WIN32
362
363 struct tap_reg
364 {
365 char *guid;
366 struct tap_reg *next;
367 };
368
369 struct panel_reg
370 {
371 char *name;
372 char *guid;
373 struct panel_reg *next;
374 };
375
376 /* Get a working tunnel adapter */
377 struct tap_reg *get_tap_reg(void)
378 {
379 HKEY adapter_key;
380 LONG status;
381 DWORD len;
382 struct tap_reg *first = NULL;
383 struct tap_reg *last = NULL;
384 int i = 0;
385
386 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);
387 if (status != ERROR_SUCCESS)
388 {
389 dolog(LOG_ERR, "Error opening registry key: %s\n", TAP_ADAPTER_KEY);
390 return NULL;
391 }
392
393 while (true)
394 {
395 char enum_name[256];
396 char unit_string[256];
397 HKEY unit_key;
398 char component_id_string[] = "ComponentId";
399 char component_id[256];
400 char net_cfg_instance_id_string[] = "NetCfgInstanceId";
401 char net_cfg_instance_id[256];
402 DWORD data_type;
403
404 len = sizeof(enum_name);
405 status = RegEnumKeyEx(adapter_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
406 if (status == ERROR_NO_MORE_ITEMS) break;
407 else if (status != ERROR_SUCCESS)
408 {
409 dolog(LOG_ERR, "Error enumerating registry subkeys of key: %s (t0)\n", TAP_ADAPTER_KEY);
410 break;
411 }
412
413 snprintf(unit_string, sizeof(unit_string), "%s\\%s", TAP_ADAPTER_KEY, enum_name);
414 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key);
415 if (status != ERROR_SUCCESS)
416 {
417 dolog(LOG_WARNING, "Error opening registry key: %s (t1)\n", unit_string);
418 }
419 else
420 {
421 len = sizeof(component_id);
422 status = RegQueryValueEx(unit_key, component_id_string, NULL, &data_type, (LPBYTE)component_id, &len);
423 if (status != ERROR_SUCCESS || data_type != REG_SZ)
424 {
425 dolog(LOG_WARNING, "Error opening registry key: %s\\%s (t2)\n", unit_string, component_id_string);
426 }
427 else
428 {
429 len = sizeof(net_cfg_instance_id);
430 status = RegQueryValueEx(unit_key, net_cfg_instance_id_string, NULL, &data_type, (LPBYTE)net_cfg_instance_id, &len);
431 if (status == ERROR_SUCCESS && data_type == REG_SZ)
432 {
433 if ( strcmp(component_id, TAP_COMPONENT_ID1) == 0 ||
434 strcmp(component_id, TAP_COMPONENT_ID2) == 0)
435 {
436 struct tap_reg *reg = (struct tap_reg *)malloc(sizeof(*reg));
437 memset(reg, 0, sizeof(*reg));
438 reg->guid = strdup(net_cfg_instance_id);
439
440 if (!first) first = reg;
441 if (last) last->next = reg;
442 last = reg;
443 }
444 }
445 }
446
447 RegCloseKey(unit_key);
448 }
449 i++;
450 }
451
452 RegCloseKey(adapter_key);
453 return first;
454 }
455
456 void free_tap_reg(struct tap_reg *tap_reg)
457 {
458 struct tap_reg *tr, *tr1;
459
460 for (tr = tap_reg; tr != NULL; tr = tr1)
461 {
462 tr1 = tr->next;
463 free(tr->guid);
464 free(tr);
465 }
466 }
467
468 void free_panel_reg(struct panel_reg *panel_reg)
469 {
470 struct panel_reg *pr, *pr1;
471
472 for (pr = panel_reg; pr != NULL; pr = pr1)
473 {
474 pr1 = pr->next;
475 free(pr->guid);
476 free(pr->name);
477 free(pr);
478 }
479 }
480
481
482 /* Collect GUID's and names of all the Connections that are available */
483 struct panel_reg *get_panel_reg(void)
484 {
485 LONG status;
486 HKEY network_connections_key;
487 DWORD len;
488 struct panel_reg *first = NULL;
489 struct panel_reg *last = NULL;
490 int i = 0;
491
492 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_REGISTRY_KEY, 0, KEY_READ, &network_connections_key);
493
494 if (status != ERROR_SUCCESS)
495 {
496 dolog(LOG_ERR, "Error opening registry key: %s (p0)\n", TAP_REGISTRY_KEY);
497 return NULL;
498 }
499
500 while (true)
501 {
502 char enum_name[256];
503 char connection_string[256];
504 HKEY connection_key;
505 char name_data[256];
506 DWORD name_type;
507 const char name_string[] = "Name";
508
509 len = sizeof(enum_name);
510 status = RegEnumKeyEx(network_connections_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
511 if (status == ERROR_NO_MORE_ITEMS) break;
512 else if (status != ERROR_SUCCESS)
513 {
514 dolog(LOG_ERR, "Error enumerating registry subkeys of key: %s (p1)\n", TAP_REGISTRY_KEY);
515 break;
516 }
517
518 i++;
519
520 if (enum_name[0] != '{') continue;
521
522 snprintf(connection_string, sizeof(connection_string), "%s\\%s\\Connection", TAP_REGISTRY_KEY, enum_name);
523
524 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connection_key);
525 if (status != ERROR_SUCCESS)
526 {
527 dolog(LOG_WARNING, "Error opening registry key: %s (p2)\n", connection_string);
528 }
529 else
530 {
531 len = sizeof(name_data);
532 status = RegQueryValueEx(connection_key, name_string, NULL, &name_type, (LPBYTE)name_data, &len);
533
534 if (status != ERROR_SUCCESS || name_type != REG_SZ)
535 {
536 dolog(LOG_WARNING, "Error opening registry key: %s\\%s\\%s (p3)\n", TAP_REGISTRY_KEY, (LPBYTE)connection_string, name_string);
537 }
538 else
539 {
540 struct panel_reg *reg = (struct panel_reg *)malloc(sizeof(*reg));
541 memset(reg, 0, sizeof(*reg));
542 reg->name = strdup(name_data);
543 reg->guid = strdup(enum_name);
544
545 /* link into return list */
546 if (!first) first = reg;
547 if (last) last->next = reg;
548 last = reg;
549 }
550
551 RegCloseKey(connection_key);
552 }
553 }
554
555 RegCloseKey(network_connections_key);
556
557 return first;
558 }
559
560 void tun_list_tap_adapters(void)
561 {
562 int links;
563 struct tap_reg *tap_reg = get_tap_reg(), *tr, *tr1;
564 struct panel_reg *panel_reg = get_panel_reg(), *pr;
565
566 dolog(LOG_INFO, "Available TAP-WIN32 adapters [name, GUID]:\n");
567
568 /* loop through each TAP-Win32 adapter registry entry */
569 for (tr = tap_reg; tr != NULL; tr = tr->next)
570 {
571 links = 0;
572
573 /* loop through each network connections entry in the control panel */
574 for (pr = panel_reg; pr != NULL; pr = pr->next)
575 {
576 if (strcmp(tr->guid, pr->guid) == 0)
577 {
578 dolog(LOG_INFO, "'%s' %s\n", pr->name, tr->guid);
579 links++;
580 }
581 }
582
583 if (links > 1)
584 {
585 dolog(LOG_WARNING, "*** Adapter with GUID %s has %u links from the Network Connections control panel, it should only be 1\n", tr->guid, links);
586 }
587 else if (links == 0)
588 {
589 dolog(LOG_WARNING, "[NULL] %s\n", tr->guid);
590 dolog(LOG_WARNING, "*** Adapter with GUID %s doesn't have a link from the control panel\n", tr->guid);
591 }
592
593 /* check for TAP-Win32 adapter duplicated GUIDs */
594 for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next)
595 {
596 if (tr != tr1 && strcmp(tr->guid, tr1->guid) == 0)
597 {
598 dolog(LOG_WARNING, "*** Duplicate Adapter GUID %s\n", tr->guid);
599 }
600 }
601 }
602
603 free_tap_reg(tap_reg);
604 free_panel_reg(panel_reg);
605 }
606
607 bool tun_fixup_adapters(void)
608 {
609 int links, count = 0, found = 0;
610 struct tap_reg *tap_reg = get_tap_reg(), *tr = NULL, *tr1 = NULL;
611 struct panel_reg *panel_reg = get_panel_reg(), *pr = NULL, *first = NULL, *prf = NULL;
612 bool ok;
613
614 /* loop through each TAP-Win32 adapter registry entry */
615 for (tr = tap_reg; tr != NULL; tr = tr->next)
616 {
617 links = 0;
618 ok = true;
619
620 /* loop through each network connections entry in the control panel */
621 for (pr = panel_reg; pr != NULL; pr = pr->next)
622 {
623 if (strcmp(tr->guid, pr->guid) == 0)
624 {
625 links++;
626 prf = pr;
627
628 /* Is this the one wanted by the user? */
629 if (strcasecmp(g_aiccu->ipv6_interface, pr->name) == 0) found++;
630 }
631 }
632
633 if (links > 1)
634 {
635 dolog(LOG_WARNING, "*** Adapter with GUID %s has %u links from the Network Connections control panel, it should only be 1\n", tr->guid, links);
636 ok = false;
637 }
638 else if (links == 0)
639 {
640 dolog(LOG_WARNING, "[NULL] %s\n", tr->guid);
641 dolog(LOG_WARNING, "*** Adapter with GUID %s doesn't have a link from the control panel\n", tr->guid);
642 ok = false;
643 }
644
645 /* check for TAP-Win32 adapter duplicated GUIDs */
646 for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next)
647 {
648 if (tr != tr1 && strcmp(tr->guid, tr1->guid) == 0)
649 {
650 dolog(LOG_WARNING, "*** Duplicate Adapter GUID %s\n", tr->guid);
651 ok = false;
652 }
653 }
654
655 if (ok)
656 {
657 count++;
658 first = prf;
659 }
660 }
661
662 ok = false;
663
664 /* When the user didn't configure us correctly and we find a single TAP interface, just rename it */
665 if (found == 0 && count == 1 && first)
666 {
667 dolog(LOG_INFO, "Renaming adapter '%s' to '%s' and using it\n", first->name, g_aiccu->ipv6_interface);
668 aiccu_win32_rename_adapter(first->name);
669 ok = true;
670 }
671 else if (found == 1 && count == 1)
672 {
673 D(dolog(LOG_DEBUG, "Using configured interface %s\n", g_aiccu->ipv6_interface));
674 ok = true;
675 }
676 else
677 {
678 ok = false;
679 dolog(LOG_WARNING, "Found = %u, Count = %u\n", found, count);
680 }
681
682 free_tap_reg(tap_reg);
683 free_panel_reg(panel_reg);
684
685 return ok;
686 }
687
688 #endif
689
690 bool tun_start(struct tun_reader *tun)
691 {
692 #ifndef _WIN32
693 pthread_t thread;
694 #ifdef linux
695 struct ifreq ifr;
696
697 /* Create a new tap device */
698 tun_fd = open("/dev/net/tun", O_RDWR);
699 if (tun_fd == -1)
700 {
701 tun_log(LOG_ERR, "start", "Couldn't open device %s: %s (%d)\n", "/dev/net/tun", strerror(errno), errno);
702 return false;
703 }
704
705 memset(&ifr, 0, sizeof(ifr));
706 /* Request a TUN device */
707 ifr.ifr_flags = IFF_TUN;
708 /* Set the interface name */
709 strncpy(ifr.ifr_name, g_aiccu->ipv6_interface, sizeof(ifr.ifr_name));
710
711 if (ioctl(tun_fd, TUNSETIFF, &ifr))
712 {
713 tun_log(LOG_ERR, "start", "Couldn't set interface name to %s: %s (%d)\n",
714 g_aiccu->ipv6_interface, strerror(errno), errno);
715 return false;
716 }
717
718 #else /* *BSD/Darwin */
719
720 char buf[128];
721 unsigned int i;
722 int mode = IFF_MULTICAST | IFF_POINTOPOINT;
723
724 /* Try the configured interface */
725 tun_log(LOG_DEBUG, "start", "Trying Configured TUN/TAP interface %s...\n", g_aiccu->ipv6_interface);
726 snprintf(buf, sizeof(buf), "/dev/%s", g_aiccu->ipv6_interface);
727 tun_fd = open(buf, O_RDWR);
728 if (tun_fd < 0)
729 {
730 /* Fall back to trying all /dev/tun* devices */
731 for (i = 0; i < 256; ++i)
732 {
733 snprintf(buf, sizeof(buf), "/dev/tun%u", i);
734 tun_log(LOG_DEBUG, "start", "Trying TUN/TAP interface %s...\n", &buf[8]);
735 tun_fd = open(buf, O_RDWR);
736 if (tun_fd >= 0)
737 {
738 /* Copy over the name of the interface so that configging goes okay */
739 if (g_aiccu->ipv6_interface) free(g_aiccu->ipv6_interface);
740 snprintf(buf, sizeof(buf), "tun%u", i);
741 g_aiccu->ipv6_interface = strdup(buf);
742 }
743 break;
744 }
745 }
746
747 if (tun_fd < 0)
748 {
749 tun_log(LOG_ERR, "start", "Couldn't open device %s or /dev/tun*: %s (%d)\n", g_aiccu->ipv6_interface, strerror(errno), errno);
750 return false;
751 }
752
753 tun_log(LOG_DEBUG, "start", "Using TUN/TAP interface %s\n", g_aiccu->ipv6_interface);
754
755 #ifndef _FREEBSD
756 #ifndef _DARWIN
757 #ifndef _AIX
758 tun_log(LOG_DEBUG, "start", "Setting TUNSIFMODE for %s\n", g_aiccu->ipv6_interface);
759 if (ioctl(tun_fd, TUNSIFMODE, &mode, sizeof(mode)) == -1)
760 {
761 tun_log(LOG_ERR, "start", "Couldn't set interface %s's TUNSIFMODE to MULTICAST|POINTOPOINT: %s (%d)\n",
762 g_aiccu->ipv6_interface, strerror(errno), errno);
763 close(tun_fd);
764 tun_fd = -1;
765 return false;
766 }
767 #endif
768 #endif
769 #endif
770
771 #ifdef NEED_IFHEAD
772 tun_log(LOG_DEBUG, "start", "Setting TUNSIFHEAD for %s\n", g_aiccu->ipv6_interface);
773 mode = 1;
774 if (ioctl(tun_fd, TUNSIFHEAD, &mode, sizeof(mode)) == -1)
775 {
776 tun_log(LOG_ERR, "start", "Couldn't set interface %s's TUNSIFHEAD to enabled: %s (%d)\n",
777 g_aiccu->ipv6_interface, strerror(errno), errno);
778 close(tun_fd);
779 tun_fd = -1;
780 return false;
781 }
782 #endif
783
784 #endif /* linux */
785
786
787 #else /* Windows */
788
789 HKEY key;
790 DWORD pID;
791 HANDLE h;
792 int i;
793
794 char adapterid[1024];
795 char tapname[1024];
796 DWORD len;
797
798 if (!tun_fixup_adapters())
799 {
800 tun_log(LOG_ERR, "start", "TAP-Win32 Adapter not configured properly...\n");
801 return false;
802 }
803
804 /* Open registry and look for network adapters */
805 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_REGISTRY_KEY, 0, KEY_READ, &key))
806 {
807 tun_log(LOG_ERR, "start", "Could not open the networking registry key\n");
808 return false;
809 }
810
811 for (i = 0; device_handle == INVALID_HANDLE_VALUE; i++)
812 {
813 len = sizeof(adapterid);
814 if (RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) break;
815
816 snprintf(tapname, sizeof(tapname), TAP_DEVICE_DIR "%s.tap", adapterid);
817 tun_log(LOG_DEBUG, "start", "Trying %s\n", tapname);
818 device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
819
820 if (device_handle != INVALID_HANDLE_VALUE)
821 {
822 unsigned long status, info[3] = {0,0,0};
823
824 /* get driver version info */
825 if (DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), &len, NULL))
826 {
827 D(tun_log(LOG_DEBUG, "start", "TAP-Win32 Driver Version %d.%d %s", (int)info[0], (int)info[1], info[2] ? "(DEBUG)" : ""));
828 }
829
830 if (!(info[0] > TAP_WIN32_MIN_MAJOR || (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR)))
831 {
832 tun_log(LOG_ERR, "start", "A TAP-Win32 driver is required that is at least version %d.%d -- If you recently upgraded your Tap32 driver, a reboot is probably required at this point to get Windows to see the new driver.", TAP_WIN32_MIN_MAJOR, TAP_WIN32_MIN_MINOR);
833 CloseHandle(device_handle);
834 device_handle = INVALID_HANDLE_VALUE;
835 continue;
836 }
837
838 /* Note: we use TAP mode on Windows, not TUN */
839
840 /* Try to mark the device as 'up */
841 status = true;
842 DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
843 }
844 }
845
846 RegCloseKey(key);
847
848 if (device_handle == INVALID_HANDLE_VALUE)
849 {
850 tun_log(LOG_ERR, "start", "No working Tap device found!\n");
851 return false;
852 }
853
854 #endif /* _WIN32 */
855
856 /* Launch a thread for reader */
857 #ifndef _WIN32
858 pthread_create(&thread, NULL, tun_reader, (void *)tun);
859 #else
860 h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, tun, 0, &pID);
861 #endif
862
863 /* We now return, the real tunneling tool can call tun_write() when it wants */
864
865 return true;
866 }