1 // SoftEther VPN Source Code - Stable Edition Repository
2 // Cedar Communication Module
3 //
4 // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
5 //
6 // Copyright (c) Daiyuu Nobori.
7 // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
8 // Copyright (c) SoftEther Corporation.
9 // Copyright (c) all contributors on SoftEther VPN project in GitHub.
10 //
11 // All Rights Reserved.
12 //
13 // http://www.softether.org/
14 //
15 // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
16 // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
17 //
18 // License: The Apache License, Version 2.0
19 // https://www.apache.org/licenses/LICENSE-2.0
20 //
21 // DISCLAIMER
22 // ==========
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
31 //
32 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
33 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
34 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
35 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
36 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
37 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
38 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
39 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
40 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
41 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
42 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
43 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
44 // LAW OR COURT RULE.
45 //
46 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
47 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
48 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
49 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
50 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
51 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
52 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
53 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
54 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
55 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
56 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
57 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
58 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
59 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
60 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
61 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
62 // STATEMENT FOR WARNING AND DISCLAIMER.
63 //
64 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
65 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
66 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
67 //
68 //
69 // SOURCE CODE CONTRIBUTION
70 // ------------------------
71 //
72 // Your contribution to SoftEther VPN Project is much appreciated.
73 // Please send patches to us through GitHub.
74 // Read the SoftEther VPN Patch Acceptance Policy in advance:
75 // http://www.softether.org/5-download/src/9.patch
76 //
77 //
78 // DEAR SECURITY EXPERTS
79 // ---------------------
80 //
81 // If you find a bug or a security vulnerability please kindly inform us
82 // about the problem immediately so that we can fix the security problem
83 // to protect a lot of users around the world as soon as possible.
84 //
85 // Our e-mail address for security reports is:
86 // softether-vpn-security [at] softether.org
87 //
88 // Please note that the above e-mail address is not a technical support
89 // inquiry address. If you need technical assistance, please visit
90 // http://www.softether.org/ and ask your question on the users forum.
91 //
92 // Thank you for your cooperation.
93 //
94 //
95 // NO MEMORY OR RESOURCE LEAKS
96 // ---------------------------
97 //
98 // The memory-leaks and resource-leaks verification under the stress
99 // test has been passed before release this source code.
100
101
102 // IPsec_IPC.c
103 // In-process VPN client module
104
105 #include "CedarPch.h"
106
107 // Extract the MS-CHAP v2 authentication information by parsing the password string
ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO * d,char * password)108 bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password)
109 {
110 TOKEN_LIST *t;
111 bool ret = false;
112 // Validate arguments
113 if (d == NULL || password == NULL)
114 {
115 return false;
116 }
117
118 Zero(d, sizeof(IPC_MSCHAP_V2_AUTHINFO));
119
120 if (StartWith(password, IPC_PASSWORD_MSCHAPV2_TAG) == false)
121 {
122 return false;
123 }
124
125 t = ParseTokenWithNullStr(password, ":");
126
127 if (t->NumTokens == 6)
128 {
129 BUF *b1, *b2, *b3, *b4;
130
131 b1 = StrToBin(t->Token[2]);
132 b2 = StrToBin(t->Token[3]);
133 b3 = StrToBin(t->Token[4]);
134 b4 = StrToBin(t->Token[5]);
135
136 if (IsEmptyStr(t->Token[1]) == false && b1->Size == 16 && b2->Size == 16 && b3->Size == 24
137 && b4->Size == 8)
138 {
139 UINT64 eap_client_ptr = 0;
140
141 StrCpy(d->MsChapV2_PPPUsername, sizeof(d->MsChapV2_PPPUsername), t->Token[1]);
142 Copy(d->MsChapV2_ServerChallenge, b1->Buf, 16);
143 Copy(d->MsChapV2_ClientChallenge, b2->Buf, 16);
144 Copy(d->MsChapV2_ClientResponse, b3->Buf, 24);
145 Copy(&eap_client_ptr, b4->Buf, 8);
146
147 d->MsChapV2_EapClient = (EAP_CLIENT *)eap_client_ptr;
148
149 ret = true;
150 }
151
152 FreeBuf(b1);
153 FreeBuf(b2);
154 FreeBuf(b3);
155 FreeBuf(b4);
156 }
157
158 FreeToken(t);
159
160 return ret;
161 }
162
163 // Start an IPC connection asynchronously
NewIPCAsync(CEDAR * cedar,IPC_PARAM * param,SOCK_EVENT * sock_event)164 IPC_ASYNC *NewIPCAsync(CEDAR *cedar, IPC_PARAM *param, SOCK_EVENT *sock_event)
165 {
166 IPC_ASYNC *a;
167 // Validate arguments
168 if (cedar == NULL || param == NULL)
169 {
170 return NULL;
171 }
172
173 a = ZeroMalloc(sizeof(IPC_ASYNC));
174
175 a->TubeForDisconnect = NewTube(0);
176
177 a->Cedar = cedar;
178 AddRef(a->Cedar->ref);
179
180 Copy(&a->Param, param, sizeof(IPC_PARAM));
181
182 if (param->ClientCertificate != NULL)
183 {
184 // Client certificate must be copied for async processing
185 a->Param.ClientCertificate = CloneX(param->ClientCertificate);
186 }
187
188 if (sock_event != NULL)
189 {
190 a->SockEvent = sock_event;
191 AddRef(a->SockEvent->ref);
192 }
193
194 a->Thread = NewThread(IPCAsyncThreadProc, a);
195
196 return a;
197 }
198
199 // asynchronous IPC connection creation thread
IPCAsyncThreadProc(THREAD * thread,void * param)200 void IPCAsyncThreadProc(THREAD *thread, void *param)
201 {
202 IPC_ASYNC *a;
203 // Validate arguments
204 if (thread == NULL || param == NULL)
205 {
206 return;
207 }
208
209 a = (IPC_ASYNC *)param;
210
211 // Attempt to connect
212 a->Ipc = NewIPCByParam(a->Cedar, &a->Param, &a->ErrorCode);
213
214 if (a->Ipc != NULL)
215 {
216 if (a->Param.IsL3Mode)
217 {
218 DHCP_OPTION_LIST cao;
219
220 Zero(&cao, sizeof(cao));
221
222 // Get an IP address from the DHCP server in the case of L3 mode
223 Debug("IPCDhcpAllocateIPEx() start...\n");
224 if (IPCDhcpAllocateIPEx(a->Ipc, &cao, a->TubeForDisconnect, a->Param.IsOpenVPN))
225 {
226 UINT t;
227 IP ip, subnet, gw;
228
229 Debug("IPCDhcpAllocateIPEx() Ok.\n");
230
231 // Calculate the DHCP update interval
232 t = cao.LeaseTime;
233 if (t == 0)
234 {
235 t = 600;
236 }
237
238 t = t / 3;
239
240 if (t == 0)
241 {
242 t = 1;
243 }
244
245 // Save the options list
246 Copy(&a->L3ClientAddressOption, &cao, sizeof(DHCP_OPTION_LIST));
247 a->L3DhcpRenewInterval = t * 1000;
248
249 // Set the obtained IP address parameters to the IPC virtual host
250 UINTToIP(&ip, cao.ClientAddress);
251 UINTToIP(&subnet, cao.SubnetMask);
252 UINTToIP(&gw, cao.Gateway);
253
254 IPCSetIPv4Parameters(a->Ipc, &ip, &subnet, &gw, &cao.ClasslessRoute);
255
256 a->L3NextDhcpRenewTick = Tick64() + a->L3DhcpRenewInterval;
257 }
258 else
259 {
260 Debug("IPCDhcpAllocateIPEx() Error.\n");
261
262 a->DhcpAllocFailed = true;
263
264 FreeIPC(a->Ipc);
265 a->Ipc = NULL;
266 }
267 }
268 }
269
270 // Procedure complete
271 a->Done = true;
272
273 if (a->SockEvent != NULL)
274 {
275 SetSockEvent(a->SockEvent);
276 }
277 }
278
279 // Release the IPC asynchronous connection object
FreeIPCAsync(IPC_ASYNC * a)280 void FreeIPCAsync(IPC_ASYNC *a)
281 {
282 // Validate arguments
283 if (a == NULL)
284 {
285 return;
286 }
287
288 TubeDisconnect(a->TubeForDisconnect);
289 WaitThread(a->Thread, INFINITE);
290 ReleaseThread(a->Thread);
291
292 if (a->Ipc != NULL)
293 {
294 FreeIPC(a->Ipc);
295 a->Ipc = NULL;
296 }
297
298 if (a->SockEvent != NULL)
299 {
300 ReleaseSockEvent(a->SockEvent);
301 }
302
303 ReleaseCedar(a->Cedar);
304
305 ReleaseTube(a->TubeForDisconnect);
306
307 if (a->Param.ClientCertificate != NULL)
308 {
309 FreeX(a->Param.ClientCertificate);
310 }
311
312 Free(a);
313 }
314
315 // Start a new IPC connection by specifying the parameter structure
NewIPCByParam(CEDAR * cedar,IPC_PARAM * param,UINT * error_code)316 IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code)
317 {
318 IPC *ipc;
319 // Validate arguments
320 if (cedar == NULL || param == NULL)
321 {
322 return NULL;
323 }
324
325 ipc = NewIPC(cedar, param->ClientName, param->Postfix, param->HubName,
326 param->UserName, param->Password, error_code, ¶m->ClientIp,
327 param->ClientPort, ¶m->ServerIp, param->ServerPort,
328 param->ClientHostname, param->CryptName,
329 param->BridgeMode, param->Mss, NULL, param->ClientCertificate, param->Layer);
330
331 return ipc;
332 }
333
334 // Start a new IPC connection
NewIPC(CEDAR * cedar,char * client_name,char * postfix,char * hubname,char * username,char * password,UINT * error_code,IP * client_ip,UINT client_port,IP * server_ip,UINT server_port,char * client_hostname,char * crypt_name,bool bridge_mode,UINT mss,EAP_CLIENT * eap_client,X * client_certificate,UINT layer)335 IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password,
336 UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port,
337 char *client_hostname, char *crypt_name,
338 bool bridge_mode, UINT mss, EAP_CLIENT *eap_client, X *client_certificate,
339 UINT layer)
340 {
341 IPC *ipc;
342 UINT dummy_int = 0;
343 SOCK *a;
344 SOCK *s;
345 PACK *p;
346 UINT err = ERR_INTERNAL_ERROR;
347 char server_str[MAX_SIZE];
348 char macstr[30];
349 UINT server_ver, server_build;
350 UCHAR unique[SHA1_SIZE];
351 NODE_INFO info;
352 BUF *b;
353 UCHAR mschap_v2_server_response_20[20];
354 UINT64 u64;
355 // Validate arguments
356 if (cedar == NULL || username == NULL || password == NULL || client_hostname == NULL)
357 {
358 return NULL;
359 }
360 if (IsEmptyStr(client_name))
361 {
362 client_name = "InProc VPN Connection";
363 }
364 if (IsEmptyStr(crypt_name))
365 {
366 crypt_name = "";
367 }
368 if (error_code == NULL)
369 {
370 error_code = &dummy_int;
371 }
372
373 Zero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
374
375 err = *error_code = ERR_INTERNAL_ERROR;
376
377 a = GetInProcListeningSock(cedar);
378 if (a == NULL)
379 {
380 return NULL;
381 }
382
383 ipc = ZeroMalloc(sizeof(IPC));
384
385 ipc->Cedar = cedar;
386 AddRef(cedar->ref);
387
388 ipc->Layer = layer;
389 if (ipc->Layer == 0)
390 {
391 ipc->Layer = IPC_LAYER_2;
392 }
393
394 ipc->FlushList = NewTubeFlushList();
395
396 StrCpy(ipc->ClientHostname, sizeof(ipc->ClientHostname), client_hostname);
397 StrCpy(ipc->HubName, sizeof(ipc->HubName), hubname);
398 StrCpy(ipc->UserName, sizeof(ipc->UserName), username);
399 StrCpy(ipc->Password, sizeof(ipc->Password), password);
400
401 // Connect the in-process socket
402 s = ConnectInProc(a, client_ip, client_port, server_ip, server_port);
403 if (s == NULL)
404 {
405 goto LABEL_ERROR;
406 }
407
408 // Protocol initialization process
409 if (ClientUploadSignature(s) == false)
410 {
411 err = ERR_DISCONNECTED;
412 goto LABEL_ERROR;
413 }
414
415 p = HttpClientRecv(s);
416 if (p == NULL)
417 {
418 err = ERR_DISCONNECTED;
419 goto LABEL_ERROR;
420 }
421
422 err = GetErrorFromPack(p);
423 if (err != ERR_NO_ERROR)
424 {
425 FreePack(p);
426 goto LABEL_ERROR;
427 }
428
429 if (GetHello(p, ipc->random, &server_ver, &server_build, server_str, sizeof(server_str)) == false)
430 {
431 FreePack(p);
432 err = ERR_DISCONNECTED;
433 goto LABEL_ERROR;
434 }
435
436 FreePack(p);
437
438 // Upload the authentication data
439 if (client_certificate != NULL)
440 {
441 p = PackLoginWithOpenVPNCertificate(hubname, username, client_certificate);
442 }
443 else
444 {
445 p = PackLoginWithPlainPassword(hubname, username, password);
446 }
447 PackAddStr(p, "hello", client_name);
448 PackAddInt(p, "client_ver", cedar->Version);
449 PackAddInt(p, "client_build", cedar->Build);
450 PackAddInt(p, "max_connection", 1);
451 PackAddInt(p, "use_encrypt", 0);
452 PackAddInt(p, "use_compress", 0);
453 PackAddInt(p, "half_connection", 0);
454 PackAddInt(p, "adjust_mss", mss);
455 PackAddBool(p, "require_bridge_routing_mode", bridge_mode);
456 PackAddBool(p, "require_monitor_mode", false);
457 PackAddBool(p, "qos", false);
458
459 if (eap_client != NULL)
460 {
461 UINT64 ptr = (UINT64)eap_client;
462 PackAddInt64(p, "release_me_eap_client", ptr);
463
464 AddRef(eap_client->Ref);
465 }
466
467 // Unique ID is determined by the sum of the connecting client IP address and the client_name
468 b = NewBuf();
469 WriteBuf(b, client_ip, sizeof(IP));
470 WriteBufStr(b, client_name);
471 WriteBufStr(b, crypt_name);
472
473 HashSha1(unique, b->Buf, b->Size);
474
475 FreeBuf(b);
476
477 PackAddData(p, "unique_id", unique, SHA1_SIZE);
478
479 PackAddStr(p, "inproc_postfix", postfix);
480 PackAddStr(p, "inproc_cryptname", crypt_name);
481 PackAddInt(p, "inproc_layer", ipc->Layer);
482
483 // Node information
484 Zero(&info, sizeof(info));
485 StrCpy(info.ClientProductName, sizeof(info.ClientProductName), client_name);
486 info.ClientProductVer = Endian32(cedar->Version);
487 info.ClientProductBuild = Endian32(cedar->Build);
488 StrCpy(info.ServerProductName, sizeof(info.ServerProductName), server_str);
489 info.ServerProductVer = Endian32(server_ver);
490 info.ServerProductBuild = Endian32(server_build);
491 StrCpy(info.ClientOsName, sizeof(info.ClientOsName), client_name);
492 StrCpy(info.ClientOsVer, sizeof(info.ClientOsVer), "-");
493 StrCpy(info.ClientOsProductId, sizeof(info.ClientOsProductId), "-");
494 info.ClientIpAddress = IPToUINT(&s->LocalIP);
495 info.ClientPort = Endian32(s->LocalPort);
496 StrCpy(info.ClientHostname, sizeof(info.ClientHostname), ipc->ClientHostname);
497 IPToStr(info.ServerHostname, sizeof(info.ServerHostname), &s->RemoteIP);
498 info.ServerIpAddress = IPToUINT(&s->RemoteIP);
499 info.ServerPort = Endian32(s->RemotePort);
500 StrCpy(info.HubName, sizeof(info.HubName), hubname);
501 Copy(info.UniqueId, unique, 16);
502 if (IsIP6(&s->LocalIP))
503 {
504 Copy(info.ClientIpAddress6, s->LocalIP.ipv6_addr, 16);
505 }
506 if (IsIP6(&s->RemoteIP))
507 {
508 Copy(info.ServerIpAddress6, s->RemoteIP.ipv6_addr, 16);
509 }
510 OutRpcNodeInfo(p, &info);
511
512 if (HttpClientSend(s, p) == false)
513 {
514 FreePack(p);
515 err = ERR_DISCONNECTED;
516 goto LABEL_ERROR;
517 }
518
519 FreePack(p);
520
521 // Receive a Welcome packet
522 p = HttpClientRecv(s);
523 if (p == NULL)
524 {
525 err = ERR_DISCONNECTED;
526 goto LABEL_ERROR;
527 }
528
529 err = GetErrorFromPack(p);
530 if (err != ERR_NO_ERROR)
531 {
532 FreePack(p);
533 goto LABEL_ERROR;
534 }
535
536 if (ParseWelcomeFromPack(p, ipc->SessionName, sizeof(ipc->SessionName),
537 ipc->ConnectionName, sizeof(ipc->ConnectionName), &ipc->Policy) == false)
538 {
539 err = ERR_PROTOCOL_ERROR;
540 FreePack(p);
541 goto LABEL_ERROR;
542 }
543
544 if (PackGetData2(p, "IpcMacAddress", ipc->MacAddress, 6) == false || IsZero(ipc->MacAddress, 6))
545 {
546 err = ERR_PROTOCOL_ERROR;
547 FreePack(p);
548 goto LABEL_ERROR;
549 }
550
551 if (PackGetData2(p, "IpcMsChapV2ServerResponse", mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20)))
552 {
553 Copy(ipc->MsChapV2_ServerResponse, mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
554 }
555
556 PackGetStr(p, "IpcHubName", ipc->HubName, sizeof(ipc->HubName));
557 Debug("IPC Hub Name: %s\n", ipc->HubName);
558
559 MacToStr(macstr, sizeof(macstr), ipc->MacAddress);
560
561 Debug("IPC: Session = %s, Connection = %s, Mac = %s\n", ipc->SessionName, ipc->ConnectionName, macstr);
562
563 u64 = PackGetInt64(p, "IpcSessionSharedBuffer");
564 ipc->IpcSessionSharedBuffer = (SHARED_BUFFER *)u64;
565 ipc->IpcSessionShared = ipc->IpcSessionSharedBuffer->Data;
566
567 FreePack(p);
568
569 ReleaseSock(a);
570 ipc->Sock = s;
571
572 Debug("NewIPC() Succeed.\n");
573
574 ipc->Interrupt = NewInterruptManager();
575
576 // Create an ARP table
577 ipc->ArpTable = NewList(IPCCmpArpTable);
578
579 // Create an IPv4 reception queue
580 ipc->IPv4RecviedQueue = NewQueue();
581
582 return ipc;
583
584 LABEL_ERROR:
585 Debug("NewIPC() Failed: Err = %u\n", err);
586 Disconnect(s);
587 ReleaseSock(s);
588 ReleaseSock(a);
589 FreeIPC(ipc);
590 *error_code = err;
591 return NULL;
592 }
593
594 // Create a new IPC based on SOCK
NewIPCBySock(CEDAR * cedar,SOCK * s,void * mac_address)595 IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address)
596 {
597 IPC *ipc;
598 // Validate arguments
599 if (cedar == NULL || mac_address == NULL || s == NULL)
600 {
601 return NULL;
602 }
603
604 ipc = ZeroMalloc(sizeof(IPC));
605
606 ipc->Cedar = cedar;
607 AddRef(cedar->ref);
608
609 ipc->Sock = s;
610 AddRef(s->ref);
611
612 Copy(ipc->MacAddress, mac_address, 6);
613
614 ipc->Interrupt = NewInterruptManager();
615
616 // Create an ARP table
617 ipc->ArpTable = NewList(IPCCmpArpTable);
618
619 // Create an IPv4 reception queue
620 ipc->IPv4RecviedQueue = NewQueue();
621
622 ipc->FlushList = NewTubeFlushList();
623
624 return ipc;
625 }
626
627 // Get whether the IPC is connected
IsIPCConnected(IPC * ipc)628 bool IsIPCConnected(IPC *ipc)
629 {
630 // Validate arguments
631 if (ipc == NULL)
632 {
633 return false;
634 }
635
636 if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false)
637 {
638 return false;
639 }
640
641 return true;
642 }
643
644 // Get to hit the SOCK_EVENT when a new data has arrived in the IPC
IPCSetSockEventWhenRecvL2Packet(IPC * ipc,SOCK_EVENT * e)645 void IPCSetSockEventWhenRecvL2Packet(IPC *ipc, SOCK_EVENT *e)
646 {
647 // Validate arguments
648 if (ipc == NULL || e == NULL)
649 {
650 return;
651 }
652
653 JoinSockToSockEvent(ipc->Sock, e);
654 }
655
656 // End of IPC connection
FreeIPC(IPC * ipc)657 void FreeIPC(IPC *ipc)
658 {
659 UINT i;
660 // Validate arguments
661 if (ipc == NULL)
662 {
663 return;
664 }
665
666 FreeTubeFlushList(ipc->FlushList);
667
668 Disconnect(ipc->Sock);
669 ReleaseSock(ipc->Sock);
670
671 if (ipc->Policy != NULL)
672 {
673 Free(ipc->Policy);
674 }
675
676 ReleaseCedar(ipc->Cedar);
677
678 FreeInterruptManager(ipc->Interrupt);
679
680 for (i = 0;i < LIST_NUM(ipc->ArpTable);i++)
681 {
682 IPC_ARP *a = LIST_DATA(ipc->ArpTable, i);
683 IPCFreeARP(a);
684 }
685
686 ReleaseList(ipc->ArpTable);
687
688 while (true)
689 {
690 BLOCK *b = GetNext(ipc->IPv4RecviedQueue);
691 if (b == NULL)
692 {
693 break;
694 }
695
696 FreeBlock(b);
697 }
698
699 ReleaseQueue(ipc->IPv4RecviedQueue);
700
701 ReleaseSharedBuffer(ipc->IpcSessionSharedBuffer);
702
703 Free(ipc);
704 }
705
706 // Set User Class option if corresponding Virtual Hub optin is set
IPCDhcpSetConditionalUserClass(IPC * ipc,DHCP_OPTION_LIST * req)707 void IPCDhcpSetConditionalUserClass(IPC *ipc, DHCP_OPTION_LIST *req)
708 {
709 HUB *hub;
710
711 hub = GetHub(ipc->Cedar, ipc->HubName);
712 if (hub == NULL)
713 {
714 return;
715 }
716
717 if (hub->Option && hub->Option->UseHubNameAsDhcpUserClassOption)
718 {
719 StrCpy(req->UserClass, sizeof(req->UserClass), ipc->HubName);
720 }
721 ReleaseHub(hub);
722 }
723
724 // Release the IP address from the DHCP server
IPCDhcpFreeIP(IPC * ipc,IP * dhcp_server)725 void IPCDhcpFreeIP(IPC *ipc, IP *dhcp_server)
726 {
727 DHCP_OPTION_LIST req;
728 UINT tran_id = Rand32();
729 // Validate arguments
730 if (ipc == NULL || dhcp_server == NULL)
731 {
732 return;
733 }
734
735 Zero(&req, sizeof(req));
736 req.Opcode = DHCP_RELEASE;
737 req.ServerAddress = IPToUINT(dhcp_server);
738 IPCDhcpSetConditionalUserClass(ipc, &req);
739
740 FreeDHCPv4Data(IPCSendDhcpRequest(ipc, NULL, tran_id, &req, 0, 0, NULL));
741 }
742
743 // Update the IP address using the DHCP
IPCDhcpRenewIP(IPC * ipc,IP * dhcp_server)744 void IPCDhcpRenewIP(IPC *ipc, IP *dhcp_server)
745 {
746 DHCP_OPTION_LIST req;
747 UINT tran_id = Rand32();
748 // Validate arguments
749 if (ipc == NULL || dhcp_server == NULL)
750 {
751 return;
752 }
753
754 // Send a DHCP Request
755 Zero(&req, sizeof(req));
756 req.Opcode = DHCP_REQUEST;
757 StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
758 req.RequestedIp = IPToUINT(&ipc->ClientIPAddress);
759 IPCDhcpSetConditionalUserClass(ipc, &req);
760
761 FreeDHCPv4Data(IPCSendDhcpRequest(ipc, dhcp_server, tran_id, &req, 0, 0, NULL));
762 }
763
764 // Get the information other than the IP address with using DHCP
IPCDhcpRequestInformIP(IPC * ipc,DHCP_OPTION_LIST * opt,TUBE * discon_poll_tube,IP * client_ip)765 bool IPCDhcpRequestInformIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, IP *client_ip)
766 {
767 DHCP_OPTION_LIST req;
768 DHCPV4_DATA *d;
769 UINT tran_id = Rand32();
770 bool ok;
771 // Validate arguments
772 if (ipc == NULL || opt == NULL || client_ip == NULL)
773 {
774 return false;
775 }
776
777 // Send a DHCP Inform
778 Zero(&req, sizeof(req));
779 req.Opcode = DHCP_INFORM;
780 req.ClientAddress = IPToUINT(client_ip);
781 StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
782 IPCDhcpSetConditionalUserClass(ipc, &req);
783
784 d = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_ACK, IPC_DHCP_TIMEOUT, discon_poll_tube);
785 if (d == NULL)
786 {
787 return false;
788 }
789
790 // Analyze the DHCP Ack
791 ok = true;
792 if (d->ParsedOptionList->SubnetMask == 0)
793 {
794 ok = false;
795 }
796
797 if (ok == false)
798 {
799 FreeDHCPv4Data(d);
800 return false;
801 }
802
803 Copy(opt, d->ParsedOptionList, sizeof(DHCP_OPTION_LIST));
804
805 FreeDHCPv4Data(d);
806
807 return true;
808 }
809
810 // Make a request for IP addresses using DHCP
IPCDhcpAllocateIP(IPC * ipc,DHCP_OPTION_LIST * opt,TUBE * discon_poll_tube)811 bool IPCDhcpAllocateIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube)
812 {
813 return IPCDhcpAllocateIPEx(ipc, opt, discon_poll_tube, false);
814 }
IPCDhcpAllocateIPEx(IPC * ipc,DHCP_OPTION_LIST * opt,TUBE * discon_poll_tube,bool openvpn_compatible)815 bool IPCDhcpAllocateIPEx(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, bool openvpn_compatible)
816 {
817 DHCP_OPTION_LIST req;
818 DHCPV4_DATA *d, *d2;
819 UINT tran_id = Rand32();
820 bool ok;
821 UINT request_ip = 0;
822 IP current_scanning_ip;
823 UCHAR current_scanning_addr8;
824 UCHAR begin_scanning_addr8;
825 UINT64 giveup = Tick64() + (UINT64)IPC_DHCP_TIMEOUT_TOTAL_GIVEUP;
826 LIST *release_list;
827 bool ret = false;
828 // Validate arguments
829 if (ipc == NULL || opt == NULL)
830 {
831 return false;
832 }
833
834 release_list = NewListFast(NULL);
835
836 Zero(¤t_scanning_ip, sizeof(current_scanning_ip));
837 current_scanning_addr8 = 0;
838 begin_scanning_addr8 = 0;
839
840 LABEL_RETRY_FOR_OPENVPN:
841 tran_id = Rand32();
842 // Send a DHCP Discover
843 Zero(&req, sizeof(req));
844 req.RequestedIp = request_ip;
845 req.Opcode = DHCP_DISCOVER;
846 StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
847 IPCDhcpSetConditionalUserClass(ipc, &req);
848
849 d = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_OFFER, IPC_DHCP_TIMEOUT, discon_poll_tube);
850 if (d == NULL)
851 {
852 goto LABEL_CLEANUP;
853 }
854
855 // Analyze the DHCP Offer
856 ok = true;
857 if (IsValidUnicastIPAddressUINT4(d->ParsedOptionList->ClientAddress) == false)
858 {
859 ok = false;
860 }
861 if (IsValidUnicastIPAddressUINT4(d->ParsedOptionList->ServerAddress) == false)
862 {
863 ok = false;
864 }
865 if (d->ParsedOptionList->SubnetMask == 0)
866 {
867 ok = false;
868 }
869 if (d->ParsedOptionList->LeaseTime == 0)
870 {
871 d->ParsedOptionList->LeaseTime = IPC_DHCP_DEFAULT_LEASE;
872 }
873 if (d->ParsedOptionList->LeaseTime <= IPC_DHCP_MIN_LEASE)
874 {
875 d->ParsedOptionList->LeaseTime = IPC_DHCP_MIN_LEASE;
876 }
877
878 if (ok == false)
879 {
880 FreeDHCPv4Data(d);
881 goto LABEL_CLEANUP;
882 }
883
884 if (openvpn_compatible)
885 {
886 UINT ip = d->ParsedOptionList->ClientAddress;
887
888 if (OvsIsCompatibleL3IP(ip) == false)
889 {
890 char tmp[64];
891
892 DHCP_OPTION_LIST req;
893 IPC_DHCP_RELESAE_QUEUE *q;
894
895 // If the offered IP address is not used, place the address
896 // in release memo list to release at the end of this function
897 Zero(&req, sizeof(req));
898 req.Opcode = DHCP_RELEASE;
899 req.ServerAddress = d->ParsedOptionList->ServerAddress;
900
901 q = ZeroMalloc(sizeof(IPC_DHCP_RELESAE_QUEUE));
902 Copy(&q->Req, &req, sizeof(DHCP_OPTION_LIST));
903 q->TranId = tran_id;
904 Copy(q->MacAddress, ipc->MacAddress, 6);
905
906 Add(release_list, q);
907
908 FreeDHCPv4Data(d);
909
910 if (Tick64() >= giveup)
911 {
912 goto LABEL_CLEANUP;
913 }
914
915 if (IsZero(¤t_scanning_ip, sizeof(IP)))
916 {
917 UINTToIP(¤t_scanning_ip, ip);
918 current_scanning_addr8 = current_scanning_ip.addr[3];
919
920 if ((current_scanning_addr8 % 4) != 1)
921 {
922 current_scanning_addr8 = (UCHAR)(((((UINT)current_scanning_addr8 - 1) / 4) + 1) * 4 + 1);
923 }
924
925 begin_scanning_addr8 = current_scanning_addr8;
926 }
927 else
928 {
929 current_scanning_addr8 += 4;
930
931 if (current_scanning_addr8 == begin_scanning_addr8)
932 {
933 goto LABEL_CLEANUP;
934 }
935 }
936
937 current_scanning_ip.addr[3] = current_scanning_addr8;
938
939 request_ip = IPToUINT(¤t_scanning_ip);
940
941 IPToStr32(tmp, sizeof(tmp), request_ip);
942
943 // Generate another MAC address
944 ipc->MacAddress[5]++;
945
946 Debug("Trying Allocating IP for OpenVPN: %s\n", tmp);
947
948 goto LABEL_RETRY_FOR_OPENVPN;
949 }
950 }
951
952 // Send a DHCP Request
953 Zero(&req, sizeof(req));
954 req.Opcode = DHCP_REQUEST;
955 StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
956 req.ServerAddress = d->ParsedOptionList->ServerAddress;
957 req.RequestedIp = d->ParsedOptionList->ClientAddress;
958 IPCDhcpSetConditionalUserClass(ipc, &req);
959
960 d2 = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_ACK, IPC_DHCP_TIMEOUT, discon_poll_tube);
961 if (d2 == NULL)
962 {
963 FreeDHCPv4Data(d);
964 goto LABEL_CLEANUP;
965 }
966
967 // Analyze the DHCP Ack
968 ok = true;
969 if (IsValidUnicastIPAddressUINT4(d2->ParsedOptionList->ClientAddress) == false)
970 {
971 ok = false;
972 }
973 if (IsValidUnicastIPAddressUINT4(d2->ParsedOptionList->ServerAddress) == false)
974 {
975 ok = false;
976 }
977 if (d2->ParsedOptionList->SubnetMask == 0)
978 {
979 ok = false;
980 }
981 if (d2->ParsedOptionList->LeaseTime == 0)
982 {
983 d2->ParsedOptionList->LeaseTime = IPC_DHCP_DEFAULT_LEASE;
984 }
985 if (d2->ParsedOptionList->LeaseTime <= IPC_DHCP_MIN_LEASE)
986 {
987 d2->ParsedOptionList->LeaseTime = IPC_DHCP_MIN_LEASE;
988 }
989
990 if (ok == false)
991 {
992 FreeDHCPv4Data(d);
993 FreeDHCPv4Data(d2);
994 goto LABEL_CLEANUP;
995 }
996
997 Copy(opt, d2->ParsedOptionList, sizeof(DHCP_OPTION_LIST));
998
999 FreeDHCPv4Data(d);
1000 FreeDHCPv4Data(d2);
1001
1002 ret = true;
1003
1004 LABEL_CLEANUP:
1005 if (release_list != NULL)
1006 {
1007 // Release the IP address that was acquired from the DHCP server to no avail on the way
1008 UINT i;
1009 UCHAR mac_backup[6];
1010
1011 Copy(mac_backup, ipc->MacAddress, 6);
1012
1013 for (i = 0;i < LIST_NUM(release_list);i++)
1014 {
1015 IPC_DHCP_RELESAE_QUEUE *q = LIST_DATA(release_list, i);
1016
1017 Copy(ipc->MacAddress, q->MacAddress, 6);
1018 FreeDHCPv4Data(IPCSendDhcpRequest(ipc, NULL, q->TranId, &q->Req, 0, 0, NULL));
1019
1020 IPCProcessInterrupts(ipc);
1021
1022 Free(q);
1023 }
1024
1025 Copy(ipc->MacAddress, mac_backup, 6);
1026
1027 ReleaseList(release_list);
1028 }
1029 return ret;
1030 }
1031
1032 // Send out a DHCP request, and wait for a corresponding response
IPCSendDhcpRequest(IPC * ipc,IP * dest_ip,UINT tran_id,DHCP_OPTION_LIST * opt,UINT expecting_code,UINT timeout,TUBE * discon_poll_tube)1033 DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt, UINT expecting_code, UINT timeout, TUBE *discon_poll_tube)
1034 {
1035 UINT resend_interval;
1036 UINT64 giveup_time;
1037 UINT64 next_send_time = 0;
1038 TUBE *tubes[3];
1039 UINT num_tubes = 0;
1040 // Validate arguments
1041 if (ipc == NULL || opt == NULL || (expecting_code != 0 && timeout == 0))
1042 {
1043 return NULL;
1044 }
1045
1046 // Retransmission interval
1047 resend_interval = MAX(1, (timeout / 3) - 100);
1048
1049 // Time-out time
1050 giveup_time = Tick64() + (UINT64)timeout;
1051
1052 AddInterrupt(ipc->Interrupt, giveup_time);
1053
1054 tubes[num_tubes++] = ipc->Sock->RecvTube;
1055 tubes[num_tubes++] = ipc->Sock->SendTube;
1056
1057 if (discon_poll_tube != NULL)
1058 {
1059 tubes[num_tubes++] = discon_poll_tube;
1060 }
1061
1062 while (true)
1063 {
1064 UINT64 now = Tick64();
1065 BUF *dhcp_packet;
1066
1067 IPCFlushArpTable(ipc);
1068
1069 // Time-out inspection
1070 if ((expecting_code != 0) && (now >= giveup_time))
1071 {
1072 return NULL;
1073 }
1074
1075 // Send by building a DHCP packet periodically
1076 if (next_send_time == 0 || next_send_time <= now)
1077 {
1078 dhcp_packet = IPCBuildDhcpRequest(ipc, dest_ip, tran_id, opt);
1079 if (dhcp_packet == NULL)
1080 {
1081 return NULL;
1082 }
1083
1084 IPCSendIPv4(ipc, dhcp_packet->Buf, dhcp_packet->Size);
1085
1086 FreeBuf(dhcp_packet);
1087
1088 if (expecting_code == 0)
1089 {
1090 return NULL;
1091 }
1092
1093 next_send_time = now + (UINT64)resend_interval;
1094
1095 AddInterrupt(ipc->Interrupt, next_send_time);
1096 }
1097
1098 // Happy processing
1099 IPCProcessL3Events(ipc);
1100
1101 while (true)
1102 {
1103 // Receive a packet
1104 BLOCK *b = IPCRecvIPv4(ipc);
1105 PKT *pkt;
1106 DHCPV4_DATA *dhcp;
1107
1108 if (b == NULL)
1109 {
1110 break;
1111 }
1112
1113 // Parse the packet
1114 pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
1115
1116 dhcp = ParseDHCPv4Data(pkt);
1117
1118 if (dhcp != NULL)
1119 {
1120 if (Endian32(dhcp->Header->TransactionId) == tran_id && dhcp->OpCode == expecting_code)
1121 {
1122 // Expected operation code and transaction ID are returned
1123 FreePacketWithData(pkt);
1124 FreeBlock(b);
1125
1126 return dhcp;
1127 }
1128
1129 FreeDHCPv4Data(dhcp);
1130 }
1131
1132 FreePacketWithData(pkt);
1133
1134 FreeBlock(b);
1135 }
1136
1137 if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false ||
1138 (discon_poll_tube != NULL && IsTubeConnected(discon_poll_tube) == false))
1139 {
1140 // Session is disconnected
1141 return NULL;
1142 }
1143
1144 // Keep the CPU waiting
1145 WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(ipc->Interrupt));
1146 }
1147
1148 return NULL;
1149 }
1150
1151 // Build a DHCP request packet
IPCBuildDhcpRequest(IPC * ipc,IP * dest_ip,UINT tran_id,DHCP_OPTION_LIST * opt)1152 BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt)
1153 {
1154 IPV4_HEADER ip;
1155 UDP_HEADER* udp;
1156 DHCPV4_HEADER dhcp;
1157 UINT blank_size = 128 + 64;
1158 BUF *ret;
1159 BUF *b;
1160 UDPV4_PSEUDO_HEADER *ph;
1161 UINT ph_size;
1162 UINT udp_size;
1163 UINT magic_number = Endian32(DHCP_MAGIC_COOKIE);
1164 USHORT checksum;
1165 // Validate arguments
1166 if (ipc == NULL || opt == NULL)
1167 {
1168 return NULL;
1169 }
1170
1171 // DHCPv4 Options
1172 b = IPCBuildDhcpRequestOptions(ipc, opt);
1173 if (b == NULL)
1174 {
1175 return NULL;
1176 }
1177
1178 // DHCPv4 Header
1179 Zero(&dhcp, sizeof(dhcp));
1180 dhcp.OpCode = 1;
1181 dhcp.HardwareType = ARP_HARDWARE_TYPE_ETHERNET;
1182 dhcp.HardwareAddressSize = 6;
1183 dhcp.Hops = 0;
1184 dhcp.TransactionId = Endian32(tran_id);
1185 dhcp.ClientIP = IPToUINT(&ipc->ClientIPAddress);
1186 if (dhcp.ClientIP == 0)
1187 {
1188 dhcp.ClientIP = opt->ClientAddress;
1189 }
1190 Copy(dhcp.ClientMacAddress, ipc->MacAddress, 6);
1191
1192 // UDP pseudo header
1193 ph_size = b->Size + sizeof(dhcp) + blank_size + sizeof(UINT) + sizeof(UDPV4_PSEUDO_HEADER);
1194 udp_size = b->Size + sizeof(dhcp) + blank_size + sizeof(UINT) + sizeof(UDP_HEADER);
1195
1196 ph = ZeroMalloc(ph_size);
1197 ph->SrcIP = IPToUINT(&ipc->ClientIPAddress);
1198 ph->DstIP = IPToUINT(dest_ip);
1199 ph->Protocol = IP_PROTO_UDP;
1200 ph->PacketLength1 = Endian16(udp_size);
1201 ph->SrcPort = Endian16(NAT_DHCP_CLIENT_PORT);
1202 ph->DstPort = Endian16(NAT_DHCP_SERVER_PORT);
1203 ph->PacketLength2 = Endian16(udp_size);
1204
1205 Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER), &dhcp, sizeof(dhcp));
1206 Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER) + sizeof(dhcp) + blank_size, &magic_number, sizeof(UINT));
1207 Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER) + sizeof(dhcp) + blank_size + sizeof(UINT),
1208 b->Buf, b->Size);
1209
1210 // UDP Header
1211 udp = (UDP_HEADER *)(((UCHAR *)ph) + 12);
1212
1213 // Calculate the checksum
1214 checksum = IpChecksum(ph, ph_size);
1215 if (checksum == 0x0000)
1216 {
1217 checksum = 0xffff;
1218 }
1219 udp->Checksum = checksum;
1220
1221 // IP Header
1222 Zero(&ip, sizeof(ip));
1223 IPV4_SET_VERSION(&ip, 4);
1224 IPV4_SET_HEADER_LEN(&ip, 5);
1225 ip.Identification = Rand16();
1226 ip.TimeToLive = 128;
1227 ip.Protocol = IP_PROTO_UDP;
1228 ip.SrcIP = IPToUINT(&ipc->ClientIPAddress);
1229 if (dest_ip != NULL)
1230 {
1231 ip.DstIP = IPToUINT(dest_ip);
1232 }
1233 else
1234 {
1235 ip.DstIP = Endian32(0xffffffff);
1236 }
1237 ip.TotalLength = Endian16((USHORT)(sizeof(IPV4_HEADER) + udp_size));
1238 ip.Checksum = IpChecksum(&ip, sizeof(IPV4_HEADER));
1239
1240 ret = NewBuf();
1241
1242 WriteBuf(ret, &ip, sizeof(IPV4_HEADER));
1243 WriteBuf(ret, udp, udp_size);
1244
1245 FreeBuf(b);
1246 Free(ph);
1247
1248 return ret;
1249 }
1250
1251 // Build a option data in the DHCP request packet
IPCBuildDhcpRequestOptions(IPC * ipc,DHCP_OPTION_LIST * opt)1252 BUF *IPCBuildDhcpRequestOptions(IPC *ipc, DHCP_OPTION_LIST *opt)
1253 {
1254 LIST *o;
1255 UCHAR opcode;
1256 UCHAR client_id[7];
1257 BUF *ret;
1258 // Validate arguments
1259 if (ipc == NULL || opt == NULL)
1260 {
1261 return NULL;
1262 }
1263
1264 o = NewListFast(NULL);
1265
1266 // Opcode
1267 opcode = opt->Opcode;
1268 Add(o, NewDhcpOption(DHCP_ID_MESSAGE_TYPE, &opcode, sizeof(opcode)));
1269
1270 // Server ID
1271 if (opt->ServerAddress != 0)
1272 {
1273 Add(o, NewDhcpOption(DHCP_ID_SERVER_ADDRESS, &opt->ServerAddress, 4));
1274 }
1275
1276 // Client MAC Address
1277 client_id[0] = ARP_HARDWARE_TYPE_ETHERNET;
1278 Copy(client_id + 1, ipc->MacAddress, 6);
1279 Add(o, NewDhcpOption(DHCP_ID_CLIENT_ID, client_id, sizeof(client_id)));
1280
1281 // Requested IP Address
1282 if (opt->RequestedIp != 0)
1283 {
1284 Add(o, NewDhcpOption(DHCP_ID_REQUEST_IP_ADDRESS, &opt->RequestedIp, 4));
1285 }
1286
1287 // Hostname
1288 if (IsEmptyStr(opt->Hostname) == false)
1289 {
1290 Add(o, NewDhcpOption(DHCP_ID_HOST_NAME, opt->Hostname, StrLen(opt->Hostname)));
1291 }
1292
1293 // User Class
1294 if (IsEmptyStr(opt->UserClass) == false)
1295 {
1296 Add(o, NewDhcpOption(DHCP_ID_USER_CLASS, opt->UserClass, StrLen(opt->UserClass)));
1297 }
1298
1299 // Vendor
1300 Add(o, NewDhcpOption(DHCP_ID_VENDOR_ID, IPC_DHCP_VENDOR_ID, StrLen(IPC_DHCP_VENDOR_ID)));
1301
1302 // Parameter Request List
1303 if (opcode == DHCP_DISCOVER || opcode == DHCP_REQUEST || opcode == DHCP_INFORM)
1304 {
1305 UCHAR param_list[12];
1306
1307 param_list[0] = 1;
1308 param_list[1] = 15;
1309 param_list[2] = 3;
1310 param_list[3] = 6;
1311 param_list[4] = 44;
1312 param_list[5] = 46;
1313 param_list[6] = 47;
1314 param_list[7] = 31;
1315 param_list[8] = 33;
1316 param_list[9] = 121;
1317 param_list[10] = 249;
1318 param_list[11] = 43;
1319
1320 Add(o, NewDhcpOption(DHCP_ID_REQ_PARAM_LIST, param_list, sizeof(param_list)));
1321 }
1322
1323 ret = BuildDhcpOptionsBuf(o);
1324
1325 FreeDhcpOptions(o);
1326
1327 return ret;
1328 }
1329
1330 // Process the received ARP
IPCProcessArp(IPC * ipc,BLOCK * b)1331 void IPCProcessArp(IPC *ipc, BLOCK *b)
1332 {
1333 UCHAR *dest_mac;
1334 UCHAR *src_mac;
1335 ARPV4_HEADER *arp;
1336 UCHAR *sender_mac;
1337 IP sender_ip;
1338 UCHAR *target_mac;
1339 IP target_ip;
1340 // Validate arguments
1341 if (ipc == NULL || b == NULL || b->Size < (14 + sizeof(ARPV4_HEADER)))
1342 {
1343 return;
1344 }
1345
1346 dest_mac = b->Buf + 0;
1347 src_mac = b->Buf + 6;
1348
1349 arp = (ARPV4_HEADER *)(b->Buf + 14);
1350
1351 if (arp->HardwareType != Endian16(ARP_HARDWARE_TYPE_ETHERNET))
1352 {
1353 return;
1354 }
1355 if (arp->ProtocolType != Endian16(MAC_PROTO_IPV4))
1356 {
1357 return;
1358 }
1359 if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
1360 {
1361 return;
1362 }
1363
1364 sender_mac = arp->SrcAddress;
1365 UINTToIP(&sender_ip, arp->SrcIP);
1366
1367 target_mac = arp->TargetAddress;
1368 UINTToIP(&target_ip, arp->TargetIP);
1369
1370 if (CmpIpAddr(&sender_ip, &ipc->ClientIPAddress) == 0)
1371 {
1372 // Source is myself
1373 return;
1374 }
1375
1376 IPCAssociateOnArpTable(ipc, &sender_ip, sender_mac);
1377 IPCAssociateOnArpTable(ipc, &target_ip, target_mac);
1378
1379 if (Endian16(arp->Operation) == ARP_OPERATION_REQUEST)
1380 {
1381 // Received an ARP request
1382 if (CmpIpAddr(&target_ip, &ipc->ClientIPAddress) == 0)
1383 {
1384 // Create a response since a request for its own IP address have received
1385 if (IsValidUnicastMacAddress(sender_mac))
1386 {
1387 UCHAR tmp[14 + sizeof(ARPV4_HEADER)];
1388 ARPV4_HEADER *arp = (ARPV4_HEADER *)(tmp + 14);
1389
1390 Copy(tmp + 0, sender_mac, 6);
1391 Copy(tmp + 6, ipc->MacAddress, 6);
1392 WRITE_USHORT(tmp + 12, MAC_PROTO_ARPV4);
1393
1394 arp->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
1395 arp->ProtocolType = Endian16(MAC_PROTO_IPV4);
1396 arp->HardwareSize = 6;
1397 arp->ProtocolSize = 4;
1398 arp->Operation = Endian16(ARP_OPERATION_RESPONSE);
1399
1400 Copy(arp->SrcAddress, ipc->MacAddress, 6);
1401 arp->SrcIP = IPToUINT(&ipc->ClientIPAddress);
1402
1403 Copy(arp->TargetAddress, sender_mac, 6);
1404 arp->TargetIP = IPToUINT(&sender_ip);
1405
1406 IPCSendL2(ipc, tmp, sizeof(tmp));
1407 }
1408 }
1409 }
1410 }
1411
1412 // Associate the MAC address and IP address on the ARP table
IPCAssociateOnArpTable(IPC * ipc,IP * ip,UCHAR * mac_address)1413 void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address)
1414 {
1415 IPC_ARP *a;
1416 // Validate arguments
1417 if (ipc == NULL || ip == NULL || IsValidUnicastIPAddress4(ip) == false || IsValidUnicastMacAddress(mac_address) == false)
1418 {
1419 return;
1420 }
1421 if (CmpIpAddr(&ipc->ClientIPAddress, ip) == 0 || Cmp(ipc->MacAddress, mac_address, 6) == 0)
1422 {
1423 return;
1424 }
1425 if (IsInSameNetwork4(ip, &ipc->ClientIPAddress, &ipc->SubnetMask) == false)
1426 {
1427 // Not to learn the IP address of outside the subnet
1428 return;
1429 }
1430
1431 if (CmpIpAddr(&ipc->BroadcastAddress, ip) == 0)
1432 {
1433 // Not to learn the broadcast IP address
1434 return;
1435 }
1436
1437 // Search whether there is ARP table entry already
1438 a = IPCSearchArpTable(ipc, ip);
1439 if (a == NULL)
1440 {
1441 // Add to the ARP table
1442 a = IPCNewARP(ip, mac_address);
1443
1444 Insert(ipc->ArpTable, a);
1445 }
1446 else
1447 {
1448 Copy(a->MacAddress, mac_address, 6);
1449
1450 // There is the ARP table entry already
1451 if (a->Resolved == false)
1452 {
1453 a->Resolved = true;
1454 a->GiveupTime = 0;
1455
1456 // Send all the packets that are accumulated to be sent
1457 while (true)
1458 {
1459 BLOCK *b = GetNext(a->PacketQueue);
1460
1461 if (b == NULL)
1462 {
1463 break;
1464 }
1465
1466 IPCSendIPv4WithDestMacAddr(ipc, b->Buf, b->Size, a->MacAddress);
1467
1468 FreeBlock(b);
1469 }
1470 }
1471
1472 // Extend the expiration date
1473 a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
1474 }
1475 }
1476
1477 // Identifiy whether the MAC address is a normal unicast address
IsValidUnicastMacAddress(UCHAR * mac)1478 bool IsValidUnicastMacAddress(UCHAR *mac)
1479 {
1480 // Validate arguments
1481 if (mac == NULL)
1482 {
1483 return false;
1484 }
1485
1486 if (mac[0] & 0x01)
1487 {
1488 return false;
1489 }
1490
1491 if (IsZero(mac, 6))
1492 {
1493 return false;
1494 }
1495
1496 return true;
1497 }
1498
1499 // Identify whether the IP address is a normal unicast address
IsValidUnicastIPAddress4(IP * ip)1500 bool IsValidUnicastIPAddress4(IP *ip)
1501 {
1502 UINT i;
1503 // Validate arguments
1504 if (IsIP4(ip) == false)
1505 {
1506 return false;
1507 }
1508
1509 if (IsZeroIP(ip))
1510 {
1511 return false;
1512 }
1513
1514 if (ip->addr[0] >= 224 && ip->addr[0] <= 239)
1515 {
1516 // IPv4 Multicast
1517 return false;
1518 }
1519
1520 for (i = 0;i < 4;i++)
1521 {
1522 if (ip->addr[i] != 255)
1523 {
1524 return true;
1525 }
1526 }
1527
1528 return false;
1529 }
IsValidUnicastIPAddressUINT4(UINT ip)1530 bool IsValidUnicastIPAddressUINT4(UINT ip)
1531 {
1532 IP a;
1533
1534 UINTToIP(&a, ip);
1535
1536 return IsValidUnicastIPAddress4(&a);
1537 }
1538
1539 // Interrupt process (This is called periodically)
IPCProcessInterrupts(IPC * ipc)1540 void IPCProcessInterrupts(IPC *ipc)
1541 {
1542 // Validate arguments
1543 if (ipc == NULL)
1544 {
1545 return;
1546 }
1547
1548 FlushTubeFlushList(ipc->FlushList);
1549 }
1550
1551 // Process the L3 event by the IPC
IPCProcessL3Events(IPC * ipc)1552 void IPCProcessL3Events(IPC *ipc)
1553 {
1554 IPCProcessL3EventsEx(ipc, 0);
1555 }
IPCProcessL3EventsEx(IPC * ipc,UINT64 now)1556 void IPCProcessL3EventsEx(IPC *ipc, UINT64 now)
1557 {
1558 // Validate arguments
1559 if (ipc == NULL)
1560 {
1561 return;
1562 }
1563 if (now == 0)
1564 {
1565 now = Tick64();
1566 }
1567
1568 // Remove old ARP table entries
1569 IPCFlushArpTableEx(ipc, now);
1570
1571 // Receive all the L2 packet
1572 while (true)
1573 {
1574 BLOCK *b = IPCRecvL2(ipc);
1575 if (b == NULL)
1576 {
1577 // All reception completed
1578 break;
1579 }
1580
1581 if (b->Size >= 14)
1582 {
1583 UCHAR *dest_mac = b->Buf + 0;
1584 UCHAR *src_mac = b->Buf + 6;
1585 USHORT protocol = READ_USHORT(b->Buf + 12);
1586
1587 // Confirm the destination MAC address
1588 // (Receive if the destination MAC address is the IPC address or a broadcast address)
1589 if (Cmp(dest_mac, ipc->MacAddress, 6) == 0 || dest_mac[0] & 0x01)
1590 {
1591 // If the source MAC address is itselves or invalid address, ignore the packet
1592 if (Cmp(src_mac, ipc->MacAddress, 6) != 0 && IsValidUnicastMacAddress(src_mac))
1593 {
1594 if (protocol == MAC_PROTO_ARPV4)
1595 {
1596 // ARP receiving process
1597 IPCProcessArp(ipc, b);
1598 }
1599 else if (protocol == MAC_PROTO_IPV4)
1600 {
1601 // IPv4 receiving process
1602 if (b->Size >= (14 + 20))
1603 {
1604 UCHAR *data = Clone(b->Buf + 14, b->Size - 14);
1605 UINT size = b->Size - 14;
1606 IP ip_src, ip_dst;
1607 bool ok = false;
1608
1609 // Extract the IP address portion
1610 UINTToIP(&ip_src, *((UINT *)(((UCHAR *)data) + 12)));
1611 UINTToIP(&ip_dst, *((UINT *)(((UCHAR *)data) + 16)));
1612
1613 // Receive only if the IPv4 destination address is its own
1614 // or 255.255.255.255 or a multicast address or a broadcast address
1615 if (CmpIpAddr(&ip_dst, &ipc->ClientIPAddress) == 0)
1616 {
1617 ok = true;
1618 }
1619 else if (ip_dst.addr[0] == 255 && ip_dst.addr[1] == 255 &&
1620 ip_dst.addr[2] == 255 && ip_dst.addr[3] == 255)
1621 {
1622 ok = true;
1623 }
1624 else if (ip_dst.addr[0] >= 224 && ip_dst.addr[0] <= 239)
1625 {
1626 ok = true;
1627 }
1628 else
1629 {
1630 if (CmpIpAddr(&ipc->BroadcastAddress, &ip_dst) == 0)
1631 {
1632 ok = true;
1633 }
1634
1635 if (IsZeroIP(&ipc->ClientIPAddress))
1636 {
1637 // Client IP address is undetermined
1638 ok = true;
1639 }
1640 }
1641
1642 if (ok)
1643 {
1644 IPCAssociateOnArpTable(ipc, &ip_src, src_mac);
1645
1646 // Place in the reception queue
1647 InsertQueue(ipc->IPv4RecviedQueue, NewBlock(data, size, 0));
1648 }
1649 else
1650 {
1651 // This packet is discarded because it is irrelevant for me
1652 Free(data);
1653 }
1654 }
1655 }
1656 }
1657 }
1658 }
1659
1660 FreeBlock(b);
1661 }
1662
1663 IPCProcessInterrupts(ipc);
1664 }
1665
1666 // Configure IPv4 parameters
IPCSetIPv4Parameters(IPC * ipc,IP * ip,IP * subnet,IP * gw,DHCP_CLASSLESS_ROUTE_TABLE * rt)1667 bool IPCSetIPv4Parameters(IPC *ipc, IP *ip, IP *subnet, IP *gw, DHCP_CLASSLESS_ROUTE_TABLE *rt)
1668 {
1669 bool changed = false;
1670 // Validate arguments
1671 if (ipc == NULL || ip == NULL || subnet == NULL)
1672 {
1673 return false;
1674 }
1675
1676 if (CmpIpAddr(&ipc->ClientIPAddress, ip) != 0)
1677 {
1678 changed = true;
1679 }
1680 Copy(&ipc->ClientIPAddress, ip, sizeof(IP));
1681
1682 if (CmpIpAddr(&ipc->SubnetMask, subnet) != 0)
1683 {
1684 changed = true;
1685 }
1686 Copy(&ipc->SubnetMask, subnet, sizeof(IP));
1687
1688 if (gw != NULL)
1689 {
1690 if (CmpIpAddr(&ipc->DefaultGateway, gw) != 0)
1691 {
1692 changed = true;
1693 }
1694
1695 Copy(&ipc->DefaultGateway, gw, sizeof(IP));
1696 }
1697 else
1698 {
1699 if (IsZeroIP(&ipc->DefaultGateway) == false)
1700 {
1701 changed = true;
1702 }
1703
1704 Zero(&ipc->DefaultGateway, sizeof(IP));
1705 }
1706
1707 GetBroadcastAddress4(&ipc->BroadcastAddress, ip, subnet);
1708
1709 if (rt != NULL && rt->NumExistingRoutes >= 1)
1710 {
1711 if (Cmp(&ipc->ClasslessRoute, rt, sizeof(DHCP_CLASSLESS_ROUTE_TABLE)) != 0)
1712 {
1713 changed = true;
1714
1715 Copy(&ipc->ClasslessRoute, rt, sizeof(DHCP_CLASSLESS_ROUTE_TABLE));
1716 }
1717 }
1718
1719 return changed;
1720 }
1721
1722 // Send an IPv4 packet (client -> server)
IPCSendIPv4(IPC * ipc,void * data,UINT size)1723 void IPCSendIPv4(IPC *ipc, void *data, UINT size)
1724 {
1725 IP ip_src, ip_dst;
1726 IP ip_dst_local;
1727 bool is_broadcast = false;
1728 UCHAR uc;
1729 DHCP_CLASSLESS_ROUTE *r = NULL;
1730 // Validate arguments
1731 if (ipc == NULL || data == NULL || size < 20 || size > 1500)
1732 {
1733 return;
1734 }
1735
1736 uc = ((UCHAR *)data)[0];
1737 if (((uc >> 4) & 0x0f) != 4)
1738 {
1739 // Not an IPv4
1740 return;
1741 }
1742
1743 // Extract the IP address portion
1744 UINTToIP(&ip_src, *((UINT *)(((UCHAR *)data) + 12)));
1745 UINTToIP(&ip_dst, *((UINT *)(((UCHAR *)data) + 16)));
1746
1747 // Filter the source IP address
1748 if (CmpIpAddr(&ip_src, &ipc->ClientIPAddress) != 0)
1749 {
1750 // Cut off packets from illegal IP address
1751 return;
1752 }
1753
1754 if (IsZeroIP(&ip_dst))
1755 {
1756 // Illegal destination address
1757 return;
1758 }
1759
1760 if (CmpIpAddr(&ip_dst, &ipc->ClientIPAddress) == 0)
1761 {
1762 // Packet destined for myself
1763 return;
1764 }
1765
1766 // Get the IP address of the relayed destination
1767 Copy(&ip_dst_local, &ip_dst, sizeof(IP));
1768
1769 if (IsInSameNetwork4(&ip_dst, &ipc->ClientIPAddress, &ipc->SubnetMask) == false)
1770 {
1771 r = GetBestClasslessRoute(&ipc->ClasslessRoute, &ip_dst);
1772
1773 if (r == NULL)
1774 {
1775 Copy(&ip_dst_local, &ipc->DefaultGateway, sizeof(IP));
1776 }
1777 else
1778 {
1779 Copy(&ip_dst_local, &r->Gateway, sizeof(IP));
1780 }
1781 }
1782
1783 if (CmpIpAddr(&ipc->BroadcastAddress, &ip_dst) == 0)
1784 {
1785 // Local Broadcast
1786 is_broadcast = true;
1787 }
1788
1789 if (ip_dst.addr[0] == 255 && ip_dst.addr[1] == 255 && ip_dst.addr[2] == 255 && ip_dst.addr[3] == 255)
1790 {
1791 // Global Broadcast
1792 is_broadcast = true;
1793 }
1794
1795 if (ip_dst.addr[0] >= 224 && ip_dst.addr[0] <= 239)
1796 {
1797 // IPv4 Multicast
1798 is_broadcast = true;
1799 }
1800
1801 if (is_broadcast)
1802 {
1803 // Send a broadcast packet
1804 UCHAR dest[6];
1805 UINT i;
1806
1807 // Destination
1808 for (i = 0;i < 6;i++)
1809 {
1810 dest[i] = 0xff;
1811 }
1812
1813 // Send
1814 IPCSendIPv4WithDestMacAddr(ipc, data, size, dest);
1815
1816 return;
1817 }
1818
1819 if (IsZeroIP(&ip_dst_local))
1820 {
1821 // Unable to send
1822 return;
1823 }
1824
1825 // Send a unicast packet
1826 IPCSendIPv4Unicast(ipc, data, size, &ip_dst_local);
1827 }
1828
1829 // Send an IPv4 packet with a specified destination MAC address
IPCSendIPv4WithDestMacAddr(IPC * ipc,void * data,UINT size,UCHAR * dest_mac_addr)1830 void IPCSendIPv4WithDestMacAddr(IPC *ipc, void *data, UINT size, UCHAR *dest_mac_addr)
1831 {
1832 UCHAR tmp[1514];
1833 // Validate arguments
1834 if (ipc == NULL || data == NULL || size < 20 || size > 1500 || dest_mac_addr == NULL)
1835 {
1836 return;
1837 }
1838
1839 // Destination
1840 Copy(tmp + 0, dest_mac_addr, 6);
1841
1842 // Source
1843 Copy(tmp + 6, ipc->MacAddress, 6);
1844
1845 // Protocol number
1846 WRITE_USHORT(tmp + 12, MAC_PROTO_IPV4);
1847
1848 // Data
1849 Copy(tmp + 14, data, size);
1850
1851 // Send
1852 IPCSendL2(ipc, tmp, size + 14);
1853 }
1854
1855 // Remove old ARP table entries
IPCFlushArpTable(IPC * ipc)1856 void IPCFlushArpTable(IPC *ipc)
1857 {
1858 IPCFlushArpTableEx(ipc, 0);
1859 }
IPCFlushArpTableEx(IPC * ipc,UINT64 now)1860 void IPCFlushArpTableEx(IPC *ipc, UINT64 now)
1861 {
1862 UINT i;
1863 LIST *o = NULL;
1864 // Validate arguments
1865 if (ipc == NULL)
1866 {
1867 return;
1868 }
1869 if (now == 0)
1870 {
1871 now = Tick64();
1872 }
1873
1874 for (i = 0;i < LIST_NUM(ipc->ArpTable);i++)
1875 {
1876 IPC_ARP *a = LIST_DATA(ipc->ArpTable, i);
1877 bool b = false;
1878
1879 if (a->Resolved && a->ExpireTime <= now)
1880 {
1881 b = true;
1882 }
1883 else if (a->Resolved == false && a->GiveupTime <= now)
1884 {
1885 b = true;
1886 }
1887
1888 if (b)
1889 {
1890 if (o == NULL)
1891 {
1892 o = NewListFast(NULL);
1893 }
1894
1895 Add(o, a);
1896 }
1897 }
1898
1899 if (o != NULL)
1900 {
1901 for (i = 0;i < LIST_NUM(o);i++)
1902 {
1903 IPC_ARP *a = LIST_DATA(o, i);
1904
1905 IPCFreeARP(a);
1906
1907 Delete(ipc->ArpTable, a);
1908 }
1909
1910 ReleaseList(o);
1911 }
1912 }
1913
1914 // Send an IPv4 unicast packet
IPCSendIPv4Unicast(IPC * ipc,void * data,UINT size,IP * next_ip)1915 void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip)
1916 {
1917 IPC_ARP *a;
1918 // Validate arguments
1919 if (ipc == NULL || data == NULL || size < 20 || size > 1500 || next_ip == NULL)
1920 {
1921 return;
1922 }
1923
1924 a = IPCSearchArpTable(ipc, next_ip);
1925
1926 if (a != NULL)
1927 {
1928 // ARP entry is found
1929 if (a->Resolved)
1930 {
1931 // Send
1932 a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
1933
1934 IPCSendIPv4WithDestMacAddr(ipc, data, size, a->MacAddress);
1935 }
1936 else
1937 {
1938 // Undeliverable because of unresolved table. Accumulate in the queue
1939 if (a->PacketQueue->num_item < IPC_MAX_PACKET_QUEUE_LEN)
1940 {
1941 InsertQueue(a->PacketQueue, NewBlock(Clone(data, size), size, false));
1942 }
1943 }
1944 }
1945 else
1946 {
1947 ARPV4_HEADER arp;
1948 UCHAR tmp[14 + sizeof(ARPV4_HEADER)];
1949 UINT i;
1950
1951 // Because there is no such ARP entry, create a new one
1952 a = IPCNewARP(next_ip, NULL);
1953
1954 // Send an ARP request
1955 Zero(&arp, sizeof(arp));
1956 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
1957 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
1958 arp.HardwareSize = 6;
1959 arp.ProtocolSize = 4;
1960 arp.Operation = Endian16(ARP_OPERATION_REQUEST);
1961 Copy(&arp.SrcAddress, &ipc->MacAddress, 6);
1962 arp.SrcIP = IPToUINT(&ipc->ClientIPAddress);
1963 arp.TargetIP = IPToUINT(next_ip);
1964
1965 for (i = 0;i < 6;i++)
1966 {
1967 tmp[i] = 0xff;
1968 }
1969
1970 Copy(tmp + 6, ipc->MacAddress, 6);
1971
1972 WRITE_USHORT(tmp + 12, MAC_PROTO_ARPV4);
1973 Copy(tmp + 14, &arp, sizeof(ARPV4_HEADER));
1974
1975 IPCSendL2(ipc, tmp, 14 + sizeof(ARPV4_HEADER));
1976
1977 // Accumulate the IP packet to be transmitted in the queue
1978 if (a->PacketQueue->num_item < IPC_MAX_PACKET_QUEUE_LEN)
1979 {
1980 InsertQueue(a->PacketQueue, NewBlock(Clone(data, size), size, false));
1981 }
1982
1983 Insert(ipc->ArpTable, a);
1984 }
1985 }
1986
1987 // Search the ARP table
IPCSearchArpTable(IPC * ipc,IP * ip)1988 IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip)
1989 {
1990 IPC_ARP t;
1991 IPC_ARP *a;
1992 // Validate arguments
1993 if (ipc == NULL || ip == NULL)
1994 {
1995 return NULL;
1996 }
1997
1998 Copy(&t.Ip, ip, sizeof(IP));
1999
2000 a = Search(ipc->ArpTable, &t);
2001
2002 return a;
2003 }
2004
2005 // Release the ARP entry
IPCFreeARP(IPC_ARP * a)2006 void IPCFreeARP(IPC_ARP *a)
2007 {
2008 BLOCK *b;
2009 // Validate arguments
2010 if (a == NULL)
2011 {
2012 return;
2013 }
2014
2015 while (true)
2016 {
2017 b = GetNext(a->PacketQueue);
2018 if (b == NULL)
2019 {
2020 break;
2021 }
2022
2023 FreeBlock(b);
2024 }
2025
2026 ReleaseQueue(a->PacketQueue);
2027
2028 Free(a);
2029 }
2030
2031 // Create a new ARP entry
IPCNewARP(IP * ip,UCHAR * mac_address)2032 IPC_ARP *IPCNewARP(IP *ip, UCHAR *mac_address)
2033 {
2034 IPC_ARP *a;
2035 // Validate arguments
2036 if (ip == NULL)
2037 {
2038 return NULL;
2039 }
2040
2041 a = ZeroMalloc(sizeof(IPC_ARP));
2042
2043 Copy(&a->Ip, ip, sizeof(IP));
2044 if (mac_address != NULL)
2045 {
2046 Copy(a->MacAddress, mac_address, 6);
2047 a->Resolved = true;
2048 a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
2049 }
2050 else
2051 {
2052 a->GiveupTime = Tick64() + (UINT64)IPC_ARP_GIVEUPTIME;
2053 }
2054
2055 a->PacketQueue = NewQueueFast();
2056
2057 return a;
2058 }
2059
2060 // Compare ARP entries
IPCCmpArpTable(void * p1,void * p2)2061 int IPCCmpArpTable(void *p1, void *p2)
2062 {
2063 IPC_ARP *a1, *a2;
2064 // Validate arguments
2065 if (p1 == NULL || p2 == NULL)
2066 {
2067 return 0;
2068 }
2069 a1 = *(IPC_ARP **)p1;
2070 a2 = *(IPC_ARP **)p2;
2071 if (a1 == NULL || a2 == NULL)
2072 {
2073 return 0;
2074 }
2075
2076 return CmpIpAddr(&a1->Ip, &a2->Ip);
2077 }
2078
2079 // Send an Ethernet packet (client -> server)
IPCSendL2(IPC * ipc,void * data,UINT size)2080 void IPCSendL2(IPC *ipc, void *data, UINT size)
2081 {
2082 // Validate arguments
2083 if (ipc == NULL || data == NULL || size == 0)
2084 {
2085 return;
2086 }
2087
2088 if (ipc->Sock == NULL)
2089 {
2090 return;
2091 }
2092
2093 TubeSendEx(ipc->Sock->SendTube, data, size, NULL, true);
2094 AddTubeToFlushList(ipc->FlushList, ipc->Sock->SendTube);
2095 }
2096
2097 // Receive an IPv4 packet (server -> client)
IPCRecvIPv4(IPC * ipc)2098 BLOCK *IPCRecvIPv4(IPC *ipc)
2099 {
2100 BLOCK *b;
2101 // Validate arguments
2102 if (ipc == NULL)
2103 {
2104 return NULL;
2105 }
2106
2107 b = GetNext(ipc->IPv4RecviedQueue);
2108
2109 return b;
2110 }
2111
2112 // Receive an Ethernet packet (server -> client)
IPCRecvL2(IPC * ipc)2113 BLOCK *IPCRecvL2(IPC *ipc)
2114 {
2115 TUBEDATA *d;
2116 BLOCK *b;
2117 // Validate arguments
2118 if (ipc == NULL)
2119 {
2120 return NULL;
2121 }
2122
2123 if (ipc->Sock == NULL)
2124 {
2125 return NULL;
2126 }
2127
2128 d = TubeRecvAsync(ipc->Sock->RecvTube);
2129
2130 if (d == NULL)
2131 {
2132 return NULL;
2133 }
2134
2135 b = NewBlock(d->Data, d->DataSize, 0);
2136
2137 Free(d->Header);
2138 Free(d);
2139
2140 return b;
2141 }
2142
2143
2144
2145