浏览代码

Merge branch 'master' into rpmspec_update

* master:
  v4.19-9582-beta
Jeff Tang 10 年之前
父节点
当前提交
5f0f05aa76
共有 59 个文件被更改,包括 4248 次插入109 次删除
  1. 10 0
      src/Cedar/Bridge.c
  2. 4 0
      src/Cedar/Bridge.h
  3. 791 3
      src/Cedar/BridgeUnix.c
  4. 23 1
      src/Cedar/BridgeUnix.h
  5. 8 3
      src/Cedar/BridgeWin32.c
  6. 7 1
      src/Cedar/BridgeWin32.h
  7. 28 0
      src/Cedar/Cedar.c
  8. 7 6
      src/Cedar/Cedar.h
  9. 12 0
      src/Cedar/CedarType.h
  10. 1 0
      src/Cedar/Command.c
  11. 101 0
      src/Cedar/Hub.c
  12. 5 0
      src/Cedar/Hub.h
  13. 1 1
      src/Cedar/IPsec_EtherIP.c
  14. 15 1
      src/Cedar/IPsec_IKE.c
  15. 21 5
      src/Cedar/IPsec_IPC.c
  16. 2 1
      src/Cedar/IPsec_IPC.h
  17. 192 38
      src/Cedar/IPsec_L2TP.c
  18. 5 1
      src/Cedar/IPsec_L2TP.h
  19. 132 10
      src/Cedar/IPsec_PPP.c
  20. 6 1
      src/Cedar/IPsec_PPP.h
  21. 1 0
      src/Cedar/NM.c
  22. 3 1
      src/Cedar/Nat.c
  23. 1 0
      src/Cedar/Nat.h
  24. 564 6
      src/Cedar/NativeStack.c
  25. 46 0
      src/Cedar/NativeStack.h
  26. 33 2
      src/Cedar/Protocol.c
  27. 1588 0
      src/Cedar/Radius.c
  28. 246 1
      src/Cedar/Radius.h
  29. 8 0
      src/Cedar/Sam.c
  30. 14 0
      src/Cedar/Server.c
  31. 130 16
      src/Cedar/Virtual.c
  32. 8 3
      src/Cedar/Virtual.h
  33. 2 2
      src/CurrentBuild.txt
  34. 1 0
      src/Mayaqua/MayaType.h
  35. 135 0
      src/Mayaqua/Memory.c
  36. 16 0
      src/Mayaqua/Memory.h
  37. 63 0
      src/Mayaqua/Network.c
  38. 4 0
      src/Mayaqua/Network.h
  39. 1 0
      src/Mayaqua/TcpIp.c
  40. 3 2
      src/Mayaqua/Tick64.c
  41. 1 1
      src/Mayaqua/Tick64.h
  42. 二进制
      src/bin/hamcore/SeLow_x64.sys
  43. 二进制
      src/bin/hamcore/SeLow_x86.sys
  44. 二进制
      src/bin/hamcore/pxwfp_x64.sys
  45. 二进制
      src/bin/hamcore/pxwfp_x86.sys
  46. 二进制
      src/bin/hamcore/see.sys
  47. 二进制
      src/bin/hamcore/see_x64.sys
  48. 2 0
      src/bin/hamcore/strtable_cn.stb
  49. 2 0
      src/bin/hamcore/strtable_en.stb
  50. 2 0
      src/bin/hamcore/strtable_ja.stb
  51. 二进制
      src/bin/hamcore/vpn_driver.sys
  52. 二进制
      src/bin/hamcore/vpn_driver6.sys
  53. 二进制
      src/bin/hamcore/vpn_driver6_x64.sys
  54. 二进制
      src/bin/hamcore/vpn_driver_x64.sys
  55. 二进制
      src/bin/vpnweb.cab
  56. 二进制
      src/bin/vpnweb.ocx
  57. 1 1
      src/vpnweb/vpnweb.h
  58. 1 1
      src/vpnweb/vpnweb_i.c
  59. 1 1
      src/vpnweb/vpnweb_p.c

+ 10 - 0
src/Cedar/Bridge.c

@@ -556,6 +556,16 @@ BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, boo
 	return b;
 }
 
+// Raw IP bridge is supported only on Linux
+bool IsRawIpBridgeSupported()
+{
+#ifdef	UNIX_LINUX
+	return true;
+#else	// UNIX_LINUX
+	return false;
+#endif	// UNIX_LINUX
+}
+
 
 // Developed by SoftEther VPN Project at University of Tsukuba in Japan.
 // Department of Computer Science has dozens of overly-enthusiastic geeks.

+ 4 - 0
src/Cedar/Bridge.h

@@ -126,6 +126,9 @@
 
 #endif	// OS_WIN32
 
+// Constants
+#define	BRIDGE_SPECIAL_IPRAW_NAME		"ipv4_rawsocket_virtual_router"
+
 // Bridge
 struct BRIDGE
 {
@@ -171,6 +174,7 @@ bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename);
 bool IsBridgeSupported();
 bool IsNeedWinPcap();
 UINT GetEthDeviceHash();
+bool IsRawIpBridgeSupported();
 
 #endif	// BRIDGE_H
 

+ 791 - 3
src/Cedar/BridgeUnix.c

@@ -374,7 +374,7 @@ TOKEN_LIST *GetEthListSolaris()
 
 #ifdef	UNIX_LINUX
 // Get Ethernet device list on Linux
-TOKEN_LIST *GetEthListLinux()
+TOKEN_LIST *GetEthListLinux(bool enum_normal, bool enum_rawip)
 {
 	struct ifreq ifr;
 	TOKEN_LIST *t;
@@ -383,6 +383,11 @@ TOKEN_LIST *GetEthListLinux()
 	LIST *o;
 	char name[MAX_SIZE];
 
+	if (enum_normal == false && enum_rawip)
+	{
+		return ParseToken(BRIDGE_SPECIAL_IPRAW_NAME, NULL);
+	}
+
 	o = NewListFast(CompareStr);
 
 	s = UnixEthOpenRawSocket();
@@ -431,7 +436,7 @@ TOKEN_LIST *GetEthListLinux()
 	Sort(o);
 
 	t = ZeroMalloc(sizeof(TOKEN_LIST));
-	t->NumTokens = LIST_NUM(o);
+	t->NumTokens = LIST_NUM(o) + (enum_rawip ? 1 : 0);
 	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
 
 	for (i = 0;i < LIST_NUM(o);i++)
@@ -440,6 +445,11 @@ TOKEN_LIST *GetEthListLinux()
 		t->Token[i] = name;
 	}
 
+	if (enum_rawip)
+	{
+		t->Token[t->NumTokens - 1] = CopyStr(BRIDGE_SPECIAL_IPRAW_NAME);
+	}
+
 	ReleaseList(o);
 
 	return t;
@@ -542,11 +552,15 @@ TOKEN_LIST *GetEthListBpf()
 
 // Enumerate Ethernet devices
 TOKEN_LIST *GetEthList()
+{
+	return GetEthListEx(NULL, true, false);
+}
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden, bool enum_normal, bool enum_rawip)
 {
 	TOKEN_LIST *t = NULL;
 
 #if	defined(UNIX_LINUX)
-	t = GetEthListLinux();
+	t = GetEthListLinux(enum_normal, enum_rawip);
 #elif	defined(UNIX_SOLARIS)
 	t = GetEthListSolaris();
 #elif	defined(BRIDGE_PCAP)
@@ -575,6 +589,11 @@ ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
 		return NULL;
 	}
 
