1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Cedar Communication Module
3
4
5 // Cedar.c
6 // Cedar Communication Module
7
8 #include "Cedar.h"
9
10 #include "Admin.h"
11 #include "Bridge.h"
12 #include "Connection.h"
13 #include "Layer3.h"
14 #include "Link.h"
15 #include "Listener.h"
16 #include "Protocol.h"
17 #include "Sam.h"
18 #include "Server.h"
19 #include "Session.h"
20 #include "VLanWin32.h"
21 #include "WebUI.h"
22
23 #include "Mayaqua/Cfg.h"
24 #include "Mayaqua/Encrypt.h"
25 #include "Mayaqua/FileIO.h"
26 #include "Mayaqua/HTTP.h"
27 #include "Mayaqua/Mayaqua.h"
28 #include "Mayaqua/Memory.h"
29 #include "Mayaqua/Microsoft.h"
30 #include "Mayaqua/Object.h"
31 #include "Mayaqua/Str.h"
32 #include "Mayaqua/Table.h"
33 #include "Mayaqua/Tick64.h"
34 #include "Mayaqua/Win32.h"
35
36 #include <sodium.h>
37
38 static UINT init_cedar_counter = 0;
39 static REF *cedar_log_ref = NULL;
40 static LOG *cedar_log;
41
42 // Check whether there is any EAP-enabled RADIUS configuration
CedarIsThereAnyEapEnabledRadiusConfig(CEDAR * c)43 bool CedarIsThereAnyEapEnabledRadiusConfig(CEDAR *c)
44 {
45 bool ret = false;
46 UINT i;
47 if (c == NULL)
48 {
49 return false;
50 }
51
52 LockHubList(c);
53 {
54 for (i = 0;i < LIST_NUM(c->HubList);i++)
55 {
56 HUB *hub = LIST_DATA(c->HubList, i);
57
58 if (hub->RadiusConvertAllMsChapv2AuthRequestToEap)
59 {
60 ret = true;
61 break;
62 }
63 }
64 }
65 UnlockHubList(c);
66
67 return ret;
68 }
69
70 // Get build date of current code
GetCurrentBuildDate()71 UINT64 GetCurrentBuildDate()
72 {
73 SYSTEMTIME st;
74
75 Zero(&st, sizeof(st));
76
77 st.wYear = BUILD_DATE_Y;
78 st.wMonth = BUILD_DATE_M;
79 st.wDay = BUILD_DATE_D;
80 st.wHour = BUILD_DATE_HO;
81 st.wMinute = BUILD_DATE_MI;
82 st.wSecond = BUILD_DATE_SE;
83
84 return SystemToUINT64(&st);
85 }
86
87 // Check current windows version is supported
IsSupportedWinVer(RPC_WINVER * v)88 bool IsSupportedWinVer(RPC_WINVER *v)
89 {
90 // Validate arguments
91 if (v == NULL)
92 {
93 return false;
94 }
95
96 if (v->IsWindows == false)
97 {
98 return true;
99 }
100
101 if (v->IsNT == false)
102 {
103 return true;
104 }
105
106 if (v->IsBeta)
107 {
108 return true;
109 }
110
111 if (v->VerMajor <= 4)
112 {
113 // Windows NT
114 return true;
115 }
116
117 if (v->VerMajor == 5 && v->VerMinor == 0)
118 {
119 // Windows 2000
120 if (v->ServicePack <= 4)
121 {
122 // SP4 or earlier
123 return true;
124 }
125 }
126
127 if (v->VerMajor == 5 && v->VerMinor == 1)
128 {
129 // Windows XP x86
130 if (v->ServicePack <= 3)
131 {
132 // SP3 or earlier
133 return true;
134 }
135 }
136
137 if (v->VerMajor == 5 && v->VerMinor == 2)
138 {
139 // Windows XP x64, Windows Server 2003
140 if (v->ServicePack <= 2)
141 {
142 // SP2 or earlier
143 return true;
144 }
145 }
146
147 if (v->VerMajor == 6 && v->VerMinor == 0)
148 {
149 // Windows Vista, Server 2008
150 if (v->ServicePack <= 2)
151 {
152 // SP2 or earlier
153 return true;
154 }
155 }
156
157 if (v->VerMajor == 6 && v->VerMinor == 1)
158 {
159 // Windows 7, Server 2008 R2
160 if (v->ServicePack <= 1)
161 {
162 // SP1 or earlier
163 return true;
164 }
165 }
166
167 if (v->VerMajor == 6 && v->VerMinor == 2)
168 {
169 // Windows 8, Server 2012
170 if (v->ServicePack <= 0)
171 {
172 // SP0 only
173 return true;
174 }
175 }
176
177 if (v->VerMajor == 6 && v->VerMinor == 3)
178 {
179 // Windows 8.1, Server 2012 R2
180 if (v->ServicePack <= 0)
181 {
182 // SP0 only
183 return true;
184 }
185 }
186
187 if ((v->VerMajor == 6 && v->VerMinor == 4) || (v->VerMajor == 10 && v->VerMinor == 0))
188 {
189 // Windows 10 or Windows Server 2016
190 if (v->ServicePack <= 0)
191 {
192 // SP0 only
193 return true;
194 }
195 }
196
197 return false;
198 }
199
200 // Get version of Windows
GetWinVer(RPC_WINVER * v)201 void GetWinVer(RPC_WINVER *v)
202 {
203 // Validate arguments
204 if (v == NULL)
205 {
206 return;
207 }
208
209 #ifdef OS_WIN32
210 Win32GetWinVer(v);
211 #else // OS_WIN32
212 Zero(v, sizeof(RPC_WINVER));
213 StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
214 #endif // OS_WIN32
215 }
216
217 // Close tiny log
FreeTinyLog(TINY_LOG * t)218 void FreeTinyLog(TINY_LOG *t)
219 {
220 // Validate arguments
221 if (t == NULL)
222 {
223 return;
224 }
225
226 FileClose(t->io);
227 DeleteLock(t->Lock);
228 Free(t);
229 }
230
231 // Write to tiny log
WriteTinyLog(TINY_LOG * t,char * str)232 void WriteTinyLog(TINY_LOG *t, char *str)
233 {
234 BUF *b;
235 char dt[MAX_PATH];
236 // Validate arguments
237 if (t == NULL)
238 {
239 return;
240 }
241
242 GetDateTimeStrMilli64(dt, sizeof(dt), LocalTime64());
243 StrCat(dt, sizeof(dt), ": ");
244
245 b = NewBuf();
246
247 WriteBuf(b, dt, StrLen(dt));
248 WriteBuf(b, str, StrLen(str));
249 WriteBuf(b, "\r\n", 2);
250
251 Lock(t->Lock);
252 {
253 FileWrite(t->io, b->Buf, b->Size);
254 //FileFlush(t->io);
255 }
256 Unlock(t->Lock);
257
258 FreeBuf(b);
259 }
260
261 // Initialize tiny log
NewTinyLog()262 TINY_LOG *NewTinyLog()
263 {
264 char name[MAX_PATH];
265 SYSTEMTIME st;
266 TINY_LOG *t;
267
268 LocalTime(&st);
269
270 MakeDir(TINY_LOG_DIRNAME);
271
272 Format(name, sizeof(name), TINY_LOG_FILENAME,
273 st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
274
275 t = ZeroMalloc(sizeof(TINY_LOG));
276
277 StrCpy(t->FileName, sizeof(t->FileName), name);
278 t->io = FileCreate(name);
279 t->Lock = NewLock();
280
281 return t;
282 }
283
284 // Compare entries of No-SSL connection list
CompareNoSslList(void * p1,void * p2)285 int CompareNoSslList(void *p1, void *p2)
286 {
287 NON_SSL *n1, *n2;
288 if (p1 == NULL || p2 == NULL)
289 {
290 return 0;
291 }
292 n1 = *(NON_SSL **)p1;
293 n2 = *(NON_SSL **)p2;
294 if (n1 == NULL || n2 == NULL)
295 {
296 return 0;
297 }
298 return CmpIpAddr(&n1->IpAddress, &n2->IpAddress);
299 }
300
301 // Decrement connection count of Non-SSL connection list entry
DecrementNoSsl(CEDAR * c,IP * ip,UINT num_dec)302 void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec)
303 {
304 // Validate arguments
305 if (c == NULL || ip == NULL)
306 {
307 return;
308 }
309
310 LockList(c->NonSslList);
311 {
312 NON_SSL *n = SearchNoSslList(c, ip);
313
314 if (n != NULL)
315 {
316 if (n->Count >= num_dec)
317 {
318 n->Count -= num_dec;
319 }
320 }
321 }
322 UnlockList(c->NonSslList);
323 }
324
325 // Add new entry to Non-SSL connection list
AddNoSsl(CEDAR * c,IP * ip)326 bool AddNoSsl(CEDAR *c, IP *ip)
327 {
328 NON_SSL *n;
329 bool ret = true;
330 // Validate arguments
331 if (c == NULL || ip == NULL)
332 {
333 return true;
334 }
335
336 LockList(c->NonSslList);
337 {
338 DeleteOldNoSsl(c);
339
340 n = SearchNoSslList(c, ip);
341
342 if (n == NULL)
343 {
344 n = ZeroMalloc(sizeof(NON_SSL));
345 Copy(&n->IpAddress, ip, sizeof(IP));
346 n->Count = 0;
347
348 Add(c->NonSslList, n);
349 }
350
351 n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
352
353 n->Count++;
354
355 if (n->Count > NON_SSL_MIN_COUNT)
356 {
357 ret = false;
358 }
359 }
360 UnlockList(c->NonSslList);
361
362 return ret;
363 }
364
365 // Delete old entries in Non-SSL connection list
DeleteOldNoSsl(CEDAR * c)366 void DeleteOldNoSsl(CEDAR *c)
367 {
368 UINT i;
369 LIST *o;
370 // Validate arguments
371 if (c == NULL)
372 {
373 return;
374 }
375
376 o = NewListFast(NULL);
377
378 for (i = 0;i < LIST_NUM(c->NonSslList);i++)
379 {
380 NON_SSL *n = LIST_DATA(c->NonSslList, i);
381
382 if (n->EntryExpires <= Tick64())
383 {
384 Add(o, n);
385 }
386 }
387
388 for (i = 0;i < LIST_NUM(o);i++)
389 {
390 NON_SSL *n = LIST_DATA(o, i);
391
392 Delete(c->NonSslList, n);
393 Free(n);
394 }
395
396 ReleaseList(o);
397 }
398
399 // Search entry in Non-SSL connection list
SearchNoSslList(CEDAR * c,IP * ip)400 NON_SSL *SearchNoSslList(CEDAR *c, IP *ip)
401 {
402 NON_SSL *n, t;
403 // Validate arguments
404 if (c == NULL || ip == NULL)
405 {
406 return NULL;
407 }
408
409 Zero(&t, sizeof(t));
410 Copy(&t.IpAddress, ip, sizeof(IP));
411
412 n = Search(c->NonSslList, &t);
413
414 if (n == NULL)
415 {
416 return NULL;
417 }
418
419 return n;
420 }
421
422 // Initialize Non-SSL connection list
InitNoSslList(CEDAR * c)423 void InitNoSslList(CEDAR *c)
424 {
425 // Validate arguments
426 if (c == NULL)
427 {
428 return;
429 }
430
431 c->NonSslList = NewList(CompareNoSslList);
432 }
433
434 // Free Non-SSL connection list
FreeNoSslList(CEDAR * c)435 void FreeNoSslList(CEDAR *c)
436 {
437 UINT i;
438 // Validate arguments
439 if (c == NULL)
440 {
441 return;
442 }
443
444 for (i = 0;i < LIST_NUM(c->NonSslList);i++)
445 {
446 NON_SSL *n = LIST_DATA(c->NonSslList, i);
447
448 Free(n);
449 }
450
451 ReleaseList(c->NonSslList);
452 c->NonSslList = NULL;
453 }
454
455 // Start Cedar log
StartCedarLog()456 void StartCedarLog()
457 {
458 if (cedar_log_ref == NULL)
459 {
460 cedar_log_ref = NewRef();
461 }
462 else
463 {
464 AddRef(cedar_log_ref);
465 }
466
467 cedar_log = NewLog("debug_log", "debug", LOG_SWITCH_DAY);
468 }
469
470 // Stop Cedar log
StopCedarLog()471 void StopCedarLog()
472 {
473 if (cedar_log_ref == NULL)
474 {
475 return;
476 }
477
478 if (Release(cedar_log_ref) == 0)
479 {
480 FreeLog(cedar_log);
481 cedar_log = NULL;
482 cedar_log_ref = NULL;
483 }
484 }
485
486
487 // Get sum of traffic data size
GetTrafficPacketSize(TRAFFIC * t)488 UINT64 GetTrafficPacketSize(TRAFFIC *t)
489 {
490 // Validate arguments
491 if (t == NULL)
492 {
493 return 0;
494 }
495
496 return t->Recv.BroadcastBytes + t->Recv.UnicastBytes +
497 t->Send.BroadcastBytes + t->Send.UnicastBytes;
498 }
499
500 // Get sum of the number of packets in traffic
GetTrafficPacketNum(TRAFFIC * t)501 UINT64 GetTrafficPacketNum(TRAFFIC *t)
502 {
503 // Validate arguments
504 if (t == NULL)
505 {
506 return 0;
507 }
508
509 return t->Recv.BroadcastCount + t->Recv.UnicastCount +
510 t->Send.BroadcastCount + t->Send.UnicastCount;
511 }
512
513 // Check whether the certificate is signed by CA which is trusted by the hub
CheckSignatureByCaLinkMode(SESSION * s,X * x)514 bool CheckSignatureByCaLinkMode(SESSION *s, X *x)
515 {
516 LINK *k;
517 HUB *h;
518 bool ret = false;
519 // Validate arguments
520 if (s == NULL || x == NULL)
521 {
522 return false;
523 }
524
525 if (s->LinkModeClient == false || (k = s->Link) == NULL)
526 {
527 return false;
528 }
529
530 h = k->Hub;
531
532 if (h->HubDb != NULL)
533 {
534 LockList(h->HubDb->RootCertList);
535 {
536 X *root_cert;
537 root_cert = GetIssuerFromList(h->HubDb->RootCertList, x);
538 if (root_cert != NULL)
539 {
540 ret = true;
541 }
542 }
543 UnlockList(h->HubDb->RootCertList);
544 }
545
546 return ret;
547 }
548
549 // Check whether the certificate is signed by CA which is trusted by Cedar
CheckSignatureByCa(CEDAR * cedar,X * x)550 bool CheckSignatureByCa(CEDAR *cedar, X *x)
551 {
552 X *ca;
553 // Validate arguments
554 if (cedar == NULL || x == NULL)
555 {
556 return false;
557 }
558
559 // Get the CA which signed the certificate
560 ca = FindCaSignedX(cedar->CaList, x);
561 if (ca == NULL)
562 {
563 // Not found
564 return false;
565 }
566
567 // Found
568 FreeX(ca);
569 return true;
570 }
571
572 // Get the CA which signed the certificate
FindCaSignedX(LIST * o,X * x)573 X *FindCaSignedX(LIST *o, X *x)
574 {
575 X *ret;
576 // Validate arguments
577 if (o == NULL || x == NULL)
578 {
579 return NULL;
580 }
581
582 ret = NULL;
583
584 LockList(o);
585 {
586 UINT i;
587 for (i = 0;i < LIST_NUM(o);i++)
588 {
589 X *ca = LIST_DATA(o, i);
590 if (CheckXDateNow(ca))
591 {
592 if (CompareName(ca->subject_name, x->issuer_name))
593 {
594 K *k = GetKFromX(ca);
595 if (k != NULL)
596 {
597 if (CheckSignature(x, k))
598 {
599 ret = CloneX(ca);
600 }
601 FreeK(k);
602 }
603 }
604 else if (CompareX(ca, x))
605 {
606 ret = CloneX(ca);
607 }
608 }
609
610 if (ret != NULL)
611 {
612 break;
613 }
614 }
615 }
616 UnlockList(o);
617
618 return ret;
619 }
620
621 // Delete trusted CA from Cedar
DeleteCa(CEDAR * cedar,UINT ptr)622 bool DeleteCa(CEDAR *cedar, UINT ptr)
623 {
624 bool b = false;
625 // Validate arguments
626 if (cedar == NULL || ptr == 0)
627 {
628 return false;
629 }
630
631 LockList(cedar->CaList);
632 {
633 UINT i;
634
635 for (i = 0;i < LIST_NUM(cedar->CaList);i++)
636 {
637 X *x = LIST_DATA(cedar->CaList, i);
638
639 if (POINTER_TO_KEY(x) == ptr)
640 {
641 Delete(cedar->CaList, x);
642 FreeX(x);
643
644 b = true;
645
646 break;
647 }
648 }
649 }
650 UnlockList(cedar->CaList);
651
652 return b;
653 }
654
655 // Add trusted CA to Cedar
AddCa(CEDAR * cedar,X * x)656 void AddCa(CEDAR *cedar, X *x)
657 {
658 // Validate arguments
659 if (cedar == NULL || x == NULL)
660 {
661 return;
662 }
663
664 LockList(cedar->CaList);
665 {
666 UINT i;
667 bool ok = true;
668
669 for (i = 0;i < LIST_NUM(cedar->CaList);i++)
670 {
671 X *exist_x = LIST_DATA(cedar->CaList, i);
672 if (CompareX(exist_x, x))
673 {
674 ok = false;
675 break;
676 }
677 }
678
679 if (ok)
680 {
681 Insert(cedar->CaList, CloneX(x));
682 }
683 }
684 UnlockList(cedar->CaList);
685 }
686
687 // Delete connection from Cedar
DelConnection(CEDAR * cedar,CONNECTION * c)688 void DelConnection(CEDAR *cedar, CONNECTION *c)
689 {
690 // Validate arguments
691 if (cedar == NULL || c == NULL)
692 {
693 return;
694 }
695
696 LockList(cedar->ConnectionList);
697 {
698 Debug("Connection %s Deleted from Cedar.\n", c->Name);
699 if (Delete(cedar->ConnectionList, c))
700 {
701 ReleaseConnection(c);
702 }
703 }
704 UnlockList(cedar->ConnectionList);
705 }
706
707 // Add connection to Cedar
AddConnection(CEDAR * cedar,CONNECTION * c)708 void AddConnection(CEDAR *cedar, CONNECTION *c)
709 {
710 char tmp[MAX_SIZE];
711 UINT i;
712 // Validate arguments
713 if (cedar == NULL || c == NULL)
714 {
715 return;
716 }
717
718 // Determine the name of the connection
719 i = Inc(cedar->ConnectionIncrement);
720 Format(tmp, sizeof(tmp), "CID-%u", i);
721
722
723 Lock(c->lock);
724 {
725 Free(c->Name);
726 c->Name = CopyStr(tmp);
727 }
728 Unlock(c->lock);
729
730 LockList(cedar->ConnectionList);
731 {
732 Add(cedar->ConnectionList, c);
733 AddRef(c->ref);
734 Debug("Connection %s Inserted to Cedar.\n", c->Name);
735 }
736 UnlockList(cedar->ConnectionList);
737 }
738
739 // Stop all connections
StopAllConnection(CEDAR * c)740 void StopAllConnection(CEDAR *c)
741 {
742 UINT num;
743 UINT i;
744 CONNECTION **connections;
745 // Validate arguments
746 if (c == NULL)
747 {
748 return;
749 }
750
751 LockList(c->ConnectionList);
752 {
753 connections = ToArray(c->ConnectionList);
754 num = LIST_NUM(c->ConnectionList);
755 DeleteAll(c->ConnectionList);
756 }
757 UnlockList(c->ConnectionList);
758
759 for (i = 0;i < num;i++)
760 {
761 StopConnection(connections[i], false);
762 ReleaseConnection(connections[i]);
763 }
764 Free(connections);
765 }
766
767 // Delete a hub in Cedar
DelHub(CEDAR * c,HUB * h)768 void DelHub(CEDAR *c, HUB *h)
769 {
770 DelHubEx(c, h, false);
771 }
DelHubEx(CEDAR * c,HUB * h,bool no_lock)772 void DelHubEx(CEDAR *c, HUB *h, bool no_lock)
773 {
774 // Validate arguments
775 if (c == NULL || h == NULL)
776 {
777 return;
778 }
779
780 if (no_lock == false)
781 {
782 LockHubList(c);
783 }
784
785 if (Delete(c->HubList, h))
786 {
787 ReleaseHub(h);
788 }
789
790 if (no_lock == false)
791 {
792 UnlockHubList(c);
793 }
794 }
795
796 // Add a new hub to Cedar
AddHub(CEDAR * c,HUB * h)797 void AddHub(CEDAR *c, HUB *h)
798 {
799 // Validate arguments
800 if (c == NULL || h == NULL)
801 {
802 return;
803 }
804
805 LockHubList(c);
806 {
807 #if 0
808 // We shall not check here the number of hub
809 if (LIST_NUM(c->HubList) >= MAX_HUBS)
810 {
811 // over limit
812 UnlockHubList(c);
813 return;
814 }
815 #endif
816
817 // Confirm there is no hub which have same name
818 if (IsHub(c, h->Name))
819 {
820 // exist
821 UnlockHubList(c);
822 return;
823 }
824
825 // Register the hub
826 Insert(c->HubList, h);
827 AddRef(h->ref);
828 }
829 UnlockHubList(c);
830 }
831
832 // Stop all hubs in Cedar
StopAllHub(CEDAR * c)833 void StopAllHub(CEDAR *c)
834 {
835 HUB **hubs;
836 UINT i, num;
837 // Validate arguments
838 if (c == NULL)
839 {
840 return;
841 }
842
843 LockHubList(c);
844 {
845 hubs = ToArray(c->HubList);
846 num = LIST_NUM(c->HubList);
847 DeleteAll(c->HubList);
848 }
849 UnlockHubList(c);
850
851 for (i = 0;i < num;i++)
852 {
853 StopHub(hubs[i]);
854 ReleaseHub(hubs[i]);
855 }
856
857 Free(hubs);
858 }
859
860 // Get reverse listener socket in Cedar
GetReverseListeningSock(CEDAR * c)861 SOCK *GetReverseListeningSock(CEDAR *c)
862 {
863 SOCK *s = NULL;
864 // Validate arguments
865 if (c == NULL)
866 {
867 return NULL;
868 }
869
870 LockList(c->ListenerList);
871 {
872 UINT i;
873 for (i = 0;i < LIST_NUM(c->ListenerList);i++)
874 {
875 LISTENER *r = LIST_DATA(c->ListenerList, i);
876
877 if (r->Protocol == LISTENER_REVERSE)
878 {
879 Lock(r->lock);
880 {
881 s = r->Sock;
882
883 AddRef(s->ref);
884 }
885 Unlock(r->lock);
886 break;
887 }
888 }
889 }
890 UnlockList(c->ListenerList);
891
892 return s;
893 }
894
895 // Get in-process listener socket in Cedar
GetInProcListeningSock(CEDAR * c)896 SOCK *GetInProcListeningSock(CEDAR *c)
897 {
898 SOCK *s = NULL;
899 // Validate arguments
900 if (c == NULL)
901 {
902 return NULL;
903 }
904
905 LockList(c->ListenerList);
906 {
907 UINT i;
908 for (i = 0;i < LIST_NUM(c->ListenerList);i++)
909 {
910 LISTENER *r = LIST_DATA(c->ListenerList, i);
911
912 if (r->Protocol == LISTENER_INPROC)
913 {
914 Lock(r->lock);
915 {
916 s = r->Sock;
917
918 if (s != NULL)
919 {
920 AddRef(s->ref);
921 }
922 }
923 Unlock(r->lock);
924 break;
925 }
926 }
927 }
928 UnlockList(c->ListenerList);
929
930 return s;
931 }
932
933 // Add a new listener to Cedar
AddListener(CEDAR * c,LISTENER * r)934 void AddListener(CEDAR *c, LISTENER *r)
935 {
936 // Validate arguments
937 if (c == NULL || r == NULL)
938 {
939 return;
940 }
941
942 LockList(c->ListenerList);
943 {
944 Add(c->ListenerList, r);
945 AddRef(r->ref);
946 }
947 UnlockList(c->ListenerList);
948 }
949
950 // Stop all listener in Cedar
StopAllListener(CEDAR * c)951 void StopAllListener(CEDAR *c)
952 {
953 LISTENER **array;
954 UINT i, num;
955 // Validate arguments
956 if (c == NULL)
957 {
958 return;
959 }
960
961 LockList(c->ListenerList);
962 {
963 array = ToArray(c->ListenerList);
964 num = LIST_NUM(c->ListenerList);
965 DeleteAll(c->ListenerList);
966 }
967 UnlockList(c->ListenerList);
968
969 for (i = 0;i < num;i++)
970 {
971 StopListener(array[i]);
972 ReleaseListener(array[i]);
973 }
974 Free(array);
975 }
976
977 // Budget management functions
CedarAddQueueBudget(CEDAR * c,int diff)978 void CedarAddQueueBudget(CEDAR *c, int diff)
979 {
980 // Validate arguments
981 if (c == NULL || diff == 0)
982 {
983 return;
984 }
985
986 Lock(c->QueueBudgetLock);
987 {
988 int v = (int)c->QueueBudget;
989 v += diff;
990 c->QueueBudget = (UINT)v;
991 }
992 Unlock(c->QueueBudgetLock);
993 }
CedarAddFifoBudget(CEDAR * c,int diff)994 void CedarAddFifoBudget(CEDAR *c, int diff)
995 {
996 // Validate arguments
997 if (c == NULL || diff == 0)
998 {
999 return;
1000 }
1001
1002 Lock(c->FifoBudgetLock);
1003 {
1004 int v = (int)c->FifoBudget;
1005 v += diff;
1006 c->FifoBudget = (UINT)v;
1007 }
1008 Unlock(c->FifoBudgetLock);
1009 }
CedarGetQueueBudgetConsuming(CEDAR * c)1010 UINT CedarGetQueueBudgetConsuming(CEDAR *c)
1011 {
1012 // Validate arguments
1013 if (c == NULL)
1014 {
1015 return 0;
1016 }
1017
1018 return c->QueueBudget;
1019 }
CedarGetFifoBudgetConsuming(CEDAR * c)1020 UINT CedarGetFifoBudgetConsuming(CEDAR *c)
1021 {
1022 // Validate arguments
1023 if (c == NULL)
1024 {
1025 return 0;
1026 }
1027
1028 return c->FifoBudget;
1029 }
CedarGetQueueBudgetBalance(CEDAR * c)1030 UINT CedarGetQueueBudgetBalance(CEDAR *c)
1031 {
1032 UINT current = CedarGetQueueBudgetConsuming(c);
1033 UINT budget = QUEUE_BUDGET;
1034
1035 if (current <= budget)
1036 {
1037 return budget - current;
1038 }
1039 else
1040 {
1041 return 0;
1042 }
1043 }
CedarGetFifoBudgetBalance(CEDAR * c)1044 UINT CedarGetFifoBudgetBalance(CEDAR *c)
1045 {
1046 UINT current = CedarGetFifoBudgetConsuming(c);
1047 UINT budget = FIFO_BUDGET;
1048
1049 if (current <= budget)
1050 {
1051 return budget - current;
1052 }
1053 else
1054 {
1055 return 0;
1056 }
1057 }
1058
1059 // Add the current TCP queue size
CedarAddCurrentTcpQueueSize(CEDAR * c,int diff)1060 void CedarAddCurrentTcpQueueSize(CEDAR *c, int diff)
1061 {
1062 // Validate arguments
1063 if (c == NULL || diff == 0)
1064 {
1065 return;
1066 }
1067
1068 Lock(c->CurrentTcpQueueSizeLock);
1069 {
1070 int v = (int)c->CurrentTcpQueueSize;
1071 v += diff;
1072 c->CurrentTcpQueueSize = (UINT)v;
1073 }
1074 Unlock(c->CurrentTcpQueueSizeLock);
1075 }
1076
1077 // Get the current TCP queue size
CedarGetCurrentTcpQueueSize(CEDAR * c)1078 UINT CedarGetCurrentTcpQueueSize(CEDAR *c)
1079 {
1080 // Validate arguments
1081 if (c == NULL)
1082 {
1083 return 0;
1084 }
1085
1086 return c->CurrentTcpQueueSize;
1087 }
1088
1089 // Stop Cedar
StopCedar(CEDAR * c)1090 void StopCedar(CEDAR *c)
1091 {
1092 // Validate arguments
1093 if (c == NULL)
1094 {
1095 return;
1096 }
1097
1098 // Stop flag
1099 c->Halt = true;
1100
1101 // Stop all listener
1102 StopAllListener(c);
1103 // Stop all connections
1104 StopAllConnection(c);
1105 // Stop all hubs
1106 StopAllHub(c);
1107 // Free all virtual L3 switch
1108 L3FreeAllSw(c);
1109 }
1110
1111 // Clean up Cedar
CleanupCedar(CEDAR * c)1112 void CleanupCedar(CEDAR *c)
1113 {
1114 UINT i;
1115 // Validate arguments
1116 if (c == NULL)
1117 {
1118 return;
1119 }
1120
1121 WuFreeWebUI(c->WebUI);
1122 FreeCedarLayer3(c);
1123
1124 for (i = 0; i < LIST_NUM(c->WgkList); ++i)
1125 {
1126 WGK *wgk = LIST_DATA(c->WgkList, i);
1127 Free(wgk);
1128 }
1129 ReleaseList(c->WgkList);
1130
1131 for (i = 0;i < LIST_NUM(c->CaList);i++)
1132 {
1133 X *x = LIST_DATA(c->CaList, i);
1134 FreeX(x);
1135 }
1136 ReleaseList(c->CaList);
1137
1138 ReleaseList(c->ListenerList);
1139 ReleaseList(c->HubList);
1140 ReleaseList(c->ConnectionList);
1141 //CleanupUDPEntry(c);
1142 ReleaseList(c->UDPEntryList);
1143 DeleteLock(c->lock);
1144 DeleteCounter(c->ConnectionIncrement);
1145 DeleteCounter(c->CurrentSessions);
1146
1147 if (c->DebugLog != NULL)
1148 {
1149 FreeLog(c->DebugLog);
1150 }
1151
1152 if (c->ServerX)
1153 {
1154 FreeX(c->ServerX);
1155 }
1156 if (c->ServerK)
1157 {
1158 FreeK(c->ServerK);
1159 }
1160
1161 if (c->CipherList)
1162 {
1163 Free(c->CipherList);
1164 }
1165
1166 for (i = 0;i < LIST_NUM(c->TrafficDiffList);i++)
1167 {
1168 TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
1169 Free(d->Name);
1170 Free(d->HubName);
1171 Free(d);
1172 }
1173
1174 ReleaseList(c->TrafficDiffList);
1175
1176 Free(c->ServerStr);
1177 Free(c->MachineName);
1178
1179 Free(c->HttpUserAgent);
1180 Free(c->HttpAccept);
1181 Free(c->HttpAcceptLanguage);
1182 Free(c->HttpAcceptEncoding);
1183
1184 FreeTraffic(c->Traffic);
1185
1186 DeleteLock(c->TrafficLock);
1187
1188 FreeNetSvcList(c);
1189
1190 Free(c->VerString);
1191 Free(c->BuildInfo);
1192
1193 FreeLocalBridgeList(c);
1194
1195 DeleteCounter(c->AssignedBridgeLicense);
1196 DeleteCounter(c->AssignedClientLicense);
1197
1198 FreeNoSslList(c);
1199
1200 DeleteLock(c->CedarSuperLock);
1201
1202 DeleteCounter(c->AcceptingSockets);
1203
1204 ReleaseIntList(c->UdpPortList);
1205
1206 DeleteLock(c->OpenVPNPublicPortsLock);
1207
1208 DeleteLock(c->CurrentRegionLock);
1209
1210 DeleteLock(c->CurrentTcpQueueSizeLock);
1211 DeleteLock(c->QueueBudgetLock);
1212 DeleteLock(c->FifoBudgetLock);
1213
1214 DeleteCounter(c->CurrentActiveLinks);
1215
1216 Free(c);
1217 }
1218
1219 // Release reference of the Cedar
ReleaseCedar(CEDAR * c)1220 void ReleaseCedar(CEDAR *c)
1221 {
1222 // Validate arguments
1223 if (c == NULL)
1224 {
1225 return;
1226 }
1227
1228 if (Release(c->ref) == 0)
1229 {
1230 CleanupCedar(c);
1231 }
1232 }
1233
1234 // Set cipher list entry
SetCedarCipherList(CEDAR * cedar,char * name)1235 void SetCedarCipherList(CEDAR *cedar, char *name)
1236 {
1237 // Validate arguments
1238 if (cedar == NULL)
1239 {
1240 return;
1241 }
1242
1243 if (cedar->CipherList != NULL)
1244 {
1245 Free(cedar->CipherList);
1246 }
1247 if (name != NULL)
1248 {
1249 cedar->CipherList = CopyStr(name);
1250 }
1251 else
1252 {
1253 cedar->CipherList = NULL;
1254 }
1255 }
1256
1257 // Compare net service list entries
CompareNetSvc(void * p1,void * p2)1258 int CompareNetSvc(void *p1, void *p2)
1259 {
1260 NETSVC *n1, *n2;
1261 if (p1 == NULL || p2 == NULL)
1262 {
1263 return 0;
1264 }
1265 n1 = *(NETSVC **)p1;
1266 n2 = *(NETSVC **)p2;
1267 if (n1 == NULL || n2 == NULL)
1268 {
1269 return 0;
1270 }
1271 if (n1->Port > n2->Port)
1272 {
1273 return 1;
1274 }
1275 else if (n1->Port < n2->Port)
1276 {
1277 return -1;
1278 }
1279 else if (n1->Udp > n2->Udp)
1280 {
1281 return 1;
1282 }
1283 else if (n1->Udp < n2->Udp)
1284 {
1285 return -1;
1286 }
1287 return 0;
1288 }
1289
1290 // Initialize net service list
InitNetSvcList(CEDAR * cedar)1291 void InitNetSvcList(CEDAR *cedar)
1292 {
1293 char filename[MAX_PATH] = "/etc/services";
1294 BUF *b;
1295 // Validate arguments
1296 if (cedar == NULL)
1297 {
1298 return;
1299 }
1300
1301 #ifdef OS_WIN32
1302 Format(filename, sizeof(filename), "%s\\drivers\\etc\\services", MsGetSystem32Dir());
1303 #endif
1304
1305 cedar->NetSvcList = NewList(CompareNetSvc);
1306
1307 b = ReadDump(filename);
1308 if (b == NULL)
1309 {
1310 return;
1311 }
1312
1313 while (true)
1314 {
1315 char *s = CfgReadNextLine(b);
1316 if (s == NULL)
1317 {
1318 break;
1319 }
1320
1321 Trim(s);
1322 if (s[0] != '#')
1323 {
1324 TOKEN_LIST *t = ParseToken(s, " \t/");
1325 if (t->NumTokens >= 3)
1326 {
1327 NETSVC *n = ZeroMalloc(sizeof(NETSVC));
1328 n->Name = CopyStr(t->Token[0]);
1329 n->Udp = (StrCmpi(t->Token[2], "udp") == 0 ? true : false);
1330 n->Port = ToInt(t->Token[1]);
1331 Add(cedar->NetSvcList, n);
1332 }
1333 FreeToken(t);
1334 }
1335 Free(s);
1336 }
1337
1338 FreeBuf(b);
1339 }
1340
1341 // Get net service name
GetSvcName(CEDAR * cedar,bool udp,UINT port)1342 char *GetSvcName(CEDAR *cedar, bool udp, UINT port)
1343 {
1344 char *ret = NULL;
1345 NETSVC t;
1346 // Validate arguments
1347 if (cedar == NULL)
1348 {
1349 return NULL;
1350 }
1351
1352 t.Udp = (udp == 0 ? false : true);
1353 t.Port = port;
1354
1355 LockList(cedar->NetSvcList);
1356 {
1357 NETSVC *n = Search(cedar->NetSvcList, &t);
1358 if (n != NULL)
1359 {
1360 ret = n->Name;
1361 }
1362 }
1363 UnlockList(cedar->NetSvcList);
1364
1365 return ret;
1366 }
1367
1368 // Free net service list
FreeNetSvcList(CEDAR * cedar)1369 void FreeNetSvcList(CEDAR *cedar)
1370 {
1371 UINT i;
1372 // Validate arguments
1373 if (cedar == NULL)
1374 {
1375 return;
1376 }
1377
1378 for (i = 0;i < LIST_NUM(cedar->NetSvcList);i++)
1379 {
1380 NETSVC *n = LIST_DATA(cedar->NetSvcList, i);
1381 Free(n->Name);
1382 Free(n);
1383 }
1384 ReleaseList(cedar->NetSvcList);
1385 }
1386
1387 // Change certificate of Cedar
SetCedarCert(CEDAR * c,X * server_x,K * server_k)1388 void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
1389 {
1390 // Validate arguments
1391 if (server_x == NULL || server_k == NULL)
1392 {
1393 return;
1394 }
1395
1396 Lock(c->lock);
1397 {
1398 if (c->ServerX != NULL)
1399 {
1400 FreeX(c->ServerX);
1401 }
1402
1403 if (c->ServerK != NULL)
1404 {
1405 FreeK(c->ServerK);
1406 }
1407
1408 c->ServerX = CloneX(server_x);
1409 c->ServerK = CloneK(server_k);
1410 }
1411 Unlock(c->lock);
1412 }
1413
1414 // Set the Cedar into VPN Bridge mode
SetCedarVpnBridge(CEDAR * c)1415 void SetCedarVpnBridge(CEDAR *c)
1416 {
1417 // Validate arguments
1418 if (c == NULL)
1419 {
1420 return;
1421 }
1422
1423 c->Bridge = true;
1424
1425 Free(c->ServerStr);
1426 c->ServerStr = CopyStr(CEDAR_BRIDGE_STR);
1427 }
1428
CedarForceLink()1429 void CedarForceLink()
1430 {
1431 }
1432
1433 // Get version of the Cedar
GetCedarVersion(char * tmp,UINT size)1434 void GetCedarVersion(char *tmp, UINT size)
1435 {
1436 // Validate arguments
1437 if (tmp == NULL)
1438 {
1439 return;
1440 }
1441
1442 Format(tmp, size, "%u.%02u.%u", CEDAR_VERSION_MAJOR, CEDAR_VERSION_MINOR, CEDAR_VERSION_BUILD);
1443 }
1444
GetCedarVersionNumber()1445 UINT GetCedarVersionNumber()
1446 {
1447 return CEDAR_VERSION_MAJOR * 100 + CEDAR_VERSION_MINOR;
1448 }
1449
1450 // Create Cedar object
NewCedar(X * server_x,K * server_k)1451 CEDAR *NewCedar(X *server_x, K *server_k)
1452 {
1453 CEDAR *c;
1454 char tmp[MAX_SIZE];
1455 char tmp2[MAX_SIZE];
1456 char *beta_str;
1457
1458 CedarForceLink();
1459
1460 c = ZeroMalloc(sizeof(CEDAR));
1461
1462 c->CurrentActiveLinks = NewCounter();
1463
1464 c->AcceptingSockets = NewCounter();
1465
1466 c->CedarSuperLock = NewLock();
1467
1468 c->CurrentRegionLock = NewLock();
1469
1470 #ifdef BETA_NUMBER
1471 c->Beta = BETA_NUMBER;
1472 #endif // BETA_NUMBER
1473
1474 InitNoSslList(c);
1475
1476 c->AssignedBridgeLicense = NewCounter();
1477 c->AssignedClientLicense = NewCounter();
1478
1479 c->CurrentTcpQueueSizeLock = NewLock();
1480 c->QueueBudgetLock = NewLock();
1481 c->FifoBudgetLock = NewLock();
1482
1483 Rand(c->UniqueId, sizeof(c->UniqueId));
1484
1485 c->CreatedTick = Tick64();
1486
1487 c->lock = NewLock();
1488 c->ref = NewRef();
1489
1490 c->OpenVPNPublicPortsLock = NewLock();
1491 c->CurrentTcpConnections = GetNumTcpConnectionsCounter();
1492
1493 c->ListenerList = NewList(CompareListener);
1494 c->UDPEntryList = NewList(CompareUDPEntry);
1495 c->HubList = NewList(CompareHub);
1496 c->ConnectionList = NewList(CompareConnection);
1497
1498 c->ConnectionIncrement = NewCounter();
1499 c->CurrentSessions = NewCounter();
1500
1501 if (server_k && server_x)
1502 {
1503 c->ServerK = CloneK(server_k);
1504 c->ServerX = CloneX(server_x);
1505 }
1506
1507 c->Version = GetCedarVersionNumber();
1508 c->Build = CEDAR_VERSION_BUILD;
1509 c->ServerStr = CopyStr(CEDAR_SERVER_STR);
1510
1511 GetMachineName(tmp, sizeof(tmp));
1512 c->MachineName = CopyStr(tmp);
1513
1514 c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT);
1515 c->HttpAccept = CopyStr(DEFAULT_ACCEPT);
1516 c->HttpAcceptLanguage = CopyStr("ja");
1517 c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING);
1518
1519 c->Traffic = NewTraffic();
1520 c->TrafficLock = NewLock();
1521 c->CaList = NewList(CompareCert);
1522 c->WgkList = NewList(CompareWgk);
1523
1524 c->TrafficDiffList = NewList(NULL);
1525
1526 SetCedarCipherList(c, SERVER_DEFAULT_CIPHER_NAME);
1527
1528 c->ClientId = _II("CLIENT_ID");
1529
1530 c->UdpPortList = NewIntList(false);
1531
1532 c->DhParamBits = DH_PARAM_BITS_DEFAULT;
1533
1534 InitNetSvcList(c);
1535
1536 InitLocalBridgeList(c);
1537
1538 InitCedarLayer3(c);
1539
1540 c->WebUI = WuNewWebUI(c);
1541
1542 #ifdef ALPHA_VERSION
1543 beta_str = "Alpha";
1544 #else // ALPHA_VERSION
1545 #ifndef RELEASE_CANDIDATE
1546 beta_str = "Beta";
1547 #else // RELEASE_CANDIDATE
1548 beta_str = "Release Candidate";
1549 #endif // RELEASE_CANDIDATE
1550 #endif // ALPHA_VERSION
1551
1552 ToStr(tmp2, c->Beta);
1553
1554 Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)",
1555 CEDAR_VERSION_MAJOR, CEDAR_VERSION_MINOR, CEDAR_VERSION_BUILD,
1556 c->Beta == 0 ? "" : beta_str,
1557 c->Beta == 0 ? "" : tmp2,
1558 _SS("LANGSTR"));
1559 Trim(tmp);
1560
1561 if (true)
1562 {
1563 SYSTEMTIME st;
1564 Zero(&st, sizeof(st));
1565
1566 st.wYear = BUILD_DATE_Y;
1567 st.wMonth = BUILD_DATE_M;
1568 st.wDay = BUILD_DATE_D;
1569
1570 c->BuiltDate = SystemToUINT64(&st);
1571 }
1572
1573 c->VerString = CopyStr(tmp);
1574
1575 Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s",
1576 BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE);
1577
1578 c->BuildInfo = CopyStr(tmp);
1579
1580 return c;
1581 }
1582
1583 // Cumulate traffic size
AddTraffic(TRAFFIC * dst,TRAFFIC * diff)1584 void AddTraffic(TRAFFIC *dst, TRAFFIC *diff)
1585 {
1586 // Validate arguments
1587 if (dst == NULL || diff == NULL)
1588 {
1589 return;
1590 }
1591
1592 dst->Recv.BroadcastBytes += diff->Recv.BroadcastBytes;
1593 dst->Recv.BroadcastCount += diff->Recv.BroadcastCount;
1594 dst->Recv.UnicastBytes += diff->Recv.UnicastBytes;
1595 dst->Recv.UnicastCount += diff->Recv.UnicastCount;
1596
1597 dst->Send.BroadcastBytes += diff->Send.BroadcastBytes;
1598 dst->Send.BroadcastCount += diff->Send.BroadcastCount;
1599 dst->Send.UnicastBytes += diff->Send.UnicastBytes;
1600 dst->Send.UnicastCount += diff->Send.UnicastCount;
1601 }
1602
1603 // Create new traffic size object
NewTraffic()1604 TRAFFIC *NewTraffic()
1605 {
1606 TRAFFIC *t;
1607
1608 t = ZeroMalloc(sizeof(TRAFFIC));
1609 return t;
1610 }
1611
1612 // Free traffic size object
FreeTraffic(TRAFFIC * t)1613 void FreeTraffic(TRAFFIC *t)
1614 {
1615 // Validate arguments
1616 if (t == NULL)
1617 {
1618 return;
1619 }
1620
1621 Free(t);
1622 }
1623
1624 // Initialize Cedar communication module
InitCedar()1625 void InitCedar()
1626 {
1627 if ((init_cedar_counter++) > 0)
1628 {
1629 return;
1630 }
1631
1632 if (sodium_init() == -1)
1633 {
1634 Debug("InitCedar(): sodium_init() failed!\n");
1635 return;
1636 }
1637
1638 // Initialize protocol module
1639 InitProtocol();
1640 }
1641
1642 // Free Cedar communication module
FreeCedar()1643 void FreeCedar()
1644 {
1645 if ((--init_cedar_counter) > 0)
1646 {
1647 return;
1648 }
1649
1650 // Free protocol module
1651 FreeProtocol();
1652 }
1653
1654