1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Cedar Communication Module
3
4
5 // VLanUnix.c
6 // Virtual device driver library for UNIX
7
8 #ifdef UNIX
9
10 #include "VLanUnix.h"
11
12 #include "Connection.h"
13 #include "Session.h"
14
15 #include "Mayaqua/FileIO.h"
16 #include "Mayaqua/Mayaqua.h"
17 #include "Mayaqua/Memory.h"
18 #include "Mayaqua/Str.h"
19 #include "Mayaqua/TunTap.h"
20
21 #ifdef UNIX_BSD
22 // For "sockaddr" in <net/if_arp.h>
23 #include <sys/socket.h>
24 #endif
25
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <net/if_arp.h>
29 #include <net/if.h>
30 #include <sys/ioctl.h>
31
32 #ifdef UNIX_OPENBSD
33 #include <netinet/if_ether.h>
34 #else
35 #include <net/ethernet.h>
36 #endif
37
38 static LIST *unix_vlan = NULL;
39
40 #ifndef NO_VLAN
41
42 // Get the PACKET_ADAPTER
VLanGetPacketAdapter()43 PACKET_ADAPTER *VLanGetPacketAdapter()
44 {
45 PACKET_ADAPTER *pa;
46
47 pa = NewPacketAdapter(VLanPaInit, VLanPaGetCancel,
48 VLanPaGetNextPacket, VLanPaPutPacket, VLanPaFree);
49 if (pa == NULL)
50 {
51 return NULL;
52 }
53
54 return pa;
55 }
56
57 // PA initialization
VLanPaInit(SESSION * s)58 bool VLanPaInit(SESSION *s)
59 {
60 VLAN *v;
61 // Validate arguments
62 if (s == NULL)
63 {
64 return false;
65 }
66
67 // Connect to the driver
68 v = NewVLan(s->ClientOption->DeviceName, NULL);
69 if (v == NULL)
70 {
71 // Failure
72 return false;
73 }
74
75 s->PacketAdapter->Param = v;
76
77 return true;
78 }
79
80 // Get the cancel object
VLanPaGetCancel(SESSION * s)81 CANCEL *VLanPaGetCancel(SESSION *s)
82 {
83 VLAN *v;
84 // Validate arguments
85 if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
86 {
87 return NULL;
88 }
89
90 return VLanGetCancel(v);
91 }
92
93 // Release the packet adapter
VLanPaFree(SESSION * s)94 void VLanPaFree(SESSION *s)
95 {
96 VLAN *v;
97 // Validate arguments
98 if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
99 {
100 return;
101 }
102
103 // End the virtual LAN card
104 FreeVLan(v);
105
106 s->PacketAdapter->Param = NULL;
107 }
108
109 // Write a packet
VLanPaPutPacket(SESSION * s,void * data,UINT size)110 bool VLanPaPutPacket(SESSION *s, void *data, UINT size)
111 {
112 VLAN *v;
113 // Validate arguments
114 if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
115 {
116 return false;
117 }
118
119 return VLanPutPacket(v, data, size);
120 }
121
122 // Get the next packet
VLanPaGetNextPacket(SESSION * s,void ** data)123 UINT VLanPaGetNextPacket(SESSION *s, void **data)
124 {
125 VLAN *v;
126 UINT size;
127 // Validate arguments
128 if (data == NULL || (s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
129 {
130 return INFINITE;
131 }
132
133 if (VLanGetNextPacket(v, data, &size) == false)
134 {
135 return INFINITE;
136 }
137
138 return size;
139 }
140
141 // Write a packet to the virtual LAN card
VLanPutPacket(VLAN * v,void * buf,UINT size)142 bool VLanPutPacket(VLAN *v, void *buf, UINT size)
143 {
144 UINT ret;
145 // Validate arguments
146 if (v == NULL)
147 {
148 return false;
149 }
150 if (v->Halt)
151 {
152 return false;
153 }
154 if (size > MAX_PACKET_SIZE)
155 {
156 return false;
157 }
158 if (buf == NULL || size == 0)
159 {
160 if (buf != NULL)
161 {
162 Free(buf);
163 }
164 return true;
165 }
166
167 ret = write(v->fd, buf, size);
168
169 if (ret >= 1)
170 {
171 Free(buf);
172 return true;
173 }
174
175 if (errno == EAGAIN || ret == 0)
176 {
177 Free(buf);
178 return true;
179 }
180
181 return false;
182 }
183
184 // Get the next packet from the virtual LAN card
VLanGetNextPacket(VLAN * v,void ** buf,UINT * size)185 bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size)
186 {
187 UCHAR tmp[TAP_READ_BUF_SIZE];
188 int ret;
189 // Validate arguments
190 if (v == NULL || buf == NULL || size == 0)
191 {
192 return false;
193 }
194 if (v->Halt)
195 {
196 return false;
197 }
198
199 // Read
200 ret = read(v->fd, tmp, sizeof(tmp));
201
202 if (ret == 0 ||
203 (ret == -1 && errno == EAGAIN))
204 {
205 // No packet
206 *buf = NULL;
207 *size = 0;
208 return true;
209 }
210 else if (ret == -1 || ret > TAP_READ_BUF_SIZE)
211 {
212 // Error
213 return false;
214 }
215 else
216 {
217 // Reading packet success
218 *buf = Malloc(ret);
219 Copy(*buf, tmp, ret);
220 *size = ret;
221 return true;
222 }
223 }
224
225 // Get the cancel object
VLanGetCancel(VLAN * v)226 CANCEL *VLanGetCancel(VLAN *v)
227 {
228 CANCEL *c;
229 int fd;
230 int yes = 0;
231 // Validate arguments
232 if (v == NULL)
233 {
234 return NULL;
235 }
236
237 c = NewCancel();
238 UnixDeletePipe(c->pipe_read, c->pipe_write);
239 c->pipe_read = c->pipe_write = -1;
240
241 fd = v->fd;
242
243 UnixSetSocketNonBlockingMode(fd, true);
244
245 c->SpecialFlag = true;
246 c->pipe_read = fd;
247
248 return c;
249 }
250
251 // Close the Virtual LAN card
FreeVLan(VLAN * v)252 void FreeVLan(VLAN *v)
253 {
254 // Validate arguments
255 if (v == NULL)
256 {
257 return;
258 }
259
260 Free(v->InstanceName);
261
262 Free(v);
263 }
264
265 // Create a tap
NewTap(char * name,char * mac_address,bool create_up)266 VLAN *NewTap(char *name, char *mac_address, bool create_up)
267 {
268 int fd;
269 VLAN *v;
270 // Validate arguments
271 if (name == NULL || mac_address == NULL)
272 {
273 return NULL;
274 }
275
276 fd = UnixCreateTapDeviceEx(name, "tap", mac_address, create_up);
277 if (fd == -1)
278 {
279 return NULL;
280 }
281
282 v = ZeroMalloc(sizeof(VLAN));
283 v->Halt = false;
284 v->InstanceName = CopyStr(name);
285 v->fd = fd;
286
287 return v;
288 }
289
290 // Close the tap
FreeTap(VLAN * v)291 void FreeTap(VLAN *v)
292 {
293 // Validate arguments
294 if (v == NULL)
295 {
296 return;
297 }
298
299 close(v->fd);
300 FreeVLan(v);
301 }
302
303 // Get the Virtual LAN card list
NewVLan(char * instance_name,VLAN_PARAM * param)304 VLAN *NewVLan(char *instance_name, VLAN_PARAM *param)
305 {
306 int fd;
307 VLAN *v;
308 // Validate arguments
309 if (instance_name == NULL)
310 {
311 return NULL;
312 }
313
314 // Open the tap
315 fd = UnixVLanGet(instance_name);
316 if (fd == -1)
317 {
318 return NULL;
319 }
320
321 v = ZeroMalloc(sizeof(VLAN));
322 v->Halt = false;
323 v->InstanceName = CopyStr(instance_name);
324 v->fd = fd;
325
326 return v;
327 }
328
329 // Generate TUN interface name
GenerateTunName(char * name,char * prefix,char * tun_name,size_t tun_name_len)330 void GenerateTunName(char *name, char *prefix, char *tun_name, size_t tun_name_len)
331 {
332 char instance_name_lower[MAX_SIZE];
333
334 // Generate the device name
335 StrCpy(instance_name_lower, sizeof(instance_name_lower), name);
336 Trim(instance_name_lower);
337 StrLower(instance_name_lower);
338 Format(tun_name, tun_name_len, "%s_%s", prefix, instance_name_lower);
339
340 tun_name[15] = 0;
341 }
342 // Create a tap device
UnixCreateTapDeviceEx(char * name,char * prefix,UCHAR * mac_address,bool create_up)343 int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address, bool create_up)
344 {
345 int fd = -1, s = -1;
346 char tap_name[MAX_SIZE], tap_path[MAX_SIZE];
347 struct ifreq ifr;
348
349 // Validate arguments
350 if (name == NULL)
351 {
352 return -1;
353 }
354
355 GenerateTunName(name, prefix, tap_name, sizeof(tap_name));
356
357 // Open the tun / tap
358 #ifndef UNIX_BSD
359 if (GetOsInfo()->OsType == OSTYPE_LINUX)
360 {
361 // Linux
362 if (IsFile(TAP_FILENAME_1) == false)
363 {
364 char tmp[MAX_SIZE];
365
366 Format(tmp, sizeof(tmp), "%s c 10 200", TAP_FILENAME_1);
367 Run("mknod", tmp, true, true);
368
369 Format(tmp, sizeof(tmp), "600 %s", TAP_FILENAME_1);
370 Run("chmod", tmp, true, true);
371 }
372 }
373
374 fd = open(TAP_FILENAME_1, O_RDWR);
375 if (fd == -1)
376 {
377 // Failure
378 fd = open(TAP_FILENAME_2, O_RDWR);
379 if (fd == -1)
380 {
381 return -1;
382 }
383 }
384 #else // UNIX_BSD
385 {
386 sprintf(tap_path, "%s", TAP_DIR TAP_NAME);
387 for (int i = 0; i < TAP_MAX; i++) {
388 sprintf(tap_path + StrLen(TAP_DIR TAP_NAME), "%d", i);
389 fd = open(tap_path, O_RDWR);
390 if (fd != -1)
391 {
392 break;
393 }
394 }
395
396 if (fd == -1)
397 {
398 return -1;
399 }
400 }
401 #endif // UNIX_BSD
402
403 #ifdef UNIX_LINUX
404 // Create a TAP device for Linux
405
406 // Set the name and the flags
407 Zero(&ifr, sizeof(ifr));
408 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), tap_name);
409 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
410
411 if (ioctl(fd, TUNSETIFF, &ifr) == -1)
412 {
413 // Failure
414 close(fd);
415 return -1;
416 }
417
418 s = socket(AF_INET, SOCK_DGRAM, 0);
419 if (s != -1)
420 {
421 // Set the MAC address
422 if (mac_address != NULL)
423 {
424 Zero(&ifr, sizeof(ifr));
425 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), tap_name);
426 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
427 Copy(&ifr.ifr_hwaddr.sa_data, mac_address, ETHER_ADDR_LEN);
428 ioctl(s, SIOCSIFHWADDR, &ifr);
429 }
430
431 if (create_up)
432 {
433 Zero(&ifr, sizeof(ifr));
434 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), tap_name);
435 ioctl(s, SIOCGIFFLAGS, &ifr);
436 ifr.ifr_flags |= IFF_UP;
437 ioctl(s, SIOCSIFFLAGS, &ifr);
438 }
439
440 close(s);
441 }
442 #endif // UNIX_LINUX
443
444 #ifdef UNIX_BSD
445 // Create a TAP device for BSD
446 Zero(&ifr, sizeof(ifr));
447
448 // Get the current name
449 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), tap_path + StrLen(TAP_DIR));
450
451 s = socket(AF_INET, SOCK_DGRAM, 0);
452 if (s != -1)
453 {
454 // Set the name, if possible
455 #ifdef SIOCSIFNAME
456 ifr.ifr_data = tap_name;
457 ioctl(s, SIOCSIFNAME, &ifr);
458 #else // SIOCSIFNAME
459 StrCpy(tap_name, sizeof(tap_name), ifr.ifr_name);
460 #endif // SIOCSIFNAME
461
462 // Set the MAC address
463 if (mac_address != NULL)
464 {
465 Zero(&ifr, sizeof(ifr));
466 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), tap_name);
467 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
468 ifr.ifr_addr.sa_family = AF_LINK;
469 Copy(&ifr.ifr_addr.sa_data, mac_address, ETHER_ADDR_LEN);
470 ioctl(s, SIOCSIFLLADDR, &ifr);
471 }
472
473 if (create_up)
474 {
475 Zero(&ifr, sizeof(ifr));
476 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), tap_name);
477 ioctl(s, SIOCGIFFLAGS, &ifr);
478 ifr.ifr_flags |= IFF_UP;
479 ioctl(s, SIOCSIFFLAGS, &ifr);
480 }
481
482 close(s);
483 }
484 #endif // UNIX_BSD
485
486 #ifdef UNIX_SOLARIS
487 // Create a TAP device for Solaris
488 {
489 int ip_fd;
490 int tun_fd;
491 int ppa;
492
493 tun_fd = open(tap_name, O_RDWR);
494 if (tun_fd == -1)
495 {
496 // Failure
497 close(fd);
498 return -1;
499 }
500
501 ip_fd = open("/dev/ip", O_RDWR);
502 if (ip_fd == -1)
503 {
504 // Failure
505 close(tun_fd);
506 close(fd);
507 return -1;
508 }
509
510 ppa = -1;
511 ppa = ioctl(tun_fd, TUNNEWPPA, ppa);
512 if (ppa == -1)
513 {
514 // Failure
515 close(tun_fd);
516 close(fd);
517 close(ip_fd);
518 return -1;
519 }
520
521 if (ioctl(fd, I_PUSH, "ip") < 0)
522 {
523 // Failure
524 close(tun_fd);
525 close(fd);
526 close(ip_fd);
527 return -1;
528 }
529
530 if (ioctl(fd, IF_UNITSEL, (char *)&ppa) < 0)
531 {
532 // Failure
533 close(tun_fd);
534 close(fd);
535 close(ip_fd);
536 return -1;
537 }
538
539 if (ioctl(ip_fd, I_LINK, fd) < 0)
540 {
541 // Failure
542 close(tun_fd);
543 close(fd);
544 close(ip_fd);
545 return -1;
546 }
547
548 close(tun_fd);
549 close(ip_fd);
550 }
551 #endif // UNIX_SOLARIS
552
553 return fd;
554 }
UnixCreateTapDevice(char * name,UCHAR * mac_address,bool create_up)555 int UnixCreateTapDevice(char *name, UCHAR *mac_address, bool create_up)
556 {
557 return UnixCreateTapDeviceEx(name, "vpn", mac_address, create_up);
558 }
559
560 // Close the tap device
UnixCloseTapDevice(int fd)561 void UnixCloseTapDevice(int fd)
562 {
563 // Validate arguments
564 if (fd == -1)
565 {
566 return;
567 }
568
569 close(fd);
570 }
571
572 #else // NO_VLAN
573
UnixCloseTapDevice(int fd)574 void UnixCloseTapDevice(int fd)
575 {
576 }
577
UnixCreateTapDeviceEx(char * name,char * prefix,UCHAR * mac_address,bool create_up)578 int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address, bool create_up)
579 {
580 return -1;
581 }
UnixCreateTapDevice(char * name,UCHAR * mac_address,bool create_up)582 int UnixCreateTapDevice(char *name, UCHAR *mac_address, bool create_up)
583 {
584 return -1;
585 }
586
587 #endif // NO_VLAN
588
589 // Comparison of the VLAN list entries
UnixCompareVLan(void * p1,void * p2)590 int UnixCompareVLan(void *p1, void *p2)
591 {
592 UNIX_VLAN_LIST *v1, *v2;
593 if (p1 == NULL || p2 == NULL)
594 {
595 return 0;
596 }
597 v1 = *(UNIX_VLAN_LIST **)p1;
598 v2 = *(UNIX_VLAN_LIST **)p2;
599 if (v1 == NULL || v2 == NULL)
600 {
601 return 0;
602 }
603
604 return StrCmpi(v1->Name, v2->Name);
605 }
606
607 // Initialize the VLAN list
UnixVLanInit()608 void UnixVLanInit()
609 {
610 unix_vlan = NewList(UnixCompareVLan);
611 }
612
613 // Create a VLAN
UnixVLanCreateEx(char * name,char * prefix,UCHAR * mac_address,bool create_up)614 bool UnixVLanCreateEx(char *name, char *prefix, UCHAR *mac_address, bool create_up)
615 {
616 // Validate arguments
617 char tmp[MAX_SIZE];
618 if (name == NULL)
619 {
620 return false;
621 }
622
623 StrCpy(tmp, sizeof(tmp), name);
624 Trim(tmp);
625 name = tmp;
626
627 LockList(unix_vlan);
628 {
629 UNIX_VLAN_LIST *t, tt;
630 int fd;
631
632 // Check whether a device with the same name exists
633 Zero(&tt, sizeof(tt));
634 StrCpy(tt.Name, sizeof(tt.Name), name);
635
636 t = Search(unix_vlan, &tt);
637 if (t != NULL)
638 {
639 // Already exist
640 UnlockList(unix_vlan);
641 return false;
642 }
643
644 // Create a tap device
645 fd = UnixCreateTapDeviceEx(name, prefix, mac_address, create_up);
646 if (fd == -1)
647 {
648 // Failure to create
649 UnlockList(unix_vlan);
650 return false;
651 }
652
653 t = ZeroMalloc(sizeof(UNIX_VLAN_LIST));
654 t->fd = fd;
655 StrCpy(t->Name, sizeof(t->Name), name);
656
657 Insert(unix_vlan, t);
658 }
659 UnlockList(unix_vlan);
660
661 return true;
662 }
UnixVLanCreate(char * name,UCHAR * mac_address,bool create_up)663 bool UnixVLanCreate(char *name, UCHAR *mac_address, bool create_up)
664 {
665 return UnixVLanCreateEx(name, "vpn", mac_address, create_up);
666 }
667
668 // Set a VLAN up/down
UnixVLanSetState(char * name,bool state_up)669 bool UnixVLanSetState(char* name, bool state_up)
670 {
671 #ifdef UNIX_LINUX
672 UNIX_VLAN_LIST *t, tt;
673 struct ifreq ifr;
674 int s;
675 char eth_name[MAX_SIZE];
676
677 LockList(unix_vlan);
678 {
679 int result;
680 // Find a device with the same name
681 Zero(&tt, sizeof(tt));
682 StrCpy(tt.Name, sizeof(tt.Name), name);
683
684 t = Search(unix_vlan, &tt);
685 if (t == NULL)
686 {
687 // No such device
688 UnlockList(unix_vlan);
689 return false;
690 }
691
692 GenerateTunName(name, "vpn", eth_name, sizeof(eth_name));
693 Zero(&ifr, sizeof(ifr));
694 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
695
696 s = socket(AF_INET, SOCK_DGRAM, 0);
697 if (s == -1)
698 {
699 // Failed to create socket
700 UnlockList(unix_vlan);
701 return false;
702 }
703
704 ioctl(s, SIOCGIFFLAGS, &ifr);
705 if (state_up)
706 {
707 ifr.ifr_flags |= IFF_UP;
708 }
709 else
710 {
711 ifr.ifr_flags &= ~IFF_UP;
712 }
713 result = ioctl(s, SIOCSIFFLAGS, &ifr);
714 close(s);
715 }
716 UnlockList(unix_vlan);
717 #endif // UNIX_LINUX
718
719 return true;
720 }
721
722 // Enumerate VLANs
UnixVLanEnum()723 TOKEN_LIST *UnixVLanEnum()
724 {
725 TOKEN_LIST *ret;
726 UINT i;
727 if (unix_vlan == NULL)
728 {
729 return NullToken();
730 }
731
732 ret = ZeroMalloc(sizeof(TOKEN_LIST));
733
734 LockList(unix_vlan);
735 {
736 ret->NumTokens = LIST_NUM(unix_vlan);
737 ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
738
739 for (i = 0;i < ret->NumTokens;i++)
740 {
741 UNIX_VLAN_LIST *t = LIST_DATA(unix_vlan, i);
742
743 ret->Token[i] = CopyStr(t->Name);
744 }
745 }
746 UnlockList(unix_vlan);
747
748 return ret;
749 }
750
751 // Delete the VLAN
UnixVLanDelete(char * name)752 void UnixVLanDelete(char *name)
753 {
754 // Validate arguments
755 if (name == NULL || unix_vlan == NULL)
756 {
757 return;
758 }
759
760 LockList(unix_vlan);
761 {
762 UINT i;
763 UNIX_VLAN_LIST *t, tt;
764
765 Zero(&tt, sizeof(tt));
766 StrCpy(tt.Name, sizeof(tt.Name), name);
767
768 t = Search(unix_vlan, &tt);
769 if (t != NULL)
770 {
771 UnixCloseTapDevice(t->fd);
772 Delete(unix_vlan, t);
773 Free(t);
774 }
775 }
776 UnlockList(unix_vlan);
777 }
778
779 // Get the VLAN
UnixVLanGet(char * name)780 int UnixVLanGet(char *name)
781 {
782 int fd = -1;
783 // Validate arguments
784 if (name == NULL || unix_vlan == NULL)
785 {
786 return -1;
787 }
788
789 LockList(unix_vlan);
790 {
791 UINT i;
792 UNIX_VLAN_LIST *t, tt;
793
794 Zero(&tt, sizeof(tt));
795 StrCpy(tt.Name, sizeof(tt.Name), name);
796
797 t = Search(unix_vlan, &tt);
798 if (t != NULL)
799 {
800 fd = t->fd;
801 }
802 }
803 UnlockList(unix_vlan);
804
805 return fd;
806 }
807
808 // Release the VLAN list
UnixVLanFree()809 void UnixVLanFree()
810 {
811 UINT i;
812
813 for (i = 0;i < LIST_NUM(unix_vlan);i++)
814 {
815 UNIX_VLAN_LIST *t = LIST_DATA(unix_vlan, i);
816
817 UnixCloseTapDevice(t->fd);
818 Free(t);
819 }
820
821 ReleaseList(unix_vlan);
822 unix_vlan = NULL;
823 }
824
825 #endif
826