+	if (StrCmpi(name, BRIDGE_SPECIAL_IPRAW_NAME) == 0)
+	{
+		return OpenEthLinuxIpRaw();
+	}
+
 	if (tapmode)
 	{
 #ifndef	NO_VLAN
@@ -732,6 +751,10 @@ UINT EthGetMtu(ETH *e)
 	{
 		return 0;
 	}
+	if (e->IsRawIpMode)
+	{
+		return 0;
+	}
 
 	if (e->CurrentMtu != 0)
 	{
@@ -802,6 +825,10 @@ bool EthSetMtu(ETH *e, UINT mtu)
 	{
 		return false;
 	}
+	if (e->IsRawIpMode)
+	{
+		return false;
+	}
 
 	if (mtu == 0)
 	{
@@ -865,6 +892,11 @@ bool EthIsChangeMtuSupported(ETH *e)
 		return false;
 	}
 
+	if (e->IsRawIpMode)
+	{
+		return false;
+	}
+
 	return true;
 #else	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
 	return false;
@@ -1526,6 +1558,13 @@ void CloseEth(ETH *e)
 		return;
 	}
 
+	if (e->IsRawIpMode)
+	{
+		CloseEthLinuxIpRaw(e);
+
+		return;
+	}
+
 	if (e->Tap != NULL)
 	{
 #ifndef	NO_VLAN
@@ -1647,6 +1686,11 @@ UINT EthGetPacketLinux(ETH *e, void **data)
 		return INFINITE;
 	}
 
+	if (e->IsRawIpMode)
+	{
+		return EthGetPacketLinuxIpRaw(e, data);
+	}
+
 	if (e->Tap != NULL)
 	{
 #ifndef	NO_VLAN
@@ -1949,6 +1993,11 @@ void EthPutPacket(ETH *e, void *data, UINT size)
 	{
 		return;
 	}
+	if (e->IsRawIpMode)
+	{
+		EthPutPacketLinuxIpRaw(e, data, size);
+		return;
+	}
 	if (size < 14 || size > MAX_PACKET_SIZE)
 	{
 		Free(data);
@@ -2017,6 +2066,745 @@ void EthPutPacket(ETH *e, void *data, UINT size)
 	Free(data);
 }
 
+
+
+
+// Open ETH by using IP raw packets
+ETH *OpenEthLinuxIpRaw()
+{
+	ETH *e;
+
+	if (IsRawIpBridgeSupported() == false)
+	{
+		return NULL;
+	}
+
+	e = ZeroMalloc(sizeof(ETH));
+
+	e->IsRawIpMode = true;
+
+	e->RawTcp = NewUDP4(MAKE_SPECIAL_PORT(IPPROTO_TCP), NULL);
+	e->RawUdp = NewUDP4(MAKE_SPECIAL_PORT(IPPROTO_UDP), NULL);
+	e->RawIcmp = NewUDP4(MAKE_SPECIAL_PORT(IPPROTO_ICMP), NULL);
+
+	if (e->RawTcp == NULL || e->RawUdp == NULL || e->RawIcmp == NULL)
+	{
+		ReleaseSock(e->RawTcp);
+		ReleaseSock(e->RawUdp);
+		ReleaseSock(e->RawIcmp);
+
+		Free(e);
+		return NULL;
+	}
+
+	ClearSockDfBit(e->RawTcp);
+	ClearSockDfBit(e->RawUdp);
+	ClearSockDfBit(e->RawIcmp);
+
+	SetRawSockHeaderIncludeOption(e->RawTcp, true);
+	SetRawSockHeaderIncludeOption(e->RawUdp, true);
+	SetRawSockHeaderIncludeOption(e->RawIcmp, true);
+
+	e->Name = CopyStr(BRIDGE_SPECIAL_IPRAW_NAME);
+	e->Title = CopyStr(BRIDGE_SPECIAL_IPRAW_NAME);
+	e->Cancel = NewCancel();
+
+	UnixDeletePipe(e->Cancel->pipe_read, e->Cancel->pipe_write);
+	e->Cancel->pipe_read = e->Cancel->pipe_write = -1;
+
+	UnixSetSocketNonBlockingMode(e->RawTcp->socket, true);
+	UnixSetSocketNonBlockingMode(e->RawUdp->socket, true);
+	UnixSetSocketNonBlockingMode(e->RawIcmp->socket, true);
+
+	e->Cancel->SpecialFlag = true;
+	e->Cancel->pipe_read = e->RawTcp->socket;
+	e->Cancel->pipe_special_read2 = e->RawUdp->socket;
+	e->Cancel->pipe_special_read3 = e->RawIcmp->socket;
+
+	e->RawIpMyMacAddr[2] = 0x01;
+	e->RawIpMyMacAddr[5] = 0x01;
+
+	SetIP(&e->MyIP, 10, 171, 7, 253);
+	SetIP(&e->YourIP, 10, 171, 7, 254);
+
+	e->RawIpSendQueue = NewQueueFast();
+
+	e->RawIP_TmpBufferSize = 67000;
+	e->RawIP_TmpBuffer = Malloc(e->RawIP_TmpBufferSize);
+
+	return e;
+}
+
+// Close ETH by using IP raw packets
+void CloseEthLinuxIpRaw(ETH *e)
+{
+	if (e == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		BUF *buf = GetNext(e->RawIpSendQueue);
+		if (buf == NULL)
+		{
+			break;
+		}
+
+		FreeBuf(buf);
+	}
+	ReleaseQueue(e->RawIpSendQueue);
+
+	Free(e->Name);
+	Free(e->Title);
+
+	ReleaseSock(e->RawTcp);
+	ReleaseSock(e->RawUdp);
+	ReleaseSock(e->RawIcmp);
+
+	ReleaseCancel(e->Cancel);
+
+	Free(e->RawIP_TmpBuffer);
+
+	Free(e);
+}
+
+// Receive an IP raw packet
+UINT EthGetPacketLinuxIpRaw(ETH *e, void **data)
+{
+	UINT r;
+	BUF *b;
+	// Validate arguments
+	if (e == NULL || data == NULL)
+	{
+		return INFINITE;
+	}
+	if (e->RawIp_HasError)
+	{
+		return INFINITE;
+	}
+
+	b = GetNext(e->RawIpSendQueue);
+	if (b != NULL)
+	{
+		UINT size;
+
+		*data = b->Buf;
+		size = b->Size;
+
+		Free(b);
+
+		return size;
+	}
+
+	r = EthGetPacketLinuxIpRawForSock(e, data, e->RawTcp, IP_PROTO_TCP);
+	if (r == 0)
+	{
+		r = EthGetPacketLinuxIpRawForSock(e, data, e->RawUdp, IP_PROTO_UDP);
+		if (r == 0)
+		{
+			r = EthGetPacketLinuxIpRawForSock(e, data, e->RawIcmp, IP_PROTO_ICMPV4);
+		}
+	}
+
+	if (r == INFINITE)
+	{
+		e->RawIp_HasError = true;
+	}
+
+	return r;
+}
+
+// Receive an IP raw packet for the specified socket
+UINT EthGetPacketLinuxIpRawForSock(ETH *e, void **data, SOCK *s, UINT proto)
+{
+	UCHAR *tmp;
+	UINT r;
+	IP src_addr;
+	UINT src_port;
+	UINT ret = INFINITE;
+	UCHAR *retbuf;
+	PKT *p;
+	bool ok = false;
+	// Validate arguments
+	if (e == NULL || data == NULL)
+	{
+		return INFINITE;
+	}
+
+	tmp = e->RawIP_TmpBuffer;
+
+LABEL_RETRY:
+	*data = NULL;
+
+	r = RecvFrom(s, &src_addr, &src_port, tmp, e->RawIP_TmpBufferSize);
+	if (r == SOCK_LATER)
+	{
+		return 0;
+	}
+
+	if (r == 0)
+	{
+		if (s->IgnoreRecvErr)
+		{
+			return 0;
+		}
+		else
+		{
+			return INFINITE;
+		}
+	}
+
+	ret = 14 + r;
+	retbuf = Malloc(ret);
+	*data = retbuf;
+
+	Copy(retbuf, e->RawIpYourMacAddr, 6);
+	Copy(retbuf + 6, e->RawIpMyMacAddr, 6);
+	retbuf[12] = 0x08;
+	retbuf[13] = 0x00;
+	Copy(retbuf + 14, tmp, r);
+
+	// Mangle packet
+	p = ParsePacket(retbuf, ret);
+	if (p != NULL)
+	{
+		if (p->TypeL3 == L3_IPV4)
+		{
+			IPV4_HEADER *ip;
+			IP original_dest_ip;
+
+			ip = p->L3.IPv4Header;
+
+			UINTToIP(&original_dest_ip, ip->DstIP);
+
+			if (IsZeroIP(&e->MyPhysicalIPForce) == false && CmpIpAddr(&e->MyPhysicalIPForce, &original_dest_ip) == 0 ||
+				(IsIPMyHost(&original_dest_ip) && IsLocalHostIP(&original_dest_ip) == false && IsHostIPAddress4(&original_dest_ip)))
+			{
+				if (IsZeroIP(&e->MyPhysicalIPForce) && CmpIpAddr(&e->MyPhysicalIP, &original_dest_ip) != 0)
+				{
+					// Update MyPhysicalIP
+					Copy(&e->MyPhysicalIP, &original_dest_ip, sizeof(IP));
+//					Debug("e->MyPhysicalIP = %r\n", &e->MyPhysicalIP);
+				}
+
+				if (IsZeroIP(&e->MyPhysicalIPForce) == false)
+				{
+					Copy(&e->MyPhysicalIP, &e->MyPhysicalIPForce, sizeof(IP));
+				}
+
+				ip->DstIP = IPToUINT(&e->YourIP);
+				ip->Checksum = 0;
+				ip->Checksum = IpChecksum(ip, IPV4_GET_HEADER_LEN(ip) * 5);
+
+				if (p->TypeL4 == L4_TCP)
+				{
+					TCP_HEADER *tcp = p->L4.TCPHeader;
+/*
+					if (Endian16(tcp->SrcPort) == 80)
+					{
+						IP a, b;
+						UINTToIP(&a, ip->SrcIP);
+						UINTToIP(&b, ip->DstIP);
+						Debug("%r %r %u %u\n", &a, &b, Endian16(tcp->SrcPort), Endian16(tcp->DstPort));
+					}*/
+
+					ok = true;
+				}
+				else if (p->TypeL4 == L4_UDP)
+				{
+					UDP_HEADER *udp = p->L4.UDPHeader;
+
+					udp->Checksum = 0;
+
+					ok = true;
+				}
+				else if (p->TypeL4 == L4_ICMPV4)
+				{
+					ICMP_HEADER *icmp = p->L4.ICMPHeader;
+
+					if (icmp->Type == ICMP_TYPE_DESTINATION_UNREACHABLE || icmp->Type == ICMP_TYPE_TIME_EXCEEDED)
+					{
+						// Rewrite the Src IP of the IPv4 header of the ICMP response packet
+						UINT size = p->PacketSize - ((UCHAR *)icmp - (UCHAR *)p->PacketData);
+						UCHAR *data = (UCHAR *)icmp;
+						IPV4_HEADER *orig_ipv4 = (IPV4_HEADER *)(((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+						UINT orig_ipv4_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+						UINT orig_ipv4_header_size = GetIpHeaderSize((UCHAR *)orig_ipv4, orig_ipv4_size);
+
+						if (orig_ipv4_header_size >= sizeof(IPV4_HEADER) && orig_ipv4_size >= orig_ipv4_header_size)
+						{
+							if (orig_ipv4->Protocol == IP_PROTO_ICMPV4)
+							{
+								// Search the inner ICMP header
+								UINT inner_icmp_size = orig_ipv4_size - orig_ipv4_header_size;
+
+								if (inner_icmp_size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+								{
+									ICMP_HEADER *inner_icmp = (ICMP_HEADER *)(((UCHAR *)data) +
+										sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + orig_ipv4_header_size);
+
+									if (inner_icmp->Type == ICMP_TYPE_ECHO_REQUEST)
+									{
+										ICMP_ECHO *inner_echo = (ICMP_ECHO *)(((UCHAR *)inner_icmp) + sizeof(ICMP_HEADER));
+
+										inner_icmp->Checksum = 0;
+										orig_ipv4->SrcIP = IPToUINT(&e->YourIP);
+										orig_ipv4->Checksum = 0;
+										orig_ipv4->Checksum = IpChecksum(orig_ipv4, orig_ipv4_header_size);
+
+										// Rewrite the outer ICMP header
+										if (true)
+										{
+											UCHAR *payload;
+											UINT payload_size;
+											ICMP_ECHO *echo;
+
+											// Echo Response
+											echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
+
+											if (size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+											{
+												payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
+												payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+												// Rewrite the header
+												icmp->Checksum = 0;
+												icmp->Checksum = IpChecksum(icmp, size);
+											}
+										}
+									}
+								}
+							}
+						}
+					}
+
+					icmp->Checksum = 0;
+					icmp->Checksum = IpChecksum(icmp, p->PayloadSize);
+
+					ok = true;
+				}
+				else if (p->TypeL4 == L4_FRAGMENT)
+				{
+					ok = true;
+				}
+			}
+		}
+
+		FreePacket(p);
+	}
+
+	if (ok == false)
+	{
+		Free(*data);
+		*data = NULL;
+
+		goto LABEL_RETRY;
+	}
+
+	return ret;
+}
+
+// Send internal IP packet (insert into the send queue)
+void EthSendIpPacketInnerIpRaw(ETH *e, void *data, UINT size, USHORT protocol)
+{
+	BUF *b;
+	if (e == NULL || data == NULL || size == 0)
+	{
+		return;
+	}
+
+	if (e->RawIpSendQueue->num_item >= 1024)
+	{
+		return;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, e->RawIpYourMacAddr, 6);
+	WriteBuf(b, e->RawIpMyMacAddr, 6);
+	WriteBufShort(b, protocol);
+	WriteBuf(b, data, size);
+	SeekBufToBegin(b);
+
+	InsertQueue(e->RawIpSendQueue, b);
+}
+
+// Process the packet internal if necessary
+bool EthProcessIpPacketInnerIpRaw(ETH *e, PKT *p)
+{
+	bool ret = false;
+	if (e == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	if (p->TypeL3 == L3_ARPV4)
+	{
+		// ARP processing
+		ARPV4_HEADER *arp = p->L3.ARPv4Header;
+
+		if (Endian16(arp->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+			Endian16(arp->ProtocolType) == MAC_PROTO_IPV4 &&
+			arp->HardwareSize == 6 && arp->ProtocolType == 4)
+		{
+			if (IPToUINT(&e->MyIP) == arp->TargetIP)
+			{
+				if (Endian16(arp->Operation) == ARP_OPERATION_REQUEST)
+				{
+					ARPV4_HEADER r;
+
+					Zero(&r, sizeof(r));
+					r.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+					r.ProtocolType = Endian16(MAC_PROTO_IPV4);
+					r.HardwareSize = 6;
+					r.ProtocolSize = 4;
+					r.Operation = Endian16(ARP_OPERATION_RESPONSE);
+					Copy(r.SrcAddress, e->RawIpMyMacAddr, 6);
+					Copy(r.TargetAddress, arp->SrcAddress, 6);
+					r.SrcIP = IPToUINT(&e->MyIP);
+					r.TargetIP = arp->SrcIP;
+
+					EthSendIpPacketInnerIpRaw(e, &r, sizeof(ARPV4_HEADER), MAC_PROTO_ARPV4);
+				}
+			}
+		}
+	}
+	else if (p->TypeL3 == L3_IPV4 && p->TypeL4 == L4_UDP && p->TypeL7 == L7_DHCPV4)
+	{
+		// DHCP processing
+		DHCPV4_HEADER *dhcp;
+		UCHAR *data;
+		UINT size;
+		UINT dhcp_header_size;
+		UINT dhcp_data_offset;
+		UINT tran_id;
+		UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
+		bool ok;
+		DHCP_OPTION_LIST *opt;
+
+		dhcp = p->L7.DHCPv4Header;
+		tran_id = Endian32(dhcp->TransactionId);
+
+		// Get the DHCP data and size
+		dhcp_header_size = sizeof(DHCPV4_HEADER);
+		dhcp_data_offset = (UINT)(((UCHAR *)p->L7.DHCPv4Header) - ((UCHAR *)p->MacHeader) + dhcp_header_size);
+		data = ((UCHAR *)dhcp) + dhcp_header_size;
+		size = p->PacketSize - dhcp_data_offset;
+		if (dhcp_header_size < 5)
+		{
+			// Data size is invalid
+			return false;
+		}
+
+		// Search for Magic Cookie
+		ok = false;
+		while (size >= 5)
+		{
+			if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
+			{
+				// Found
+				data += 4;
+				size -= 4;
+				ok = true;
+				break;
+			}
+			data++;
+			size--;
+		}
+
+		if (ok == false)
+		{
+			// The packet is invalid
+			return false;
+		}
+
+		// Parse DHCP options list
+		opt = ParseDhcpOptionList(data, size);
+		if (opt == NULL)
+		{
+			// The packet is invalid
+			return false;
+		}
+
+		if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST || opt->Opcode == DHCP_INFORM))
+		{
+			// Operate as the server
+			UINT ip = IPToUINT(&e->YourIP);
+			if (ip != 0 || opt->Opcode == DHCP_INFORM)
+			{
+				// Respond if there is providable IP address
+				DHCP_OPTION_LIST ret;
+				LIST *o;
+				UINT hw_type;
+				UINT hw_addr_size;
+				UINT new_ip = ip;
+				IP default_dns;
+
+				Zero(&default_dns, sizeof(default_dns));
+
+				Zero(&ret, sizeof(ret));
+
+				ret.Opcode = (opt->Opcode == DHCP_DISCOVER ? DHCP_OFFER : DHCP_ACK);
+				ret.ServerAddress = IPToUINT(&e->MyIP);
+				ret.LeaseTime = 3600;
+				if (opt->Opcode == DHCP_INFORM)
+				{
+					ret.LeaseTime = 0;
+				}
+
+				ret.SubnetMask = SetIP32(255, 255, 255, 252);
+
+				if (UnixGetDefaultDns(&default_dns) && IsZeroIp(&default_dns) == false)
+				{
+					ret.DnsServer = IPToUINT(&default_dns);
+					ret.DnsServer2 = SetIP32(8, 8, 8, 8);
+				}
+				else
+				{
+					ret.DnsServer = SetIP32(8, 8, 8, 8);
+					ret.DnsServer2 = SetIP32(8, 8, 4, 4);
+				}
+
+				ret.Gateway = IPToUINT(&e->MyIP);
+
+				if (opt->Opcode != DHCP_INFORM)
+				{
+					char client_mac[MAX_SIZE];
+					char client_ip[64];
+					IP ips;
+					BinToStr(client_mac, sizeof(client_mac), p->MacAddressSrc, 6);
+					UINTToIP(&ips, ip);
+					IPToStr(client_ip, sizeof(client_ip), &ips);
+					Debug("IP_RAW: DHCP %s : %s given %s\n",
+						ret.Opcode == DHCP_OFFER ? "DHCP_OFFER" : "DHCP_ACK",
+						client_mac, client_ip);
+				}
+
+				// Build a DHCP option
+				o = BuildDhcpOption(&ret);
+				if (o != NULL)
+				{
+					BUF *b = BuildDhcpOptionsBuf(o);
+					if (b != NULL)
+					{
+						UINT dest_ip = p->L3.IPv4Header->SrcIP;
+						UINT blank_size = 128 + 64;
+						UINT dhcp_packet_size;
+						UINT magic = Endian32(DHCP_MAGIC_COOKIE);
+						DHCPV4_HEADER *dhcp;
+						void *magic_cookie_addr;
+						void *buffer_addr;
+
+						if (dest_ip == 0)
+						{
+							dest_ip = 0xffffffff;
+						}
+
+						// Calculate the DHCP packet size
+						dhcp_packet_size = blank_size + sizeof(DHCPV4_HEADER) + sizeof(magic) + b->Size;
+
+						if (dhcp_packet_size < DHCP_MIN_SIZE)
+						{
+							// Padding
+							dhcp_packet_size = DHCP_MIN_SIZE;
+						}
+
+						// Create a header
+						dhcp = ZeroMalloc(dhcp_packet_size);
+
+						dhcp->OpCode = 2;
+						dhcp->HardwareType = hw_type;
+						dhcp->HardwareAddressSize = hw_addr_size;
+						dhcp->Hops = 0;
+						dhcp->TransactionId = Endian32(tran_id);
+						dhcp->Seconds = 0;
+						dhcp->Flags = 0;
+						dhcp->YourIP = new_ip;
+						dhcp->ServerIP = IPToUINT(&e->MyIP);
+						Copy(dhcp->ClientMacAddress, p->MacAddressSrc, 6);
+
+						// Calculate the address
+						magic_cookie_addr = (((UCHAR *)dhcp) + sizeof(DHCPV4_HEADER) + blank_size);
+						buffer_addr = ((UCHAR *)magic_cookie_addr) + sizeof(magic);
+
+						// Magic Cookie
+						Copy(magic_cookie_addr, &magic, sizeof(magic));
+
+						// Buffer
+						Copy(buffer_addr, b->Buf, b->Size);
+
+						if (true)
+						{
+							UCHAR *data = ZeroMalloc(sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + dhcp_packet_size);
+							IPV4_HEADER *ipv4 = (IPV4_HEADER *)(data);
+							UDP_HEADER *udp = (UDP_HEADER *)(data + sizeof(IPV4_HEADER));
+
+							Copy(data + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), dhcp, dhcp_packet_size);
+
+							IPV4_SET_VERSION(ipv4, 4);
+							IPV4_SET_HEADER_LEN(ipv4, 5);
+							ipv4->TotalLength = Endian16(sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + dhcp_packet_size);
+							ipv4->TimeToLive = 63;
+							ipv4->Protocol = IP_PROTO_UDP;
+							ipv4->SrcIP = IPToUINT(&e->MyIP);
+							ipv4->DstIP = dest_ip;
+							ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+							udp->SrcPort = Endian16(NAT_DHCP_SERVER_PORT);
+							udp->DstPort = Endian16(NAT_DHCP_CLIENT_PORT);
+							udp->PacketLength = Endian16(sizeof(UDP_HEADER) + dhcp_packet_size);
+							udp->Checksum = CalcChecksumForIPv4(ipv4->SrcIP, ipv4->DstIP, IP_PROTO_UDP,
+								dhcp, dhcp_packet_size, 0);
+							if (udp->Checksum == 0)
+							{
+								udp->Checksum = 0xffff;
+							}
+
+							EthSendIpPacketInnerIpRaw(e, data, sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + dhcp_packet_size, MAC_PROTO_IPV4);
+
+							Free(data);
+						}
+
+						// Release the memory
+						Free(dhcp);
+						FreeBuf(b);
+					}
+					FreeDhcpOptions(o);
+				}
+			}
+		}
+
+		Free(opt);
+	}
+
+	return ret;
+}
+
+// Send an IP raw packet
+void EthPutPacketLinuxIpRaw(ETH *e, void *data, UINT size)
+{
+	PKT *p;
+	// Validate arguments
+	if (e == NULL || data == NULL)
+	{
+		return;
+	}
+	if (size < 14 || size > MAX_PACKET_SIZE || e->RawIp_HasError)
+	{
+		Free(data);
+		return;
+	}
+
+	p = ParsePacket(data, size);
+
+	if (p->BroadcastPacket || Cmp(p->MacAddressDest, e->RawIpMyMacAddr, 6) == 0)
+	{
+		if (IsValidUnicastMacAddress(p->MacAddressSrc))
+		{
+			Copy(e->RawIpYourMacAddr, p->MacAddressSrc, 6);
+		}
+	}
+
+	if (IsZero(e->RawIpYourMacAddr, 6) || IsValidUnicastMacAddress(p->MacAddressSrc) == false ||
+		(p->BroadcastPacket == false && Cmp(p->MacAddressDest, e->RawIpMyMacAddr, 6) != 0))
+	{
+		Free(data);
+		FreePacket(p);
+		return;
+	}
+
+	if (p != NULL)
+	{
+		SOCK *s = NULL;
+
+		if (p->TypeL3 == L3_IPV4)
+		{
+			if (p->TypeL4 == L4_TCP)
+			{
+				if (IsZeroIP(&e->MyPhysicalIP) == false)
+				{
+					s = e->RawTcp;
+				}
+			}
+			else if (p->TypeL4 == L4_UDP)
+			{
+				if (EthProcessIpPacketInnerIpRaw(e, p) == false)
+				{
+					s = e->RawUdp;
+				}
+			}
+			else if (p->TypeL4 == L4_ICMPV4)
+			{
+				if (IsZeroIP(&e->MyPhysicalIP) == false)
+				{
+					s = e->RawIcmp;
+				}
+			}
+			else if (p->TypeL4 == L4_FRAGMENT)
+			{
+				if (IsZeroIP(&e->MyPhysicalIP) == false)
+				{
+					s = e->RawIcmp;
+				}
+			}
+		}
+		else if (p->TypeL3 == L3_ARPV4)
+		{
+			EthProcessIpPacketInnerIpRaw(e, p);
+		}
+
+		if (s != NULL && p->L3.IPv4Header->DstIP != 0xffffffff && p->BroadcastPacket == false &&
+			p->L3.IPv4Header->SrcIP == IPToUINT(&e->YourIP))
+		{
+			UCHAR *send_data = p->IPv4PayloadData;
+			UCHAR *head = p->PacketData;
+			UINT remove_header_size = (UINT)(send_data - head);
+
+			if (p->PacketSize > remove_header_size)
+			{
+				IP dest;
+				UINT send_data_size = p->PacketSize - remove_header_size;
+
+				// checksum
+				if (p->TypeL4 == L4_UDP)
+				{
+					p->L4.UDPHeader->Checksum = 0;
+				}
+				else if (p->TypeL4 == L4_TCP)
+				{
+					p->L4.TCPHeader->Checksum = 0;
+					p->L4.TCPHeader->Checksum = CalcChecksumForIPv4(IPToUINT(&e->MyPhysicalIP),
+						p->L3.IPv4Header->DstIP, IP_PROTO_TCP,
+						p->L4.TCPHeader, p->IPv4PayloadSize, 0);
+				}
+
+				UINTToIP(&dest, p->L3.IPv4Header->DstIP);
+
+				if (s->RawIP_HeaderIncludeFlag == false)
+				{
+					SendTo(s, &dest, 0, send_data, send_data_size);
+				}
+				else
+				{
+					IPV4_HEADER *ip = p->L3.IPv4Header;
+
+					ip->SrcIP = IPToUINT(&e->MyPhysicalIP);
+					ip->Checksum = 0;
+					ip->Checksum = IpChecksum(ip, IPV4_GET_HEADER_LEN(ip) * 4);
+
+					SendTo(s, &dest, 0, ip, ((UCHAR *)p->PacketData - (UCHAR *)ip) + p->PacketSize);
+				}
+			}
+		}
+
+		FreePacket(p);
+	}
+
+	Free(data);
+}
+
+
 #endif	// BRIDGE_C
 
 

+ 23 - 1
src/Cedar/BridgeUnix.h

@@ -162,6 +162,19 @@ struct ETH
 
 	VLAN *Tap;					// tap
 	bool Linux_IsAuxDataSupported;	// Is PACKET_AUXDATA supported
+
+	bool IsRawIpMode;			// RAW IP mode
+	SOCK *RawTcp, *RawUdp, *RawIcmp;	// RAW sockets
+	bool RawIp_HasError;
+	UCHAR RawIpMyMacAddr[6];
+	UCHAR RawIpYourMacAddr[6];
+	IP MyIP;
+	IP YourIP;
+	QUEUE *RawIpSendQueue;
+	IP MyPhysicalIP;
+	IP MyPhysicalIPForce;
+	UCHAR *RawIP_TmpBuffer;
+	UINT RawIP_TmpBufferSize;
 };
 
 #if defined( BRIDGE_BPF ) || defined( BRIDGE_PCAP )
@@ -180,7 +193,8 @@ bool IsEthSupportedLinux();
 bool IsEthSupportedSolaris();
 bool IsEthSupportedPcap();
 TOKEN_LIST *GetEthList();
-TOKEN_LIST *GetEthListLinux();
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden, bool enum_normal, bool enum_rawip);
+TOKEN_LIST *GetEthListLinux(bool enum_normal, bool enum_rawip);
 TOKEN_LIST *GetEthListSolaris();
 TOKEN_LIST *GetEthListPcap();
 ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
@@ -203,6 +217,14 @@ bool EthIsChangeMtuSupported(ETH *e);
 bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size);
 bool EthIsInterfaceDescriptionSupportedUnix();
 
+ETH *OpenEthLinuxIpRaw();
+void CloseEthLinuxIpRaw(ETH *e);
+UINT EthGetPacketLinuxIpRaw(ETH *e, void **data);
+UINT EthGetPacketLinuxIpRawForSock(ETH *e, void **data, SOCK *s, UINT proto);
+void EthPutPacketLinuxIpRaw(ETH *e, void *data, UINT size);
+bool EthProcessIpPacketInnerIpRaw(ETH *e, PKT *p);
+void EthSendIpPacketInnerIpRaw(ETH *e, void *data, UINT size, USHORT protocol);
+
 #ifdef	UNIX_SOLARIS
 // Function prototype for Solaris
 bool DlipAttatchRequest(int fd, UINT devid);

+ 8 - 3
src/Cedar/BridgeWin32.c

@@ -1356,9 +1356,9 @@ TOKEN_LIST *GetEthList()
 {
 	UINT v;
 
-	return GetEthListEx(&v);
+	return GetEthListEx(&v, true, false);
 }
-TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden)
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden, bool enum_normal, bool enum_rawip)
 {
 	TOKEN_LIST *ret;
 	UINT i;
@@ -1371,6 +1371,11 @@ TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden)
 		return NULL;
 	}
 
+	if (enum_normal == false)
+	{
+		return NullToken();
+	}
+
 	if (total_num_including_hidden == NULL)
 	{
 		total_num_including_hidden = &dummy_int;
@@ -2139,7 +2144,7 @@ RELEASE:
 		return false;
 	}
 
-	o = GetEthListEx(&total_num);
+	o = GetEthListEx(&total_num, true, false);
 	if (o == NULL || total_num == 0)
 	{
 		FreeToken(o);

+ 7 - 1
src/Cedar/BridgeWin32.h

@@ -213,6 +213,12 @@ struct ETH
 
 	SU *Su;						// SeLow handle
 	SU_ADAPTER *SuAdapter;		// SeLow adapter handle
+
+	// Unused
+	bool IsRawIpMode;			// RAW IP mode
+	UCHAR RawIpMyMacAddr[6];
+	UCHAR RawIpYourMacAddr[6];
+	IP MyPhysicalIPForce;
 };
 
 // Function prototype
@@ -221,7 +227,7 @@ void FreeEth();
 bool IsEthSupported();
 bool IsEthSupportedInner();
 TOKEN_LIST *GetEthList();
-TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden);
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden, bool enum_normal, bool enum_rawip);
 ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
 ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr);
 void CloseEth(ETH *e);

+ 28 - 0
src/Cedar/Cedar.c

@@ -118,6 +118,34 @@ static UINT init_cedar_counter = 0;
 static REF *cedar_log_ref = NULL;
 static LOG *cedar_log;
 
+// Check whether there is any EAP-enabled RADIUS configuration
+bool CedarIsThereAnyEapEnabledRadiusConfig(CEDAR *c)
+{
+	bool ret = false;
+	UINT i;
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	LockHubList(c);
+	{
+		for (i = 0;i < LIST_NUM(c->HubList);i++)
+		{
+			HUB *hub = LIST_DATA(c->HubList, i);
+
+			if (hub->RadiusConvertAllMsChapv2AuthRequestToEap)
+			{
+				ret = true;
+				break;
+			}
+		}
+	}
+	UnlockHubList(c);
+
+	return ret;
+}
+
 // Get build date of current code
 UINT64 GetCurrentBuildDate()
 {

+ 7 - 6
src/Cedar/Cedar.h

@@ -138,7 +138,7 @@
 #define	CEDAR_VER					419
 
 // Build Number
-#define	CEDAR_BUILD					9578
+#define	CEDAR_BUILD					9582
 
 // Beta number
 //#define	BETA_NUMBER					3
@@ -153,16 +153,16 @@
 
 // Specify the location to build
 #ifndef	BUILD_PLACE
-#define	BUILD_PLACE			"pc25"
+#define	BUILD_PLACE			"pc30"
 #endif	// BUILD_PLACE
 
 // Specifies the build date
 #define	BUILD_DATE_Y		2015
-#define	BUILD_DATE_M		9
-#define	BUILD_DATE_D		15
+#define	BUILD_DATE_M		10
+#define	BUILD_DATE_D		6
 #define	BUILD_DATE_HO		14
-#define	BUILD_DATE_MI		39
-#define	BUILD_DATE_SE		35
+#define	BUILD_DATE_MI		56
+#define	BUILD_DATE_SE		30
 
 // Tolerable time difference
 #define	ALLOW_TIMESTAMP_DIFF		(UINT64)(3 * 24 * 60 * 60 * 1000)
@@ -1259,6 +1259,7 @@ UINT CedarGetQueueBudgetConsuming(CEDAR *c);
 UINT CedarGetFifoBudgetConsuming(CEDAR *c);
 UINT CedarGetQueueBudgetBalance(CEDAR *c);
 UINT CedarGetFifoBudgetBalance(CEDAR *c);
+bool CedarIsThereAnyEapEnabledRadiusConfig(CEDAR *c);
 
 
 

+ 12 - 0
src/Cedar/CedarType.h

@@ -142,6 +142,16 @@ typedef struct AUTHNT AUTHNT;
 // ==============================================================
 
 typedef struct RADIUS_LOGIN_OPTION RADIUS_LOGIN_OPTION;
+typedef struct RADIUS_PACKET RADIUS_PACKET;
+typedef struct RADIUS_AVP RADIUS_AVP;
+typedef struct EAP_CLIENT EAP_CLIENT;
+typedef struct EAP_MESSAGE EAP_MESSAGE;
+typedef struct EAP_MSCHAPV2_GENERAL EAP_MSCHAPV2_GENERAL;
+typedef struct EAP_MSCHAPV2_CHALLENGE EAP_MSCHAPV2_CHALLENGE;
+typedef struct EAP_MSCHAPV2_RESPONSE EAP_MSCHAPV2_RESPONSE;
+typedef struct EAP_MSCHAPV2_SUCCESS_SERVER EAP_MSCHAPV2_SUCCESS_SERVER;
+typedef struct EAP_MSCHAPV2_SUCCESS_CLIENT EAP_MSCHAPV2_SUCCESS_CLIENT;
+typedef struct EAP_PEAP EAP_PEAP;
 
 
 // ==============================================================
@@ -738,6 +748,8 @@ typedef struct MIRROR_SERVER MIRROR_SERVER;
 // ==============================================================
 
 typedef struct NATIVE_STACK NATIVE_STACK;
+typedef struct IPTABLES_STATE IPTABLES_STATE;
+typedef struct IPTABLES_ENTRY IPTABLES_ENTRY;
 
 
 // ==============================================================

+ 1 - 0
src/Cedar/Command.c

@@ -18309,6 +18309,7 @@ UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
 		CtInsert(ct, _UU("NM_STATUS_DHCP"), tmp);
 
 		CtInsert(ct, _UU("SM_SNAT_IS_KERNEL"), t.IsKernelMode ? _UU("SEC_YES") : _UU("SEC_NO"));
+		CtInsert(ct, _UU("SM_SNAT_IS_RAW"), t.IsRawIpMode ? _UU("SEC_YES") : _UU("SEC_NO"));
 
 		CtFree(ct, c);
 	}

