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 // NativeStack.c
103 // Native IP stack
104 
105 #include "CedarPch.h"
106 
107 // Stack main thread
NsMainThread(THREAD * thread,void * param)108 void NsMainThread(THREAD *thread, void *param)
109 {
110 	NATIVE_STACK *a = (NATIVE_STACK *)param;
111 	// Validate arguments
112 	if (thread == NULL || param == NULL)
113 	{
114 		return;
115 	}
116 
117 	while (true)
118 	{
119 		SOCKSET set;
120 		bool err = false;
121 		bool flush_tube;
122 		LIST *recv_packets;
123 		bool state_changed = false;
124 
125 		InitSockSet(&set);
126 		AddSockSet(&set, a->Sock1);
127 
128 		if (a->Halt)
129 		{
130 			break;
131 		}
132 
133 		// Pass to the IPC by receiving from the bridge
134 LABEL_RESTART:
135 		state_changed = false;
136 		flush_tube = false;
137 		while (true)
138 		{
139 			void *data;
140 			UINT size;
141 
142 			size = EthGetPacket(a->Eth, &data);
143 
144 			if (size == INFINITE)
145 			{
146 				// Device error
147 				err = true;
148 				break;
149 			}
150 			else if (size == 0)
151 			{
152 				// Can not get any more
153 				break;
154 			}
155 			else
156 			{
157 				// Pass the IPC socket
158 				TubeSendEx(a->Sock1->SendTube, data, size, NULL, true);
159 				Free(data);
160 				flush_tube = true;
161 				state_changed = true;
162 			}
163 		}
164 
165 		if (flush_tube)
166 		{
167 			TubeFlush(a->Sock1->SendTube);
168 		}
169 
170 		// Pass to the bridge by receiving from IPC
171 		recv_packets = NULL;
172 		while (true)
173 		{
174 			TUBEDATA *d = TubeRecvAsync(a->Sock1->RecvTube);
175 
176 			if (d == NULL)
177 			{
178 				break;
179 			}
180 
181 			if (recv_packets == NULL)
182 			{
183 				recv_packets = NewListFast(NULL);
184 			}
185 
186 			Add(recv_packets, d);
187 
188 			state_changed = true;
189 		}
190 		if (recv_packets != NULL)
191 		{
192 			UINT i;
193 			UINT num = LIST_NUM(recv_packets);
194 			void **data_array;
195 			UINT *size_array;
196 
197 			data_array = Malloc(sizeof(void *) * num);
198 			size_array = Malloc(sizeof(UINT) * num);
199 
200 			for (i = 0;i < num;i++)
201 			{
202 				TUBEDATA *d = LIST_DATA(recv_packets, i);
203 
204 				data_array[i] = d->Data;
205 				size_array[i] = d->DataSize;
206 			}
207 
208 			EthPutPackets(a->Eth, num, data_array, size_array);
209 
210 			for (i = 0;i < num;i++)
211 			{
212 				TUBEDATA *d = LIST_DATA(recv_packets, i);
213 
214 				// Because the data buffer has been already released, not to release twice
215 				d->Data = NULL;
216 
217 				FreeTubeData(d);
218 			}
219 
220 			Free(data_array);
221 			Free(size_array);
222 
223 			ReleaseList(recv_packets);
224 		}
225 
226 		if (IsTubeConnected(a->Sock1->SendTube) == false || IsTubeConnected(a->Sock1->RecvTube) == false)
227 		{
228 			err = true;
229 		}
230 
231 		if (err)
232 		{
233 			// An error has occured
234 			Debug("Native Stack: Error !\n");
235 			a->Halt = true;
236 			continue;
237 		}
238 
239 		if (state_changed)
240 		{
241 			goto LABEL_RESTART;
242 		}
243 
244 		Select(&set, 1234, a->Cancel, NULL);
245 	}
246 
247 	Disconnect(a->Sock1);
248 	Disconnect(a->Sock2);
249 }
250 
251 // Start the iptables tracking
NsStartIpTablesTracking(NATIVE_STACK * a)252 bool NsStartIpTablesTracking(NATIVE_STACK *a)
253 {
254 	if (a->IpTablesThread != NULL)
255 	{
256 		return true;
257 	}
258 
259 	a->IpTablesInitOk = false;
260 
261 	a->IpTablesHalt = false;
262 
263 	a->IpTablesHaltEvent = NewEvent();
264 
265 	a->IpTablesThread = NewThread(NsIpTablesThread, a);
266 
267 	WaitThreadInit(a->IpTablesThread);
268 
269 	return a->IpTablesInitOk;
270 }
271 
272 // iptables thread
NsIpTablesThread(THREAD * thread,void * param)273 void NsIpTablesThread(THREAD *thread, void *param)
274 {
275 	IPTABLES_STATE *state;
276 	NATIVE_STACK *s;
277 	UINT counter = 0;
278 	BUF *seed_buf;
279 	char exe_name[MAX_PATH];
280 	if (thread == NULL || param == NULL)
281 	{
282 		return;
283 	}
284 
285 	s = (NATIVE_STACK *)param;
286 
287 	seed_buf = NewBuf();
288 
289 	WriteBuf(seed_buf, s->MacAddress, 6);
290 
291 	GetExeName(exe_name, sizeof(exe_name));
292 	WriteBufStr(seed_buf, exe_name);
293 
294 	state = StartAddIpTablesEntryForNativeStack(seed_buf->Buf, seed_buf->Size);
295 
296 	FreeBuf(seed_buf);
297 
298 	if (state == NULL)
299 	{
300 		NoticeThreadInit(thread);
301 		return;
302 	}
303 
304 	s->IpTablesInitOk = true;
305 	NoticeThreadInit(thread);
306 
307 	while (true)
308 	{
309 		UINT wait_interval;
310 
311 		if (s->IpTablesHalt)
312 		{
313 			break;
314 		}
315 
316 		if (MaintainAddIpTablesEntryForNativeStack(state))
317 		{
318 			counter = 0;
319 		}
320 
321 		counter++;
322 		wait_interval = NS_CHECK_IPTABLES_INTERVAL_INIT * counter;
323 		wait_interval = MIN(wait_interval, NS_CHECK_IPTABLES_INTERVAL_MAX);
324 
325 		//Debug("NsIpTablesThread: wait for %u\n", wait_interval);
326 		Wait(s->IpTablesHaltEvent, wait_interval);
327 	}
328 
329 	EndAddIpTablesEntryForNativeStack(state);
330 }
331 
332 // Stop the iptables tracking
NsStopIpTablesTracking(NATIVE_STACK * a)333 void NsStopIpTablesTracking(NATIVE_STACK *a)
334 {
335 	if (a->IpTablesThread == NULL)
336 	{
337 		return;
338 	}
339 
340 	a->IpTablesHalt = true;
341 	Set(a->IpTablesHaltEvent);
342 
343 	WaitThread(a->IpTablesThread, INFINITE);
344 
345 	ReleaseThread(a->IpTablesThread);
346 	ReleaseEvent(a->IpTablesHaltEvent);
347 
348 	a->IpTablesThread = NULL;
349 	a->IpTablesHaltEvent = NULL;
350 	a->IpTablesInitOk = false;
351 	a->IpTablesHalt = false;
352 }
353 
354 // Release the stack
FreeNativeStack(NATIVE_STACK * a)355 void FreeNativeStack(NATIVE_STACK *a)
356 {
357 	// Validate arguments
358 	if (a == NULL)
359 	{
360 		return;
361 	}
362 
363 	if (a->Ipc != NULL && IsZero(&a->CurrentDhcpOptionList, sizeof(a->CurrentDhcpOptionList)) == false)
364 	{
365 		IP dhcp_server;
366 
367 		UINTToIP(&dhcp_server, a->CurrentDhcpOptionList.ServerAddress);
368 
369 		IPCDhcpFreeIP(a->Ipc, &dhcp_server);
370 		SleepThread(200);
371 	}
372 
373 	a->Halt = true;
374 	Cancel(a->Cancel);
375 	Disconnect(a->Sock1);
376 	Disconnect(a->Sock2);
377 
378 	WaitThread(a->MainThread, INFINITE);
379 
380 	ReleaseThread(a->MainThread);
381 
382 	CloseEth(a->Eth);
383 	FreeIPC(a->Ipc);
384 
385 	NsStopIpTablesTracking(a);
386 
387 	ReleaseCancel(a->Cancel);
388 
389 	ReleaseSock(a->Sock1);
390 	ReleaseSock(a->Sock2);
391 
392 	ReleaseCedar(a->Cedar);
393 
394 	Free(a);
395 }
396 
397 // Create a new stack
NewNativeStack(CEDAR * cedar,char * device_name,char * mac_address_seed)398 NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_seed)
399 {
400 	ETH *eth;
401 	NATIVE_STACK *a;
402 	IP localhost;
403 	char tmp[64];
404 	bool release_cedar = false;
405 	// Validate arguments
406 	if (device_name == NULL || mac_address_seed == NULL)
407 	{
408 		return NULL;
409 	}
410 
411 	GetLocalHostIP4(&localhost);
412 
413 	// Open the Eth device
414 	eth = OpenEth(device_name, false, false, NULL);
415 	if (eth == NULL)
416 	{
417 		return NULL;
418 	}
419 
420 	if (cedar == NULL)
421 	{
422 		cedar = NewCedar(NULL, NULL);
423 		release_cedar = true;
424 	}
425 
426 	a = ZeroMalloc(sizeof(NATIVE_STACK));
427 
428 	NewSocketPair(&a->Sock1, &a->Sock2, &localhost, 1, &localhost, 1);
429 
430 	a->Cedar = cedar;
431 	AddRef(a->Cedar->ref);
432 
433 	NsGenMacAddress(a->MacAddress, mac_address_seed, device_name);
434 
435 	BinToStr(tmp, sizeof(tmp), a->MacAddress, sizeof(a->MacAddress));
436 	Debug("NewNativeStack: MAC Address = %s\n", tmp);
437 
438 	a->Ipc = NewIPCBySock(cedar, a->Sock2, a->MacAddress);
439 
440 	StrCpy(a->DeviceName, sizeof(a->DeviceName), device_name);
441 
442 	a->Eth = eth;
443 	a->Cancel = EthGetCancel(eth);
444 
445 	a->MainThread = NewThread(NsMainThread, a);
446 
447 	if (release_cedar)
448 	{
449 		ReleaseCedar(cedar);
450 	}
451 
452 	a->IsIpRawMode = a->Eth->IsRawIpMode;
453 
454 	return a;
455 }
456 
457 // Identify whether the specified MAC address is for the Native Stack which operate on the same host
NsIsMacAddressOnLocalhost(UCHAR * mac)458 bool NsIsMacAddressOnLocalhost(UCHAR *mac)
459 {
460 	UCHAR tmp[2];
461 	// Validate arguments
462 	if (mac == NULL)
463 	{
464 		return false;
465 	}
466 
467 	if (mac[0] != NS_MAC_ADDRESS_BYTE_1)
468 	{
469 		return false;
470 	}
471 
472 	NsGenMacAddressSignatureForMachine(tmp, mac);
473 
474 	if (Cmp(mac + 4, tmp, 2) == 0)
475 	{
476 		return true;
477 	}
478 
479 	return false;
480 }
481 
482 // Determine the last two bytes of the MAC address
NsGenMacAddressSignatureForMachine(UCHAR * dst_last_2,UCHAR * src_mac_addr_4)483 void NsGenMacAddressSignatureForMachine(UCHAR *dst_last_2, UCHAR *src_mac_addr_4)
484 {
485 	char machine_name[MAX_SIZE];
486 	BUF *b;
487 	UCHAR hash[SHA1_SIZE];
488 	// Validate arguments
489 	if (dst_last_2 == NULL || src_mac_addr_4 == NULL)
490 	{
491 		return;
492 	}
493 
494 	GetMachineHostName(machine_name, sizeof(machine_name));
495 
496 	Trim(machine_name);
497 	StrUpper(machine_name);
498 
499 	b = NewBuf();
500 	WriteBuf(b, src_mac_addr_4, 4);
501 	WriteBufStr(b, machine_name);
502 
503 	HashSha1(hash, b->Buf, b->Size);
504 
505 	FreeBuf(b);
506 
507 	Copy(dst_last_2, hash, 2);
508 }
509 
510 // Generate the MAC address
NsGenMacAddress(void * dest,char * mac_address_seed,char * device_name)511 void NsGenMacAddress(void *dest, char *mac_address_seed, char *device_name)
512 {
513 	char tmp[MAX_SIZE];
514 	UCHAR mac[6];
515 	UCHAR hash[SHA1_SIZE];
516 
517 	Zero(tmp, sizeof(tmp));
518 
519 	StrCat(tmp, sizeof(tmp), mac_address_seed);
520 	StrCat(tmp, sizeof(tmp), "@");
521 	StrCat(tmp, sizeof(tmp), device_name);
522 
523 	Trim(tmp);
524 
525 	StrLower(tmp);
526 
527 	HashSha1(hash, tmp, StrLen(tmp));
528 
529 	mac[0] = NS_MAC_ADDRESS_BYTE_1;
530 	mac[1] = hash[1];
531 	mac[2] = hash[2];
532 	mac[3] = hash[3];
533 	mac[4] = hash[4];
534 	mac[5] = hash[5];
535 
536 	NsGenMacAddressSignatureForMachine(mac + 4, mac);
537 
538 	Copy(dest, mac, 6);
539 }
540 
541 // Add the iptables entries for native stack
StartAddIpTablesEntryForNativeStack(void * seed,UINT seed_size)542 IPTABLES_STATE *StartAddIpTablesEntryForNativeStack(void *seed, UINT seed_size)
543 {
544 	IPTABLES_STATE *ret = NULL;
545 	bool ok = false;
546 
547 	if (IsIpTablesSupported())
548 	{
549 		IPTABLES_ENTRY *e;
550 		UINT i;
551 
552 		ret = ZeroMalloc(sizeof(IPTABLES_STATE));
553 
554 		ret->EntryList = NewListFast(NULL);
555 
556 		HashSha1(ret->SeedHash, seed, seed_size);
557 
558 		// Create a pair of entry
559 		e = ZeroMalloc(sizeof(IPTABLES_ENTRY));
560 		GenerateDummyIpAndMark(ret->SeedHash, e, 0);
561 		StrCpy(e->Chain, sizeof(e->Chain), "OUTPUT");
562 		Format(e->ConditionAndArgs, sizeof(e->ConditionAndArgs),
563 			"-p tcp --tcp-flags RST RST --sport %u:%u ! -s %r/32 ! -d %r/32 -m connmark ! --mark 0x%x -j DROP",
564 			NN_RAW_IP_PORT_START, NN_RAW_IP_PORT_END,
565 			&e->DummySrcIp, &e->DummyDestIP, e->DummyMark);
566 		Add(ret->EntryList, e);
567 
568 		e = ZeroMalloc(sizeof(IPTABLES_ENTRY));
569 		GenerateDummyIpAndMark(ret->SeedHash, e, 1);
570 		StrCpy(e->Chain, sizeof(e->Chain), "OUTPUT");
571 		Format(e->ConditionAndArgs, sizeof(e->ConditionAndArgs),
572 			"-p icmp --icmp-type 3/3 ! -s %r/32 ! -d %r/32 -m connmark ! --mark 0x%x -j DROP",
573 			&e->DummySrcIp, &e->DummyDestIP, e->DummyMark);
574 		Add(ret->EntryList, e);
575 
576 		ok = true;
577 
578 		// Insert entries if not exists
579 		for (i = 0; i < LIST_NUM(ret->EntryList);i++)
580 		{
581 			UINT j;
582 			IPTABLES_ENTRY *e = LIST_DATA(ret->EntryList, i);
583 
584 			for (j = 0;j < 100;j++)
585 			{
586 				if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) != 0)
587 				{
588 					char cmdline[MAX_PATH];
589 
590 					Format(cmdline, sizeof(cmdline),
591 						"iptables -D %s %s",
592 						e->Chain, e->ConditionAndArgs);
593 
594 					system(cmdline);
595 				}
596 				else
597 				{
598 					break;
599 				}
600 			}
601 
602 			if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
603 			{
604 				char cmdline[MAX_PATH];
605 
606 				Format(cmdline, sizeof(cmdline),
607 					"iptables -I %s %s",
608 					e->Chain, e->ConditionAndArgs);
609 
610 				system(cmdline);
611 
612 				if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
613 				{
614 					Debug("Run \"%s\" failed.\n", cmdline);
615 					ok = false;
616 					break;
617 				}
618 				else
619 				{
620 					Debug("Run \"%s\" ok.\n", cmdline);
621 				}
622 			}
623 		}
624 	}
625 
626 	if (ok == false)
627 	{
628 		EndAddIpTablesEntryForNativeStack(ret);
629 		ret = NULL;
630 	}
631 
632 	return ret;
633 }
634 
635 // Maintain the iptables
MaintainAddIpTablesEntryForNativeStack(IPTABLES_STATE * s)636 bool MaintainAddIpTablesEntryForNativeStack(IPTABLES_STATE *s)
637 {
638 	UINT i;
639 	bool ret = false;
640 	if (s == NULL)
641 	{
642 		return false;
643 	}
644 
645 	if (s->HasError)
646 	{
647 		return false;
648 	}
649 
650 	// Insert entries if not exists
651 	for (i = 0; i < LIST_NUM(s->EntryList);i++)
652 	{
653 		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
654 
655 		if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
656 		{
657 			char cmdline[MAX_PATH];
658 
659 			Format(cmdline, sizeof(cmdline),
660 				"iptables -I %s %s",
661 				e->Chain, e->ConditionAndArgs);
662 
663 			system(cmdline);
664 
665 			if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
666 			{
667 				Debug("Run \"%s\" failed.\n", cmdline);
668 				s->HasError = true;
669 				break;
670 			}
671 			else
672 			{
673 				Debug("Run \"%s\" ok.\n", cmdline);
674 				ret = true;
675 			}
676 		}
677 	}
678 
679 	return ret;
680 }
681 
682 // Stop the iptables management
EndAddIpTablesEntryForNativeStack(IPTABLES_STATE * s)683 void EndAddIpTablesEntryForNativeStack(IPTABLES_STATE *s)
684 {
685 	UINT i;
686 	if (s == NULL)
687 	{
688 		return;
689 	}
690 
691 	// Delete entries
692 	for (i = 0; i < LIST_NUM(s->EntryList);i++)
693 	{
694 		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
695 		UINT j;
696 
697 		for (j = 0;j < 100;j++)
698 		{
699 			if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) != 0)
700 			{
701 				char cmdline[MAX_PATH];
702 
703 				Format(cmdline, sizeof(cmdline),
704 					"iptables -D %s %s",
705 					e->Chain, e->ConditionAndArgs);
706 
707 				system(cmdline);
708 			}
709 			else
710 			{
711 				break;
712 			}
713 		}
714 	}
715 
716 	FreeIpTablesState(s);
717 }
718 
719 // Generate a set of dummy IP addresses and mark
GenerateDummyIpAndMark(void * hash_seed,IPTABLES_ENTRY * e,UINT id)720 void GenerateDummyIpAndMark(void *hash_seed, IPTABLES_ENTRY *e, UINT id)
721 {
722 	PRAND *p;
723 	BUF *b;
724 	if (hash_seed == NULL || e == NULL)
725 	{
726 		return;
727 	}
728 
729 	b = NewBuf();
730 	WriteBufInt(b, id);
731 	WriteBuf(b, hash_seed, SHA1_SIZE);
732 	WriteBufStr(b, "20151002");
733 
734 	p = NewPRand(b->Buf, b->Size);
735 	FreeBuf(b);
736 
737 	GenerateDummyIp(p, &e->DummySrcIp);
738 	GenerateDummyIp(p, &e->DummyDestIP);
739 	e->DummyMark = GenerateDummyMark(p);
740 
741 	FreePRand(p);
742 }
743 
744 // Generate a dummy iptables mark
GenerateDummyMark(PRAND * p)745 UINT GenerateDummyMark(PRAND *p)
746 {
747 	UINT i;
748 	if (p == NULL)
749 	{
750 		return 0;
751 	}
752 
753 	while (true)
754 	{
755 		i = PRandInt(p);
756 
757 		if (i >= 1000000000 && i <= 0x7FFFFFFE)
758 		{
759 			return i;
760 		}
761 	}
762 
763 	return 0;
764 }
765 
766 // Generate a dummy IP
GenerateDummyIp(PRAND * p,IP * ip)767 void GenerateDummyIp(PRAND *p, IP *ip)
768 {
769 	UINT i;
770 	if (p == NULL || ip == NULL)
771 	{
772 		return;
773 	}
774 
775 	Zero(ip, sizeof(IP));
776 
777 	for (i = 1;i < 4;i++)
778 	{
779 		UINT v = 0;
780 		while (true)
781 		{
782 			v = PRandInt(p) % 256;
783 			if (v >= 1 && v <= 254)
784 			{
785 				break;
786 			}
787 		}
788 
789 		ip->addr[i] = (UCHAR)v;
790 	}
791 
792 	ip->addr[0] = 127;
793 }
794 
795 // Search an entry
SearchIpTables(IPTABLES_STATE * s,char * chain,IP * src_ip,IP * dest_ip,UINT mark)796 IPTABLES_ENTRY *SearchIpTables(IPTABLES_STATE *s, char *chain, IP *src_ip, IP *dest_ip, UINT mark)
797 {
798 	char ip_str1[64];
799 	char ip_str2[64];
800 	char mark_str1[64];
801 	char mark_str2[64];
802 	UINT i;
803 	if (s == NULL || chain == NULL || src_ip == NULL || dest_ip == NULL || mark == 0)
804 	{
805 		return NULL;
806 	}
807 
808 	IPToStr(ip_str1, sizeof(ip_str1), src_ip);
809 	IPToStr(ip_str2, sizeof(ip_str2), dest_ip);
810 	ToStr(mark_str1, mark);
811 	Format(mark_str2, sizeof(mark_str2), "%x", mark);
812 
813 	for (i = 0;i < LIST_NUM(s->EntryList);i++)
814 	{
815 		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
816 
817 		if (StrCmpi(e->Chain, chain) == 0)
818 		{
819 			if (InStr(e->ConditionAndArgs, ip_str1) &&
820 				InStr(e->ConditionAndArgs, ip_str2) &&
821 				(InStr(e->ConditionAndArgs, mark_str1) || InStr(e->ConditionAndArgs, mark_str2)))
822 			{
823 				return e;
824 			}
825 		}
826 	}
827 
828 	return NULL;
829 }
830 
831 // Search an entry and get the line number
GetCurrentIpTableLineNumber(char * chain,IP * src_ip,IP * dest_ip,UINT mark)832 UINT GetCurrentIpTableLineNumber(char *chain, IP *src_ip, IP *dest_ip, UINT mark)
833 {
834 	IPTABLES_STATE *s;
835 	IPTABLES_ENTRY *e;
836 	UINT ret = 0;
837 
838 	if (chain == NULL || src_ip == NULL || dest_ip == NULL || mark == 0)
839 	{
840 		return 0;
841 	}
842 
843 	s = GetCurrentIpTables();
844 
845 	e = SearchIpTables(s, chain, src_ip, dest_ip, mark);
846 
847 	if (e != NULL)
848 	{
849 		ret = e->LineNumber;
850 	}
851 
852 	FreeIpTablesState(s);
853 
854 	return ret;
855 }
856 
857 // Free the iptables state
FreeIpTablesState(IPTABLES_STATE * s)858 void FreeIpTablesState(IPTABLES_STATE *s)
859 {
860 	UINT i;
861 	if (s == NULL)
862 	{
863 		return;
864 	}
865 
866 	for (i = 0;i < LIST_NUM(s->EntryList);i++)
867 	{
868 		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
869 
870 		Free(e);
871 	}
872 
873 	ReleaseList(s->EntryList);
874 
875 	Free(s);
876 }
877 
878 // Get the current iptables state
GetCurrentIpTables()879 IPTABLES_STATE *GetCurrentIpTables()
880 {
881 	IPTABLES_STATE *ret = NULL;
882 	TOKEN_LIST *t = NULL;
883 
884 #ifdef	OS_UNIX
885 	t = UnixExec("iptables -L -x -n --line-numbers");
886 #endif	// OS_UNIX
887 
888 	if (t != NULL)
889 	{
890 		UINT i;
891 		UINT tmp_num = 0;
892 
893 		for (i = 0;i < t->NumTokens;i++)
894 		{
895 			char *line = t->Token[i];
896 			if (StartWith(line, "Chain INPUT") ||
897 				StartWith(line, "Chain FORWARD") ||
898 				StartWith(line, "Chain OUTPUT"))
899 			{
900 				tmp_num++;
901 			}
902 		}
903 
904 		if (tmp_num >= 3)
905 		{
906 			char current_chain[64];
907 			UINT mode = 0;
908 
909 			Zero(current_chain, sizeof(current_chain));
910 
911 			for (i = 0;i < t->NumTokens;i++)
912 			{
913 				char *line = t->Token[i];
914 
915 				if (StartWith(line, "Chain"))
916 				{
917 					TOKEN_LIST *t2 = ParseToken(line, " \t");
918 					if (t2 != NULL)
919 					{
920 						if (t2->NumTokens >= 4)
921 						{
922 							StrCpy(current_chain, sizeof(current_chain), t2->Token[1]);
923 							mode = 1;
924 
925 							if (ret == NULL)
926 							{
927 								ret = ZeroMalloc(sizeof(IPTABLES_STATE));
928 								ret->EntryList = NewListFast(NULL);
929 							}
930 
931 						}
932 						FreeToken(t2);
933 					}
934 				}
935 
936 				if (mode == 1)
937 				{
938 					if (StartWith(line, "num"))
939 					{
940 						mode = 2;
941 					}
942 				}
943 				else if (mode == 2)
944 				{
945 					TOKEN_LIST *t2 = ParseToken(line, " \t");
946 					if (t2 != NULL)
947 					{
948 						if (t2->NumTokens >= 6 && ToInt(t2->Token[0]) != 0)
949 						{
950 							IPTABLES_ENTRY *e = ZeroMalloc(sizeof(IPTABLES_ENTRY));
951 
952 							StrCpy(e->Chain, sizeof(e->Chain), current_chain);
953 							e->LineNumber = ToInt(t2->Token[0]);
954 							StrCpy(e->ConditionAndArgs, sizeof(e->ConditionAndArgs), line);
955 
956 							Add(ret->EntryList, e);
957 						}
958 
959 						FreeToken(t2);
960 					}
961 				}
962 			}
963 		}
964 
965 		FreeToken(t);
966 	}
967 
968 	return ret;
969 }
970 
971 // Get whether iptables is supported
IsIpTablesSupported()972 bool IsIpTablesSupported()
973 {
974 #ifdef	UNIX_LINUX
975 	IPTABLES_STATE *s = GetCurrentIpTables();
976 	if (s != NULL)
977 	{
978 		FreeIpTablesState(s);
979 		return true;
980 	}
981 	else
982 	{
983 		return false;
984 	}
985 #else	// UNIX_LINUX
986 	return false;
987 #endif	// UNIX_LINUX
988 }
989 
990 
991 
992 
993