1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Cedar Communication Module
3 // © 2020 Nokia
4
5 // Session.c
6 // Session Manager
7
8 #include "Session.h"
9
10 #include "BridgeUnix.h"
11 #include "BridgeWin32.h"
12 #include "Client.h"
13 #include "Connection.h"
14 #include "Hub.h"
15 #include "Link.h"
16 #include "Nat.h"
17 #include "Protocol.h"
18 #include "SecureNAT.h"
19 #include "Server.h"
20 #include "UdpAccel.h"
21 #include "VLanUnix.h"
22
23 #include "Mayaqua/Internat.h"
24 #include "Mayaqua/Kernel.h"
25 #include "Mayaqua/Mayaqua.h"
26 #include "Mayaqua/Memory.h"
27 #include "Mayaqua/Microsoft.h"
28 #include "Mayaqua/Object.h"
29 #include "Mayaqua/Str.h"
30 #include "Mayaqua/Table.h"
31 #include "Mayaqua/TcpIp.h"
32 #include "Mayaqua/Tick64.h"
33
34 // TODO: Mayaqua should not depend on Cedar.
35 #include "Cedar/WinUi.h"
36
37 // Main routine of the session
SessionMain(SESSION * s)38 void SessionMain(SESSION *s)
39 {
40 CONNECTION *c;
41 POLICY *policy;
42 UINT64 now;
43 UINT i = 0;
44 PACKET_ADAPTER *pa;
45 bool pa_inited = false;
46 UINT packet_size;
47 void *packet;
48 bool packet_put;
49 bool pa_fail = false;
50 UINT test = 0;
51 bool update_hub_last_comm = false;
52 UINT err = ERR_SESSION_TIMEOUT;
53 UINT64 next_black_list_check = 0;
54 UINT64 next_update_hub_last_comm = 0;
55 UINT64 auto_disconnect_tick = 0;
56 bool block_all_packets = false;
57 UINT64 next_check_block_all_packets = 0;
58 TRAFFIC t;
59 SOCK *msgdlg_sock = NULL;
60 SOCK *nicinfo_sock = NULL;
61 bool is_server_session = false;
62 bool lock_receive_blocks_queue = false;
63 UINT static_ip = 0;
64
65 // Validate arguments
66 if (s == NULL)
67 {
68 return;
69 }
70
71 Debug("SessionMain: %s\n", s->Name);
72
73 Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
74
75 // Generate a string from the session key
76 BinToStr(s->SessionKeyStr, sizeof(s->SessionKeyStr), s->SessionKey, sizeof(s->SessionKey));
77
78 // Reset the number of retries
79 s->CurrentRetryCount = 0;
80 s->ConnectSucceed = true;
81 s->SessionTimeOuted = false;
82 s->NumDisconnected = 0;
83
84 c = s->Connection;
85 policy = s->Policy;
86
87 // Initialize the packet adapter
88 #ifdef OS_WIN32
89 if (s->IsVPNClientAndVLAN_Win32)
90 {
91 MsBeginVLanCard();
92
93 if (MsIsVLanCardShouldStop())
94 {
95 err = ERR_SUSPENDING;
96 goto CLEANUP;
97 }
98 }
99 #endif // OS_WIN32
100
101 pa = s->PacketAdapter;
102 if (pa->Init(s) == false)
103 {
104 // Initialization Failed
105 if (s->VLanDeviceErrorCount >= 2)
106 {
107 s->ForceStopFlag = true;
108 }
109 else
110 {
111 s->VLanDeviceErrorCount++;
112 }
113 err = ERR_DEVICE_DRIVER_ERROR;
114 goto CLEANUP;
115 }
116 pa_inited = true;
117
118 if (s->BridgeMode == false)
119 {
120 s->Cancel2 = pa->GetCancel(s);
121 }
122 else
123 {
124 CANCEL *c = pa->GetCancel(s);
125 CANCEL *old = s->Cancel1;
126 s->Cancel1 = c;
127 ReleaseCancel(old);
128 }
129
130 s->RetryFlag = false;
131
132 s->LastCommTime = Tick64();
133 if (s->ServerMode == false)
134 {
135 s->NextConnectionTime = Tick64() + (UINT64)((UINT64)s->ClientOption->AdditionalConnectionInterval * (UINT64)1000);
136 }
137
138 s->NumConnectionsEstablished++;
139 s->CurrentConnectionEstablishTime = Tick64();
140 if (s->FirstConnectionEstablisiedTime == 0) /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
141 {
142 s->FirstConnectionEstablisiedTime = Tick64(); /* !!! Do not correct the spelling to keep the backward protocol compatibility !!! */
143 }
144
145 if (s->ServerMode == false && s->Cedar->Client != NULL)
146 {
147 if (s->Policy != NULL)
148 {
149 if (s->Policy->AutoDisconnect)
150 {
151 auto_disconnect_tick = s->CurrentConnectionEstablishTime +
152 (UINT64)s->Policy->AutoDisconnect * 1000ULL;
153 }
154 }
155 }
156
157 s->LastIncrementTraffic = Tick64();
158
159 c->Err = ERR_SESSION_TIMEOUT;
160 s->VLanDeviceErrorCount = 0;
161
162 s->LastTryAddConnectTime = Tick64();
163
164 Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
165
166 if (policy != NULL)
167 {
168 // Determine the mode by referencing the contents of the policy
169 if (policy->MonitorPort)
170 {
171 s->IsMonitorMode = true;
172 }
173
174 if (policy->NoRouting == false || policy->NoBridge == false)
175 {
176 s->IsBridgeMode = true;
177 }
178 }
179
180 if (s->ServerMode == false && s->Cedar->Client != NULL)
181 {
182 if (IsEmptyUniStr(s->Client_Message) == false)
183 {
184 UI_MSG_DLG dlg;
185
186 Zero(&dlg, sizeof(dlg));
187 if (s->ClientOption != NULL)
188 {
189 StrCpy(dlg.HubName, sizeof(dlg.HubName), s->ClientOption->HubName);
190 StrCpy(dlg.ServerName, sizeof(dlg.ServerName), s->ClientOption->Hostname);
191 }
192
193 dlg.Msg = s->Client_Message;
194
195 msgdlg_sock = CncMsgDlg(&dlg);
196 }
197
198 if (s->Win32HideNicInfoWindow == false)
199 {
200 UI_NICINFO info;
201
202 Zero(&info, sizeof(info));
203 if (s->ClientOption != NULL)
204 {
205 StrCpy(info.NicName, sizeof(info.NicName), s->ClientOption->DeviceName);
206 UniStrCpy(info.AccountName, sizeof(info.AccountName), s->ClientOption->AccountName);
207 }
208
209 nicinfo_sock = CncNicInfo(&info);
210 }
211 }
212
213 is_server_session = s->ServerMode;
214
215 lock_receive_blocks_queue = s->LinkModeServer;
216
217 now = Tick64();
218
219 while (true)
220 {
221 Zero(&t, sizeof(t));
222
223
224 if (next_update_hub_last_comm == 0 ||
225 (next_update_hub_last_comm <= now))
226 {
227 next_update_hub_last_comm = now + 1000;
228
229 if (s->Hub != NULL)
230 {
231 if (update_hub_last_comm)
232 {
233 Lock(s->Hub->lock);
234 {
235 s->Hub->LastCommTime = SystemTime64();
236 }
237 Unlock(s->Hub->lock);
238
239 update_hub_last_comm = false;
240 }
241 }
242 }
243
244
245 if (is_server_session && s->LinkModeServer == false && s->SecureNATMode == false && s->BridgeMode == false && s->L3SwitchMode == false)
246 {
247 if (s->Hub != NULL && s->Hub->ForceDisableComm)
248 {
249 // Disconnect the session forcibly because the ForceDisableComm flag is set
250 err = ERR_SERVER_CANT_ACCEPT;
251 pa_fail = true;
252 }
253 }
254
255 if (s->InProcMode)
256 {
257 if (c->TubeSock == NULL || IsTubeConnected(c->TubeSock->SendTube) == false || IsTubeConnected(c->TubeSock->RecvTube) == false)
258 {
259 // Disconnection occurs in the in-process mode
260 err = ERR_DISCONNECTED;
261 pa_fail = true;
262 }
263 }
264
265 if (s->IsRUDPSession)
266 {
267 if (s->NumDisconnected >= 1 && s->EnableUdpRecovery == false)
268 {
269 // Disconnection occurs in the R-UDP session (UDP recovery is invalid)
270 err = ERR_DISCONNECTED;
271 pa_fail = true;
272 }
273 }
274
275 // Chance of additional connection
276 if (is_server_session == false)
277 {
278 if (GetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT) == false)
279 {
280 ClientAdditionalConnectChance(s);
281 }
282 }
283
284 // Receive a block
285 ConnectionReceive(c, s->Cancel1, s->Cancel2);
286
287 // Get the current time
288 now = Tick64();
289
290 if (s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->FatalError)
291 {
292 // A serious error occurs during sending any data on UDP socket
293 // in the case of using UDP acceleration function
294 err = ERR_DISCONNECTED;
295 pa_fail = true;
296 }
297
298 #ifdef OS_WIN32
299 if (s->IsVPNClientAndVLAN_Win32)
300 {
301 if (MsIsVLanCardShouldStop())
302 {
303 // System is suspending
304 err = ERR_SUSPENDING;
305 pa_fail = true;
306 }
307 }
308 #endif // OS_WIN32
309
310 // Pass the received block to the PacketAdapter
311 if (lock_receive_blocks_queue)
312 {
313 LockQueue(c->ReceivedBlocks);
314 }
315 {
316 BLOCK *b;
317 packet_put = false;
318 while (true)
319 {
320 b = GetNext(c->ReceivedBlocks);
321 if (b == NULL)
322 {
323 break;
324 }
325
326 PROBE_DATA2("GetNext", b->Buf, b->Size);
327
328 update_hub_last_comm = true;
329
330 if (b->Size >= 14)
331 {
332 UINT ip;
333 if( (ip = PrepareDHCPRequestForStaticIPv4( s, b )) != 0 )
334 {
335 // Remember the static IP address to remove it from the leased IP address list later
336 static_ip = ip;
337 }
338
339 if (b->Buf[0] & 0x01)
340 {
341 if (is_server_session == false)
342 {
343 t.Recv.BroadcastCount++;
344 t.Recv.BroadcastBytes += (UINT64)b->Size;
345 }
346 else
347 {
348 t.Send.BroadcastCount++;
349 t.Send.BroadcastBytes += (UINT64)b->Size;
350 }
351 }
352 else
353 {
354 if (is_server_session == false)
355 {
356 t.Recv.UnicastCount++;
357 t.Recv.UnicastBytes += (UINT64)b->Size;
358 }
359 else
360 {
361 t.Send.UnicastCount++;
362 t.Send.UnicastBytes += (UINT64)b->Size;
363 }
364 }
365 }
366
367 packet_put = true;
368 PROBE_DATA2("pa->PutPacket", b->Buf, b->Size);
369 if (pa->PutPacket(s, b->Buf, b->Size) == false)
370 {
371 pa_fail = true;
372 err = ERR_DEVICE_DRIVER_ERROR;
373 Free(b->Buf);
374 Debug(" Error: pa->PutPacket(Packet) Failed.\n");
375 }
376 Free(b);
377 }
378
379 if (true /* packet_put || is_server_session 2014.7.23 for optimizing */)
380 {
381 PROBE_DATA2("pa->PutPacket", NULL, 0);
382 if (pa->PutPacket(s, NULL, 0) == false)
383 {
384 Debug(" Error: pa->PutPacket(NULL) Failed.\n");
385 pa_fail = true;
386 err = ERR_DEVICE_DRIVER_ERROR;
387 }
388 }
389 }
390 if (lock_receive_blocks_queue)
391 {
392 UnlockQueue(c->ReceivedBlocks);
393 }
394
395 // Add the packet to be transmitted to SendBlocks by acquiring from PacketAdapter
396 {
397 UINT i, max_num = MAX_SEND_SOCKET_QUEUE_NUM;
398 i = 0;
399 while (packet_size = pa->GetNextPacket(s, &packet))
400 {
401 BLOCK *b;
402 if (packet_size == INFINITE)
403 {
404 err = ERR_DEVICE_DRIVER_ERROR;
405 pa_fail = true;
406 Debug(" Error: pa->GetNextPacket() Failed.\n");
407 break;
408 }
409
410 update_hub_last_comm = true;
411
412 if ((c->CurrentSendQueueSize > MAX_BUFFERING_PACKET_SIZE) ||
413 block_all_packets)
414 {
415 // WHERE;
416 // Discard because it exceeded the buffer size limit
417 Free(packet);
418 }
419 else
420 {
421 bool priority;
422 QUEUE *q = NULL;
423 // Buffering
424 if (packet_size >= 14)
425 {
426 UCHAR *buf = (UCHAR *)packet;
427 if (buf[0] & 0x01)
428 {
429 if (is_server_session == false)
430 {
431 t.Send.BroadcastCount++;
432 t.Send.BroadcastBytes += (UINT64)packet_size;
433 }
434 else
435 {
436 t.Recv.BroadcastCount++;
437 t.Recv.BroadcastBytes += (UINT64)packet_size;
438 }
439 }
440 else
441 {
442 if (is_server_session == false)
443 {
444 t.Send.UnicastCount++;
445 t.Send.UnicastBytes += (UINT64)packet_size;
446 }
447 else
448 {
449 t.Recv.UnicastCount++;
450 t.Recv.UnicastBytes += (UINT64)packet_size;
451 }
452 }
453 }
454 priority = IsPriorityHighestPacketForQoS(packet, packet_size);
455
456 b = NewBlock(packet, packet_size, s->UseCompress ? 1 : 0);
457 b->PriorityQoS = priority;
458
459 if (b->PriorityQoS && c->Protocol == CONNECTION_TCP && s->QoS)
460 {
461 q = c->SendBlocks2;
462 }
463 else
464 {
465 q = c->SendBlocks;
466 }
467
468 if (q->num_item > MAX_STORED_QUEUE_NUM)
469 {
470 q = NULL;
471 }
472
473 if (q != NULL)
474 {
475 c->CurrentSendQueueSize += b->Size;
476 InsertQueue(q, b);
477 }
478 else
479 {
480 FreeBlock(b);
481 }
482 }
483
484 if ((i % 16) == 0)
485 {
486 int diff = ((int)c->CurrentSendQueueSize) - ((int)c->LastPacketQueueSize);
487 CedarAddCurrentTcpQueueSize(c->Cedar, diff);
488 c->LastPacketQueueSize = c->CurrentSendQueueSize;
489 }
490
491 i++;
492 if (i >= max_num)
493 {
494 break;
495 }
496 }
497 }
498
499 AddTrafficForSession(s, &t);
500
501 if (true)
502 {
503 int diff = ((int)c->CurrentSendQueueSize) - ((int)c->LastPacketQueueSize);
504 CedarAddCurrentTcpQueueSize(c->Cedar, diff);
505 c->LastPacketQueueSize = c->CurrentSendQueueSize;
506 }
507
508 now = Tick64();
509
510 // Send a block
511 ConnectionSend(c, now);
512
513 // Determine the automatic disconnection
514 if (auto_disconnect_tick != 0 && auto_disconnect_tick <= now)
515 {
516 err = ERR_AUTO_DISCONNECTED;
517 s->CurrentRetryCount = INFINITE;
518 break;
519 }
520
521 // Stop determination
522 if (s->Halt)
523 {
524 if (s->ForceStopFlag)
525 {
526 err = ERR_USER_CANCEL;
527 }
528 break;
529 }
530
531 // Increments the number of logins for user object and Virtual HUB object.
532 // (It's incremented only if the time 30 seconds passed after connection.
533 // If not do this, it will be incremented on DoS attacks or any error.)
534 if (s->NumLoginIncrementTick != 0 && s->NumLoginIncrementTick <= now)
535 {
536 s->NumLoginIncrementTick = 0;
537
538 if (s->NumLoginIncrementHubObject != NULL)
539 {
540 s->NumLoginIncrementHubObject->NumLogin++;
541 }
542
543 if (s->NumLoginIncrementUserObject != NULL)
544 {
545 s->NumLoginIncrementUserObject->NumLogin++;
546 }
547 }
548
549 if (is_server_session)
550 {
551 HUB *hub;
552
553 // Update of traffic data of the user
554 if ((s->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)
555 {
556 IncrementUserTraffic(s->Hub, s->UserNameReal, s);
557 s->LastIncrementTraffic = now;
558 }
559
560 hub = s->Hub;
561
562 if (hub != NULL)
563 {
564 if ((hub->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)
565 {
566 hub->LastIncrementTraffic = now;
567 IncrementHubTraffic(s->Hub);
568 }
569 }
570 }
571
572 if (s->LinkModeServer == false && s->SecureNATMode == false && s->BridgeMode == false && s->L3SwitchMode == false && s->InProcMode == false)
573 {
574 bool timeouted = false;
575
576 if ((now > s->LastCommTime) && ((now - s->LastCommTime) >= ((UINT64)s->Timeout)))
577 {
578 // When communication is not possible for the predetermined time
579 timeouted = true;
580 WHERE;
581 }
582
583 if (c->Protocol == CONNECTION_TCP)
584 {
585 if (GetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT))
586 {
587 UINT num_tcp_connections = Count(c->CurrentNumConnection);
588
589 if (num_tcp_connections == 0)
590 {
591 // All TCP connections are disconnected.
592 // Terminate the session immediately.
593 timeouted = true;
594 }
595 }
596 }
597
598 if (is_server_session == false && s->ClientOption != NULL && s->ClientOption->ConnectionDisconnectSpan == 0)
599 {
600 if (LIST_NUM(s->Connection->Tcp->TcpSockList) < s->MaxConnection)
601 {
602 if ((s->LastTryAddConnectTime +
603 (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000 * 2 + CONNECTING_TIMEOUT * 2))
604 <= Tick64())
605 {
606 if (s->IsRUDPSession == false || LIST_NUM(s->Connection->Tcp->TcpSockList) == 0)
607 {
608 timeouted = true;
609 WHERE;
610 }
611 }
612 }
613 }
614
615 if (timeouted)
616 {
617 // Timeout occurs
618 Debug("** Session Timeouted.\n");
619 s->SessionTimeOuted = true;
620 err = ERR_SESSION_TIMEOUT;
621 }
622 }
623
624 // Time-out decision
625 if (pa_fail || s->SessionTimeOuted)
626 {
627 s->Halt = true;
628 s->RetryFlag = true; // Retry flag
629 break;
630 }
631 }
632
633 CLEANUP:
634 Debug("Session %s Finishing...\n", s->Name);
635
636 // Remove from the session list of the HUB
637 if (s->ServerMode)
638 {
639 // Update the user information
640 IncrementUserTraffic(s->Hub, s->UserNameReal, s);
641
642 // Clear the DHCP lease record if assigned as a static client IP address
643 ClearDHCPLeaseRecordForIPv4(s, static_ip);
644
645 DelSession(s->Hub, s);
646 }
647
648 s->ConnectSucceed = false;
649 Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
650
651 if (s->Connection)
652 {
653 int diff = -((int)s->Connection->LastTcpQueueSize);
654 s->Connection->LastTcpQueueSize = 0;
655 s->Connection->Halt = true;
656 CedarAddCurrentTcpQueueSize(s->Cedar, diff);
657
658 diff = ((int)c->CurrentSendQueueSize) - ((int)c->LastPacketQueueSize);
659 CedarAddCurrentTcpQueueSize(c->Cedar, diff);
660 c->LastPacketQueueSize = c->CurrentSendQueueSize;
661 }
662
663 // Release the packet adapter
664 if (pa_inited)
665 {
666 pa->Free(s);
667 }
668
669 #ifdef OS_WIN32
670 if (s->IsVPNClientAndVLAN_Win32)
671 {
672 MsEndVLanCard();
673 }
674 #endif // OS_WIN32
675
676 if (s->ServerMode == false)
677 {
678 // Cancel to make all additional connection
679 StopAllAdditionalConnectThread(s->Connection);
680 }
681
682 if (s->BridgeMode)
683 {
684 // Terminate the bridge
685 if (s->Bridge->Active)
686 {
687 CloseEth(s->Bridge->Eth);
688 s->Bridge->Eth = NULL;
689 }
690 }
691
692 if (s->Cancel2 != NULL)
693 {
694 // Release the Cancel 2
695 ReleaseCancel(s->Cancel2);
696 s->Cancel2 = NULL;
697 }
698
699 // Terminate the connection
700 EndTunnelingMode(c);
701
702 if (nicinfo_sock != NULL)
703 {
704 CncNicInfoFree(nicinfo_sock);
705 }
706
707 if (msgdlg_sock != NULL)
708 {
709 CndMsgDlgFree(msgdlg_sock);
710 }
711
712 c->Err = err;
713 }
714
715 // Get the time for the next delayed packet
GetNextDelayedPacketTickDiff(SESSION * s)716 UINT GetNextDelayedPacketTickDiff(SESSION *s)
717 {
718 UINT i;
719 UINT ret = 0x7fffffff;
720 UINT64 now;
721 // Validate arguments
722 if (s == NULL)
723 {
724 return 0;
725 }
726
727 if (LIST_NUM(s->DelayedPacketList) >= 1)
728 {
729 now = TickHighres64();
730
731 LockList(s->DelayedPacketList);
732 {
733 for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
734 {
735 PKT *p = LIST_DATA(s->DelayedPacketList, i);
736 UINT64 t = p->DelayedForwardTick;
737 UINT d = 0x7fffffff;
738
739 if (now >= t)
740 {
741 d = 0;
742 }
743 else
744 {
745 d = (UINT)(t - now);
746 }
747
748 ret = MIN(ret, d);
749 }
750 }
751 UnlockList(s->DelayedPacketList);
752 }
753
754 return ret;
755 }
756
757 // Determine whether the packet have priority in the VoIP / QoS function
IsPriorityHighestPacketForQoS(void * data,UINT size)758 bool IsPriorityHighestPacketForQoS(void *data, UINT size)
759 {
760 UCHAR *buf;
761 // Validate arguments
762 if (data == NULL)
763 {
764 return false;
765 }
766
767 buf = (UCHAR *)data;
768 if (size >= 16)
769 {
770 if (buf[12] == 0x08 && buf[13] == 0x00 && buf[15] != 0x00 && buf[15] != 0x08)
771 {
772 // IPv4 packet and ToS != 0
773 return true;
774 }
775
776 if (size >= 34 && size <= 128)
777 {
778 if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x01)
779 {
780 // IMCPv4 packet
781 return true;
782 }
783 }
784 }
785
786 return false;
787 }
788
789 // Update the traffic information of the user
IncrementUserTraffic(HUB * hub,char * username,SESSION * s)790 void IncrementUserTraffic(HUB *hub, char *username, SESSION *s)
791 {
792 TRAFFIC report_traffic;
793 // Validate arguments
794 if (hub == NULL || username == NULL || s == NULL)
795 {
796 return;
797 }
798
799 Lock(s->TrafficLock);
800 {
801 // Calculate the traffic information (difference between last time) to be reported
802 report_traffic.Send.BroadcastBytes =
803 s->Traffic->Send.BroadcastBytes - s->OldTraffic->Send.BroadcastBytes;
804 report_traffic.Send.BroadcastCount =
805 s->Traffic->Send.BroadcastCount - s->OldTraffic->Send.BroadcastCount;
806 report_traffic.Send.UnicastBytes =
807 s->Traffic->Send.UnicastBytes - s->OldTraffic->Send.UnicastBytes;
808 report_traffic.Send.UnicastCount =
809 s->Traffic->Send.UnicastCount - s->OldTraffic->Send.UnicastCount;
810 report_traffic.Recv.BroadcastBytes =
811 s->Traffic->Recv.BroadcastBytes - s->OldTraffic->Recv.BroadcastBytes;
812 report_traffic.Recv.BroadcastCount =
813 s->Traffic->Recv.BroadcastCount - s->OldTraffic->Recv.BroadcastCount;
814 report_traffic.Recv.UnicastBytes =
815 s->Traffic->Recv.UnicastBytes - s->OldTraffic->Recv.UnicastBytes;
816 report_traffic.Recv.UnicastCount =
817 s->Traffic->Recv.UnicastCount - s->OldTraffic->Recv.UnicastCount;
818 Copy(s->OldTraffic, s->Traffic, sizeof(TRAFFIC));
819
820 if (hub->FarmMember == false)
821 {
822 // Update the user information in the local database if it is not a farm member
823 AcLock(hub);
824 {
825 USER *u = AcGetUser(hub, username);
826 if (u != NULL)
827 {
828 Lock(u->lock);
829 {
830 AddTraffic(u->Traffic, &report_traffic);
831 }
832 Unlock(u->lock);
833 if (u->Group != NULL)
834 {
835 Lock(u->Group->lock);
836 {
837 AddTraffic(u->Group->Traffic, &report_traffic);
838 }
839 Unlock(u->Group->lock);
840 }
841 ReleaseUser(u);
842 }
843 }
844 AcUnlock(hub);
845 }
846 else
847 {
848 // Update the traffic difference report list in the case of farm member
849 AddTrafficDiff(hub, username, TRAFFIC_DIFF_USER, &report_traffic);
850 }
851 }
852 Unlock(s->TrafficLock);
853 }
854
855 // Cumulate the traffic information of the connection
AddTrafficForSession(SESSION * s,TRAFFIC * t)856 void AddTrafficForSession(SESSION *s, TRAFFIC *t)
857 {
858 HUB *h;
859 TRAFFIC t2;
860 // Validate arguments
861 if (s == NULL || t == NULL)
862 {
863 return;
864 }
865
866 Lock(s->TrafficLock);
867 {
868 AddTraffic(s->Traffic, t);
869 }
870 Unlock(s->TrafficLock);
871
872 if (s->ServerMode)
873 {
874 Copy(&t2.Recv, &t->Send, sizeof(TRAFFIC_ENTRY));
875 Copy(&t2.Send, &t->Recv, sizeof(TRAFFIC_ENTRY));
876 Lock(s->Cedar->TrafficLock);
877 {
878 AddTraffic(s->Cedar->Traffic, &t2);
879 }
880 Unlock(s->Cedar->TrafficLock);
881
882 h = s->Hub;
883 Lock(h->TrafficLock);
884 {
885 AddTraffic(h->Traffic, &t2);
886 }
887 Unlock(h->TrafficLock);
888 }
889 }
890
891 // A chance to establish an additional connection for client
ClientAdditionalConnectChance(SESSION * s)892 void ClientAdditionalConnectChance(SESSION *s)
893 {
894 // Validate arguments
895 if (s == NULL)
896 {
897 return;
898 }
899
900 if (s->ServerMode)
901 {
902 // Do not connect additionally in the server mode
903 return;
904 }
905 if (s->Connection->Protocol != CONNECTION_TCP)
906 {
907 // Connect additionally only in the case of TCP protocol
908 return;
909 }
910 if (s->IsRUDPSession && s->EnableUdpRecovery == false)
911 {
912 // Do not connect additionally if the UDP recovery is disabled in the case of R-UDP session
913 return;
914 }
915
916 if (s->IsRUDPSession && (s->Connection->AdditionalConnectionFailedCounter > MAX_ADDITIONAL_CONNECTION_FAILED_COUNTER))
917 {
918 // Not to make a large amount of repeated connection retry within a certain time in the case of R-UDP session
919 return;
920 }
921
922 while (true)
923 {
924 if (s->Halt)
925 {
926 return;
927 }
928 // Consider whether there is a need to put an additional connection
929 // by examining the number of current connections and MaxConnection property
930 if (Count(s->Connection->CurrentNumConnection) < s->MaxConnection)
931 {
932 // Get the current time
933 UINT64 now = Tick64();
934
935 // Examine the NextConnectionTime, and if the time passed,
936 // attempt to make a connection
937 if (s->NextConnectionTime == 0 ||
938 s->ClientOption->AdditionalConnectionInterval == 0 ||
939 (s->NextConnectionTime <= now))
940 {
941 // Start the work to put an additional connection
942 s->NextConnectionTime = now + ((UINT64)s->ClientOption->AdditionalConnectionInterval * (UINT64)1000);
943 SessionAdditionalConnect(s);
944 }
945 else
946 {
947 break;
948 }
949 }
950 else
951 {
952 break;
953 }
954 }
955 }
956
957 // Release the packet adapter
FreePacketAdapter(PACKET_ADAPTER * pa)958 void FreePacketAdapter(PACKET_ADAPTER *pa)
959 {
960 // Validate arguments
961 if (pa == NULL)
962 {
963 return;
964 }
965
966 Free(pa);
967 }
968
969 // Create a new packet adapter
NewPacketAdapter(PA_INIT * init,PA_GETCANCEL * getcancel,PA_GETNEXTPACKET * getnext,PA_PUTPACKET * put,PA_FREE * free)970 PACKET_ADAPTER *NewPacketAdapter(PA_INIT *init, PA_GETCANCEL *getcancel, PA_GETNEXTPACKET *getnext,
971 PA_PUTPACKET *put, PA_FREE *free)
972 {
973 PACKET_ADAPTER *pa;
974 // Validate arguments
975 if (init == NULL || getcancel == NULL || getnext == NULL || put == NULL || free == NULL)
976 {
977 return NULL;
978 }
979
980 pa = ZeroMalloc(sizeof(PACKET_ADAPTER));
981
982 pa->Init = init;
983 pa->Free = free;
984 pa->GetCancel = getcancel;
985 pa->GetNextPacket = getnext;
986 pa->PutPacket = put;
987
988 return pa;
989 }
990
991 // Thread for putting an additional connection
ClientAdditionalThread(THREAD * t,void * param)992 void ClientAdditionalThread(THREAD *t, void *param)
993 {
994 SESSION *s;
995 CONNECTION *c;
996 // Validate arguments
997 if (t == NULL || param == NULL)
998 {
999 return;
1000 }
1001
1002 s = (SESSION *)param;
1003
1004 s->LastTryAddConnectTime = Tick64();
1005
1006 c = s->Connection;
1007 // Increment of connection counter
1008 Inc(c->CurrentNumConnection);
1009 LockList(c->ConnectingThreads);
1010 {
1011 // Add to processing thread
1012 Add(c->ConnectingThreads, t);
1013 AddRef(t->ref);
1014 }
1015 UnlockList(c->ConnectingThreads);
1016
1017 // Notify the completion of initialization
1018 NoticeThreadInit(t);
1019
1020 Debug("Additional Connection #%u\n", Count(c->CurrentNumConnection));
1021
1022 // Put an additional connection
1023 if (ClientAdditionalConnect(c, t) == false)
1024 {
1025 // Decrement the counter which is currently processing
1026 Dec(c->CurrentNumConnection);
1027
1028 if (c->AdditionalConnectionFailedCounter == 0)
1029 {
1030 c->LastCounterResetTick = Tick64();
1031 }
1032
1033 c->AdditionalConnectionFailedCounter++;
1034
1035 if ((c->LastCounterResetTick + (UINT64)ADDITIONAL_CONNECTION_COUNTER_RESET_INTERVAL) <= Tick64())
1036 {
1037 // Reset the number of failures periodically
1038 c->AdditionalConnectionFailedCounter = 0;
1039 c->LastCounterResetTick = Tick64();
1040 }
1041 }
1042 else
1043 {
1044 s->LastTryAddConnectTime = Tick64();
1045 c->AdditionalConnectionFailedCounter = 0;
1046 c->LastCounterResetTick = Tick64();
1047 }
1048
1049 // Remove from the processing thread
1050 LockList(c->ConnectingThreads);
1051 {
1052 // Remove from the processing thread
1053 if (Delete(c->ConnectingThreads, t))
1054 {
1055 ReleaseThread(t);
1056 }
1057 }
1058 UnlockList(c->ConnectingThreads);
1059 ReleaseSession(s);
1060 }
1061
1062 // Put an additional connection from the client to the server
SessionAdditionalConnect(SESSION * s)1063 void SessionAdditionalConnect(SESSION *s)
1064 {
1065 THREAD *t;
1066 // Validate arguments
1067 if (s == NULL)
1068 {
1069 return;
1070 }
1071
1072 // s->LastTryAddConnectTime = Tick64();
1073
1074 AddRef(s->ref);
1075 t = NewThread(ClientAdditionalThread, (void *)s);
1076 WaitThreadInit(t);
1077 ReleaseThread(t);
1078 }
1079
1080 // Connect the client session to the server
SessionConnect(SESSION * s)1081 bool SessionConnect(SESSION *s)
1082 {
1083 CONNECTION *c;
1084 bool ret = false;
1085 // Validate arguments
1086 if (s == NULL)
1087 {
1088 return false;
1089 }
1090
1091 s->ClientStatus = CLIENT_STATUS_CONNECTING;
1092
1093 Debug("SessionConnect() Started.\n");
1094
1095 // Initialize the session
1096 Lock(s->lock);
1097 {
1098 s->Err = ERR_NO_ERROR;
1099 if (s->Policy != NULL)
1100 {
1101 Free(s->Policy);
1102 s->Policy = NULL;
1103 }
1104 }
1105 Unlock(s->lock);
1106
1107 s->CancelConnect = false;
1108
1109 // Create a Client Connection
1110 c = NewClientConnection(s);
1111 s->Connection = c;
1112
1113 // Connect the client to the server
1114 ret = ClientConnect(c);
1115 s->Err = c->Err;
1116
1117 s->CancelConnect = false;
1118
1119 if (s->Cedar->Client != NULL)
1120 {
1121 if (s->Policy != NULL)
1122 {
1123 if (s->Policy->NoSavePassword)
1124 {
1125 s->Client_NoSavePassword = true;
1126
1127 if (s->Account != NULL)
1128 {
1129 Lock(s->Account->lock);
1130 {
1131 if (s->Account->ClientAuth != NULL)
1132 {
1133 if (s->Account->ClientAuth->AuthType == AUTHTYPE_PASSWORD ||
1134 s->Account->ClientAuth->AuthType == AUTHTYPE_RADIUS)
1135 {
1136 Zero(s->Account->ClientAuth->HashedPassword, sizeof(s->Account->ClientAuth->HashedPassword));
1137 Zero(s->Account->ClientAuth->PlainPassword, sizeof(s->Account->ClientAuth->PlainPassword));
1138 }
1139 }
1140 }
1141 Unlock(s->Account->lock);
1142
1143 CiSaveConfigurationFile(s->Cedar->Client);
1144 }
1145 }
1146 }
1147 }
1148
1149 if (c->ClientConnectError_NoSavePassword)
1150 {
1151 s->Client_NoSavePassword = true;
1152 }
1153
1154 // Release the client connection
1155 s->Connection = NULL;
1156 ReleaseConnection(c);
1157
1158 Lock(s->lock);
1159 {
1160 if (s->Policy != NULL)
1161 {
1162 Free(s->Policy);
1163 s->Policy = NULL;
1164 }
1165 }
1166 Unlock(s->lock);
1167
1168 return ret;
1169 }
1170
1171 // Stop the session
StopSession(SESSION * s)1172 void StopSession(SESSION *s)
1173 {
1174 StopSessionEx(s, false);
1175 }
StopSessionEx(SESSION * s,bool no_wait)1176 void StopSessionEx(SESSION *s, bool no_wait)
1177 {
1178 // Validate arguments
1179 if (s == NULL)
1180 {
1181 return;
1182 }
1183
1184 // Halting flag
1185 s->UserCanceled = true;
1186 s->CancelConnect = true;
1187 s->Halt = true;
1188
1189 Debug("Stop Session %s\n", s->Name);
1190
1191 // Cancel
1192 Cancel(s->Cancel1);
1193
1194 // Event
1195 Set(s->HaltEvent);
1196
1197 // Server and client mode
1198 if (s->Connection)
1199 {
1200 CONNECTION *c = s->Connection;
1201 AddRef(c->ref);
1202 StopConnection(c, no_wait);
1203 ReleaseConnection(c);
1204 }
1205
1206 // Wait until the stop
1207 if (no_wait == false)
1208 {
1209 while (true)
1210 {
1211 s->ForceStopFlag = true;
1212 s->Halt = true;
1213 if (WaitThread(s->Thread, 20))
1214 {
1215 break;
1216 }
1217 }
1218 }
1219 else
1220 {
1221 s->ForceStopFlag = true;
1222 s->Halt = true;
1223 }
1224 }
1225
1226 // Cleanup the session
CleanupSession(SESSION * s)1227 void CleanupSession(SESSION *s)
1228 {
1229 // Validate arguments
1230 if (s == NULL)
1231 {
1232 return;
1233 }
1234
1235 // Release the delayed packet list
1236 if (s->DelayedPacketList != NULL)
1237 {
1238 UINT i;
1239 for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
1240 {
1241 PKT *p = LIST_DATA(s->DelayedPacketList, i);
1242
1243 Free(p->PacketData);
1244 FreePacket(p);
1245 }
1246
1247 ReleaseList(s->DelayedPacketList);
1248 }
1249
1250 // Release the client connection options
1251 if (s->ClientOption != NULL)
1252 {
1253 #ifdef OS_UNIX
1254 UnixVLanSetState(s->ClientOption->DeviceName, false);
1255 #endif
1256 Free(s->ClientOption);
1257 }
1258
1259 // Release the client authentication data
1260 if (s->ClientAuth != NULL)
1261 {
1262 if (s->ClientAuth->ClientX != NULL)
1263 {
1264 FreeX(s->ClientAuth->ClientX);
1265 }
1266 if (s->ClientAuth->ClientX != NULL)
1267 {
1268 FreeK(s->ClientAuth->ClientK);
1269 }
1270 Free(s->ClientAuth);
1271 }
1272
1273 FreeTraffic(s->Traffic);
1274 Free(s->Name);
1275
1276 if (s->Thread != NULL)
1277 {
1278 ReleaseThread(s->Thread);
1279 }
1280
1281 DeleteLock(s->lock);
1282
1283 ReleaseEvent(s->HaltEvent);
1284
1285 if (s->Cancel1)
1286 {
1287 ReleaseCancel(s->Cancel1);
1288 }
1289
1290 if (s->Cancel2)
1291 {
1292 ReleaseCancel(s->Cancel2);
1293 }
1294
1295 if (s->Policy)
1296 {
1297 Free(s->Policy);
1298 }
1299
1300 if (s->Connection)
1301 {
1302 ReleaseConnection(s->Connection);
1303 }
1304
1305 Free(s->Username);
1306
1307 if (s->PacketAdapter)
1308 {
1309 FreePacketAdapter(s->PacketAdapter);
1310 }
1311
1312 if (s->OldTraffic != NULL)
1313 {
1314 FreeTraffic(s->OldTraffic);
1315 }
1316
1317 DeleteLock(s->TrafficLock);
1318
1319 if (s->CancelList != NULL)
1320 {
1321 ReleaseCancelList(s->CancelList);
1322 }
1323
1324 if (s->Client_Message != NULL)
1325 {
1326 Free(s->Client_Message);
1327 }
1328
1329 DeleteCounter(s->LoggingRecordCount);
1330
1331 ReleaseSharedBuffer(s->IpcSessionSharedBuffer);
1332
1333 Free(s);
1334 }
1335
1336 // Release the session
ReleaseSession(SESSION * s)1337 void ReleaseSession(SESSION *s)
1338 {
1339 // Validate arguments
1340 if (s == NULL)
1341 {
1342 return;
1343 }
1344
1345 if (Release(s->ref) == 0)
1346 {
1347 CleanupSession(s);
1348 }
1349 }
1350
1351 // Display the total data transfer size of the session
PrintSessionTotalDataSize(SESSION * s)1352 void PrintSessionTotalDataSize(SESSION *s)
1353 {
1354 // Validate arguments
1355 if (s == NULL)
1356 {
1357 return;
1358 }
1359
1360 Debug(
1361 "-- SESSION TOTAL PKT INFORMATION --\n\n"
1362 " TotalSendSize: %I64u\n"
1363 " TotalSendSizeReal: %I64u\n"
1364 " TotalRecvSize: %I64u\n"
1365 " TotalRecvSizeReal: %I64u\n"
1366 " Compression Rate: %.2f%% (Send)\n"
1367 " %.2f%% (Recv)\n",
1368 s->TotalSendSize, s->TotalSendSizeReal,
1369 s->TotalRecvSize, s->TotalRecvSizeReal,
1370 (float)((double)s->TotalSendSizeReal / (double)s->TotalSendSize * 100.0f),
1371 (float)((double)s->TotalRecvSizeReal / (double)s->TotalRecvSize * 100.0f)
1372 );
1373
1374 }
1375
1376 // Client thread
ClientThread(THREAD * t,void * param)1377 void ClientThread(THREAD *t, void *param)
1378 {
1379 SESSION *s;
1380 bool use_password_dlg;
1381 bool no_save_password = false;
1382 bool is_vpngate_connection = false;
1383 CEDAR *cedar;
1384 bool num_active_sessions_incremented = false;
1385 // Validate arguments
1386 if (t == NULL || param == NULL)
1387 {
1388 return;
1389 }
1390
1391 Debug("ClientThread 0x%x Started.\n", t);
1392
1393 s = (SESSION *)param;
1394 AddRef(s->ref);
1395 s->Thread = t;
1396 AddRef(t->ref);
1397
1398 if (s->LinkModeClient == false)
1399 {
1400 CiIncrementNumActiveSessions();
1401 num_active_sessions_incremented = true;
1402 }
1403
1404 NoticeThreadInit(t);
1405
1406 cedar = s->Cedar;
1407
1408 s->ClientStatus = CLIENT_STATUS_CONNECTING;
1409 s->RetryFlag = true;
1410 s->CurrentRetryCount = 0;
1411
1412 Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
1413
1414 if (s->Cedar->Client != NULL)
1415 {
1416 no_save_password = s->Cedar->Client->DontSavePassword;
1417 }
1418
1419 s->Win32HideConnectWindow = s->ClientOption->HideStatusWindow;
1420 s->Win32HideNicInfoWindow = s->ClientOption->HideNicInfoWindow;
1421
1422
1423 while (true)
1424 {
1425 Zero(&s->ServerIP_CacheForNextConnect, sizeof(IP));
1426
1427 if (s->Link != NULL && ((*s->Link->StopAllLinkFlag) || s->Link->Halting))
1428 {
1429 s->Err = ERR_USER_CANCEL;
1430 break;
1431 }
1432
1433 CLog(s->Cedar->Client, "LC_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);
1434 if (s->LinkModeClient && s->Link != NULL)
1435 {
1436 HLog(s->Link->Hub, "LH_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);
1437 }
1438
1439 Debug("Trying to Connect to Server... (%u / %u)\n", s->CurrentRetryCount + 0,
1440 s->ClientOption->NumRetry);
1441
1442 // Initialize
1443 // s->TotalRecvSize = s->TotalRecvSizeReal =
1444 // s->TotalSendSize = s->TotalSendSizeReal = 0;
1445 s->NextConnectionTime = 0;
1446
1447 // Connect
1448 s->ClientStatus = CLIENT_STATUS_CONNECTING;
1449 s->Halt = false;
1450 SessionConnect(s);
1451 if (s->UserCanceled)
1452 {
1453 s->Err = ERR_USER_CANCEL;
1454 }
1455 Debug("Disconnected. Err = %u : %S\n", s->Err, _E(s->Err));
1456
1457 PrintSessionTotalDataSize(s);
1458
1459 CLog(s->Cedar->Client, "LC_CONNECT_ERROR", s->ClientOption->AccountName,
1460 GetUniErrorStr(s->Err), s->Err);
1461 #ifdef OS_UNIX
1462 UnixVLanSetState(s->ClientOption->DeviceName, false);
1463 #endif
1464 if (s->LinkModeClient && s->Link != NULL)
1465 {
1466 HLog(s->Link->Hub, "LH_CONNECT_ERROR", s->ClientOption->AccountName,
1467 GetUniErrorStr(s->Err), s->Err);
1468 }
1469
1470 s->ClientStatus = CLIENT_STATUS_RETRY;
1471
1472 if (s->Link != NULL)
1473 {
1474 ((LINK *)s->Link)->LastError = s->Err;
1475 }
1476
1477 if (s->Halt && (s->RetryFlag == false) || s->ForceStopFlag)
1478 {
1479 // Must be aborted
1480 if (s->Err == ERR_DEVICE_DRIVER_ERROR)
1481 {
1482 #ifdef OS_WIN32
1483 wchar_t tmp[MAX_SIZE];
1484 if (s->Account != NULL && s->Cedar->Client != NULL)
1485 {
1486 UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_DEVICE_ERROR"), s->ClientOption->DeviceName,
1487 s->Err, _E(s->Err));
1488 MsgBox(NULL, 0x10000 | 0x40000 | 0x200000 | 0x30, tmp);
1489 }
1490 #endif // OS_WIN32
1491 }
1492 break;
1493 }
1494 // Determine whether to display the password re-entry dialog
1495 use_password_dlg = false;
1496
1497 if (s->Account != NULL && s->Cedar->Client != NULL)
1498 {
1499 #ifdef OS_WIN32
1500 if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD || s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
1501 {
1502 if (s->Err == ERR_AUTH_FAILED || s->Err == ERR_PROXY_AUTH_FAILED)
1503 {
1504 use_password_dlg = true;
1505 }
1506 }
1507 #endif // OS_WIN32
1508 }
1509
1510 // Failed to connect or the connection is disconnected
1511 // Wait for retry interval
1512 if (use_password_dlg == false)
1513 {
1514 UINT retry_interval = s->RetryInterval;
1515
1516 if (s->LinkModeClient)
1517 {
1518 UINT current_num_links = Count(s->Cedar->CurrentActiveLinks);
1519 UINT max_retry_interval = MAX(1000 * current_num_links, retry_interval);
1520
1521 retry_interval += retry_interval * MIN(s->CurrentRetryCount, 1000);
1522 retry_interval = MIN(retry_interval, max_retry_interval);
1523
1524 // On the cascade client, adjust the retry_interval. (+/- 20%)
1525 if (retry_interval >= 1000 && retry_interval <= (60 * 60 * 1000))
1526 {
1527 retry_interval = (retry_interval * 8 / 10) + (Rand32() % (retry_interval * 4 / 10));
1528 }
1529 }
1530
1531 if (s->Err == ERR_HUB_IS_BUSY || s->Err == ERR_LICENSE_ERROR ||
1532 s->Err == ERR_HUB_STOPPING || s->Err == ERR_TOO_MANY_USER_SESSION)
1533 {
1534 retry_interval = RETRY_INTERVAL_SPECIAL;
1535 }
1536
1537 if (s->CurrentRetryCount >= s->ClientOption->NumRetry)
1538 {
1539 // Retry count excess
1540
1541 #ifndef OS_WIN32
1542
1543 break;
1544
1545 #else // OS_WIN32
1546
1547 if (s->Win32HideConnectWindow == false &&
1548 s->Cedar->Client != NULL && s->Account != NULL)
1549 {
1550 // Show a reconnection dialog
1551 UI_CONNECTERROR_DLG p;
1552 Zero(&p, sizeof(p));
1553 UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);
1554 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
1555 p.Err = s->Err;
1556 p.CurrentRetryCount = s->CurrentRetryCount + 1;
1557 s->Halt = false;
1558 p.RetryLimit = 0;
1559 p.RetryIntervalSec = 0;
1560 p.CancelEvent = s->HaltEvent;
1561 p.HideWindow = s->Win32HideConnectWindow;
1562 if (CncConnectErrorDlg(s, &p) == false)
1563 {
1564 // Abort
1565 break;
1566 }
1567 else
1568 {
1569 s->Win32HideConnectWindow = p.HideWindow;
1570 goto SKIP;
1571 }
1572 }
1573 else
1574 {
1575 break;
1576 }
1577
1578 #endif
1579 }
1580
1581 #ifndef OS_WIN32
1582
1583 // Simple wait
1584 Wait(s->HaltEvent, retry_interval);
1585
1586 #else // OS_WIN32
1587
1588 if (s->Win32HideConnectWindow == false &&
1589 s->Cedar->Client != NULL && s->Account != NULL)
1590 {
1591 // Show a reconnection dialog
1592 UI_CONNECTERROR_DLG p;
1593 Zero(&p, sizeof(p));
1594 UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);
1595 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
1596 p.Err = s->Err;
1597 p.CurrentRetryCount = s->CurrentRetryCount + 1;
1598 p.RetryLimit = s->ClientOption->NumRetry;
1599 p.RetryIntervalSec = retry_interval;
1600 p.CancelEvent = s->HaltEvent;
1601 s->Halt = false;
1602 p.HideWindow = s->Win32HideConnectWindow;
1603 if (CncConnectErrorDlg(s, &p) == false)
1604 {
1605 // Abort
1606 break;
1607 }
1608 s->Win32HideConnectWindow = p.HideWindow;
1609 }
1610 else
1611 {
1612 // Simple wait
1613 Wait(s->HaltEvent, s->RetryInterval);
1614 }
1615
1616 #endif // OS_WIN32
1617 }
1618 else
1619 {
1620 #ifdef OS_WIN32
1621 // Wait for re-entry the password
1622 UI_PASSWORD_DLG p;
1623 Zero(&p, sizeof(p));
1624 if (s->Client_NoSavePassword == false)
1625 {
1626 p.ShowNoSavePassword = true;
1627 }
1628 p.NoSavePassword = no_save_password;
1629 p.CancelEvent = s->HaltEvent;
1630 if (s->Err == ERR_PROXY_AUTH_FAILED)
1631 {
1632 p.ProxyServer = true;
1633 }
1634
1635 if (p.ProxyServer)
1636 {
1637 StrCpy(p.Username, sizeof(p.Username), s->ClientOption->ProxyUsername);
1638 StrCpy(p.Password, sizeof(p.Password), s->ClientOption->ProxyPassword);
1639 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->ProxyName);
1640 }
1641 else
1642 {
1643 bool empty = false;
1644
1645 StrCpy(p.Username, sizeof(p.Username), s->ClientAuth->Username);
1646 if (s->ClientAuth->AuthType == AUTHTYPE_RADIUS)
1647 {
1648 if (StrLen(s->ClientAuth->PlainPassword) == 0)
1649 {
1650 empty = true;
1651 }
1652 }
1653 else if (s->ClientAuth->AuthType == AUTHTYPE_PASSWORD)
1654 {
1655 if (IsZero(s->ClientAuth->HashedPassword, sizeof(s->ClientAuth->HashedPassword)))
1656 {
1657 empty = true;
1658 }
1659 }
1660
1661 StrCpy(p.Password, sizeof(p.Password), empty ? "" : HIDDEN_PASSWORD);
1662 StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
1663 }
1664
1665 p.RetryIntervalSec = s->RetryInterval / 1000;
1666 p.Type = s->ClientAuth->AuthType;
1667
1668 // Display the password re-entry dialog
1669 if (CncPasswordDlg(s, &p) == false)
1670 {
1671 // Abort the connection
1672 break;
1673 }
1674 else
1675 {
1676 // Overwrite the user name
1677 if (p.ProxyServer)
1678 {
1679 // User name of the proxy
1680 StrCpy(s->ClientOption->ProxyUsername, sizeof(s->ClientOption->ProxyUsername), p.Username);
1681 }
1682 else
1683 {
1684 // The user name for connecting to the server
1685 StrCpy(s->ClientAuth->Username, sizeof(s->ClientAuth->Username), p.Username);
1686 s->ClientAuth->AuthType = p.Type;
1687 }
1688
1689 if (StrCmp(p.Password, HIDDEN_PASSWORD) != 0)
1690 {
1691 // Password is re-entered
1692 if (p.ProxyServer)
1693 {
1694 // Password for the proxy server
1695 StrCpy(s->ClientOption->ProxyPassword, sizeof(s->ClientOption->ProxyPassword), p.Password);
1696 }
1697 else
1698 {
1699 if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
1700 {
1701 // Plaintext password authentication
1702 StrCpy(s->ClientAuth->PlainPassword, sizeof(s->ClientAuth->PlainPassword), p.Password);
1703 }
1704 else
1705 {
1706 // Encrypted password authentication
1707 HashPassword(s->ClientAuth->HashedPassword, s->ClientAuth->Username, p.Password);
1708 }
1709 }
1710 }
1711
1712 no_save_password = p.NoSavePassword;
1713
1714 if (s->Account != NULL && s->Cedar->Client != NULL)
1715 {
1716 s->Cedar->Client->DontSavePassword = no_save_password;
1717 if (p.NoSavePassword == false)
1718 {
1719 // Update the account database of the client
1720 if (p.ProxyServer == false)
1721 {
1722 // Update the Server connection information
1723 ACCOUNT *a = s->Account;
1724 Lock(a->lock);
1725 {
1726 CiFreeClientAuth(a->ClientAuth);
1727 a->ClientAuth = CopyClientAuth(s->ClientAuth);
1728 }
1729 Unlock(a->lock);
1730 CiSaveConfigurationFile(s->Cedar->Client);
1731 }
1732 else
1733 {
1734 // Update the proxy connection information
1735 ACCOUNT *a = s->Account;
1736 Lock(a->lock);
1737 {
1738 Copy(a->ClientOption, s->ClientOption, sizeof(CLIENT_OPTION));
1739 }
1740 Unlock(a->lock);
1741 CiSaveConfigurationFile(s->Cedar->Client);
1742 }
1743 }
1744 }
1745 }
1746 #endif // OS_WIN32
1747 }
1748
1749 SKIP:
1750 // Increase the number of retries
1751 if (s->ConnectSucceed == false)
1752 {
1753 s->CurrentRetryCount++;
1754 }
1755
1756 if (s->ForceStopFlag)
1757 {
1758 break;
1759 }
1760 }
1761
1762 Debug("Session Halt.\n");
1763
1764 s->ClientStatus = CLIENT_STATUS_IDLE;
1765
1766 // Regard as that the session is ended here
1767 if (s->Account != NULL)
1768 {
1769 s->Account->ClientSession = NULL;
1770 ReleaseSession(s);
1771 }
1772
1773 Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
1774
1775
1776 ReleaseSession(s);
1777
1778 if (num_active_sessions_incremented)
1779 {
1780 CiDecrementNumActiveSessions();
1781 }
1782 }
1783
1784 // Create an RPC session
NewRpcSession(CEDAR * cedar,CLIENT_OPTION * option)1785 SESSION *NewRpcSession(CEDAR *cedar, CLIENT_OPTION *option)
1786 {
1787 return NewRpcSessionEx(cedar, option, NULL, NULL);
1788 }
NewRpcSessionEx(CEDAR * cedar,CLIENT_OPTION * option,UINT * err,char * client_str)1789 SESSION *NewRpcSessionEx(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str)
1790 {
1791 return NewRpcSessionEx2(cedar, option, err, client_str, NULL);
1792 }
NewRpcSessionEx2(CEDAR * cedar,CLIENT_OPTION * option,UINT * err,char * client_str,void * hWnd)1793 SESSION *NewRpcSessionEx2(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str, void *hWnd)
1794 {
1795 SESSION *s;
1796 CONNECTION *c;
1797 SOCK *sock;
1798 // Validate arguments
1799 if (cedar == NULL || option == NULL)
1800 {
1801 return NULL;
1802 }
1803
1804 s = ZeroMalloc(sizeof(SESSION));
1805
1806 s->LoggingRecordCount = NewCounter();
1807 s->lock = NewLock();
1808 s->ref = NewRef();
1809 s->Cedar = cedar;
1810 s->ServerMode = false;
1811 s->Name = CopyStr("CLIENT_RPC_SESSION");
1812 s->CreatedTime = s->LastCommTime = Tick64();
1813 s->Traffic = NewTraffic();
1814 s->HaltEvent = NewEvent();
1815 s->TrafficLock = NewLock();
1816 s->Cancel1 = NewCancel();
1817
1818 // Copy the client connection options
1819 s->ClientOption = Malloc(sizeof(CLIENT_OPTION));
1820 Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));
1821
1822 s->MaxConnection = option->MaxConnection;
1823 s->UseEncrypt = option->UseEncrypt;
1824 s->UseCompress = option->UseCompress;
1825
1826 // Create a connection
1827 c = s->Connection = NewClientConnectionEx(s, client_str, cedar->Version, cedar->Build);
1828 c->hWndForUI = hWnd;
1829
1830 // Connect to the server
1831 sock = ClientConnectToServer(c);
1832 if (sock == NULL)
1833 {
1834 // Connection failure
1835 if (err != NULL)
1836 {
1837 *err = c->Err;
1838 }
1839 ReleaseSession(s);
1840 return NULL;
1841 }
1842
1843 // Send a signature
1844 if (ClientUploadSignature(sock) == false)
1845 {
1846 // Failure
1847 if (err != NULL)
1848 {
1849 *err = c->Err;
1850 }
1851 ReleaseSession(s);
1852 return NULL;
1853 }
1854
1855 // Receive a Hello packet
1856 if (ClientDownloadHello(c, sock) == false)
1857 {
1858 // Failure
1859 if (err != NULL)
1860 {
1861 *err = c->Err;
1862 }
1863 ReleaseSession(s);
1864 return NULL;
1865 }
1866
1867 return s;
1868 }
1869
1870 // Create a client session
NewClientSessionEx(CEDAR * cedar,CLIENT_OPTION * option,CLIENT_AUTH * auth,PACKET_ADAPTER * pa,ACCOUNT * account)1871 SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa, ACCOUNT *account)
1872 {
1873 SESSION *s;
1874 THREAD *t;
1875 // Validate arguments
1876 if (cedar == NULL || option == NULL || auth == NULL || pa == NULL ||
1877 (auth->AuthType == CLIENT_AUTHTYPE_SECURE && auth->SecureSignProc == NULL))
1878 {
1879 return NULL;
1880 }
1881
1882 // Initialize the SESSION object
1883 s = ZeroMalloc(sizeof(SESSION));
1884
1885 s->LoggingRecordCount = NewCounter();
1886
1887 s->lock = NewLock();
1888 s->ref = NewRef();
1889 s->Cedar = cedar;
1890 s->ServerMode = false;
1891 s->Name = CopyStr("CLIENT_SESSION");
1892 s->CreatedTime = s->LastCommTime = Tick64();
1893 s->Traffic = NewTraffic();
1894 s->HaltEvent = NewEvent();
1895 s->PacketAdapter = pa;
1896 s->TrafficLock = NewLock();
1897 s->OldTraffic = NewTraffic();
1898 s->Cancel1 = NewCancel();
1899 s->CancelList = NewCancelList();
1900
1901 // Copy the client connection options
1902 s->ClientOption = Malloc(sizeof(CLIENT_OPTION));
1903 Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));
1904
1905 if (GetGlobalServerFlag(GSF_DISABLE_SESSION_RECONNECT))
1906 {
1907 s->ClientOption->DisableQoS = true;
1908 s->ClientOption->MaxConnection = 1;
1909 s->ClientOption->HalfConnection = false;
1910 }
1911
1912 s->MaxConnection = option->MaxConnection;
1913 s->UseEncrypt = option->UseEncrypt;
1914 s->UseCompress = option->UseCompress;
1915
1916 // Set the retry interval
1917 s->RetryInterval = MAKESURE(option->RetryInterval, 0, 4000000) * 1000;
1918 s->RetryInterval = MAKESURE(s->RetryInterval, MIN_RETRY_INTERVAL, MAX_RETRY_INTERVAL);
1919
1920 // Interval for additional connection creation is at least 1 second
1921 s->ClientOption->AdditionalConnectionInterval = MAX(s->ClientOption->AdditionalConnectionInterval, 1);
1922
1923 // Hold whether the virtual LAN card is used in client mode
1924 s->ClientModeAndUseVLan = (StrLen(s->ClientOption->DeviceName) == 0) ? false : true;
1925
1926 if (s->ClientOption->NoRoutingTracking)
1927 {
1928 s->ClientModeAndUseVLan = false;
1929 }
1930
1931 if (pa->Id == PACKET_ADAPTER_ID_VLAN_WIN32)
1932 {
1933 s->IsVPNClientAndVLAN_Win32 = true;
1934 }
1935
1936 if (StrLen(option->DeviceName) == 0)
1937 {
1938 // NAT mode
1939 s->ClientModeAndUseVLan = false;
1940 s->VirtualHost = true;
1941 }
1942
1943 // Copy the client authentication data
1944 s->ClientAuth = Malloc(sizeof(CLIENT_AUTH));
1945 Copy(s->ClientAuth, auth, sizeof(CLIENT_AUTH));
1946
1947 // Clone the certificate and the private key
1948 if (s->ClientAuth->ClientX != NULL)
1949 {
1950 s->ClientAuth->ClientX = CloneX(s->ClientAuth->ClientX);
1951 }
1952 if (s->ClientAuth->ClientK != NULL)
1953 {
1954 if (s->ClientAuth->AuthType != CLIENT_AUTHTYPE_OPENSSLENGINE)
1955 {
1956 s->ClientAuth->ClientK = CloneK(s->ClientAuth->ClientK);
1957 }
1958 else
1959 {
1960 s->ClientAuth->ClientK = OpensslEngineToK(s->ClientAuth->OpensslEnginePrivateKeyName, s->ClientAuth->OpensslEngineName);
1961 }
1962 }
1963
1964 if (StrCmpi(s->ClientOption->DeviceName, LINK_DEVICE_NAME) == 0)
1965 {
1966 // Link client mode
1967 s->LinkModeClient = true;
1968 s->Link = (LINK *)s->PacketAdapter->Param;
1969 }
1970
1971 if (StrCmpi(s->ClientOption->DeviceName, SNAT_DEVICE_NAME) == 0)
1972 {
1973 // SecureNAT mode
1974 s->SecureNATMode = true;
1975 }
1976
1977 if (StrCmpi(s->ClientOption->DeviceName, BRIDGE_DEVICE_NAME) == 0)
1978 {
1979 // Bridge mode
1980 s->BridgeMode = true;
1981 }
1982
1983 if (s->VirtualHost)
1984 {
1985 VH *v = (VH *)s->PacketAdapter->Param;
1986
1987 // Add the session object to VH
1988 v->Session = s;
1989 AddRef(s->ref);
1990 }
1991
1992 s->Account = account;
1993
1994 if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
1995 {
1996 // Do not retry in the case of a smart card authentication
1997 s->ClientOption->NumRetry = 0;
1998 }
1999
2000 // Create a client thread
2001 t = NewThread(ClientThread, (void *)s);
2002 WaitThreadInit(t);
2003 ReleaseThread(t);
2004
2005 return s;
2006 }
NewClientSession(CEDAR * cedar,CLIENT_OPTION * option,CLIENT_AUTH * auth,PACKET_ADAPTER * pa)2007 SESSION *NewClientSession(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa)
2008 {
2009 return NewClientSessionEx(cedar, option, auth, pa, NULL);
2010 }
2011
2012 // Get the session from the session key
GetSessionFromKey(CEDAR * cedar,UCHAR * session_key)2013 SESSION *GetSessionFromKey(CEDAR *cedar, UCHAR *session_key)
2014 {
2015 HUB *h;
2016 UINT i, j;
2017 // Validate arguments
2018 if (cedar == NULL || session_key == NULL)
2019 {
2020 return NULL;
2021 }
2022
2023 LockList(cedar->HubList);
2024 {
2025 for (i = 0;i < LIST_NUM(cedar->HubList);i++)
2026 {
2027 h = LIST_DATA(cedar->HubList, i);
2028 LockList(h->SessionList);
2029 {
2030 for (j = 0;j < LIST_NUM(h->SessionList);j++)
2031 {
2032 SESSION *s = LIST_DATA(h->SessionList, j);
2033 Lock(s->lock);
2034 {
2035 if (Cmp(s->SessionKey, session_key, SHA1_SIZE) == 0)
2036 {
2037 // Session found
2038 AddRef(s->ref);
2039
2040 // Unlock
2041 Unlock(s->lock);
2042 UnlockList(h->SessionList);
2043 UnlockList(cedar->HubList);
2044 return s;
2045 }
2046 }
2047 Unlock(s->lock);
2048 }
2049 }
2050 UnlockList(h->SessionList);
2051 }
2052 }
2053 UnlockList(cedar->HubList);
2054
2055 return NULL;
2056 }
2057
2058 // Create a new session key
NewSessionKey(CEDAR * cedar,UCHAR * session_key,UINT * session_key_32)2059 void NewSessionKey(CEDAR *cedar, UCHAR *session_key, UINT *session_key_32)
2060 {
2061 // Validate arguments
2062 if (cedar == NULL || session_key == NULL || session_key_32 == NULL)
2063 {
2064 return;
2065 }
2066
2067 Rand(session_key, SHA1_SIZE);
2068 *session_key_32 = Rand32();
2069 }
2070
2071 bool if_init(SESSION *s);
2072 CANCEL *if_getcancel(SESSION *s);
2073 UINT if_getnext(SESSION *s, void **data);
2074 bool if_putpacket(SESSION *s, void *data, UINT size);
2075 void if_free(SESSION *s);
2076
2077
2078 // Create a server session
NewServerSession(CEDAR * cedar,CONNECTION * c,HUB * h,char * username,POLICY * policy)2079 SESSION *NewServerSession(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy)
2080 {
2081 return NewServerSessionEx(cedar, c, h, username, policy, false, NULL);
2082 }
NewServerSessionEx(CEDAR * cedar,CONNECTION * c,HUB * h,char * username,POLICY * policy,bool inproc_mode,UCHAR * ipc_mac_address)2083 SESSION *NewServerSessionEx(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy, bool inproc_mode, UCHAR *ipc_mac_address)
2084 {
2085 SESSION *s;
2086 char name[MAX_SIZE];
2087 char hub_name_upper[MAX_SIZE];
2088 char user_name_upper[MAX_USERNAME_LEN + 1];
2089 // Validate arguments
2090 if (cedar == NULL || c == NULL || h == NULL || username == NULL || policy == NULL)
2091 {
2092 return NULL;
2093 }
2094
2095 // Initialize the SESSION object
2096 s = ZeroMalloc(sizeof(SESSION));
2097
2098 s->LoggingRecordCount = NewCounter();
2099 s->lock = NewLock();
2100 s->ref = NewRef();
2101 s->Cedar = cedar;
2102 s->ServerMode = true;
2103 s->CreatedTime = s->LastCommTime = Tick64();
2104 s->Traffic = NewTraffic();
2105 s->HaltEvent = NewEvent();
2106 s->Cancel1 = NewCancel();
2107 s->CancelList = NewCancelList();
2108 s->Thread = c->Thread;
2109 s->TrafficLock = NewLock();
2110 s->OldTraffic = NewTraffic();
2111 s->QoS = GetServerCapsBool(cedar->Server, "b_support_qos");
2112 AddRef(s->Thread->ref);
2113 s->Hub = h;
2114 s->ClientStatus = CLIENT_STATUS_ESTABLISHED;
2115
2116 // Delayed packet list
2117 s->DelayedPacketList = NewList(NULL);
2118
2119 // Packet adapter for the HUB
2120 s->PacketAdapter = GetHubPacketAdapter();
2121
2122 s->Connection = c;
2123 AddRef(c->ref);
2124
2125 // Determine the new session name
2126 StrCpy(hub_name_upper, sizeof(hub_name_upper), h->Name);
2127 StrUpper(hub_name_upper);
2128 StrCpy(user_name_upper, sizeof(user_name_upper), username);
2129 StrUpper(user_name_upper);
2130
2131 if ((StrCmpi(username, ADMINISTRATOR_USERNAME) != 0) && (StrCmpi(username, BRIDGE_USER_NAME) != 0) || (cedar->Server == NULL || cedar->Server->ServerType == SERVER_TYPE_STANDALONE))
2132 {
2133 if (IsEmptyStr(c->InProcPrefix))
2134 {
2135 Format(name, sizeof(name), "SID-%s-%u", user_name_upper, Inc(h->SessionCounter));
2136 }
2137 else
2138 {
2139 Format(name, sizeof(name), "SID-%s-[%s]-%u", user_name_upper, c->InProcPrefix, Inc(h->SessionCounter));
2140 }
2141
2142 if (h->IsVgsHub || h->IsVgsSuperRelayHub)
2143 {
2144 UCHAR rand[5];
2145 char tmp[32];
2146
2147 Rand(rand, sizeof(rand));
2148
2149 BinToStr(tmp, sizeof(tmp), rand, sizeof(rand));
2150
2151 StrCat(name, sizeof(name), "-");
2152 StrCat(name, sizeof(name), tmp);
2153 }
2154 }
2155 else
2156 {
2157 UCHAR rand[SHA1_SIZE];
2158 char tmp[MAX_SIZE];
2159 Rand(rand, sizeof(rand));
2160 BinToStr(tmp, sizeof(tmp), rand, 3);
2161
2162 if (StrCmpi(username, BRIDGE_USER_NAME) != 0)
2163 {
2164 Format(name, sizeof(name), "SID-%s-%s", user_name_upper,
2165 tmp);
2166 }
2167 else
2168 {
2169 char pc_name[MAX_SIZE];
2170 TOKEN_LIST *t;
2171
2172 GetMachineName(tmp, sizeof(tmp));
2173 t = ParseToken(tmp, ".");
2174 if (t->NumTokens >= 1)
2175 {
2176 StrCpy(pc_name, sizeof(pc_name), t->Token[0]);
2177 }
2178 else
2179 {
2180 StrCpy(pc_name, sizeof(pc_name), "pc");
2181 }
2182 FreeToken(t);
2183
2184 StrUpper(pc_name);
2185
2186 Format(name, sizeof(name), "SID-%s-%s-%u", user_name_upper, pc_name,
2187 Inc(h->SessionCounter));
2188 }
2189 }
2190
2191 s->Name = CopyStr(name);
2192 s->Policy = policy;
2193 s->InProcMode = inproc_mode;
2194
2195 // Add a SESSION to the HUB
2196 AddSession(h, s);
2197
2198 // Create a key
2199 NewSessionKey(cedar, s->SessionKey, &s->SessionKey32);
2200
2201 // Generate a MAC address for IPC
2202 if (s->InProcMode)
2203 {
2204 if (ipc_mac_address != NULL)
2205 {
2206 Copy(s->IpcMacAddress, ipc_mac_address, 6);
2207 }
2208 else
2209 {
2210 char tmp[MAX_SIZE];
2211 char machine[MAX_SIZE];
2212 UCHAR hash[SHA1_SIZE];
2213
2214 GetMachineName(machine, sizeof(machine));
2215
2216 Format(tmp, sizeof(tmp), "%s@%s@%u", machine, h->Name, s->UniqueId);
2217
2218 StrUpper(tmp);
2219 Trim(tmp);
2220
2221 Sha0(hash, tmp, StrLen(tmp));
2222
2223 s->IpcMacAddress[0] = 0xCA;
2224 s->IpcMacAddress[1] = hash[1];
2225 s->IpcMacAddress[2] = hash[2];
2226 s->IpcMacAddress[3] = hash[3];
2227 s->IpcMacAddress[4] = hash[4];
2228 s->IpcMacAddress[5] = hash[5];
2229
2230 MacToStr(tmp, sizeof(tmp), s->IpcMacAddress);
2231 Debug("MAC Address for IPC: %s\n", tmp);
2232 }
2233 }
2234
2235 return s;
2236 }
2237
2238 // Check whether the specified MAC address is IPC address
IsIpcMacAddress(UCHAR * mac)2239 bool IsIpcMacAddress(UCHAR *mac)
2240 {
2241 // Validate arguments
2242 if (mac == NULL)
2243 {
2244 return false;
2245 }
2246
2247 if (mac[0] == 0xCA)
2248 {
2249 return true;
2250 }
2251
2252 return false;
2253 }
2254
2255 // Display the status on the client
PrintStatus(SESSION * s,wchar_t * str)2256 void PrintStatus(SESSION *s, wchar_t *str)
2257 {
2258 // Validate arguments
2259 if (s == NULL || str == NULL || s->Account == NULL || s->Cedar->Client == NULL
2260 || s->Account->StatusPrinter == NULL)
2261 {
2262 return;
2263 }
2264
2265 // Inform the status to the callback function
2266 s->Account->StatusPrinter(s, str);
2267 }
2268
2269 // Create a cancellation list
NewCancelList()2270 LIST *NewCancelList()
2271 {
2272 return NewList(NULL);
2273 }
2274
2275 // Add a Cancel to the cancellation list
AddCancelList(LIST * o,CANCEL * c)2276 void AddCancelList(LIST *o, CANCEL *c)
2277 {
2278 UINT i;
2279 // Validate arguments
2280 if (o == NULL || c == NULL)
2281 {
2282 return;
2283 }
2284
2285 for (i = 0;i < LIST_NUM(o);i++)
2286 {
2287 CANCEL *t = LIST_DATA(o, i);
2288 if (t == c)
2289 {
2290 return;
2291 }
2292 }
2293
2294 AddRef(c->ref);
2295 Add(o, c);
2296 }
2297
2298 // Issue all cancellations in the cancellation list
CancelList(LIST * o)2299 void CancelList(LIST *o)
2300 {
2301 UINT i;
2302 // Validate arguments
2303 if (o == NULL)
2304 {
2305 return;
2306 }
2307
2308 for (i = 0;i < LIST_NUM(o);i++)
2309 {
2310 CANCEL *c = LIST_DATA(o, i);
2311 Cancel(c);
2312 ReleaseCancel(c);
2313 }
2314
2315 DeleteAll(o);
2316 }
2317
2318 // Release the cancellation list
ReleaseCancelList(LIST * o)2319 void ReleaseCancelList(LIST *o)
2320 {
2321 UINT i;
2322 // Validate arguments
2323 if (o == NULL)
2324 {
2325 return;
2326 }
2327
2328 for (i = 0;i < LIST_NUM(o);i++)
2329 {
2330 CANCEL *c = LIST_DATA(o, i);
2331 ReleaseCancel(c);
2332 }
2333
2334 ReleaseList(o);
2335 }
2336
2337 // Notify to the client
Notify(SESSION * s,UINT code)2338 void Notify(SESSION *s, UINT code)
2339 {
2340 // Validate arguments
2341 if (s == NULL || s->Account == NULL || s->Cedar->Client == NULL)
2342 {
2343 return;
2344 }
2345
2346 CiNotify(s->Cedar->Client);
2347 }
2348
2349
PrepareDHCPRequestForStaticIPv4(SESSION * s,BLOCK * b)2350 UINT PrepareDHCPRequestForStaticIPv4(SESSION *s, BLOCK *b)
2351 {
2352 PKT *pkt = NULL;
2353 DHCPV4_HEADER *dhcp = NULL;
2354 UCHAR *data = NULL;
2355 UINT size = 0;
2356 UINT dhcp_header_size = 0;
2357 UINT dhcp_data_offset = 0;
2358 UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
2359 DHCP_OPTION_LIST *opt = NULL;
2360 USER *user = NULL;
2361 UINT ret_ip = 0;
2362
2363 if ((s->Username == NULL) || (StrLen(s->Username) == 0) || (StrCmpi(s->Username, SNAT_USER_NAME_PRINT) == 0) ||
2364 (StrCmpi( s->Username, BRIDGE_USER_NAME_PRINT) == 0) || (StrCmpi(s->Username, LINK_USER_NAME_PRINT) == 0))
2365 {
2366 return ret_ip;
2367 }
2368
2369 pkt = ParsePacket(b->Buf, b->Size);
2370 if (pkt == NULL)
2371 {
2372 return ret_ip;
2373 }
2374
2375 if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP && pkt->TypeL7 == L7_DHCPV4)
2376 {
2377 if (pkt->L7.DHCPv4Header->OpCode != 1)
2378 {
2379 goto CLEANUP_TP;
2380 }
2381
2382 dhcp = pkt->L7.DHCPv4Header;
2383 dhcp_header_size = sizeof(DHCPV4_HEADER);
2384 dhcp_data_offset = (UINT)(((UCHAR *)pkt->L7.DHCPv4Header) - ((UCHAR *)pkt->MacHeader) + dhcp_header_size);
2385 data = ((UCHAR *)dhcp) + dhcp_header_size;
2386 size = pkt->PacketSize - dhcp_data_offset;
2387
2388 if (dhcp_header_size < 5)
2389 {
2390 goto CLEANUP_TP;
2391 }
2392
2393 // Search for Magic Cookie
2394 while (size >= 5)
2395 {
2396 if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
2397 {
2398 // Found
2399 data += 4;
2400 size -= 4;
2401 opt = ParseDhcpOptionList(data, size);
2402 break;
2403 }
2404
2405 ++data;
2406 --size;
2407 }
2408
2409 if (opt == NULL)
2410 {
2411 goto CLEANUP_TP;
2412 }
2413
2414 if (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST)
2415 {
2416 if (s->Hub != NULL)
2417 {
2418 user = AcGetUser( s->Hub, s->Username );
2419 if (user != NULL)
2420 {
2421 dhcp->ServerIP = GetUserIPv4AddressFromUserNote32(user->Note);
2422 ReleaseUser(user);
2423 if (s->Hub->SecureNAT != NULL && s->Hub->SecureNAT->Nat != NULL)
2424 {
2425 VH *v = s->Hub->SecureNAT->Nat->Virtual;
2426 if (v != NULL && v->UseDhcp == true && v->DhcpLeaseList != NULL)
2427 {
2428 DHCP_LEASE *d = SearchDhcpLeaseByIp(v, dhcp->ServerIP);
2429
2430 // The given static IP address is not used - it's OK
2431 if (d == NULL)
2432 {
2433 ret_ip = dhcp->ServerIP;
2434 }
2435 }
2436 }
2437 }
2438 }
2439 }
2440 }
2441
2442 CLEANUP_TP:
2443 if (opt != NULL)
2444 {
2445 Free(opt);
2446 }
2447
2448 if (pkt != NULL)
2449 {
2450 FreePacket(pkt);
2451 }
2452
2453 return ret_ip;
2454 }
2455
ClearDHCPLeaseRecordForIPv4(SESSION * s,UINT static_ip)2456 void ClearDHCPLeaseRecordForIPv4(SESSION *s, UINT static_ip)
2457 {
2458 if (s == NULL || static_ip == 0)
2459 {
2460 return;
2461 }
2462
2463 if (s->Hub == NULL || s->Hub->SecureNAT == NULL || s->Hub->SecureNAT->Nat == NULL)
2464 {
2465 return;
2466 }
2467
2468 VH *v = s->Hub->SecureNAT->Nat->Virtual;
2469 if (v == NULL || v->DhcpLeaseList == NULL)
2470 {
2471 return;
2472 }
2473
2474 DHCP_LEASE *d = SearchDhcpLeaseByIp(v, static_ip);
2475 if (d == NULL)
2476 {
2477 return;
2478 }
2479
2480 LockList(v->DhcpLeaseList);
2481 {
2482 FreeDhcpLease(d);
2483 Delete(v->DhcpLeaseList, d);
2484 }
2485 UnlockList( v->DhcpLeaseList);
2486 }
2487