+ 101 - 0
src/Cedar/Hub.c

@@ -166,6 +166,103 @@ ADMIN_OPTION admin_options[] =
 
 UINT num_admin_options = sizeof(admin_options) / sizeof(ADMIN_OPTION);
 
+
+// Create an EAP client for the specified Virtual Hub
+EAP_CLIENT *HubNewEapClient(CEDAR *cedar, char *hubname, char *client_ip_str, char *username)
+{
+	HUB *hub = NULL;
+	EAP_CLIENT *ret = NULL;
+	char radius_servers[MAX_PATH] = {0};
+	UINT radius_port = 0;
+	UINT radius_retry_interval = 0;
+	char radius_secret[MAX_PATH] = {0};
+	char radius_suffix_filter[MAX_PATH] = {0};
+	if (cedar == NULL || hubname == NULL || client_ip_str == NULL || username == NULL)
+	{
+		return NULL;
+	}
+
+	// Find the Virtual Hub
+	LockHubList(cedar);
+	{
+		hub = GetHub(cedar, hubname);
+	}
+	UnlockHubList(cedar);
+
+	if (hub != NULL)
+	{
+		if (GetRadiusServerEx2(hub, radius_servers, sizeof(radius_servers), &radius_port, radius_secret,
+			sizeof(radius_secret), &radius_retry_interval, radius_suffix_filter, sizeof(radius_suffix_filter)))
+		{
+			bool use_peap = hub->RadiusUsePeapInsteadOfEap;
+
+			if (IsEmptyStr(radius_suffix_filter) || EndWith(username, radius_suffix_filter))
+			{
+				TOKEN_LIST *radius_servers_list = ParseToken(radius_servers, " ,;\t");
+
+				if (radius_servers_list != NULL && radius_servers_list->NumTokens >= 1)
+				{
+					// Try for each of RADIUS servers
+					UINT i;
+					bool finish = false;
+
+					for (i = 0;i < radius_servers_list->NumTokens;i++)
+					{
+						EAP_CLIENT *eap;
+						IP ip;
+
+						if (GetIP(&ip, radius_servers_list->Token[i]))
+						{
+							eap = NewEapClient(&ip, radius_port, radius_secret, radius_retry_interval,
+								RADIUS_INITIAL_EAP_TIMEOUT, client_ip_str, username);
+
+							if (eap != NULL)
+							{
+								if (use_peap == false)
+								{
+									// EAP
+									if (EapClientSendMsChapv2AuthRequest(eap))
+									{
+										eap->GiveupTimeout = RADIUS_RETRY_TIMEOUT;
+										ret = eap;
+										finish = true;
+									}
+								}
+								else
+								{
+									// PEAP
+									if (PeapClientSendMsChapv2AuthRequest(eap))
+									{
+										eap->GiveupTimeout = RADIUS_RETRY_TIMEOUT;
+										ret = eap;
+										finish = true;
+									}
+								}
+
+								if (finish == false)
+								{
+									ReleaseEapClient(eap);
+								}
+							}
+						}
+
+						if (finish)
+						{
+							break;
+						}
+					}
+				}
+
+				FreeToken(radius_servers_list);
+			}
+		}
+	}
+
+	ReleaseHub(hub);
+
+	return ret;
+}
+
 // Create a user list
 LIST *NewUserList()
 {
@@ -587,6 +684,7 @@ void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao)
 	GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxIcmpSessionsPerIp", &o->SecureNAT_MaxIcmpSessionsPerIp);
 	GetHubAdminOptionDataAndSet(ao, "AccessListIncludeFileCacheLifetime", &o->AccessListIncludeFileCacheLifetime);
 	GetHubAdminOptionDataAndSet(ao, "DisableKernelModeSecureNAT", &o->DisableKernelModeSecureNAT);
+	GetHubAdminOptionDataAndSet(ao, "DisableIpRawModeSecureNAT", &o->DisableIpRawModeSecureNAT);
 	GetHubAdminOptionDataAndSet(ao, "DisableUserModeSecureNAT", &o->DisableUserModeSecureNAT);
 	GetHubAdminOptionDataAndSet(ao, "DisableCheckMacOnLocalBridge", &o->DisableCheckMacOnLocalBridge);
 	GetHubAdminOptionDataAndSet(ao, "DisableCorrectIpOffloadChecksum", &o->DisableCorrectIpOffloadChecksum);
@@ -598,6 +696,7 @@ void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao)
 	GetHubAdminOptionDataAndSet(ao, "SuppressClientUpdateNotification", &o->SuppressClientUpdateNotification);
 	GetHubAdminOptionDataAndSet(ao, "FloodingSendQueueBufferQuota", &o->FloodingSendQueueBufferQuota);
 	GetHubAdminOptionDataAndSet(ao, "AssignVLanIdByRadiusAttribute", &o->AssignVLanIdByRadiusAttribute);
+	GetHubAdminOptionDataAndSet(ao, "DenyAllRadiusLoginWithNoVlanAssign", &o->DenyAllRadiusLoginWithNoVlanAssign);
 	GetHubAdminOptionDataAndSet(ao, "SecureNAT_RandomizeAssignIp", &o->SecureNAT_RandomizeAssignIp);
 	GetHubAdminOptionDataAndSet(ao, "DetectDormantSessionInterval", &o->DetectDormantSessionInterval);
 	GetHubAdminOptionDataAndSet(ao, "NoPhysicalIPOnPacketLog", &o->NoPhysicalIPOnPacketLog);
@@ -656,6 +755,7 @@ void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
 	Add(aol, NewAdminOption("SecureNAT_MaxIcmpSessionsPerIp", o->SecureNAT_MaxIcmpSessionsPerIp));
 	Add(aol, NewAdminOption("AccessListIncludeFileCacheLifetime", o->AccessListIncludeFileCacheLifetime));
 	Add(aol, NewAdminOption("DisableKernelModeSecureNAT", o->DisableKernelModeSecureNAT));
+	Add(aol, NewAdminOption("DisableIpRawModeSecureNAT", o->DisableIpRawModeSecureNAT));
 	Add(aol, NewAdminOption("DisableUserModeSecureNAT", o->DisableUserModeSecureNAT));
 	Add(aol, NewAdminOption("DisableCheckMacOnLocalBridge", o->DisableCheckMacOnLocalBridge));
 	Add(aol, NewAdminOption("DisableCorrectIpOffloadChecksum", o->DisableCorrectIpOffloadChecksum));
@@ -667,6 +767,7 @@ void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
 	Add(aol, NewAdminOption("SuppressClientUpdateNotification", o->SuppressClientUpdateNotification));
 	Add(aol, NewAdminOption("FloodingSendQueueBufferQuota", o->FloodingSendQueueBufferQuota));
 	Add(aol, NewAdminOption("AssignVLanIdByRadiusAttribute", o->AssignVLanIdByRadiusAttribute));
+	Add(aol, NewAdminOption("DenyAllRadiusLoginWithNoVlanAssign", o->DenyAllRadiusLoginWithNoVlanAssign));
 	Add(aol, NewAdminOption("SecureNAT_RandomizeAssignIp", o->SecureNAT_RandomizeAssignIp));
 	Add(aol, NewAdminOption("DetectDormantSessionInterval", o->DetectDormantSessionInterval));
 	Add(aol, NewAdminOption("NoPhysicalIPOnPacketLog", o->NoPhysicalIPOnPacketLog));

+ 5 - 0
src/Cedar/Hub.h

@@ -265,6 +265,7 @@ struct HUB_OPTION
 	UINT SecureNAT_MaxIcmpSessionsPerIp;	// Maximum number of ICMP sessions per IP address
 	UINT AccessListIncludeFileCacheLifetime;	// Expiration of the access list external file (in seconds)
 	bool DisableKernelModeSecureNAT;			// Disable the kernel mode NAT
+	bool DisableIpRawModeSecureNAT;			// Disable the IP Raw Mode NAT
 	bool DisableUserModeSecureNAT;			// Disable the user mode NAT
 	bool DisableCheckMacOnLocalBridge;	// Disable the MAC address verification in local bridge
 	bool DisableCorrectIpOffloadChecksum;	// Disable the correction of checksum that is IP-Offloaded
@@ -276,6 +277,7 @@ struct HUB_OPTION
 	bool SuppressClientUpdateNotification;	// Suppress the update notification function on the VPN Client
 	UINT FloodingSendQueueBufferQuota;	// The global quota of send queues of flooding packets
 	bool AssignVLanIdByRadiusAttribute;	// Assign the VLAN ID for the VPN session, by the attribute value of RADIUS
+	bool DenyAllRadiusLoginWithNoVlanAssign;	// Deny all RADIUS login with no VLAN ID assigned
 	bool SecureNAT_RandomizeAssignIp;	// Randomize the assignment IP address for new DHCP client
 	UINT DetectDormantSessionInterval;	// Interval (seconds) threshold to detect a dormant VPN session
 	bool NoPhysicalIPOnPacketLog;		// Disable saving physical IP address on the packet log
@@ -434,6 +436,8 @@ struct HUB
 	UINT RadiusRetryInterval;			// Radius retry interval
 	BUF *RadiusSecret;					// Radius shared key
 	char RadiusSuffixFilter[MAX_SIZE];	// Radius suffix filter
+	bool RadiusConvertAllMsChapv2AuthRequestToEap;	// Convert all MS-CHAPv2 auth request to EAP
+	bool RadiusUsePeapInsteadOfEap;			// Use PEAP instead of EAP
 	volatile bool Halt;					// Halting flag
 	bool Offline;						// Offline
 	bool BeingOffline;					// Be Doing Offline
@@ -636,6 +640,7 @@ void CalcTrafficDiff(TRAFFIC *diff, TRAFFIC *old, TRAFFIC *current);
 bool CheckMaxLoggedPacketsPerMinute(SESSION *s, UINT max_packets, UINT64 now);
 void VgsSetUserAgentValue(char *str);
 void VgsSetEmbTag(bool b);
+EAP_CLIENT *HubNewEapClient(CEDAR *cedar, char *hubname, char *client_ip_str, char *username);
 
 #endif	// HUB_H
 

+ 1 - 1
src/Cedar/IPsec_EtherIP.c

@@ -170,7 +170,7 @@ void EtherIPIpcConnectThread(THREAD *t, void *p)
 			&s->ClientIP, s->ClientPort,
 			&s->ServerIP, s->ServerPort,
 			tmp,
-			s->CryptName, true, mss);
+			s->CryptName, true, mss, NULL);
 
 		if (ipc != NULL)
 		{

+ 15 - 1
src/Cedar/IPsec_IKE.c

@@ -113,6 +113,7 @@
 
 #include "CedarPch.h"
 
+//#define	RAW_DEBUG
 
 // Processing of IKE received packet
 void ProcIKEPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
@@ -753,7 +754,7 @@ void ProcIPsecEspPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
 				// Transport mode
 				if (next_header == IP_PROTO_UDP)
 				{
-					if (ike->IPsec->Services.L2TP_IPsec)
+					if (ike->IPsec->Services.L2TP_IPsec || ike->IPsec->Services.EtherIP_IPsec)
 					{
 						// An UDP packet has been received
 						ProcIPsecUdpPacketRecv(ike, c, dec_data, dec_size);
@@ -791,6 +792,19 @@ void ProcIPsecEspPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
 		if (ipsec_sa->PairIPsecSa != NULL)
 		{
 			c->CurrentIpSecSaSend = ipsec_sa->PairIPsecSa;
+
+			if (p->DestPort == IPSEC_PORT_IPSEC_ESP_UDP)
+			{
+				IPSECSA *send_sa = c->CurrentIpSecSaSend;
+				if (send_sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TUNNEL)
+				{
+					send_sa->TransformSetting.CapsuleMode = IKE_P2_CAPSULE_NAT_TUNNEL_1;
+				}
+				else if (send_sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TRANSPORT)
+				{
+					send_sa->TransformSetting.CapsuleMode = IKE_P2_CAPSULE_NAT_TRANSPORT_1;
+				}
+			}
 		}
 		c->LastCommTick = ike->Now;
 		ipsec_sa->LastCommTick = ike->Now;

+ 21 - 5
src/Cedar/IPsec_IPC.c

@@ -133,20 +133,27 @@ bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *pa
 
 	t = ParseTokenWithNullStr(password, ":");
 
-	if (t->NumTokens == 5)
+	if (t->NumTokens == 6)
 	{
-		BUF *b1, *b2, *b3;
+		BUF *b1, *b2, *b3, *b4;
 
 		b1 = StrToBin(t->Token[2]);
 		b2 = StrToBin(t->Token[3]);
 		b3 = StrToBin(t->Token[4]);
+		b4 = StrToBin(t->Token[5]);
 
-		if (IsEmptyStr(t->Token[1]) == false && b1->Size == 16 && b2->Size == 16 && b3->Size == 24)
+		if (IsEmptyStr(t->Token[1]) == false && b1->Size == 16 && b2->Size == 16 && b3->Size == 24
+			 && b4->Size == 8)
 		{
+			UINT64 eap_client_ptr = 0;
+
 			StrCpy(d->MsChapV2_PPPUsername, sizeof(d->MsChapV2_PPPUsername), t->Token[1]);
 			Copy(d->MsChapV2_ServerChallenge, b1->Buf, 16);
 			Copy(d->MsChapV2_ClientChallenge, b2->Buf, 16);
 			Copy(d->MsChapV2_ClientResponse, b3->Buf, 24);
+			Copy(&eap_client_ptr, b4->Buf, 8);
+
+			d->MsChapV2_EapClient = (EAP_CLIENT *)eap_client_ptr;
 
 			ret = true;
 		}
@@ -154,6 +161,7 @@ bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *pa
 		FreeBuf(b1);
 		FreeBuf(b2);
 		FreeBuf(b3);
+		FreeBuf(b4);
 	}
 
 	FreeToken(t);
@@ -315,7 +323,7 @@ IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code)
 		param->UserName, param->Password, error_code, &param->ClientIp,
 		param->ClientPort, &param->ServerIp, param->ServerPort,
 		param->ClientHostname, param->CryptName,
-		param->BridgeMode, param->Mss);
+		param->BridgeMode, param->Mss, NULL);
 
 	return ipc;
 }
@@ -324,7 +332,7 @@ IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code)
 IPC *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)
+			bool bridge_mode, UINT mss, EAP_CLIENT *eap_client)
 {
 	IPC *ipc;
 	UINT dummy_int = 0;
@@ -431,6 +439,14 @@ IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char
 	PackAddBool(p, "require_monitor_mode", false);
 	PackAddBool(p, "qos", false);
 
+	if (eap_client != NULL)
+	{
+		UINT64 ptr = (UINT64)eap_client;
+		PackAddInt64(p, "release_me_eap_client", ptr);
+
+		AddRef(eap_client->Ref);
+	}
+
 	// Unique ID is determined by the sum of the connecting client IP address and the client_name
 	b = NewBuf();
 	WriteBuf(b, client_ip, sizeof(IP));

+ 2 - 1
src/Cedar/IPsec_IPC.h

@@ -218,12 +218,13 @@ struct IPC_MSCHAP_V2_AUTHINFO
 	UCHAR MsChapV2_ServerChallenge[16];	// MS-CHAPv2 Server Challenge
 	UCHAR MsChapV2_ClientChallenge[16];	// MS-CHAPv2 Client Challenge
 	UCHAR MsChapV2_ClientResponse[24];	// MS-CHAPv2 Client Response
+	EAP_CLIENT *MsChapV2_EapClient;		// EAP client
 };
 
 IPC *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);
+			bool bridge_mode, UINT mss, EAP_CLIENT *eap_client);
 IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code);
 IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address);
 void FreeIPC(IPC *ipc);

+ 192 - 38
src/Cedar/IPsec_L2TP.c

@@ -180,7 +180,7 @@ void SendL2TPControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id, L
 
 	p->Nr = t->LastNr + 1;
 
-	buf = BuildL2TPPacketData(p);
+	buf = BuildL2TPPacketData(p, t);
 
 	q = ZeroMalloc(sizeof(L2TP_QUEUE));
 	q->Buf = buf;
@@ -239,15 +239,33 @@ void SendL2TPDataPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s, void
 	else
 	{
 		// L2TPv3
-		buf_size = 4 + size;
-		buf = Malloc(buf_size);
+		if (t->IsYamahaV3 == false)
+		{
+			buf_size = 4 + size;
+			buf = Malloc(buf_size);
 
-		WRITE_UINT(buf, s->SessionId1);
+			WRITE_UINT(buf, s->SessionId1);
 
-		Copy(buf + 4, data, size);
+			Copy(buf + 4, data, size);
 
-		// Transmission
-		p = NewUdpPacket(&t->ServerIp, IPSEC_PORT_L2TPV3_VIRTUAL, &t->ClientIp, IPSEC_PORT_L2TPV3_VIRTUAL, buf, buf_size);
+			// Transmission
+			p = NewUdpPacket(&t->ServerIp, IPSEC_PORT_L2TPV3_VIRTUAL, &t->ClientIp, IPSEC_PORT_L2TPV3_VIRTUAL, buf, buf_size);
+		}
+		else
+		{
+			UINT header = 0x00030000;
+
+			buf_size = 8 + size;
+			buf = Malloc(buf_size);
+
+			WRITE_UINT(buf, header);
+			WRITE_UINT(buf + 4, s->SessionId1);
+
+			Copy(buf + 8, data, size);
+
+			// Transmission
+			p = NewUdpPacket(&t->ServerIp, t->ServerPort, &t->ClientIp, t->ClientPort, buf, buf_size);
+		}
 	}
 
 	L2TPSendUDP(l2tp, p);
@@ -285,14 +303,14 @@ void L2TPSendUDP(L2TP_SERVER *l2tp, UDPPACKET *p)
 }
 
 // Build a L2TP packet
-BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
+BUF *BuildL2TPPacketData(L2TP_PACKET *pp, L2TP_TUNNEL *t)
 {
 	BUF *ret;
 	UCHAR c;
 	USHORT us;
 	UINT ui;
 	// Validate arguments
-	if (pp == NULL)
+	if (pp == NULL || t == NULL)
 	{
 		return NULL;
 	}
@@ -322,9 +340,12 @@ BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
 
 	if (pp->Ver == 3)
 	{
-		// Zero as Session ID
-		ui = 0;
-		WriteBuf(ret, &ui, sizeof(UINT));
+		if (t->IsYamahaV3 == false)
+		{
+			// Zero as Session ID
+			ui = 0;
+			WriteBuf(ret, &ui, sizeof(UINT));
+		}
 	}
 
 	// Flags
@@ -339,6 +360,11 @@ BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
 		c |= L2TP_HEADER_BIT_OFFSET;
 	}
 
+	if (pp->IsControl == false && pp->Ver == 3 && t->IsYamahaV3)
+	{
+		c = 0;
+	}
+
 	WriteBuf(ret, &c, 1);
 
 	// Ver
@@ -356,6 +382,13 @@ BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
 		WriteBuf(ret, &us, sizeof(USHORT));
 	}
 
+	// Reserved
+	if (pp->IsControl == false && pp->Ver == 3 && t->IsYamahaV3)
+	{
+		us = 0;
+		WriteBuf(ret, &us, sizeof(USHORT));
+	}
+
 	// Tunnel ID
 	if (pp->Ver != 3)
 	{
@@ -387,9 +420,12 @@ BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
 	}
 	else
 	{
-		// Offset Size = 0
-		us = 0;
-		WriteBuf(ret, &us, sizeof(USHORT));
+		if (!(pp->IsControl == false && pp->Ver == 3 && t->IsYamahaV3))
+		{
+			// Offset Size = 0
+			us = 0;
+			WriteBuf(ret, &us, sizeof(USHORT));
+		}
 	}
 
 	if (pp->IsControl)
@@ -431,7 +467,8 @@ BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
 	if (pp->IsControl)
 	{
 		// Update Length
-		WRITE_USHORT(((UCHAR *)ret->Buf) + 2 + (pp->Ver == 3 ? sizeof(UINT) : 0), (USHORT)(ret->Size - (pp->Ver == 3 ? sizeof(UINT) : 0)));
+		bool l2tpv3_non_yamaha = ((pp->Ver == 3) && (t->IsYamahaV3 == false));
+		WRITE_USHORT(((UCHAR *)ret->Buf) + 2 + (l2tpv3_non_yamaha ? sizeof(UINT) : 0), (USHORT)(ret->Size - (l2tpv3_non_yamaha ? sizeof(UINT) : 0)));
 	}
 
 	SeekBuf(ret, 0, 0);
@@ -446,6 +483,7 @@ L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
 	UCHAR *buf;
 	UINT size;
 	bool is_l2tpv3 = false;
