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