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, &param->ClientIp,
327 		param->ClientPort, &param->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(&current_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(&current_scanning_ip, sizeof(IP)))
916 			{
917 				UINTToIP(&current_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(&current_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