+	bool is_l2tpv3_yamaha = false;
 	// Validate arguments
 	if (p == NULL)
 	{
@@ -456,17 +494,27 @@ L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
 
 	if (p->SrcPort == IPSEC_PORT_L2TPV3_VIRTUAL)
 	{
-		// It is L2TPv3
+		// L2TPv3 (Cisco)
 		is_l2tpv3 = true;
 	}
 
 	buf = p->Data;
 	size = p->Size;
 
-	if (is_l2tpv3)
+	if (size >= 2 && ((buf[1] & L2TP_HEADER_BIT_VER) == 3))
 	{
+		if (p->SrcPort != IPSEC_PORT_L2TPV3_VIRTUAL)
+		{
+			// L2TPv3 (YAMAHA)
+			is_l2tpv3 = true;
+			is_l2tpv3_yamaha = true;
+		}
+	}
+
+	if (is_l2tpv3 && (is_l2tpv3_yamaha == false))
+	{
+		// L2TPv3 (Cisco)
 		UINT session_id;
-		// In the case of L2TPv3
 		if (size < 4)
 		{
 			goto LABEL_ERROR;
@@ -590,6 +638,24 @@ L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
 		size = ret->Length - 4;
 	}
 
+	if (is_l2tpv3)
+	{
+		if (p->SrcPort != IPSEC_PORT_L2TPV3_VIRTUAL)
+		{
+			if (ret->IsControl == false)
+			{
+				// Reserved
+				if (size < 2)
+				{
+					goto LABEL_ERROR;
+				}
+
+				buf += 2;
+				size -= 2;
+			}
+		}
+	}
+
 	// Tunnel ID, Session ID
 	if (size < 4)
 	{
@@ -616,6 +682,11 @@ L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
 
 		// The session ID is not written in the header
 		ret->SessionId = 0;
+
+		if (ret->IsControl == false)
+		{
+			ret->SessionId = ret->TunnelId;
+		}
 	}
 
 	if (ret->HasSequence)
@@ -742,7 +813,7 @@ L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
 		ret->MessageType = READ_USHORT(a->Data);
 	}
 
-	if (ret->Ver == 3)
+	if (ret->Ver == 3 && ret->IsControl)
 	{
 		// Get the Remote Session ID in the case of L2TPv3
 		L2TP_AVP *a = GetAVPValue(ret, L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE);
@@ -752,6 +823,8 @@ L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
 		}
 	}
 
+	ret->IsYamahaV3 = is_l2tpv3_yamaha;
+
 	return ret;
 
 LABEL_ERROR:
@@ -783,6 +856,22 @@ L2TP_AVP *GetAVPValueEx(L2TP_PACKET *p, UINT type, UINT vendor_id)
 		}
 	}
 
+	if (vendor_id == 0)
+	{
+		if (type == L2TP_AVP_TYPE_V3_TUNNEL_ID)
+		{
+			return GetAVPValueEx(p, L2TPV3_CISCO_AVP_TUNNEL_ID, L2TP_AVP_VENDOR_ID_CISCO);
+		}
+		else if (type == L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL)
+		{
+			return GetAVPValueEx(p, L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, L2TP_AVP_VENDOR_ID_CISCO);
+		}
+		else if (type == L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE)
+		{
+			return GetAVPValueEx(p, L2TPV3_CISCO_AVP_SESSION_ID_REMOTE, L2TP_AVP_VENDOR_ID_CISCO);
+		}
+	}
+
 	return NULL;
 }
 
@@ -899,6 +988,9 @@ L2TP_TUNNEL *NewL2TPTunnel(L2TP_SERVER *l2tp, L2TP_PACKET *p, UDPPACKET *udp)
 		{
 			t->IsCiscoV3 = true;
 		}
+
+		// L2TPv3 on YAMAHA
+		t->IsYamahaV3 = p->IsYamahaV3;
 	}
 
 	// Transmission queue
@@ -965,6 +1057,30 @@ L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClient(L2TP_SERVER *l2tp, IP *client_ip,
 
 	return NULL;
 }
+L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClientEx(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3)
+{
+	UINT i;
+	// Validate arguments
+	if (l2tp == NULL || client_ip == 0 || tunnel_id == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+	{
+		L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+		if (t->TunnelId1 == tunnel_id && CmpIpAddr(&t->ClientIp, client_ip) == 0)
+		{
+			if (EQUAL_BOOL(t->IsV3, is_v3))
+			{
+				return t;
+			}
+		}
+	}
+
+	return NULL;
+}
 
 // Create a new tunnel ID
 UINT GenerateNewTunnelId(L2TP_SERVER *l2tp, IP *client_ip)
@@ -1179,14 +1295,23 @@ void L2TPProcessRecvControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_PACKET
 
 							if (s->IsV3)
 							{
-								// Pseudowire AVP
-								us = Endian16(s->PseudowireType);
-								Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_PW_TYPE, true, 0, &us, sizeof(USHORT)));
+								if (t->IsYamahaV3 == false)
+								{
+									// Pseudowire AVP
+									us = Endian16(s->PseudowireType);
+									Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_PW_TYPE, true, 0, &us, sizeof(USHORT)));
+								}
 
 								if (s->IsCiscoV3)
 								{
 									Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_PW_TYPE, true, L2TP_AVP_VENDOR_ID_CISCO, &us, sizeof(USHORT)));
 								}
+
+								if (t->IsYamahaV3)
+								{
+									us = Endian16(0x0003);
+									Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_CIRCUIT_STATUS, true, 0, &us, sizeof(USHORT)));
+								}
 							}
 
 							SendL2TPControlPacket(l2tp, t, session_id, pp);
@@ -1563,18 +1688,21 @@ void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
 							// Respond with SCCEP to SCCRQ
 							pp2 = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_SCCRP, t->IsV3);
 
-							// Protocol Version
-							protocol_version[0] = 1;
-							protocol_version[1] = 0;
-							Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_PROTOCOL_VERSION, true, 0, protocol_version, sizeof(protocol_version)));
-
-							// Framing Capabilities
-							Zero(caps_data, sizeof(caps_data));
-							if (t->IsV3 == false)
+							if (t->IsYamahaV3 == false)
 							{
-								caps_data[3] = 3;
+								// Protocol Version
+								protocol_version[0] = 1;
+								protocol_version[1] = 0;
+								Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_PROTOCOL_VERSION, true, 0, protocol_version, sizeof(protocol_version)));
+
+								// Framing Capabilities
+								Zero(caps_data, sizeof(caps_data));
+								if (t->IsV3 == false)
+								{
+									caps_data[3] = 3;
+								}
+								Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_FRAME_CAP, false, 0, caps_data, sizeof(caps_data)));
 							}
-							Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_FRAME_CAP, false, 0, caps_data, sizeof(caps_data)));
 
 							if (t->IsV3 == false)
 							{
@@ -1593,7 +1721,21 @@ void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
 							Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_HOST_NAME, true, 0, hostname, StrLen(hostname)));
 
 							// Vendor Name
-							Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_VENDOR_NAME, false, 0, L2TP_VENDOR_NAME, StrLen(L2TP_VENDOR_NAME)));
+							if (t->IsYamahaV3 == false)
+							{
+								Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_VENDOR_NAME, false, 0, L2TP_VENDOR_NAME, StrLen(L2TP_VENDOR_NAME)));
+							}
+							else
+							{
+								char *yamaha_str = "YAMAHA Corporation";
+								Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_VENDOR_NAME, false, 0, yamaha_str, StrLen(yamaha_str)));
+							}
+
+							if (t->IsYamahaV3)
+							{
+								UINT zero = 0;
+								Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_V3_ROUTER_ID, true, 0, &zero, sizeof(UINT)));
+							}
 
 							// Assigned Tunnel ID
 							if (t->IsV3 == false)
@@ -1635,8 +1777,11 @@ void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
 							}
 
 							// Recv Window Size
-							us = Endian16(L2TP_WINDOW_SIZE);
-							Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_RECV_WINDOW_SIZE, false, 0, &us, sizeof(USHORT)));
+							if (t->IsYamahaV3 == false)
+							{
+								us = Endian16(L2TP_WINDOW_SIZE);
+								Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_RECV_WINDOW_SIZE, false, 0, &us, sizeof(USHORT)));
+							}
 
 							SendL2TPControlPacket(l2tp, t, 0, pp2);
 
@@ -1654,7 +1799,7 @@ void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
 		L2TP_TUNNEL *t = NULL;
 		L2TP_SESSION *l2tpv3_session = NULL;
 
-		if (pp->Ver != 3 || pp->IsControl)
+		if (pp->IsControl || pp->Ver != 3)
 		{
 			t = GetTunnelFromId(l2tp, &p->SrcIP, pp->TunnelId, pp->Ver == 3);
 		}
@@ -1767,6 +1912,15 @@ void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
 						}
 					}
 				}
+				else
+				{
+					// Reply ACK for already-received packets
+					if (pp->IsZLB == false)
+					{
+						// The packet other than ZLB is treated
+						t->StateChanged = true;
+					}
+				}
 			}
 			else
 			{
@@ -2373,7 +2527,7 @@ void L2TPProcessInterrupts(L2TP_SERVER *l2tp)
 
 				pp->TunnelId = t->TunnelId1;
 				pp->Ns = t->NextNs;
-				q->Buf = BuildL2TPPacketData(pp);
+				q->Buf = BuildL2TPPacketData(pp, t);
 
 				SendL2TPControlPacketMain(l2tp, t, q);
 

+ 5 - 1
src/Cedar/IPsec_L2TP.h

@@ -189,6 +189,7 @@
 #define	L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL	63	// Local Session ID
 #define	L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE	64	// Remote Session ID
 #define	L2TP_AVP_TYPE_V3_PW_TYPE		68		// Pseudowire Type
+#define	L2TP_AVP_TYPE_V3_CIRCUIT_STATUS	71
 
 // Message Type value
 #define	L2TP_MESSAGE_TYPE_SCCRQ			1		// Start-Control-Connection-Request
@@ -247,6 +248,7 @@ struct L2TP_PACKET
 	bool HasOffset;								// Whether there is offset bit
 	bool IsPriority;							// Whether priority packet
 	bool IsZLB;									// Zero Length Bit
+	bool IsYamahaV3;							// L2TPv3 on YAMAHA
 	UINT Ver;									// Version
 	UINT Length;								// Length
 	UINT TunnelId;								// Tunnel ID
@@ -284,6 +286,7 @@ struct L2TP_TUNNEL
 {
 	bool IsV3;									// L2TPv3
 	bool IsCiscoV3;								// L2TPv3 for Cisco
+	bool IsYamahaV3;							// L2TPv3 for YAMAHA
 	IP ClientIp;								// Client IP address
 	UINT ClientPort;							// Client port number
 	IP ServerIp;								// Server IP address
@@ -339,7 +342,7 @@ void FreeL2TPServer(L2TP_SERVER *l2tp);
 void StopL2TPServer(L2TP_SERVER *l2tp, bool no_wait);
 void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p);
 L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p);
-BUF *BuildL2TPPacketData(L2TP_PACKET *pp);
+BUF *BuildL2TPPacketData(L2TP_PACKET *pp, L2TP_TUNNEL *t);
 L2TP_AVP *GetAVPValue(L2TP_PACKET *p, UINT type);
 L2TP_AVP *GetAVPValueEx(L2TP_PACKET *p, UINT type, UINT vendor_id);
 L2TP_TUNNEL *NewL2TPTunnel(L2TP_SERVER *l2tp, L2TP_PACKET *p, UDPPACKET *udp);
@@ -348,6 +351,7 @@ UINT GenerateNewTunnelIdEx(L2TP_SERVER *l2tp, IP *client_ip, bool is_32bit);
 void FreeL2TPTunnel(L2TP_TUNNEL *t);
 L2TP_TUNNEL *GetTunnelFromId(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3);
 L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClient(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id);
+L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClientEx(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3);
 void SendL2TPControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id, L2TP_PACKET *p);
 void SendL2TPControlPacketMain(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_QUEUE *q);
 void SendL2TPDataPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s, void *data, UINT size);

+ 132 - 10
src/Cedar/IPsec_PPP.c

@@ -135,6 +135,8 @@ void PPPThread(THREAD *thread, void *param)
 	p->Mru1 = p->Mru2 = PPP_MRU_DEFAULT;
 	p->RecvPacketList = NewList(NULL);
 
+	p->MsChapV2_UseDoubleMsChapV2 = CedarIsThereAnyEapEnabledRadiusConfig(p->Cedar);
+
 	//// Link establishment phase
 	IPToStr(ipstr1, sizeof(ipstr1), &p->ClientIP);
 	IPToStr(ipstr2, sizeof(ipstr2), &p->ServerIP);
@@ -244,9 +246,96 @@ void PPPThread(THREAD *thread, void *param)
 
 		PPPContinueUntilFinishAllLCPOptionRequestsDetermined(p);
 
+		if (p->MsChapV2_UseDoubleMsChapV2)
+		{
+			// Use the double-MSCHAPv2 technieue
+			GetMachineHostName(machine_name, sizeof(machine_name));
+			MsChapV2Server_GenerateChallenge(p->MsChapV2_ServerChallenge);
+
+			pp = ZeroMalloc(sizeof(PPP_PACKET));
+			pp->Protocol = PPP_PROTOCOL_CHAP;
+			pp->IsControl = true;
+			pp->Lcp = NewPPPLCP(PPP_CHAP_CODE_CHALLENGE, 99);
+
+			b = NewBuf();
+			WriteBufChar(b, 16);
+			WriteBuf(b, p->MsChapV2_ServerChallenge, sizeof(p->MsChapV2_ServerChallenge));
+			WriteBuf(b, machine_name, StrLen(machine_name));
+			pp->Lcp->Data = Clone(b->Buf, b->Size);
+			pp->Lcp->DataSize = b->Size;
+			FreeBuf(b);
+
+			PPPSendPacket(p, pp);
+
+			pp_ret = PPPRecvResponsePacket(p, pp, 0, &pp_ret_protocol, false, true);
+
+			if (pp_ret != NULL)
+			{
+				// Extract the username from the first MS-CHAP v2 packet
+				if (pp_ret->Lcp != NULL && pp_ret->Lcp->DataSize >= 51)
+				{
+					BUF *b;
+
+					b = MemToBuf(pp_ret->Lcp->Data, pp_ret->Lcp->DataSize);
+
+					if (ReadBufChar(b) == 49)
+					{
+						UCHAR client_response_buffer[49];
+						char username_tmp[MAX_SIZE];
+						char id[MAX_SIZE];
+						char hub[MAX_SIZE];
+						char client_ip_tmp[256];
+						EAP_CLIENT *eap;
+						ETHERIP_ID d;
+
+						ReadBuf(b, client_response_buffer, 49);
+
+						Zero(username_tmp, sizeof(username_tmp));
+						ReadBuf(b, username_tmp, sizeof(username_tmp));
+
+						Debug("First MS-CHAPv2: id=%s\n", username_tmp);
+
+						Zero(id, sizeof(id));
+						Zero(hub, sizeof(hub));
+
+						// The user name is divided into the ID and the virtual HUB name
+						Zero(&d, sizeof(d));
+						PPPParseUsername(p->Cedar, username_tmp, &d);
+
+						StrCpy(id, sizeof(id), d.UserName);
+						StrCpy(hub, sizeof(hub), d.HubName);
+						Debug("First MS-CHAPv2: username=%s, hubname=%s\n", id, hub);
+
+						IPToStr(client_ip_tmp, sizeof(client_ip_tmp), &p->ClientIP);
+
+						eap = HubNewEapClient(p->Cedar, hub, client_ip_tmp, id);
+
+						if (eap)
+						{
+							p->EapClient = eap;
+						}
+					}
+
+					FreeBuf(b);
+				}
+
+				FreePPPPacket(pp_ret);
+			}
+
+			FreePPPPacket(pp);
+		}
+
 		// Generate a Server Challenge packet of MS-CHAP v2
 		GetMachineHostName(machine_name, sizeof(machine_name));
-		MsChapV2Server_GenerateChallenge(p->MsChapV2_ServerChallenge);
+
+		if (p->EapClient == NULL)
+		{
+			MsChapV2Server_GenerateChallenge(p->MsChapV2_ServerChallenge);
+		}
+		else
+		{
+			Copy(p->MsChapV2_ServerChallenge, p->EapClient->MsChapV2Challenge.Chap_ChallengeValue, 16);
+		}
 
 		pp = ZeroMalloc(sizeof(PPP_PACKET));
 		pp->Protocol = PPP_PROTOCOL_CHAP;
@@ -264,7 +353,7 @@ void PPPThread(THREAD *thread, void *param)
 		PPPSendPacket(p, pp);
 
 		pp_ret_protocol = 0;
-		pp_ret = PPPRecvResponsePacket(p, pp, 0, &pp_ret_protocol, false);
+		pp_ret = PPPRecvResponsePacket(p, pp, 0, &pp_ret_protocol, false, false);
 
 		if (pp_ret != NULL)
 		{
@@ -565,7 +654,7 @@ bool PPPContinueUntilFinishAllLCPOptionRequestsDetermined(PPP_SESSION *p)
 		return false;
 	}
 
-	PPPRecvResponsePacket(p, NULL, PPP_PROTOCOL_LCP, &received_protocol, true);
+	PPPRecvResponsePacket(p, NULL, PPP_PROTOCOL_LCP, &received_protocol, true, false);
 
 	return p->ClientLCPOptionDetermined;
 }
@@ -580,7 +669,7 @@ USHORT PPPContinueCurrentProtocolRequestListening(PPP_SESSION *p, USHORT protoco
 		return 0;
 	}
 
-	PPPRecvResponsePacket(p, NULL, protocol, &received_protocol, false);
+	PPPRecvResponsePacket(p, NULL, protocol, &received_protocol, false, false);
 
 	return received_protocol;
 }
@@ -634,7 +723,7 @@ bool PPPSendRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c)
 	}
 
 	// Receive a corresponding PPP packet
-	pp2 = PPPRecvResponsePacket(p, pp, 0, NULL, false);
+	pp2 = PPPRecvResponsePacket(p, pp, 0, NULL, false, false);
 
 	if (pp2 != NULL)
 	{
@@ -880,8 +969,10 @@ PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req)
 					char server_challenge_hex[MAX_SIZE];
 					char client_challenge_hex[MAX_SIZE];
 					char client_response_hex[MAX_SIZE];
+					char eap_client_hex[64];
 					ETHERIP_ID d;
 					UINT error_code;
+					UINT64 eap_client_ptr = (UINT64)p->EapClient;
 
 					ReadBuf(b, client_response_buffer, 49);
 
@@ -913,18 +1004,21 @@ PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req)
 						p->MsChapV2_ClientChallenge, sizeof(p->MsChapV2_ClientChallenge));
 					BinToStr(client_response_hex, sizeof(client_response_hex),
 						p->MsChapV2_ClientResponse, sizeof(p->MsChapV2_ClientResponse));
+					BinToStr(eap_client_hex, sizeof(eap_client_hex),
+						&eap_client_ptr, 8);
 
-					Format(password, sizeof(password), "%s%s:%s:%s:%s",
+					Format(password, sizeof(password), "%s%s:%s:%s:%s:%s",
 						IPC_PASSWORD_MSCHAPV2_TAG,
 						username_tmp,
 						server_challenge_hex,
 						client_challenge_hex,
-						client_response_hex);
+						client_response_hex,
+						eap_client_hex);
 
 					// Attempt to connect with IPC
 					ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password,
 						&error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort,
-						p->ClientHostname, p->CryptName, false, p->AdjustMss);
+						p->ClientHostname, p->CryptName, false, p->AdjustMss, p->EapClient);
 
 					if (ipc != NULL)
 					{
@@ -1057,7 +1151,7 @@ PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req)
 
 								ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password,
 									&error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort,
-									p->ClientHostname, p->CryptName, false, p->AdjustMss);
+									p->ClientHostname, p->CryptName, false, p->AdjustMss, NULL);
 
 								if (ipc != NULL)
 								{
@@ -1555,7 +1649,8 @@ bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip)
 // (If req == NULL, process on that protocol while the protocol specified in expected_protocol have received.
 //If other protocols has arrived, without further processing, and then store that packet in the session context once,
 // return NULL by setting the received_protocol.)
-PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked)
+PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked,
+								  bool return_mschapv2_response_with_no_processing)
 {
 	UINT64 giveup_tick = Tick64() + (UINT64)PPP_PACKET_RECV_TIMEOUT;
 	UINT64 next_resend = Tick64() + (UINT64)PPP_PACKET_RESEND_INTERVAL;
@@ -1618,6 +1713,16 @@ PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expect
 				{
 					return pp;
 				}
+
+				if (return_mschapv2_response_with_no_processing)
+				{
+					// For the double-MSCHAPv2 technique
+					if (pp->IsControl && pp->Protocol == req->Protocol && pp->Lcp->Id == req->Lcp->Id &&
+						pp->Protocol == PPP_PROTOCOL_CHAP && PPP_PAP_CODE_IS_RESPONSE(pp->Lcp->Code))
+					{
+						return pp;
+					}
+				}
 			}
 
 			// Return a response immediately without processing if a protocol other than the expected received
@@ -2357,9 +2462,26 @@ void FreePPPSession(PPP_SESSION *p)
 		FreeIPC(p->Ipc);
 	}
 
+	PPPFreeEapClient(p);
+
 	Free(p);
 }
 
+// Free the associated EAP client
+void PPPFreeEapClient(PPP_SESSION *p)
+{
+	if (p == NULL)
+	{
+		return;
+	}
+
+	if (p->EapClient != NULL)
+	{
+		ReleaseEapClient(p->EapClient);
+		p->EapClient = NULL;
+	}
+}
+
 // Get the option value
 PPP_OPTION *GetOptionValue(PPP_LCP *c, UCHAR type)
 {

+ 6 - 1
src/Cedar/IPsec_PPP.h

@@ -284,6 +284,9 @@ struct PPP_SESSION
 	UCHAR MsChapV2_ClientResponse[24];	// MS-CHAPv2 Client Response
 	UCHAR MsChapV2_ServerResponse[20];	// MS-CHAPv2 Server Response
 	UINT MsChapV2_ErrorCode;			// Authentication failure error code of MS-CHAPv2
+
+	bool MsChapV2_UseDoubleMsChapV2;	// Use the double-MSCHAPv2 technieue
+	EAP_CLIENT *EapClient;				// EAP client
 };
 
 // Function prototype
@@ -316,7 +319,8 @@ bool PPPSetIPAddressValueToLCP(PPP_LCP *c, UINT type, IP *ip, bool only_modify);
 bool PPPSendRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c);
 USHORT PPPContinueCurrentProtocolRequestListening(PPP_SESSION *p, USHORT protocol);
 bool PPPContinueUntilFinishAllLCPOptionRequestsDetermined(PPP_SESSION *p);
-PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked);
+PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked,
+								  bool return_mschapv2_response_with_no_processing);
 PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req);
 void PPPSendEchoRequest(PPP_SESSION *p);
 bool PPPParseUsername(CEDAR *cedar, char *src, ETHERIP_ID *dst);
@@ -331,6 +335,7 @@ void MsChapV2Client_GenerateResponse(UCHAR *dst, UCHAR *challenge8, UCHAR *nt_pa
 void MsChapV2Server_GenerateResponse(UCHAR *dst, UCHAR *nt_password_hash_hash, UCHAR *client_response, UCHAR *challenge8);
 bool MsChapV2VerityPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password);
 char *MsChapV2DoBruteForce(IPC_MSCHAP_V2_AUTHINFO *d, LIST *password_list);
+void PPPFreeEapClient(PPP_SESSION *p);
 
 #endif	// IPSEC_PPP_H
 

+ 1 - 0
src/Cedar/NM.c

@@ -784,6 +784,7 @@ bool NmStatus(HWND hWnd, SM_SERVER *s, void *param)
 	LvInsertAdd(b, ICO_PROTOCOL_DHCP, NULL, 2, _UU("NM_STATUS_DHCP"), tmp);
 
 	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_SNAT_IS_KERNEL"), t.IsKernelMode ? _UU("SEC_YES") : _UU("SEC_NO"));
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_SNAT_IS_RAW"), t.IsRawIpMode ? _UU("SEC_YES") : _UU("SEC_NO"));
 
 	LvInsertEnd(b, hWnd, L_STATUS);
 

+ 3 - 1
src/Cedar/Nat.c

@@ -596,7 +596,7 @@ UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t)
 
 			t->NumDhcpClients = LIST_NUM(v->DhcpLeaseList);
 
-			t->IsKernelMode = NnIsActive(v);
+			t->IsKernelMode = NnIsActiveEx(v, &t->IsRawIpMode);
 		}
 		UnlockVirtual(v);
 	}
@@ -1063,6 +1063,7 @@ void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p)
 	t->NumDnsSessions = PackGetInt(p, "NumDnsSessions");
 	t->NumDhcpClients = PackGetInt(p, "NumDhcpClients");
 	t->IsKernelMode = PackGetBool(p, "IsKernelMode");
+	t->IsRawIpMode = PackGetBool(p, "IsRawIpMode");
 	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
 }
 void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t)
@@ -1080,6 +1081,7 @@ void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t)
 	PackAddInt(p, "NumDnsSessions", t->NumDnsSessions);
 	PackAddInt(p, "NumDhcpClients", t->NumDhcpClients);
 	PackAddBool(p, "IsKernelMode", t->IsKernelMode);
+	PackAddBool(p, "IsRawIpMode", t->IsRawIpMode);
 }
 void FreeRpcNatStatus(RPC_NAT_STATUS *t)
 {

+ 1 - 0
src/Cedar/Nat.h

@@ -168,6 +168,7 @@ struct RPC_NAT_STATUS
 	UINT NumDnsSessions;						// Number of DNS sessions
 	UINT NumDhcpClients;						// Number of DHCP clients
 	bool IsKernelMode;							// Whether kernel mode
+	bool IsRawIpMode;							// Whether raw IP mode
 };
 
 // RPC_NAT_INFO *

+ 564 - 6
src/Cedar/NativeStack.c

@@ -257,6 +257,109 @@ LABEL_RESTART:
 	Disconnect(a->Sock2);
 }
 
+// Start the iptables tracking
+bool NsStartIpTablesTracking(NATIVE_STACK *a)
+{
+	if (a->IpTablesThread != NULL)
+	{
+		return true;
+	}
+
+	a->IpTablesInitOk = false;
+
+	a->IpTablesHalt = false;
+
+	a->IpTablesHaltEvent = NewEvent();
+
+	a->IpTablesThread = NewThread(NsIpTablesThread, a);
+
+	WaitThreadInit(a->IpTablesThread);
+
+	return a->IpTablesInitOk;
+}
+
+// iptables thread
+void NsIpTablesThread(THREAD *thread, void *param)
+{
+	IPTABLES_STATE *state;
+	NATIVE_STACK *s;
+	UINT counter = 0;
+	BUF *seed_buf;
+	char exe_name[MAX_PATH];
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	s = (NATIVE_STACK *)param;
+
+	seed_buf = NewBuf();
+
+	WriteBuf(seed_buf, s->MacAddress, 6);
+
+	GetExeName(exe_name, sizeof(exe_name));
+	WriteBufStr(seed_buf, exe_name);
+
+	state = StartAddIpTablesEntryForNativeStack(seed_buf->Buf, seed_buf->Size);
+
+	FreeBuf(seed_buf);
+
+	if (state == NULL)
+	{
+		NoticeThreadInit(thread);
+		return;
+	}
+
+	s->IpTablesInitOk = true;
+	NoticeThreadInit(thread);
+
+	while (true)
+	{
+		UINT wait_interval;
+
+		if (s->IpTablesHalt)
+		{
+			break;
+		}
+
+		if (MaintainAddIpTablesEntryForNativeStack(state))
+		{
+			counter = 0;
+		}
+
+		counter++;
+		wait_interval = NS_CHECK_IPTABLES_INTERVAL_INIT * counter;
+		wait_interval = MIN(wait_interval, NS_CHECK_IPTABLES_INTERVAL_MAX);
+
+		//Debug("NsIpTablesThread: wait for %u\n", wait_interval);
+		Wait(s->IpTablesHaltEvent, wait_interval);
+	}
+
+	EndAddIpTablesEntryForNativeStack(state);
+}
+
+// Stop the iptables tracking
+void NsStopIpTablesTracking(NATIVE_STACK *a)
+{
+	if (a->IpTablesThread == NULL)
+	{
+		return;
+	}
+
+	a->IpTablesHalt = true;
+	Set(a->IpTablesHaltEvent);
+
+	WaitThread(a->IpTablesThread, INFINITE);
+
+	ReleaseThread(a->IpTablesThread);
+	ReleaseEvent(a->IpTablesHaltEvent);
+
+	a->IpTablesThread = NULL;
+	a->IpTablesHaltEvent = NULL;
+	a->IpTablesInitOk = false;
+	a->IpTablesHalt = false;
+}
+
 // Release the stack
 void FreeNativeStack(NATIVE_STACK *a)
 {
@@ -288,6 +391,8 @@ void FreeNativeStack(NATIVE_STACK *a)
 	CloseEth(a->Eth);
 	FreeIPC(a->Ipc);
 
+	NsStopIpTablesTracking(a);
+
 	ReleaseCancel(a->Cancel);
 
 	ReleaseSock(a->Sock1);
@@ -312,12 +417,6 @@ NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_
 		return NULL;
 	}
 
-	if (cedar == NULL)
-	{
-		cedar = NewCedar(NULL, NULL);
-		release_cedar = true;
-	}
-
 	GetLocalHostIP4(&localhost);
 
 	// Open the Eth device
@@ -327,6 +426,12 @@ NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_
 		return NULL;
 	}
 
+	if (cedar == NULL)
+	{
+		cedar = NewCedar(NULL, NULL);
+		release_cedar = true;
+	}
+
 	a = ZeroMalloc(sizeof(NATIVE_STACK));
 
 	NewSocketPair(&a->Sock1, &a->Sock2, &localhost, 1, &localhost, 1);
@@ -353,6 +458,8 @@ NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_
 		ReleaseCedar(cedar);
 	}
 
+	a->IsIpRawMode = a->Eth->IsRawIpMode;
+
 	return a;
 }
 
@@ -440,6 +547,457 @@ void NsGenMacAddress(void *dest, char *mac_address_seed, char *device_name)
 	Copy(dest, mac, 6);
 }
 
+// Add the iptables entries for native stack
+IPTABLES_STATE *StartAddIpTablesEntryForNativeStack(void *seed, UINT seed_size)
+{
+	IPTABLES_STATE *ret = NULL;
+	bool ok = false;
+
+	if (IsIpTablesSupported())
+	{
+		IPTABLES_ENTRY *e;
+		UINT i;
+
+		ret = ZeroMalloc(sizeof(IPTABLES_STATE));
+
+		ret->EntryList = NewListFast(NULL);
+
+		HashSha1(ret->SeedHash, seed, seed_size);
+
+		// Create a pair of entry
+		e = ZeroMalloc(sizeof(IPTABLES_ENTRY));
+		GenerateDummyIpAndMark(ret->SeedHash, e, 0);
+		StrCpy(e->Chain, sizeof(e->Chain), "OUTPUT");
+		Format(e->ConditionAndArgs, sizeof(e->ConditionAndArgs),
+			"-p tcp --tcp-flags RST RST --sport %u:%u ! -s %r/32 ! -d %r/32 -m connmark ! --mark 0x%x -j DROP",
+			NN_RAW_IP_PORT_START, NN_RAW_IP_PORT_END,
+			&e->DummySrcIp, &e->DummyDestIP, e->DummyMark);
+		Add(ret->EntryList, e);
+
+		e = ZeroMalloc(sizeof(IPTABLES_ENTRY));
+		GenerateDummyIpAndMark(ret->SeedHash, e, 1);
+		StrCpy(e->Chain, sizeof(e->Chain), "OUTPUT");
+		Format(e->ConditionAndArgs, sizeof(e->ConditionAndArgs),
+			"-p icmp --icmp-type 3/3 ! -s %r/32 ! -d %r/32 -m connmark ! --mark 0x%x -j DROP",
+			&e->DummySrcIp, &e->DummyDestIP, e->DummyMark);
+		Add(ret->EntryList, e);
+
+		ok = true;
+
+		// Insert entries if not exists
+		for (i = 0; i < LIST_NUM(ret->EntryList);i++)
+		{
+			UINT j;
+			IPTABLES_ENTRY *e = LIST_DATA(ret->EntryList, i);
+
+			for (j = 0;j < 100;j++)
+			{
+				if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) != 0)
+				{
+					char cmdline[MAX_PATH];
+
+					Format(cmdline, sizeof(cmdline),
+						"iptables -D %s %s",
+						e->Chain, e->ConditionAndArgs);
+
+					system(cmdline);
+				}
+				else
+				{
+					break;
+				}
+			}
+
+			if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
+			{
+				char cmdline[MAX_PATH];
+
+				Format(cmdline, sizeof(cmdline),
+					"iptables -I %s %s",
+					e->Chain, e->ConditionAndArgs);
+
+				system(cmdline);
+
+				if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
+				{
+					Debug("Run \"%s\" failed.\n", cmdline);
+					ok = false;
+					break;
+				}
+				else
+				{
+					Debug("Run \"%s\" ok.\n", cmdline);
+				}
+			}
+		}
+	}
+
+	if (ok == false)
+	{
+		EndAddIpTablesEntryForNativeStack(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+// Maintain the iptables
+bool MaintainAddIpTablesEntryForNativeStack(IPTABLES_STATE *s)
+{
+	UINT i;
+	bool ret = false;
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	if (s->HasError)
+	{
+		return false;
+	}
+
+	// Insert entries if not exists
+	for (i = 0; i < LIST_NUM(s->EntryList);i++)
+	{
+		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
+
+		if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
+		{
+			char cmdline[MAX_PATH];
+
+			Format(cmdline, sizeof(cmdline),
+				"iptables -I %s %s",
+				e->Chain, e->ConditionAndArgs);
+
+			system(cmdline);
+
+			if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) == 0)
+			{
+				Debug("Run \"%s\" failed.\n", cmdline);
+				s->HasError = true;
+				break;
+			}
+			else
+			{
+				Debug("Run \"%s\" ok.\n", cmdline);
+				ret = true;
+			}
+		}
+	}
+
+	return ret;
+}
+
+// Stop the iptables management
+void EndAddIpTablesEntryForNativeStack(IPTABLES_STATE *s)
+{
+	UINT i;
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// Delete entries
+	for (i = 0; i < LIST_NUM(s->EntryList);i++)
+	{
+		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
+		UINT j;
+
+		for (j = 0;j < 100;j++)
+		{
+			if (GetCurrentIpTableLineNumber(e->Chain, &e->DummySrcIp, &e->DummyDestIP, e->DummyMark) != 0)
+			{
+				char cmdline[MAX_PATH];
+
+				Format(cmdline, sizeof(cmdline),
+					"iptables -D %s %s",
+					e->Chain, e->ConditionAndArgs);
+
+				system(cmdline);
+			}
+			else
+			{
+				break;
+			}
+		}
+	}
+
+	FreeIpTablesState(s);
+}
+
+// Generate a set of dummy IP addresses and mark
+void GenerateDummyIpAndMark(void *hash_seed, IPTABLES_ENTRY *e, UINT id)
+{
+	PRAND *p;
+	BUF *b;
+	if (hash_seed == NULL || e == NULL)
+	{
+		return;
+	}
+
+	b = NewBuf();
+	WriteBufInt(b, id);
+	WriteBuf(b, hash_seed, SHA1_SIZE);
+	WriteBufStr(b, "20151002");
+
+	p = NewPRand(b->Buf, b->Size);
+	FreeBuf(b);
+
+	GenerateDummyIp(p, &e->DummySrcIp);
+	GenerateDummyIp(p, &e->DummyDestIP);
+	e->DummyMark = GenerateDummyMark(p);
+
+	FreePRand(p);
+}
+
+// Generate a dummy iptables mark
+UINT GenerateDummyMark(PRAND *p)
+{
+	UINT i;
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+	while (true)
+	{
+		i = PRandInt(p);
+
+		if (i >= 1000000000 && i <= 0x7FFFFFFE)
+		{
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+// Generate a dummy IP
+void GenerateDummyIp(PRAND *p, IP *ip)
+{
+	UINT i;
+	if (p == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	Zero(ip, sizeof(IP));
+
+	for (i = 1;i < 4;i++)
+	{
+		UINT v = 0;
+		while (true)
+		{
+			v = PRandInt(p) % 256;
+			if (v >= 1 && v <= 254)
+			{
+				break;
+			}
+		}
+
+		ip->addr[i] = (UCHAR)v;
+	}
+
+	ip->addr[0] = 127;
+}
+
+// Search an entry
+IPTABLES_ENTRY *SearchIpTables(IPTABLES_STATE *s, char *chain, IP *src_ip, IP *dest_ip, UINT mark)
+{
+	char ip_str1[64];
+	char ip_str2[64];
+	char mark_str1[64];
+	char mark_str2[64];
+	UINT i;
+	if (s == NULL || chain == NULL || src_ip == NULL || dest_ip == NULL || mark == 0)
+	{
+		return NULL;
+	}
+
+	IPToStr(ip_str1, sizeof(ip_str1), src_ip);
+	IPToStr(ip_str2, sizeof(ip_str2), dest_ip);
+	ToStr(mark_str1, mark);
+	Format(mark_str2, sizeof(mark_str2), "%x", mark);
+
+	for (i = 0;i < LIST_NUM(s->EntryList);i++)
+	{
+		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
+
+		if (StrCmpi(e->Chain, chain) == 0)
+		{
+			if (InStr(e->ConditionAndArgs, ip_str1) &&
+				InStr(e->ConditionAndArgs, ip_str2) &&
+				(InStr(e->ConditionAndArgs, mark_str1) || InStr(e->ConditionAndArgs, mark_str2)))
+			{
+				return e;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+// Search an entry and get the line number
+UINT GetCurrentIpTableLineNumber(char *chain, IP *src_ip, IP *dest_ip, UINT mark)
+{
+	IPTABLES_STATE *s;
+	IPTABLES_ENTRY *e;
+	UINT ret = 0;
+
+	if (chain == NULL || src_ip == NULL || dest_ip == NULL || mark == 0)
+	{
+		return 0;
+	}
+
+	s = GetCurrentIpTables();
+
+	e = SearchIpTables(s, chain, src_ip, dest_ip, mark);
+
+	if (e != NULL)
+	{
+		ret = e->LineNumber;
+	}
+
+	FreeIpTablesState(s);
+
+	return ret;
+}
+
+// Free the iptables state
+void FreeIpTablesState(IPTABLES_STATE *s)
+{
+	UINT i;
+	if (s == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(s->EntryList);i++)
+	{
+		IPTABLES_ENTRY *e = LIST_DATA(s->EntryList, i);
+
+		Free(e);
+	}
+
+	ReleaseList(s->EntryList);
+
+	Free(s);
+}
+
+// Get the current iptables state
+IPTABLES_STATE *GetCurrentIpTables()
+{
+	IPTABLES_STATE *ret = NULL;
+	TOKEN_LIST *t = NULL;
+
+#ifdef	OS_UNIX
+	t = UnixExec("iptables -L -x -n --line-numbers");
+#endif	// OS_UNIX
+
+	if (t != NULL)
+	{
+		UINT i;
+		UINT tmp_num = 0;
+
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			char *line = t->Token[i];
+			if (StartWith(line, "Chain INPUT") ||
+				StartWith(line, "Chain FORWARD") ||
+				StartWith(line, "Chain OUTPUT"))
+			{
+				tmp_num++;
+			}
+		}
+
+		if (tmp_num >= 3)
+		{
+			char current_chain[64];
+			UINT mode = 0;
+
+			Zero(current_chain, sizeof(current_chain));
+
+			for (i = 0;i < t->NumTokens;i++)
+			{
+				char *line = t->Token[i];
+
+				if (StartWith(line, "Chain"))
+				{
+					TOKEN_LIST *t2 = ParseToken(line, " \t");
+					if (t2 != NULL)
+					{
+						if (t2->NumTokens >= 4)
+						{
+							StrCpy(current_chain, sizeof(current_chain), t2->Token[1]);
+							mode = 1;
+
+							if (ret == NULL)
+							{
+								ret = ZeroMalloc(sizeof(IPTABLES_STATE));
+								ret->EntryList = NewListFast(NULL);
+							}
+
+						}
+						FreeToken(t2);
+					}
+				}
+
+				if (mode == 1)
+				{
+					if (StartWith(line, "num"))
+					{
+						mode = 2;
+					}
+				}
+				else if (mode == 2)
+				{
+					TOKEN_LIST *t2 = ParseToken(line, " \t");
+					if (t2 != NULL)
+					{
+						if (t2->NumTokens >= 6 && ToInt(t2->Token[0]) != 0)
+						{
+							IPTABLES_ENTRY *e = ZeroMalloc(sizeof(IPTABLES_ENTRY));
+
+							StrCpy(e->Chain, sizeof(e->Chain), current_chain);
+							e->LineNumber = ToInt(t2->Token[0]);
+							StrCpy(e->ConditionAndArgs, sizeof(e->ConditionAndArgs), line);
+
+							Add(ret->EntryList, e);
+						}
+
+						FreeToken(t2);
+					}
+				}
+			}
+		}
+
+		FreeToken(t);
+	}
+
+	return ret;
+}
+
+// Get whether iptables is supported
+bool IsIpTablesSupported()
+{
+#ifdef	UNIX_LINUX
+	IPTABLES_STATE *s = GetCurrentIpTables();
+	if (s != NULL)
+	{
+		FreeIpTablesState(s);
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+#else	// UNIX_LINUX
+	return false;
+#endif	// UNIX_LINUX
+}
+
+
+
 
 
 // Developed by SoftEther VPN Project at University of Tsukuba in Japan.

+ 46 - 0
src/Cedar/NativeStack.h

@@ -117,6 +117,10 @@
 //// Constants
 #define	NS_MAC_ADDRESS_BYTE_1		0xDA		// First byte of the MAC address
 
+#define	NS_CHECK_IPTABLES_INTERVAL_INIT	(1 * 1000)
+
+#define	NS_CHECK_IPTABLES_INTERVAL_MAX	(5 * 60 * 1000)
+
 //// Type
 struct NATIVE_STACK
 {
@@ -132,6 +136,30 @@ struct NATIVE_STACK
 	SOCK *Sock2;					// Sock2 (Used in the IPC side)
 	DHCP_OPTION_LIST CurrentDhcpOptionList;	// Current DHCP options list
 	IP DnsServerIP;					// IP address of the DNS server
+	IP DnsServerIP2;				// IP address of the DNS server #2
+	bool IsIpRawMode;
+	IP MyIP_InCaseOfIpRawMode;		// My IP
+
+	THREAD *IpTablesThread;
+	EVENT *IpTablesHaltEvent;
+	bool IpTablesHalt;
+	bool IpTablesInitOk;
+};
+
+struct IPTABLES_ENTRY
+{
+	char Chain[64];
+	UINT LineNumber;
+	char ConditionAndArgs[MAX_SIZE];
+	IP DummySrcIp, DummyDestIP;
+	UINT DummyMark;
+};
+
+struct IPTABLES_STATE
+{
+	UCHAR SeedHash[SHA1_SIZE];
+	LIST *EntryList;
+	bool HasError;
 };
 
 
@@ -144,6 +172,24 @@ void NsMainThread(THREAD *thread, void *param);
 void NsGenMacAddressSignatureForMachine(UCHAR *dst_last_2, UCHAR *src_mac_addr_4);
 bool NsIsMacAddressOnLocalhost(UCHAR *mac);
 
+bool NsStartIpTablesTracking(NATIVE_STACK *a);
+void NsStopIpTablesTracking(NATIVE_STACK *a);
+void NsIpTablesThread(THREAD *thread, void *param);
+
+IPTABLES_STATE *GetCurrentIpTables();
+void FreeIpTablesState(IPTABLES_STATE *s);
+bool IsIpTablesSupported();
+IPTABLES_ENTRY *SearchIpTables(IPTABLES_STATE *s, char *chain, IP *src_ip, IP *dest_ip, UINT mark);
+UINT GetCurrentIpTableLineNumber(char *chain, IP *src_ip, IP *dest_ip, UINT mark);
+
+IPTABLES_STATE *StartAddIpTablesEntryForNativeStack(void *seed, UINT seed_size);
+void EndAddIpTablesEntryForNativeStack(IPTABLES_STATE *s);
+bool MaintainAddIpTablesEntryForNativeStack(IPTABLES_STATE *s);
+
+void GenerateDummyIpAndMark(void *hash_seed, IPTABLES_ENTRY *e, UINT id);
+UINT GenerateDummyMark(PRAND *p);
+void GenerateDummyIp(PRAND *p, IP *ip);
+
 #endif	// NATIVESTACK_H
 
 

+ 33 - 2
src/Cedar/Protocol.c

@@ -1324,6 +1324,7 @@ bool ServerAccept(CONNECTION *c)
 	char *error_detail = NULL;
 	char *error_detail_2 = NULL;
 	char ctoken_hash_str[64];
+	EAP_CLIENT *release_me_eap_client = NULL;
 
 	// Validate arguments
 	if (c == NULL)
@@ -1653,6 +1654,7 @@ bool ServerAccept(CONNECTION *c)
 			if (hub->Option != NULL)
 			{
 				radius_login_opt.In_CheckVLanId = hub->Option->AssignVLanIdByRadiusAttribute;
+				radius_login_opt.In_DenyNoVlanId = hub->Option->DenyAllRadiusLoginWithNoVlanAssign;
 			}
 
 			// Get the various flags
@@ -1674,6 +1676,14 @@ bool ServerAccept(CONNECTION *c)
 			if (c->IsInProc)
 			{
 				char tmp[MAX_SIZE];
+				UINT64 ptr;
+
+				ptr = PackGetInt64(p, "release_me_eap_client");
+				if (ptr != 0)
+				{
+					release_me_eap_client = (EAP_CLIENT *)ptr;
+				}
+
 				PackGetStr(p, "inproc_postfix", c->InProcPrefix, sizeof(c->InProcPrefix));
 				Zero(tmp, sizeof(tmp));
 				PackGetStr(p, "inproc_cryptname", tmp, sizeof(tmp));
@@ -2203,9 +2213,25 @@ bool ServerAccept(CONNECTION *c)
 			FreePack(p);
 
 			// Check the assigned VLAN ID
-			if (radius_login_opt.Out_VLanId != 0)
+			if (radius_login_opt.Out_IsRadiusLogin)
 			{
-				assigned_vlan_id = radius_login_opt.Out_VLanId;
+				if (radius_login_opt.In_CheckVLanId)
+				{
+					if (radius_login_opt.Out_VLanId != 0)
+					{
+						assigned_vlan_id = radius_login_opt.Out_VLanId;
+					}
+
+					if (radius_login_opt.In_DenyNoVlanId && assigned_vlan_id == 0 || assigned_vlan_id >= 4096)
+					{
+						// Deny this session
+						Unlock(hub->lock);
+						ReleaseHub(hub);
+						c->Err = ERR_ACCESS_DENIED;
+						error_detail = "In_DenyNoVlanId";
+						goto CLEANUP;
+					}
+				}
 			}
 
 			if (StrCmpi(username, ADMINISTRATOR_USERNAME) != 0)
@@ -3807,6 +3833,11 @@ CLEANUP:
 
 	SLog(c->Cedar, "LS_CONNECTION_ERROR", c->Name, GetUniErrorStr(c->Err), c->Err);
 
+	if (release_me_eap_client != NULL)
+	{
+		ReleaseEapClient(release_me_eap_client);
+	}
+
 	return ret;
 }
 

文件差异内容过多而无法显示
+ 1588 - 0
src/Cedar/Radius.c


+ 246 - 1
src/Cedar/Radius.h

@@ -117,15 +117,260 @@
 #define	RADIUS_DEFAULT_PORT		1812			// The default port number
 #define	RADIUS_RETRY_INTERVAL	500				// Retransmission interval
 #define	RADIUS_RETRY_TIMEOUT	(10 * 1000)		// Time-out period
+#define	RADIUS_INITIAL_EAP_TIMEOUT	1600		// Initial timeout for EAP
 
 
 // RADIUS attributes
-#define	RADIUS_ATTRIBUTE_VLAN_ID	81
+#define	RADIUS_ATTRIBUTE_USER_NAME					1
+#define	RADIUS_ATTRIBUTE_NAS_IP						4
+#define	RADIUS_ATTRIBUTE_NAS_PORT					5
+#define	RADIUS_ATTRIBUTE_SERVICE_TYPE				6
+#define	RADIUS_ATTRIBUTE_FRAMED_PROTOCOL			7
+#define	RADIUS_ATTRIBUTE_FRAMED_MTU					12
+#define	RADIUS_ATTRIBUTE_STATE						24
+#define	RADIUS_ATTRIBUTE_VENDOR_SPECIFIC			26
+#define	RADIUS_ATTRIBUTE_CALLED_STATION_ID			30
+#define	RADIUS_ATTRIBUTE_CALLING_STATION_ID			31
+#define	RADIUS_ATTRIBUTE_NAS_ID						32
+#define	RADIUS_ATTRIBUTE_PROXY_STATE				33
+#define	RADIUS_ATTRIBUTE_ACCT_SESSION_ID			44
+#define	RADIUS_ATTRIBUTE_NAS_PORT_TYPE				61
+#define	RADIUS_ATTRIBUTE_TUNNEL_TYPE				64
+#define	RADIUS_ATTRIBUTE_TUNNEL_MEDIUM_TYPE			65
+#define	RADIUS_ATTRIBUTE_TUNNEL_CLIENT_ENDPOINT		66
+#define	RADIUS_ATTRIBUTE_TUNNEL_SERVER_ENDPOINT		67
+#define	RADIUS_ATTRIBUTE_EAP_MESSAGE				79
+#define	RADIUS_ATTRIBUTE_EAP_AUTHENTICATOR			80
+#define	RADIUS_ATTRIBUTE_VLAN_ID					81
 
+// RADIUS codes
+#define	RADIUS_CODE_ACCESS_REQUEST					1
+#define	RADIUS_CODE_ACCESS_ACCEPT					2
+#define	RADIUS_CODE_ACCESS_REJECT					3
+#define	RADIUS_CODE_ACCESS_CHALLENGE				11
+
+// RADIUS vendor ID
+#define	RADIUS_VENDOR_MICROSOFT						311
+
+// RADIUS MS attributes
+#define	RADIUS_MS_RAS_VENDOR						9
+#define	RADIUS_MS_CHAP_CHALLENGE					11
+#define	RADIUS_MS_VERSION							18
+#define	RADIUS_MS_CHAP2_RESPONSE					25
+#define	RADIUS_MS_RAS_CLIENT_NAME					34
+#define	RADIUS_MS_RAS_CLIENT_VERSION				35
+#define	RADIUS_MS_NETWORK_ACCESS_SERVER_TYPE		47
+#define	RADIUS_MS_RAS_CORRELATION					56
+
+// EAP code
+#define	EAP_CODE_REQUEST							1
+#define	EAP_CODE_RESPONSE							2
+#define	EAP_CODE_SUCCESS							3
+#define	EAP_CODE_FAILURE							4
+
+// EAP type
+#define	EAP_TYPE_IDENTITY							1
+#define	EAP_TYPE_LEGACY_NAK							3
+#define	EAP_TYPE_PEAP								25
+#define	EAP_TYPE_MS_AUTH							26
+
+// MS-CHAPv2 opcodes
+#define	EAP_MSCHAPV2_OP_CHALLENGE					1
+#define	EAP_MSCHAPV2_OP_RESPONSE					2
+#define	EAP_MSCHAPV2_OP_SUCCESS						3
+
+// EAP-TLS flags
+#define	EAP_TLS_FLAGS_LEN							0x80
+#define	EAP_TLS_FLAGS_MORE_FRAGMENTS				0x40
+#define	EAP_TLS_FLAGS_START							0x20
+
+
+////////// Modern implementation
+
+#ifdef	OS_WIN32
+#pragma pack(push, 1)
+#endif	// OS_WIN32
+
+struct EAP_MESSAGE
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR Data[1500];
+} GCC_PACKED;
+
+struct EAP_MSCHAPV2_GENERAL
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR Chap_Opcode;
+} GCC_PACKED;
+
+struct EAP_MSCHAPV2_CHALLENGE
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR Chap_Opcode;
+	UCHAR Chap_Id;
+	USHORT Chap_Len;
+	UCHAR Chap_ValueSize;	// = 16
+	UCHAR Chap_ChallengeValue[16];
+	char Chap_Name[256];
+} GCC_PACKED;
+
+struct EAP_MSCHAPV2_RESPONSE
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR Chap_Opcode;
+	UCHAR Chap_Id;
+	USHORT Chap_Len;
+	UCHAR Chap_ValueSize;	// = 49
+	UCHAR Chap_PeerChallange[16];
+	UCHAR Chap_Reserved[8];
+	UCHAR Chap_NtResponse[24];
+	UCHAR Chap_Flags;
+	char Chap_Name[256];
+} GCC_PACKED;
+
+struct EAP_MSCHAPV2_SUCCESS_SERVER
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR Chap_Opcode;
+	UCHAR Chap_Id;
+	USHORT Chap_Len;
+	char Message[256];
+} GCC_PACKED;
+
+struct EAP_MSCHAPV2_SUCCESS_CLIENT
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR Chap_Opcode;
+} GCC_PACKED;
+
+struct EAP_PEAP
+{
+	UCHAR Code;
+	UCHAR Id;
+	USHORT Len;		// = sizeof(Data) + 5
+	UCHAR Type;
+	UCHAR TlsFlags;
+} GCC_PACKED;
+
+#ifdef	OS_WIN32
+#pragma pack(pop)
+#endif	// OS_WIN32
+
+struct RADIUS_PACKET
+{
+	UCHAR Code;
+	UCHAR PacketId;
+	LIST *AvpList;
+	UCHAR Authenticator[16];
+
+	UINT Parse_EapAuthMessagePos;
+	UINT Parse_AuthenticatorPos;
+
+	EAP_MESSAGE *Parse_EapMessage;
+	UINT Parse_EapMessage_DataSize;
+
+	UINT Parse_StateSize;
+	UCHAR Parse_State[256];
+};
+
+struct RADIUS_AVP
+{
+	UCHAR Type;
+	UINT VendorId;
+	UCHAR VendorCode;
+	UCHAR Padding[3];
+	UCHAR DataSize;
+	UCHAR Data[256];
+};
+
+struct EAP_CLIENT
+{
+	REF *Ref;
+
+	SOCK *UdpSock;
+	IP ServerIp;
+	UINT ServerPort;
+	char SharedSecret[MAX_SIZE];
+	char ClientIpStr[256];
+	char Username[MAX_USERNAME_LEN + 1];
+	UINT ResendTimeout;
+	UINT GiveupTimeout;
+	UCHAR TmpBuffer[4096];
+	UCHAR NextEapId;
+	UCHAR LastRecvEapId;
+
+	bool PeapMode;
+
+	UCHAR LastState[256];
+	UINT LastStateSize;
+
+	EAP_MSCHAPV2_CHALLENGE MsChapV2Challenge;
+	EAP_MSCHAPV2_SUCCESS_SERVER MsChapV2Success;
+	UCHAR ServerResponse[20];
+
+	SSL_PIPE *SslPipe;
+	UCHAR NextRadiusPacketId;
+
+	BUF *PEAP_CurrentReceivingMsg;
+	UINT PEAP_CurrentReceivingTotalSize;
+	UCHAR RecvLastCode;
+
+	UINT LastRecvVLanId;
+};
+
+void FreeRadiusPacket(RADIUS_PACKET *p);
+BUF *GenerateRadiusPacket(RADIUS_PACKET *p, char *shared_secret);
+RADIUS_PACKET *ParseRadiusPacket(void *data, UINT size);
+RADIUS_PACKET *NewRadiusPacket(UCHAR code, UCHAR packet_id);
+RADIUS_AVP *NewRadiusAvp(UCHAR type, UINT vendor_id, UCHAR vendor_code, void *data, UINT size);
+RADIUS_AVP *GetRadiusAvp(RADIUS_PACKET *p, UCHAR type);
+void RadiusTest();
+
+
+EAP_CLIENT *NewEapClient(IP *server_ip, UINT server_port, char *shared_secret, UINT resend_timeout, UINT giveup_timeout, char *client_ip_str, char *username);
+void ReleaseEapClient(EAP_CLIENT *e);
+void CleanupEapClient(EAP_CLIENT *e);
+bool EapClientSendMsChapv2AuthRequest(EAP_CLIENT *e);
+bool EapClientSendMsChapv2AuthClientResponse(EAP_CLIENT *e, UCHAR *client_response, UCHAR *client_challenge);
+void EapSetRadiusGeneralAttributes(RADIUS_PACKET *r, EAP_CLIENT *e);
+bool EapSendPacket(EAP_CLIENT *e, RADIUS_PACKET *r);
+RADIUS_PACKET *EapSendPacketAndRecvResponse(EAP_CLIENT *e, RADIUS_PACKET *r);
+
+bool PeapClientSendMsChapv2AuthRequest(EAP_CLIENT *eap);
+bool PeapClientSendMsChapv2AuthClientResponse(EAP_CLIENT *e, UCHAR *client_response, UCHAR *client_challenge);
+
+bool StartPeapClient(EAP_CLIENT *e);
+bool StartPeapSslClient(EAP_CLIENT *e);
+bool SendPeapRawPacket(EAP_CLIENT *e, UCHAR *peap_data, UINT peap_size);
+bool SendPeapPacket(EAP_CLIENT *e, void *msg, UINT msg_size);
+bool GetRecvPeapMessage(EAP_CLIENT *e, EAP_MESSAGE *msg);
+
+
+////////// Classical implementation
 struct RADIUS_LOGIN_OPTION
 {
 	bool In_CheckVLanId;
+	bool In_DenyNoVlanId;
 	UINT Out_VLanId;
+	bool Out_IsRadiusLogin;
 };
 
 // Function prototype

+ 8 - 0
src/Cedar/Sam.c

@@ -268,6 +268,14 @@ bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *p
 					b = RadiusLogin(c, radius_server_addr, radius_server_port,
 						radius_secret, StrLen(radius_secret),
 						name, password, interval, mschap_v2_server_response_20, opt);
+
+					if (b)
+					{
+						if (opt != NULL)
+						{
+							opt->Out_IsRadiusLogin = true;
+						}
+					}
 				}
 
 				Lock(hub->lock);

+ 14 - 0
src/Cedar/Server.c

@@ -4098,11 +4098,13 @@ void SiLoadHubOptionCfg(FOLDER *f, HUB_OPTION *o)
 	}
 
 	o->DisableKernelModeSecureNAT = CfgGetBool(f, "DisableKernelModeSecureNAT");
+	o->DisableIpRawModeSecureNAT = CfgGetBool(f, "DisableIpRawModeSecureNAT");
 	o->DisableUserModeSecureNAT = CfgGetBool(f, "DisableUserModeSecureNAT");
 	o->DisableCheckMacOnLocalBridge = CfgGetBool(f, "DisableCheckMacOnLocalBridge");
 	o->DisableCorrectIpOffloadChecksum = CfgGetBool(f, "DisableCorrectIpOffloadChecksum");
 	o->SuppressClientUpdateNotification = CfgGetBool(f, "SuppressClientUpdateNotification");
 	o->AssignVLanIdByRadiusAttribute = CfgGetBool(f, "AssignVLanIdByRadiusAttribute");
+	o->DenyAllRadiusLoginWithNoVlanAssign = CfgGetBool(f, "DenyAllRadiusLoginWithNoVlanAssign");
 	o->SecureNAT_RandomizeAssignIp = CfgGetBool(f, "SecureNAT_RandomizeAssignIp");
 	o->DetectDormantSessionInterval = CfgGetInt(f, "DetectDormantSessionInterval");
 	o->NoPhysicalIPOnPacketLog = CfgGetBool(f, "NoPhysicalIPOnPacketLog");
@@ -4182,6 +4184,7 @@ void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o)
 	CfgAddBool(f, "DropArpInPrivacyFilterMode", o->DropArpInPrivacyFilterMode);
 	CfgAddBool(f, "SuppressClientUpdateNotification", o->SuppressClientUpdateNotification);
 	CfgAddBool(f, "AssignVLanIdByRadiusAttribute", o->AssignVLanIdByRadiusAttribute);
+	CfgAddBool(f, "DenyAllRadiusLoginWithNoVlanAssign", o->DenyAllRadiusLoginWithNoVlanAssign);
 	CfgAddBool(f, "SecureNAT_RandomizeAssignIp", o->SecureNAT_RandomizeAssignIp);
 	CfgAddBool(f, "NoPhysicalIPOnPacketLog", o->NoPhysicalIPOnPacketLog);
 	CfgAddInt(f, "DetectDormantSessionInterval", o->DetectDormantSessionInterval);
@@ -4201,6 +4204,7 @@ void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o)
 	CfgAddInt(f, "SecureNAT_MaxIcmpSessionsPerIp", o->SecureNAT_MaxIcmpSessionsPerIp);
 	CfgAddInt(f, "AccessListIncludeFileCacheLifetime", o->AccessListIncludeFileCacheLifetime);
 	CfgAddBool(f, "DisableKernelModeSecureNAT", o->DisableKernelModeSecureNAT);
+	CfgAddBool(f, "DisableIpRawModeSecureNAT", o->DisableIpRawModeSecureNAT);
 	CfgAddBool(f, "DisableUserModeSecureNAT", o->DisableUserModeSecureNAT);
 	CfgAddBool(f, "DisableCheckMacOnLocalBridge", o->DisableCheckMacOnLocalBridge);
 	CfgAddBool(f, "DisableCorrectIpOffloadChecksum", o->DisableCorrectIpOffloadChecksum);
@@ -5005,6 +5009,9 @@ void SiWriteHubCfg(FOLDER *f, HUB *h)
 		CfgAddInt(f, "RadiusServerPort", h->RadiusServerPort);
 		CfgAddInt(f, "RadiusRetryInterval", h->RadiusRetryInterval);
 		CfgAddStr(f, "RadiusSuffixFilter", h->RadiusSuffixFilter);
+
+		CfgAddBool(f, "RadiusConvertAllMsChapv2AuthRequestToEap", h->RadiusConvertAllMsChapv2AuthRequestToEap);
+		CfgAddBool(f, "RadiusUsePeapInsteadOfEap", h->RadiusUsePeapInsteadOfEap);
 	}
 	Unlock(h->RadiusOptionLock);
 
@@ -5171,6 +5178,9 @@ void SiLoadHubCfg(SERVER *s, FOLDER *f, char *name)
 
 			CfgGetStr(f, "RadiusSuffixFilter", h->RadiusSuffixFilter, sizeof(h->RadiusSuffixFilter));
 
+			h->RadiusConvertAllMsChapv2AuthRequestToEap = CfgGetBool(f, "RadiusConvertAllMsChapv2AuthRequestToEap");
+			h->RadiusUsePeapInsteadOfEap = CfgGetBool(f, "RadiusUsePeapInsteadOfEap");
+
 			if (interval == 0)
 			{
 				interval = RADIUS_RETRY_INTERVAL;
@@ -7486,6 +7496,7 @@ void SiCalledUpdateHub(SERVER *s, PACK *p)
 	o.DropArpInPrivacyFilterMode = PackGetBool(p, "DropArpInPrivacyFilterMode");
 	o.SuppressClientUpdateNotification = PackGetBool(p, "SuppressClientUpdateNotification");
 	o.AssignVLanIdByRadiusAttribute = PackGetBool(p, "AssignVLanIdByRadiusAttribute");
+	o.DenyAllRadiusLoginWithNoVlanAssign = PackGetBool(p, "DenyAllRadiusLoginWithNoVlanAssign");
 	o.SecureNAT_RandomizeAssignIp = PackGetBool(p, "SecureNAT_RandomizeAssignIp");
 	o.DetectDormantSessionInterval = PackGetInt(p, "DetectDormantSessionInterval");
 	o.VlanTypeId = PackGetInt(p, "VlanTypeId");
@@ -7527,6 +7538,7 @@ void SiCalledUpdateHub(SERVER *s, PACK *p)
 		o.AccessListIncludeFileCacheLifetime = ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME;
 	}
 	o.DisableKernelModeSecureNAT = PackGetBool(p, "DisableKernelModeSecureNAT");
+	o.DisableIpRawModeSecureNAT = PackGetBool(p, "DisableIpRawModeSecureNAT");
 	o.DisableUserModeSecureNAT = PackGetBool(p, "DisableUserModeSecureNAT");
 	o.DisableCheckMacOnLocalBridge = PackGetBool(p, "DisableCheckMacOnLocalBridge");
 	o.DisableCorrectIpOffloadChecksum = PackGetBool(p, "DisableCorrectIpOffloadChecksum");
@@ -9329,6 +9341,7 @@ void SiPackAddCreateHub(PACK *p, HUB *h)
 	PackAddBool(p, "DropArpInPrivacyFilterMode", h->Option->DropArpInPrivacyFilterMode);
 	PackAddBool(p, "SuppressClientUpdateNotification", h->Option->SuppressClientUpdateNotification);
 	PackAddBool(p, "AssignVLanIdByRadiusAttribute", h->Option->AssignVLanIdByRadiusAttribute);
+	PackAddBool(p, "DenyAllRadiusLoginWithNoVlanAssign", h->Option->DenyAllRadiusLoginWithNoVlanAssign);
 	PackAddInt(p, "ClientMinimumRequiredBuild", h->Option->ClientMinimumRequiredBuild);
 	PackAddBool(p, "SecureNAT_RandomizeAssignIp", h->Option->SecureNAT_RandomizeAssignIp);
 	PackAddBool(p, "NoPhysicalIPOnPacketLog", h->Option->NoPhysicalIPOnPacketLog);
@@ -9366,6 +9379,7 @@ void SiPackAddCreateHub(PACK *p, HUB *h)
 	PackAddInt(p, "SecureNAT_MaxIcmpSessionsPerIp", h->Option->SecureNAT_MaxIcmpSessionsPerIp);
 	PackAddInt(p, "AccessListIncludeFileCacheLifetime", h->Option->AccessListIncludeFileCacheLifetime);
 	PackAddBool(p, "DisableKernelModeSecureNAT", h->Option->DisableKernelModeSecureNAT);
+	PackAddBool(p, "DisableIpRawModeSecureNAT", h->Option->DisableIpRawModeSecureNAT);
 	PackAddBool(p, "DisableUserModeSecureNAT", h->Option->DisableUserModeSecureNAT);
 	PackAddBool(p, "DisableCheckMacOnLocalBridge", h->Option->DisableCheckMacOnLocalBridge);
 	PackAddBool(p, "DisableCorrectIpOffloadChecksum", h->Option->DisableCorrectIpOffloadChecksum);

+ 130 - 16
src/Cedar/Virtual.c

@@ -329,7 +329,7 @@ void NnDeleteSession(NATIVE_NAT *t, NATIVE_NAT_ENTRY *e)
 		break;
 
 	case NAT_ICMP:
-		Debug("NAT ICMP %u Deleted.", e->Id);
+		Debug("NAT ICMP %u Deleted.\n", e->Id);
 		break;
 	}
 
@@ -509,6 +509,7 @@ void NnCombineIp(NATIVE_NAT *t, IP_COMBINE *c, UINT offset, void *data, UINT siz
 		if (total_size == c->Size)
 		{
 			// Received whole of the IP packet
+			//Debug("Combine: %u\n", total_size);
 			NnIpReceived(t, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->Ttl,
 				c->HeadIpHeaderData, c->HeadIpHeaderDataSize, c->MaxL3Size);
 
@@ -1651,24 +1652,32 @@ UINT NnMapNewPublicPort(NATIVE_NAT *t, UINT protocol, UINT dest_ip, UINT dest_po
 {
 	UINT i;
 	UINT base_port;
+	UINT port_start = 1025;
+	UINT port_end = 65500;
 	// Validate arguments
 	if (t == NULL)
 	{
 		return 0;
 	}
 
-	base_port = Rand32() % (65500 - 1025) + 1025;
+	if (t->IsRawIpMode)
+	{
+		port_start = NN_RAW_IP_PORT_START;
+		port_end = NN_RAW_IP_PORT_END;
+	}
 
-	for (i = 0;i < (65500 - 1025);i++)
+	base_port = Rand32() % (port_end - port_start) + port_start;
+
+	for (i = 0;i < (port_end - port_start);i++)
 	{
 		UINT port;
 		NATIVE_NAT_ENTRY tt;
 		NATIVE_NAT *e;
 
 		port = base_port + i;
-		if (port > 65500)
+		if (port > port_end)
 		{
-			port = port - 65500 + 1025;
+			port = port - port_end + port_start;
 		}
 
 		// Is this port vacant?
@@ -1688,6 +1697,10 @@ UINT NnMapNewPublicPort(NATIVE_NAT *t, UINT protocol, UINT dest_ip, UINT dest_po
 
 // Examine whether the native NAT is available
 bool NnIsActive(VH *v)
+{
+	return NnIsActiveEx(v, NULL);
+}
+bool NnIsActiveEx(VH *v, bool *is_ipraw_mode)
 {
 	// Validate arguments
 	if (v == NULL)
@@ -1705,6 +1718,14 @@ bool NnIsActive(VH *v)
 		return false;
 	}
 
+	if (v->NativeNat->Active)
+	{
+		if (is_ipraw_mode != NULL)
+		{
+			*is_ipraw_mode = v->NativeNat->IsRawIpMode;
+		}
+	}
+
 	return v->NativeNat->Active;
 }
 
@@ -1745,7 +1766,7 @@ void NnMainLoop(NATIVE_NAT *t, NATIVE_STACK *a)
 	ipc = a->Ipc;
 
 	tubes[num_tubes++] = ipc->Sock->RecvTube;
-	tubes[num_tubes++] = ipc->Sock->SendTube;
+	//tubes[num_tubes++] = ipc->Sock->SendTube;	// bug 2015.10.01 remove
 	tubes[num_tubes++] = t->HaltTube;
 
 	Zero(&yahoo_ip, sizeof(yahoo_ip));
@@ -1757,13 +1778,25 @@ void NnMainLoop(NATIVE_NAT *t, NATIVE_STACK *a)
 	next_dhcp_renew_tick = Tick64() + (UINT64)dhcp_renew_interval;
 	AddInterrupt(interrupt, next_dhcp_renew_tick);
 
-	while (t->Halt == false && t->v->UseNat && ((t->v->HubOption == NULL) || (t->v->HubOption->DisableKernelModeSecureNAT == false)))
+	while (t->Halt == false && t->v->UseNat)
 	{
 		UINT64 now = Tick64();
 		bool call_cancel = false;
 		bool state_changed = false;
 		UINT wait_interval;
 
+		if (t->v->HubOption != NULL)
+		{
+			if (t->IsRawIpMode == false && t->v->HubOption->DisableKernelModeSecureNAT)
+			{
+				break;
+			}
+			if (t->IsRawIpMode && t->v->HubOption->DisableIpRawModeSecureNAT)
+			{
+				break;
+			}
+		}
+
 		IPCFlushArpTable(ipc);
 		call_cancel = false;
 
@@ -1774,7 +1807,7 @@ LABEL_RESTART:
 		{
 			BUF *dns_query;
 
-			dns_src_port = NnGenSrcPort();
+			dns_src_port = NnGenSrcPort(a->IsIpRawMode);
 			dns_tran_id = Rand16();
 
 			// Start a connectivity check periodically
@@ -1877,7 +1910,7 @@ LABEL_RESTART:
 										// DNS response has been received
 										no_store = true;
 
-										tcp_src_port = NnGenSrcPort();
+										tcp_src_port = NnGenSrcPort(a->IsIpRawMode);
 
 										// Generate a TCP connection attempt packet
 										tcp_seq = Rand32();
@@ -2347,22 +2380,47 @@ LABEL_CLEANUP:
 bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 {
 	BUF *dns_query;
+	BUF *dns_query2;
 	bool ok = false;
 	USHORT dns_tran_id = Rand16();
 	UINT64 next_send_tick = 0;
 	UINT64 giveup_time;
 	IPC *ipc;
-	UINT src_port = NnGenSrcPort();
+	UINT src_port = NnGenSrcPort(a->IsIpRawMode);
 	INTERRUPT_MANAGER *interrupt;
 	TUBE *tubes[3];
 	UINT num_tubes = 0;
 	IP yahoo_ip;
+	IP my_priv_ip;
+	UINT num_send_dns = 0;
+	IP using_dns;
 	// Validate arguments
 	if (a == NULL)
 	{
 		return false;
 	}
 
+	Copy(&using_dns, &a->DnsServerIP, sizeof(IP));
+
+	// Get my physical IP
+	if (a->IsIpRawMode)
+	{
+		if (GetMyPrivateIP(&my_priv_ip, false) == false)
+		{
+			Debug("NnTestConnectivity: GetMyPrivateIP failed.\n");
+			return false;
+		}
+		else
+		{
+			Debug("NnTestConnectivity: GetMyPrivateIP ok: %r\n", &my_priv_ip);
+
+			if (a->Eth != NULL)
+			{
+				Copy(&a->Eth->MyPhysicalIPForce, &my_priv_ip, sizeof(IP));
+			}
+		}
+	}
+
 	ipc = a->Ipc;
 	interrupt = NewInterruptManager();
 
@@ -2381,6 +2439,10 @@ bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 		IPToUINT(&ipc->ClientIPAddress), src_port, IPToUINT(&a->DnsServerIP), 53),
 		IPToUINT(&ipc->ClientIPAddress), IPToUINT(&a->DnsServerIP), IP_PROTO_UDP, 0);
 
+	dns_query2 = NnBuildIpPacket(NnBuildUdpPacket(NnBuildDnsQueryPacket(NN_CHECK_HOSTNAME, dns_tran_id),
+		IPToUINT(&ipc->ClientIPAddress), src_port, IPToUINT(&a->DnsServerIP), 53),
+		IPToUINT(&ipc->ClientIPAddress), IPToUINT(&a->DnsServerIP2), IP_PROTO_UDP, 0);
+
 	giveup_time = Tick64() + NN_CHECK_CONNECTIVITY_TIMEOUT;
 	AddInterrupt(interrupt, giveup_time);
 	while (true)
@@ -2401,7 +2463,16 @@ bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 
 			AddInterrupt(interrupt, next_send_tick);
 
-			IPCSendIPv4(ipc, dns_query->Buf, dns_query->Size);
+			if ((num_send_dns % 2) == 0)
+			{
+				IPCSendIPv4(ipc, dns_query->Buf, dns_query->Size);
+			}
+			else
+			{
+				IPCSendIPv4(ipc, dns_query2->Buf, dns_query2->Size);
+			}
+
+			num_send_dns++;
 		}
 
 		// Happy processing
@@ -2424,7 +2495,8 @@ bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 			if (pkt != NULL)
 			{
 				if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP &&
-					pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP) &&
+					(pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP) ||
+					 pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP2)) &&
 					pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
 					pkt->L4.UDPHeader->SrcPort == Endian16(53) && pkt->L4.UDPHeader->DstPort == Endian16(src_port))
 				{
@@ -2437,6 +2509,9 @@ bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 
 							if (NnParseDnsResponsePacket(pkt->Payload, pkt->PayloadSize, &ret_ip))
 							{
+								UINTToIP(&using_dns, pkt->L3.IPv4Header->SrcIP);
+								Debug("NativeStack: Using DNS: %r\n", &using_dns);
+
 								Copy(&yahoo_ip, &ret_ip, sizeof(IP));
 							}
 						}
@@ -2466,6 +2541,7 @@ bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 	}
 
 	FreeBuf(dns_query);
+	FreeBuf(dns_query2);
 
 	if (IsZeroIP(&yahoo_ip) == false)
 	{
@@ -2589,13 +2665,37 @@ bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
 
 	FreeInterruptManager(interrupt);
 
+	if (ok)
+	{
+		if (IsZeroIP(&using_dns) == false)
+		{
+			Copy(&a->DnsServerIP, &using_dns, sizeof(IP));
+		}
+
+		if (a->IsIpRawMode)
+		{
+			if (NsStartIpTablesTracking(a) == false)
+			{
+				Debug("NsStartIpTablesTracking failed.\n");
+				ok = false;
+			}
+		}
+	}
+
 	return ok;
 }
 
 // Generate source port number by a random number
-UINT NnGenSrcPort()
+UINT NnGenSrcPort(bool raw_ip_mode)
 {
-	return 1025 + Rand32() % (65500 - 1025);
+	if (raw_ip_mode == false)
+	{
+		return 1025 + Rand32() % (65500 - 1025);
+	}
+	else
+	{
+		return NN_RAW_IP_PORT_START + Rand32() % (NN_RAW_IP_PORT_END - NN_RAW_IP_PORT_START);
+	}
 }
 
 // Get a next good interface for the native NAT
@@ -2617,7 +2717,9 @@ NATIVE_STACK *NnGetNextInterface(NATIVE_NAT *t)
 	t->NextWaitTimeForRetry = NN_NEXT_WAIT_TIME_FOR_DEVICE_ENUM * MIN((t->FailedCount + 1), NN_NEXT_WAIT_TIME_MAX_FAIL_COUNT);
 
 	// Get the device list
-	device_list = GetEthList();
+	device_list = GetEthListEx(NULL,
+		!(t->v->HubOption != NULL && t->v->HubOption->DisableKernelModeSecureNAT),
+		!(t->v->HubOption != NULL && t->v->HubOption->DisableIpRawModeSecureNAT));
 
 	if (device_list == NULL || device_list->NumTokens == 0)
 	{
@@ -2720,11 +2822,17 @@ NATIVE_STACK *NnGetNextInterface(NATIVE_NAT *t)
 
 				// Determine the DNS server to use
 				UINTToIP(&ret->DnsServerIP, opt.DnsServer);
+				UINTToIP(&ret->DnsServerIP2, opt.DnsServer2);
 				if (IsZeroIP(&ret->DnsServerIP))
 				{
 					// Use 8.8.8.8 instead If the DNS is not assigned from the DHCP server
 					SetIP(&ret->DnsServerIP, 8, 8, 8, 8);
 				}
+				if (IsZeroIP(&ret->DnsServerIP2))
+				{
+					// Use 8.8.4.4 instead If the DNS is not assigned from the DHCP server
+					SetIP(&ret->DnsServerIP2, 8, 8, 4, 4);
+				}
 
 				// Connectivity test
 				// (always fail if the default gateway is not set)
@@ -2773,7 +2881,7 @@ void NativeNatThread(THREAD *thread, void *param)
 	{
 		NATIVE_STACK *a;
 
-		while (t->v->UseNat == false || (t->v->HubOption != NULL && t->v->HubOption->DisableKernelModeSecureNAT))
+		while (t->v->UseNat == false || t->v->HubOption == NULL || (t->v->HubOption->DisableKernelModeSecureNAT && t->v->HubOption->DisableIpRawModeSecureNAT))
 		{
 			if (t->Halt)
 			{
@@ -2802,6 +2910,8 @@ void NativeNatThread(THREAD *thread, void *param)
 			// Acquisition success
 			Debug("NnGetNextInterface Ok: %s\n", a->DeviceName);
 
+			t->IsRawIpMode = a->IsIpRawMode;
+
 			Lock(t->Lock);
 			{
 				if (a->Sock1 != NULL)
@@ -2830,6 +2940,8 @@ void NativeNatThread(THREAD *thread, void *param)
 			NnMainLoop(t, a);
 			Debug("NnMainLoop End.\n");
 
+			t->IsRawIpMode = false;
+
 			t->Active = false;
 			t->PublicIP = 0;
 
@@ -7425,6 +7537,8 @@ void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data,
 		return;
 	}
 
+	//Debug("ICMP: %u\n", size);
+
 	if (NnIsActive(v))
 	{
 		// Process by the Native NAT

+ 8 - 3
src/Cedar/Virtual.h

@@ -115,10 +115,13 @@
 #define	VIRTUAL_H
 
 
+#define	NN_RAW_IP_PORT_START			61001
+#define	NN_RAW_IP_PORT_END				65535
+
 #define	VIRTUAL_TCP_SEND_TIMEOUT		(21 * 1000)
 
-#define	NN_NEXT_WAIT_TIME_FOR_DEVICE_ENUM	(60 * 1000)
-#define	NN_NEXT_WAIT_TIME_MAX_FAIL_COUNT	15
+#define	NN_NEXT_WAIT_TIME_FOR_DEVICE_ENUM	(30 * 1000)
+#define	NN_NEXT_WAIT_TIME_MAX_FAIL_COUNT	30
 
 #define	NN_HOSTNAME_FORMAT				"securenat-%s"
 #define	NN_HOSTNAME_STARTWITH			"securenat-"
@@ -191,6 +194,7 @@ struct NATIVE_NAT
 	LIST *IpCombine;				// IP combining list
 	UINT CurrentIpQuota;			// Current IP combining quota
 	UCHAR CurrentMacAddress[6];		// Current MAC address
+	bool IsRawIpMode;				// Is RAW_IP mode
 };
 
 // ARP entry
@@ -643,7 +647,7 @@ BUF *NnBuildDnsQueryPacket(char *hostname, USHORT tran_id);
 BUF *NnBuildUdpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port);
 BUF *NnBuildTcpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss);
 BUF *NnBuildIpPacket(BUF *payload, UINT src_ip, UINT dst_ip, UCHAR protocol, UCHAR ttl);
-UINT NnGenSrcPort();
+UINT NnGenSrcPort(bool raw_ip_mode);
 bool NnParseDnsResponsePacket(UCHAR *data, UINT size, IP *ret_ip);
 BUF *NnReadDnsRecord(BUF *buf, bool answer, USHORT *ret_type, USHORT *ret_class);
 bool NnReadDnsLabel(BUF *buf);
@@ -656,6 +660,7 @@ UINT GetHashNativeNatTableForRecv(void *p);
 void NnSetNat(NATIVE_NAT_ENTRY *e, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT pub_ip, UINT pub_port);
 
 bool NnIsActive(VH *v);
+bool NnIsActiveEx(VH *v, bool *is_ipraw_mode);
 void NnUdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, UINT max_l3_size);
 void NnTcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *old_tcp, void *data, UINT size, UINT max_l3_size);
 void NnIcmpEchoRecvForInternet(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size);

+ 2 - 2
src/CurrentBuild.txt

@@ -1,4 +1,4 @@
-BUILD_NUMBER 9578
+BUILD_NUMBER 9582
 VERSION 419
 BUILD_NAME beta
-BUILD_DATE 20150915_143935
+BUILD_DATE 20151006_145630

+ 1 - 0
src/Mayaqua/MayaType.h

@@ -423,6 +423,7 @@ typedef struct STRMAP_ENTRY STRMAP_ENTRY;
 typedef struct SHARED_BUFFER SHARED_BUFFER;
 typedef struct HASH_LIST HASH_LIST;
 typedef struct HASH_ENTRY HASH_ENTRY;
+typedef struct PRAND PRAND;
 
 // Str.h
 typedef struct TOKEN_LIST TOKEN_LIST;

+ 135 - 0
src/Mayaqua/Memory.c

@@ -134,6 +134,70 @@
 
 static UINT fifo_current_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
 
+// New PRand
+PRAND *NewPRand(void *key, UINT key_size)
+{
+	PRAND *r;
+	UCHAR dummy[256];
+	if (key == NULL || key_size == 0)
+	{
+		key = "DUMMY";
+		key_size = 5;
+	}
+
+	r = ZeroMalloc(sizeof(PRAND));
+
+	HashSha1(r->Key, key, key_size);
+
+	r->Rc4 = NewCrypt(key, key_size);
+
+	Zero(dummy, sizeof(dummy));
+
+	Encrypt(r->Rc4, dummy, dummy, 256);
+
+	return r;
+}
+
+// Free PRand
+void FreePRand(PRAND *r)
+{
+	if (r == NULL)
+	{
+		return;
+	}
+
+	FreeCrypt(r->Rc4);
+
+	Free(r);
+}
+
+// Generate PRand
+void PRand(PRAND *p, void *data, UINT size)
+{
+	if (p == NULL)
+	{
+		return;
+	}
+
+	Zero(data, size);
+
+	Encrypt(p->Rc4, data, data, size);
+}
+
+// Generate UINT PRand
+UINT PRandInt(PRAND *p)
+{
+	UINT r;
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+	PRand(p, &r, sizeof(UINT));
+
+	return r;
+}
+
 // Check whether the specified key item is in the hash list
 bool IsInHashListKey(HASH_LIST *h, UINT key)
 {
@@ -2368,6 +2432,28 @@ UINT PeekFifo(FIFO *f, void *p, UINT size)
 	return read_size;
 }
 
+// Read all data from FIFO
+BUF *ReadFifoAll(FIFO *f)
+{
+	BUF *buf;
+	UCHAR *tmp;
+	UINT size;
+	if (f == NULL)
+	{
+		return NewBuf();
+	}
+
+	size = FifoSize(f);
+	tmp = Malloc(size);
+	ReadFifo(f, tmp, size);
+
+	buf = MemToBuf(tmp, size);
+
+	Free(tmp);
+
+	return buf;
+}
+
 // Read from the FIFO
 UINT ReadFifo(FIFO *f, void *p, UINT size)
 {
@@ -3128,6 +3214,21 @@ bool WriteBufInt(BUF *b, UINT value)
 	return true;
 }
 
+// Write a short integer in the the buffer
+bool WriteBufShort(BUF *b, USHORT value)
+{
+	// Validate arguments
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	value = Endian16(value);
+
+	WriteBuf(b, &value, sizeof(USHORT));
+	return true;
+}
+
 // Write a UCHAR to the buffer
 bool WriteBufChar(BUF *b, UCHAR uc)
 {
@@ -3194,6 +3295,23 @@ UINT ReadBufInt(BUF *b)
 	return Endian32(value);
 }
 
+// Read a short integer from the buffer
+USHORT ReadBufShort(BUF *b)
+{
+	USHORT value;
+	// Validate arguments
+	if (b == NULL)
+	{
+		return 0;
+	}
+
+	if (ReadBuf(b, &value, sizeof(USHORT)) != sizeof(USHORT))
+	{
+		return 0;
+	}
+	return Endian16(value);
+}
+
 // Write the buffer to a buffer
 void WriteBufBuf(BUF *b, BUF *bb)
 {
@@ -3459,6 +3577,23 @@ BUF *ReadRemainBuf(BUF *b)
 	return ReadBufFromBuf(b, size);
 }
 
+// Get the length of the rest
+UINT ReadBufRemainSize(BUF *b)
+{
+	// Validate arguments
+	if (b == NULL)
+	{
+		return 0;
+	}
+
+	if (b->Size < b->Current)
+	{
+		return 0;
+	}
+
+	return b->Size - b->Current;
+}
+
 // Clone the buffer
 BUF *CloneBuf(BUF *b)
 {

+ 16 - 0
src/Mayaqua/Memory.h

@@ -236,6 +236,13 @@ struct HASH_LIST
 	LIST *AllList;
 };
 
+// PRAND
+struct PRAND
+{
+	UCHAR Key[20];
+	CRYPT *Rc4;
+};
+
 // Function prototype
 HASH_LIST *NewHashList(GET_HASH *get_hash_proc, COMPARE *compare_proc, UINT bits, bool make_list);
 void ReleaseHashList(HASH_LIST *h);
@@ -250,6 +257,11 @@ void UnlockHashList(HASH_LIST *h);
 bool IsInHashListKey(HASH_LIST *h, UINT key);
 void *HashListKeyToPointer(HASH_LIST *h, UINT key);
 
+PRAND *NewPRand(void *key, UINT key_size);
+void FreePRand(PRAND *r);
+void PRand(PRAND *p, void *data, UINT size);
+UINT PRandInt(PRAND *p);
+
 LIST *NewCandidateList();
 void FreeCandidateList(LIST *o);
 int ComapreCandidate(void *p1, void *p2);
@@ -310,11 +322,13 @@ void FreeBuf(BUF *b);
 bool BufToFile(IO *o, BUF *b);
 BUF *FileToBuf(IO *o);
 UINT ReadBufInt(BUF *b);
+USHORT ReadBufShort(BUF *b);
 UINT64 ReadBufInt64(BUF *b);
 UCHAR ReadBufChar(BUF *b);
 bool WriteBufInt(BUF *b, UINT value);
 bool WriteBufInt64(BUF *b, UINT64 value);
 bool WriteBufChar(BUF *b, UCHAR uc);
+bool WriteBufShort(BUF *b, USHORT value);
 bool ReadBufStr(BUF *b, char *str, UINT size);
 bool WriteBufStr(BUF *b, char *str);
 void WriteBufLine(BUF *b, char *str);
@@ -332,10 +346,12 @@ BUF *CloneBuf(BUF *b);
 BUF *MemToBuf(void *data, UINT size);
 BUF *RandBuf(UINT size);
 BUF *ReadRemainBuf(BUF *b);
+UINT ReadBufRemainSize(BUF *b);
 bool CompareBuf(BUF *b1, BUF *b2);
 
 UINT PeekFifo(FIFO *f, void *p, UINT size);
 UINT ReadFifo(FIFO *f, void *p, UINT size);
+BUF *ReadFifoAll(FIFO *f);
 void ShrinkFifoMemory(FIFO *f);
 UCHAR *GetFifoPointer(FIFO *f);
 UCHAR *FifoPtr(FIFO *f);

+ 63 - 0
src/Mayaqua/Network.c

@@ -5842,6 +5842,11 @@ SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh)
 			SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_DH_USE);
 		}
 
+		if (server_mode == false)
+		{
+			SSL_CTX_set_options(ssl_ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+		}
+
 		ssl = SSL_new(ssl_ctx);
 	}
 	Unlock(openssl_lock);
@@ -8907,10 +8912,36 @@ void UnixSelect(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2)
 	if (c1 != NULL)
 	{
 		reads[num_read++] = p1 = c1->pipe_read;
+
+		if (c1->SpecialFlag)
+		{
+			if (c1->pipe_special_read2 != -1 && c1->pipe_special_read2 != 0)
+			{
+				reads[num_read++] = c1->pipe_special_read2;
+			}
+
+			if (c1->pipe_special_read3 != -1 && c1->pipe_special_read3 != 0)
+			{
+				reads[num_read++] = c1->pipe_special_read3;
+			}
+		}
 	}
 	if (c2 != NULL)
 	{
 		reads[num_read++] = p2 = c2->pipe_read;
+
+		if (c2->SpecialFlag)
+		{
+			if (c2->pipe_special_read2 != -1 && c2->pipe_special_read2 != 0)
+			{
+				reads[num_read++] = c2->pipe_special_read2;
+			}
+
+			if (c2->pipe_special_read3 != -1 && c2->pipe_special_read3 != 0)
+			{
+				reads[num_read++] = c2->pipe_special_read3;
+			}
+		}
 	}
 
 	// Call the select
@@ -8991,6 +9022,8 @@ CANCEL *UnixNewCancel()
 
 	UnixNewPipe(&c->pipe_read, &c->pipe_write);
 
+	c->pipe_special_read2 = c->pipe_special_read3 = -1;
+
 	return c;
 }
 
@@ -12307,6 +12340,36 @@ SOCK *NewUDPEx2RandMachineAndExePath(bool ipv6, IP *ip, UINT num_retry, UCHAR ra
 	return NewUDPEx2Rand(ipv6, ip, hash, sizeof(hash), num_retry);
 }
 
+// Set the DF bit of the socket
+void ClearSockDfBit(SOCK *s)
+{
+#ifdef	IP_PMTUDISC_DONT
+#ifdef	IP_MTU_DISCOVER
+	UINT value = IP_PMTUDISC_DONT;
+	if (s == NULL)
+	{
+		return;
+	}
+
+	setsockopt(s->socket, IPPROTO_IP, IP_MTU_DISCOVER, (char *)&value, sizeof(value));
+#endif	// IP_MTU_DISCOVER
+#endif	// IP_PMTUDISC_DONT
+}
+
+// Set the header-include option
+void SetRawSockHeaderIncludeOption(SOCK *s, bool enable)
+{
+	UINT value = BOOL_TO_INT(enable);
+	if (s == NULL || s->IsRawSocket == false)
+	{
+		return;
+	}
+
+	setsockopt(s->socket, IPPROTO_IP, IP_HDRINCL, (char *)&value, sizeof(value));
+
+	s->RawIP_HeaderIncludeFlag = enable;
+}
+
 // Create and initialize the UDP socket
 // If port is specified as 0, system assigns a certain port.
 SOCK *NewUDP(UINT port)

+ 4 - 0
src/Mayaqua/Network.h

@@ -313,6 +313,7 @@ struct SOCK
 	UINT Reverse_MyServerPort;		// Self port number when using the reverse socket
 	UCHAR Ssl_Init_Async_SendAlert[2];	// Initial state of SSL send_alert
 	bool AcceptOnlyTls;			// Accept only TLS (disable SSLv3)
+	bool RawIP_HeaderIncludeFlag;
 
 #ifdef	ENABLE_SSL_LOGGING
 	// SSL Logging (for debug)
@@ -371,6 +372,7 @@ struct CANCEL
 	void *hEvent;					// Pointer to a Win32 event handle
 #else	// OS_WIN32
 	int pipe_read, pipe_write;		// Pipe
+	int pipe_special_read2, pipe_special_read3;
 #endif	// OS_WIN32
 };
 
@@ -1323,6 +1325,8 @@ SOCK *NewUDP4(UINT port, IP *ip);
 SOCK *NewUDP6(UINT port, IP *ip);
 SOCK *NewUDPEx2Rand(bool ipv6, IP *ip, void *rand_seed, UINT rand_seed_size, UINT num_retry);
 SOCK *NewUDPEx2RandMachineAndExePath(bool ipv6, IP *ip, UINT num_retry, UCHAR rand_port_id);
+void ClearSockDfBit(SOCK *s);
+void SetRawSockHeaderIncludeOption(SOCK *s, bool enable);
 UINT GetNewAvailableUdpPortRand();
 UINT NewRandPortByMachineAndExePath(UINT start_port, UINT end_port, UINT additional_int);
 void DisableUDPChecksum(SOCK *s);

+ 1 - 0
src/Mayaqua/TcpIp.c

@@ -2874,6 +2874,7 @@ bool ParsePacketIPv4(PKT *p, UCHAR *buf, UINT size)
 	{
 		// Quit analysing since this is fragmented
 		p->TypeL4 = L4_FRAGMENT;
+
 		return true;
 	}
 

+ 3 - 2
src/Mayaqua/Tick64.c

@@ -158,13 +158,14 @@ UINT64 Tick64ToTime64(UINT64 tick)
 	}
 	LockList(tk64->AdjustTime);
 	{
-		UINT i;
-		for (i = 0;i < LIST_NUM(tk64->AdjustTime);i++)
+		INT i;
+		for (i = ((INT)LIST_NUM(tk64->AdjustTime) - 1); i >= 0; i--)
 		{
 			ADJUST_TIME *t = LIST_DATA(tk64->AdjustTime, i);
 			if (t->Tick <= tick)
 			{
 				ret = t->Time + (tick - t->Tick);
+				break;
 			}
 		}
 	}

+ 1 - 1
src/Mayaqua/Tick64.h

@@ -115,7 +115,7 @@
 #define	TICK64_H
 
 // Maximum number of correction list entries
-#define	MAX_ADJUST_TIME				5000
+#define	MAX_ADJUST_TIME				1024
 
 // Correction list entry
 struct ADJUST_TIME

二进制
src/bin/hamcore/SeLow_x64.sys


二进制
src/bin/hamcore/SeLow_x86.sys


二进制
src/bin/hamcore/pxwfp_x64.sys


二进制
src/bin/hamcore/pxwfp_x86.sys


二进制
src/bin/hamcore/see.sys


二进制
src/bin/hamcore/see_x64.sys


+ 2 - 0
src/bin/hamcore/strtable_cn.stb

@@ -559,6 +559,7 @@ HUB_AO_DropArpInPrivacyFilterMode			Drop ARP packets if the both source and dest
 HUB_AO_SuppressClientUpdateNotification		Suppress the update notification screen on the VPN Client.
 HUB_AO_FloodingSendQueueBufferQuota			Specify the quota limitation value (in bytes) of the sending queue buffer size which the flooding operation on the Virtual Hub can consume. The quota value is applied on the total length of sending queues of all active VPN sessions. Specify '0' to disable the quota. This option is effective to solve the out-of-memory problem on the network where there are many flooding packets.
 HUB_AO_AssignVLanIdByRadiusAttribute		Enable the VLAN ID dynamic assignment function. Each VPN session will be assigned its own VLAN ID by the RADIUS attribute value when the user is authenticated by the external RADIUS server unless the user object has a VLAN ID security policy. The RADIUS attribute with the name "Tunnel-Pvt-Group-ID" (ID = 81) will be used as the VLAN ID. The data type must be STRING.
+HUB_AO_DenyAllRadiusLoginWithNoVlanAssign	If you set this option to non-zero value, then all users, which RADIUS server returns no "Tunnel-Pvt-Group-ID" (ID = 81) value, will be denied to connect to the Virtual Hub. (Only if the values of AssignVLanIdByRadiusAttribute is non-zero value.)
 HUB_AO_SecureNAT_RandomizeAssignIp			If you set this option to non-zero value, then the Virtual DHCP Server of the SecureNAT function will choose an unused IP address randomly from the DHCP pool while the default behavior is to choose the first unused IP address.
 HUB_AO_DetectDormantSessionInterval			If you set this option to non-zero value, then the Virtual Hub will treat the VPN sessions, which have transmitted no packets for the last specified intervals (in seconds), as Dormant Sessions. The Virtual Hub will not flood packets, which should be flood, to any Dormant Sessions.
 HUB_AO_NoPhysicalIPOnPacketLog				If you set this option to non-zero value, then the physical IP addresses of VPN clients of either the source VPN session or the destination VPN session will not be recorded on the packet log file.
@@ -1498,6 +1499,7 @@ SM_SNAT_STATUS				SecureNAT 运行状态
 SM_SNAT_NUM_SESSION			%u 个会话
 SM_SNAT_NUM_CLIENT			%u 个客户端
 SM_SNAT_IS_KERNEL			内核模式 NAT 功能是活跃的
+SM_SNAT_IS_RAW				Raw IP mode NAT 功能是活跃的
 SM_BRIDGE_TOO_OLD_VER		当前连接的 VPN Server 版本不支持本地网桥功能。\r\n请更新到最新版本。
 SM_BRIDGE_UNSUPPORTED		当前连接的 VPN Server 运行的操作系统无法使用本地网桥功能。请参阅 VPN Server 在线文档以获得支持本地网桥功能的操作系统列表。
 SM_BRIDGE_WPCAP_REMOTE		为在此 VPN Server 上使用本地网桥功能,您必须安装 WinPcap 软件。WinPcap 软件当前没有在服务器上安装。\r\n\r\n要进行 WinPcap 软件的安装,您必须在运行 VPN Server 的服务器上启动 SoftEther VPN Server 管理器,然后连接到本机 (您自己计算机的位置),打开本地网桥功能设置窗口。\r\n首先退出此管理会话,然后在此服务器上启动 SoftEther VPN Server 管理器之后,连接到本机并继续设置进程。

+ 2 - 0
src/bin/hamcore/strtable_en.stb

@@ -553,6 +553,7 @@ HUB_AO_DropArpInPrivacyFilterMode			Drop ARP packets if the both source and dest
 HUB_AO_SuppressClientUpdateNotification		Suppress the update notification screen on the VPN Client.
 HUB_AO_FloodingSendQueueBufferQuota			Specify the quota limitation value (in bytes) of the sending queue buffer size which the flooding operation on the Virtual Hub can consume. The quota value is applied on the total length of sending queues of all active VPN sessions. Specify '0' to disable the quota. This option is effective to solve the out-of-memory problem on the network where there are many flooding packets.
 HUB_AO_AssignVLanIdByRadiusAttribute		Enable the VLAN ID dynamic assignment function. Each VPN session will be assigned its own VLAN ID by the RADIUS attribute value when the user is authenticated by the external RADIUS server unless the user object has a VLAN ID security policy. The RADIUS attribute with the name "Tunnel-Pvt-Group-ID" (ID = 81) will be used as the VLAN ID. The data type must be STRING.
+HUB_AO_DenyAllRadiusLoginWithNoVlanAssign	If you set this option to non-zero value, then all users, which RADIUS server returns no "Tunnel-Pvt-Group-ID" (ID = 81) value, will be denied to connect to the Virtual Hub. (Only if the values of AssignVLanIdByRadiusAttribute is non-zero value.)
 HUB_AO_SecureNAT_RandomizeAssignIp			If you set this option to non-zero value, then the Virtual DHCP Server of the SecureNAT function will choose an unused IP address randomly from the DHCP pool while the default behavior is to choose the first unused IP address.
 HUB_AO_DetectDormantSessionInterval			If you set this option to non-zero value, then the Virtual Hub will treat the VPN sessions, which have transmitted no packets for the last specified intervals (in seconds), as Dormant Sessions. The Virtual Hub will not flood packets, which should be flood, to any Dormant Sessions.
 HUB_AO_NoPhysicalIPOnPacketLog				If you set this option to non-zero value, then the physical IP addresses of VPN clients of either the source VPN session or the destination VPN session will not be recorded on the packet log file.
@@ -1488,6 +1489,7 @@ SM_SNAT_STATUS			SecureNAT Operating Status
 SM_SNAT_NUM_SESSION		%u Session
 SM_SNAT_NUM_CLIENT		%u Client
 SM_SNAT_IS_KERNEL		Kernel-mode NAT is Active
+SM_SNAT_IS_RAW			Raw IP mode NAT is Active
 SM_BRIDGE_TOO_OLD_VER	The Local Bridge function is not supported by the version of the VPN Server that is currently connected. \r\nTry update to a new version.
 SM_BRIDGE_UNSUPPORTED	Unable to use the Local Bridge function with the operating system that this VPN Server is operating on. For the list of operating system that the Local Bridge function can be used on, refer to the online documentation of the VPN Server.
 SM_BRIDGE_WPCAP_REMOTE	In order to use the Local Bridge function on this VPN Server, you must install the WinPcap software. The software WinPcap is currently not installed on the server computer. \r\n\r\nTo continue the installation of the WinPcap software, you must start SoftEther VPN Server Manager on the server computer that is running VPN Server and then while connected to localhost (location of your own computer), have the Local Bridge Function Setting window displayed. \r\nTo continue, first exit this management session, and then, after starting SoftEther VPN Server Manager on the server computer, connect to localhost and continue the setting process. 

+ 2 - 0
src/bin/hamcore/strtable_ja.stb

@@ -574,6 +574,7 @@ HUB_AO_DropArpInPrivacyFilterMode			送信元および宛先の両方のセッ
 HUB_AO_SuppressClientUpdateNotification		VPN Client のアップデート通知画面の表示を抑制します。
 HUB_AO_FloodingSendQueueBufferQuota			パケットの仮想 HUB 内におけるフラッディング動作時において消費することを許容する送信キューのバッファサイズの制限値 (バイト数) を指定します。クオータは、すべての接続中の VPN セッションの送信キューの合計長さに対してグローバルに適用されます。0 を指定すると無制限になります。このオプションは、フラッディングパケットが多発するネットワークにおいてメモリ消費量が増大する問題を解決するために利用できます。
 HUB_AO_AssignVLanIdByRadiusAttribute		VLAN ID の動的割り当て機能を有効にします。VPN 接続するユーザーオブジェクトのセキュリティポリシーに VLAN ID が指定されていない場合は、各 VPN セッションはユーザー認証を行った RADIUS サーバーから返却される RADIUS 属性の値に基づき VLAN が割当てられます。RADIUS 属性のうち、 "Tunnel-Pvt-Group-ID" (ID = 81) の値が使用されます。データ型は文字列である必要があります。
+HUB_AO_DenyAllRadiusLoginWithNoVlanAssign	この項目が 1 (有効) の場合は、RADIUS サーバーが "Tunnel-Pvt-Group-ID" (ID = 81) の値を返却しなかった場合は VPN 接続が拒否されます。(AssignVLanIdByRadiusAttribute の値が 1 の場合に限ります。)
 HUB_AO_SecureNAT_RandomizeAssignIp			この項目が 1 (有効) の場合は、SecureNAT 機能における仮想 DHCP サーバーは、DHCP クライアントに対して割当てる IP アドレスを指定された IP アドレスプール内の未使用アドレスからランダムに選択するようになります。なお、既定の動作は、未使用アドレスのうち最初のアドレスを割当てるようになっています。
 HUB_AO_DetectDormantSessionInterval			この項目が 0 以外の場合は、指定された秒数無通信であった VPN セッションをドーマント状態 (休止状態) として識別します。ドーマント状態の VPN セッションに対しては、仮想 HUB 内でフラッディングされるべきパケットがフラッディングされなくなります。
 HUB_AO_NoPhysicalIPOnPacketLog				この項目が 0 (有効) の場合は、パケットログに送信元および宛先 VPN セッションの物理的な接続元 VPN クライアントの IP アドレスが記録されないようになります。
@@ -1492,6 +1493,7 @@ SM_SNAT_STATUS			SecureNAT の動作状況
 SM_SNAT_NUM_SESSION		%u セッション
 SM_SNAT_NUM_CLIENT		%u クライアント
 SM_SNAT_IS_KERNEL		カーネルモード NAT で動作中
+SM_SNAT_IS_RAW			Raw IP モード NAT で動作中
 SM_BRIDGE_TOO_OLD_VER	現在接続している VPN Server のバージョンでは、ローカルブリッジ機能はサポートされていません。\r\n新しいバージョンにアップデートしてみてください。
 SM_BRIDGE_UNSUPPORTED	この VPN Server が動作しているオペレーティングシステム上では、ローカルブリッジ機能を使用することはできません。ローカルブリッジ機能が使用できるオペレーティングシステムの一覧については、VPN Server のオンラインドキュメントを参照してください。
 SM_BRIDGE_WPCAP_REMOTE	この VPN Server 上でローカルブリッジ機能を使用するためには、WinPcap ソフトウェアをインストールする必要があります。現在、サーバー コンピュータ上には WinPcap ソフトウェアがインストールされていません。\r\n\r\nWinPcap ソフトウェアのインストールを続行するためには、VPN Server が動作しているサーバー コンピュータ上で SoftEther VPN サーバー管理マネージャを起動し、localhost (自分自身) に対して接続した状態で、ローカルブリッジ機能設定画面を表示する必要があります。\r\n続行するには、一旦この管理セッションを終了し、サーバー コンピュータ上で SoftEther VPN サーバー管理マネージャを起動してから、localhost に対して接続して、設定を続行してください。

二进制
src/bin/hamcore/vpn_driver.sys


二进制
src/bin/hamcore/vpn_driver6.sys


二进制
src/bin/hamcore/vpn_driver6_x64.sys


二进制
src/bin/hamcore/vpn_driver_x64.sys


二进制
src/bin/vpnweb.cab


二进制
src/bin/vpnweb.ocx


+ 1 - 1
src/vpnweb/vpnweb.h

@@ -4,7 +4,7 @@
 
 
  /* File created by MIDL compiler version 7.00.0500 */
-/* at Tue Sep 15 14:39:53 2015
+/* at Tue Oct 06 14:56:43 2015
  */
 /* Compiler settings for .\vpnweb.idl:
     Oicf, W1, Zp8, env=Win32 (32b run)

+ 1 - 1
src/vpnweb/vpnweb_i.c

@@ -6,7 +6,7 @@
 
 
  /* File created by MIDL compiler version 7.00.0500 */
-/* at Tue Sep 15 14:39:53 2015
+/* at Tue Oct 06 14:56:43 2015
  */
 /* Compiler settings for .\vpnweb.idl:
     Oicf, W1, Zp8, env=Win32 (32b run)

+ 1 - 1
src/vpnweb/vpnweb_p.c

@@ -4,7 +4,7 @@
 
 
  /* File created by MIDL compiler version 7.00.0500 */
-/* at Tue Sep 15 14:39:53 2015
+/* at Tue Oct 06 14:56:43 2015
  */
 /* Compiler settings for .\vpnweb.idl:
     Oicf, W1, Zp8, env=Win32 (32b run)

部分文件因为文件数量过多而无法显示