Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/SoftEtherVPN/SoftEtherVPN_Stable.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordnobori <da.git@softether.co.jp>2015-10-06 14:18:00 +0300
committerdnobori <da.git@softether.co.jp>2015-10-06 14:18:00 +0300
commit4e862a7e40c095ac6ac8b1417890008fbd614ebb (patch)
tree06964105f04db7de0bac733a6c492a34ba24ce74 /src
parent3c8abd60ed71d09dc09953712c8d5a807932efb9 (diff)
v4.19-9582-beta
Diffstat (limited to 'src')
-rw-r--r--src/Cedar/Bridge.c10
-rw-r--r--src/Cedar/Bridge.h4
-rw-r--r--src/Cedar/BridgeUnix.c794
-rw-r--r--src/Cedar/BridgeUnix.h24
-rw-r--r--src/Cedar/BridgeWin32.c11
-rw-r--r--src/Cedar/BridgeWin32.h8
-rw-r--r--src/Cedar/Cedar.c28
-rw-r--r--src/Cedar/Cedar.h13
-rw-r--r--src/Cedar/CedarType.h12
-rw-r--r--src/Cedar/Command.c1
-rw-r--r--src/Cedar/Hub.c101
-rw-r--r--src/Cedar/Hub.h5
-rw-r--r--src/Cedar/IPsec_EtherIP.c2
-rw-r--r--src/Cedar/IPsec_IKE.c16
-rw-r--r--src/Cedar/IPsec_IPC.c26
-rw-r--r--src/Cedar/IPsec_IPC.h3
-rw-r--r--src/Cedar/IPsec_L2TP.c230
-rw-r--r--src/Cedar/IPsec_L2TP.h6
-rw-r--r--src/Cedar/IPsec_PPP.c142
-rw-r--r--src/Cedar/IPsec_PPP.h7
-rw-r--r--src/Cedar/NM.c1
-rw-r--r--src/Cedar/Nat.c4
-rw-r--r--src/Cedar/Nat.h1
-rw-r--r--src/Cedar/NativeStack.c570
-rw-r--r--src/Cedar/NativeStack.h46
-rw-r--r--src/Cedar/Protocol.c35
-rw-r--r--src/Cedar/Radius.c1621
-rw-r--r--src/Cedar/Radius.h247
-rw-r--r--src/Cedar/Sam.c8
-rw-r--r--src/Cedar/Server.c14
-rw-r--r--src/Cedar/Virtual.c146
-rw-r--r--src/Cedar/Virtual.h11
-rw-r--r--src/CurrentBuild.txt4
-rw-r--r--src/Mayaqua/MayaType.h1
-rw-r--r--src/Mayaqua/Memory.c135
-rw-r--r--src/Mayaqua/Memory.h16
-rw-r--r--src/Mayaqua/Network.c63
-rw-r--r--src/Mayaqua/Network.h4
-rw-r--r--src/Mayaqua/TcpIp.c1
-rw-r--r--src/Mayaqua/Tick64.c5
-rw-r--r--src/Mayaqua/Tick64.h2
-rw-r--r--src/bin/hamcore/SeLow_x64.sysbin48896 -> 0 bytes
-rw-r--r--src/bin/hamcore/SeLow_x86.sysbin41856 -> 0 bytes
-rw-r--r--src/bin/hamcore/pxwfp_x64.sysbin33024 -> 0 bytes
-rw-r--r--src/bin/hamcore/pxwfp_x86.sysbin28800 -> 0 bytes
-rw-r--r--src/bin/hamcore/see.sysbin53888 -> 0 bytes
-rw-r--r--src/bin/hamcore/see_x64.sysbin49024 -> 0 bytes
-rw-r--r--src/bin/hamcore/strtable_cn.stb2
-rw-r--r--src/bin/hamcore/strtable_en.stb2
-rw-r--r--src/bin/hamcore/strtable_ja.stb2
-rw-r--r--src/bin/hamcore/vpn_driver.sysbin36608 -> 0 bytes
-rw-r--r--src/bin/hamcore/vpn_driver6.sysbin38144 -> 0 bytes
-rw-r--r--src/bin/hamcore/vpn_driver6_x64.sysbin40704 -> 0 bytes
-rw-r--r--src/bin/hamcore/vpn_driver_x64.sysbin40448 -> 0 bytes
-rw-r--r--src/bin/vpnweb.cabbin208945 -> 208941 bytes
-rw-r--r--src/bin/vpnweb.ocxbin342248 -> 342248 bytes
-rw-r--r--src/vpnweb/vpnweb.h2
-rw-r--r--src/vpnweb/vpnweb_i.c2
-rw-r--r--src/vpnweb/vpnweb_p.c2
59 files changed, 4281 insertions, 109 deletions
diff --git a/src/Cedar/Bridge.c b/src/Cedar/Bridge.c
index b9e3a6b2..48289a67 100644
--- a/src/Cedar/Bridge.c
+++ b/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.
diff --git a/src/Cedar/Bridge.h b/src/Cedar/Bridge.h
index 20c5f159..31303979 100644
--- a/src/Cedar/Bridge.h
+++ b/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
diff --git a/src/Cedar/BridgeUnix.c b/src/Cedar/BridgeUnix.c
index 77eb0087..6ef16e58 100644
--- a/src/Cedar/BridgeUnix.c
+++ b/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;
@@ -543,10 +553,14 @@ 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
diff --git a/src/Cedar/BridgeUnix.h b/src/Cedar/BridgeUnix.h
index 917d620c..5460a2b3 100644
--- a/src/Cedar/BridgeUnix.h
+++ b/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);
diff --git a/src/Cedar/BridgeWin32.c b/src/Cedar/BridgeWin32.c
index c9afa6b7..4b4ab43a 100644
--- a/src/Cedar/BridgeWin32.c
+++ b/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);
diff --git a/src/Cedar/BridgeWin32.h b/src/Cedar/BridgeWin32.h
index f39829be..e6344ced 100644
--- a/src/Cedar/BridgeWin32.h
+++ b/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);
diff --git a/src/Cedar/Cedar.c b/src/Cedar/Cedar.c
index 73fcf085..49841778 100644
--- a/src/Cedar/Cedar.c
+++ b/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()
{
diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h
index bda14d47..311f9a38 100644
--- a/src/Cedar/Cedar.h
+++ b/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);
diff --git a/src/Cedar/CedarType.h b/src/Cedar/CedarType.h
index c918e6d6..1f3579a5 100644
--- a/src/Cedar/CedarType.h
+++ b/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;
// ==============================================================
diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c
index f51467b2..cc79f51b 100644
--- a/src/Cedar/Command.c
+++ b/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);
}
diff --git a/src/Cedar/Hub.c b/src/Cedar/Hub.c
index 4efe2915..97d88611 100644
--- a/src/Cedar/Hub.c
+++ b/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));
diff --git a/src/Cedar/Hub.h b/src/Cedar/Hub.h
index 86a719ed..385c2758 100644
--- a/src/Cedar/Hub.h
+++ b/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
diff --git a/src/Cedar/IPsec_EtherIP.c b/src/Cedar/IPsec_EtherIP.c
index b3124a4d..6551e8ab 100644
--- a/src/Cedar/IPsec_EtherIP.c
+++ b/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)
{
diff --git a/src/Cedar/IPsec_IKE.c b/src/Cedar/IPsec_IKE.c
index ca8168aa..3999709a 100644
--- a/src/Cedar/IPsec_IKE.c
+++ b/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;
diff --git a/src/Cedar/IPsec_IPC.c b/src/Cedar/IPsec_IPC.c
index 84b1c22c..108e7b6c 100644
--- a/src/Cedar/IPsec_IPC.c
+++ b/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));
diff --git a/src/Cedar/IPsec_IPC.h b/src/Cedar/IPsec_IPC.h
index 701456e7..ef040958 100644
--- a/src/Cedar/IPsec_IPC.h
+++ b/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);
diff --git a/src/Cedar/IPsec_L2TP.c b/src/Cedar/IPsec_L2TP.c
index 84cb7baf..ba5eb9b6 100644
--- a/src/Cedar/IPsec_L2TP.c
+++ b/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);
diff --git a/src/Cedar/IPsec_L2TP.h b/src/Cedar/IPsec_L2TP.h
index eaf220c7..2ee94656 100644
--- a/src/Cedar/IPsec_L2TP.h
+++ b/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);
diff --git a/src/Cedar/IPsec_PPP.c b/src/Cedar/IPsec_PPP.c
index b08f6093..aff359c4 100644
--- a/src/Cedar/IPsec_PPP.c
+++ b/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)
{
diff --git a/src/Cedar/IPsec_PPP.h b/src/Cedar/IPsec_PPP.h
index bbd4f1e2..7c60aa93 100644
--- a/src/Cedar/IPsec_PPP.h
+++ b/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
diff --git a/src/Cedar/NM.c b/src/Cedar/NM.c
index 79060903..b092ca66 100644
--- a/src/Cedar/NM.c
+++ b/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);
diff --git a/src/Cedar/Nat.c b/src/Cedar/Nat.c
index 9fd0229f..ed5f219f 100644
--- a/src/Cedar/Nat.c
+++ b/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)
{
diff --git a/src/Cedar/Nat.h b/src/Cedar/Nat.h
index 8ecc09ef..24b8169e 100644
--- a/src/Cedar/Nat.h
+++ b/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 *
diff --git a/src/Cedar/NativeStack.c b/src/Cedar/NativeStack.c
index 180f62d8..59361251 100644
--- a/src/Cedar/NativeStack.c
+++ b/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.
diff --git a/src/Cedar/NativeStack.h b/src/Cedar/NativeStack.h
index cfc69af5..8fd21488 100644
--- a/src/Cedar/NativeStack.h
+++ b/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
diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c
index 1d7045fc..08f531bf 100644
--- a/src/Cedar/Protocol.c
+++ b/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;
}
diff --git a/src/Cedar/Radius.c b/src/Cedar/Radius.c
index 7b454368..bff039d0 100644
--- a/src/Cedar/Radius.c
+++ b/src/Cedar/Radius.c
@@ -113,6 +113,1594 @@
#include "CedarPch.h"
+////////// Modern implementation
+
+
+// send PEAP-MSCHAPv2 auth client response
+bool PeapClientSendMsChapv2AuthClientResponse(EAP_CLIENT *e, UCHAR *client_response, UCHAR *client_challenge)
+{
+ bool ret = false;
+ EAP_MSCHAPV2_RESPONSE msg1;
+ EAP_MESSAGE msg2;
+ EAP_MESSAGE msg4;
+ if (e == NULL || client_response == NULL || client_challenge == NULL)
+ {
+ return false;
+ }
+
+ Zero(&msg1, sizeof(msg1));
+ Zero(&msg2, sizeof(msg2));
+ Zero(&msg4, sizeof(msg4));
+
+ msg1.Type = EAP_TYPE_MS_AUTH;
+ msg1.Chap_Opcode = EAP_MSCHAPV2_OP_RESPONSE;
+ msg1.Chap_Id = e->MsChapV2Challenge.Chap_Id;
+ msg1.Chap_Len = Endian16(54 + StrLen(e->Username));
+ msg1.Chap_ValueSize = 49;
+ Copy(msg1.Chap_PeerChallange, client_challenge, 16);
+ Copy(msg1.Chap_NtResponse, client_response, 24);
+ Copy(msg1.Chap_Name, e->Username, MIN(StrLen(e->Username), 255));
+
+ if (SendPeapPacket(e, &msg1, 59 + StrLen(e->Username)) &&
+ GetRecvPeapMessage(e, &msg2))
+ {
+ if (msg2.Type == EAP_TYPE_MS_AUTH &&
+ ((EAP_MSCHAPV2_GENERAL *)&msg2)->Chap_Opcode == EAP_MSCHAPV2_OP_SUCCESS)
+ {
+ EAP_MSCHAPV2_SUCCESS_SERVER *eaps = (EAP_MSCHAPV2_SUCCESS_SERVER *)&msg2;
+
+ if (StartWith(eaps->Message, "S="))
+ {
+ BUF *buf = StrToBin(eaps->Message + 2);
+
+ if (buf && buf->Size == 20)
+ {
+ Copy(&e->MsChapV2Success, eaps, sizeof(EAP_MSCHAPV2_SUCCESS_SERVER));
+ Copy(e->ServerResponse, buf->Buf, 20);
+
+ if (true)
+ {
+ EAP_MSCHAPV2_SUCCESS_CLIENT msg3;
+
+ Zero(&msg3, sizeof(msg3));
+ msg3.Type = EAP_TYPE_MS_AUTH;
+ msg3.Chap_Opcode = EAP_MSCHAPV2_OP_SUCCESS;
+
+ if (SendPeapPacket(e, &msg3, 6) && GetRecvPeapMessage(e, &msg4))
+ {
+ UCHAR *rd = ((UCHAR *)&msg4);
+ if (rd[4] == 0x01 && rd[8] == 0x21 && rd[9] == 0x80 &&
+ rd[10] == 0x03 && rd[11] == 0x00 && rd[12] == 0x02 &&
+ rd[13] == 0x00 && rd[14] == 0x01)
+ {
+ UCHAR reply[15];
+ Zero(reply, sizeof(reply));
+ reply[4] = 0x02; reply[5] = rd[5]; reply[6] = 0x00; reply[7] = 0x0b;
+ reply[8] = 0x21; reply[9] = 0x80; reply[10] = 0x03; reply[11] = 0x00;
+ reply[12] = 0x02; reply[13] = 0x00; reply[14] = 0x01;
+ if (SendPeapPacket(e, reply, sizeof(reply)))
+ {
+ if (e->RecvLastCode == RADIUS_CODE_ACCESS_ACCEPT)
+ {
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(buf);
+ }
+ }
+ }
+
+ return ret;
+}
+
+// send PEAP-MSCHAPv2 auth request
+bool PeapClientSendMsChapv2AuthRequest(EAP_CLIENT *eap)
+{
+ bool ret = false;
+ UINT num_retry = 0;
+ if (eap == NULL)
+ {
+ return false;
+ }
+
+ if (StartPeapClient(eap))
+ {
+ if (StartPeapSslClient(eap))
+ {
+ EAP_MESSAGE recv_msg;
+ EAP_MESSAGE send_msg;
+
+ if (GetRecvPeapMessage(eap, &recv_msg) && recv_msg.Type == EAP_TYPE_IDENTITY)
+ {
+LABEL_RETRY:
+ num_retry++;
+ if (num_retry >= 10)
+ {
+ return false;
+ }
+ Zero(&send_msg, sizeof(send_msg));
+ send_msg.Type = EAP_TYPE_IDENTITY;
+ send_msg.Len = Endian16(5 + StrLen(eap->Username));
+ Copy(send_msg.Data, eap->Username, StrLen(eap->Username));
+
+ if (SendPeapPacket(eap, &send_msg, 5 + StrLen(eap->Username)) &&
+ GetRecvPeapMessage(eap, &recv_msg))
+ {
+LABEL_RETRY2:
+ num_retry++;
+ if (num_retry >= 10)
+ {
+ return false;
+ }
+ if (recv_msg.Type == EAP_TYPE_MS_AUTH &&
+ ((EAP_MSCHAPV2_GENERAL *)&recv_msg)->Chap_Opcode == EAP_MSCHAPV2_OP_CHALLENGE)
+ {
+ EAP_MSCHAPV2_CHALLENGE *svr_challenge = (EAP_MSCHAPV2_CHALLENGE *)&recv_msg;
+
+ Copy(&eap->MsChapV2Challenge, svr_challenge, sizeof(EAP_MSCHAPV2_CHALLENGE));
+
+ ret = true;
+
+ eap->PeapMode = true;
+ }
+ else if (recv_msg.Type == EAP_TYPE_IDENTITY)
+ {
+ UCHAR *rd = ((UCHAR *)&recv_msg);
+ if (rd[4] == 0x01 && rd[8] == 0x21 && rd[9] == 0x80 &&
+ rd[10] == 0x03 && rd[11] == 0x00 && rd[12] == 0x02 &&
+ rd[13] == 0x00)
+ {
+ if (rd[14] == 0x02)
+ {
+ // Fail
+ return false;
+ }
+ }
+
+ goto LABEL_RETRY;
+ }
+ else
+ {
+ EAP_MESSAGE nak;
+
+ Zero(&nak, sizeof(nak));
+ nak.Type = EAP_TYPE_LEGACY_NAK;
+ nak.Data[0] = EAP_TYPE_MS_AUTH;
+
+ if (SendPeapPacket(eap, &nak, 6) &&
+ GetRecvPeapMessage(eap, &recv_msg))
+ {
+ goto LABEL_RETRY2;
+ }
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+// Send a PEAP packet (encrypted)
+bool SendPeapRawPacket(EAP_CLIENT *e, UCHAR *peap_data, UINT peap_size)
+{
+ LIST *fragments = NULL;
+ bool ret = false;
+ BUF *buf = NULL;
+ UINT i;
+ UINT num;
+ bool send_empty = false;
+ bool include_len = false;
+ if (e == NULL)
+ {
+ return false;
+ }
+
+ // divide into 1024 bytes
+ buf = NewBuf();
+
+ // size
+ if ((peap_size + 6 + 2) >= 256)
+ {
+ WriteBufInt(buf, peap_size);
+ include_len = true;
+ }
+
+ // data
+ WriteBuf(buf, peap_data, peap_size);
+
+ if (peap_data == NULL)
+ {
+ send_empty = true;
+ }
+
+ SeekBufToBegin(buf);
+
+ fragments = NewListFast(NULL);
+ for (num = 0;;num++)
+ {
+ UCHAR tmp[1024];
+ EAP_PEAP *send_peap_message;
+ UINT sz;
+
+ sz = ReadBuf(buf, tmp, 1024);
+
+ if (sz == 0)
+ {
+ break;
+ }
+
+ // add header
+ send_peap_message = ZeroMalloc(sizeof(EAP_PEAP) + sz);
+ send_peap_message->Code = EAP_CODE_RESPONSE;
+ send_peap_message->Id = e->LastRecvEapId + num;
+ send_peap_message->Len = Endian16((UINT)(((UINT)sizeof(EAP_PEAP) + (UINT)sz)));
+ send_peap_message->Type = EAP_TYPE_PEAP;
+ send_peap_message->TlsFlags = 0;
+
+ if (num == 0 && include_len)
+ {
+ send_peap_message->TlsFlags |= EAP_TLS_FLAGS_LEN;
+ }
+ if (ReadBufRemainSize(buf) != 0)
+ {
+ send_peap_message->TlsFlags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+ }
+
+ Copy(((UCHAR *)send_peap_message) + sizeof(EAP_PEAP), tmp, sz);
+
+ Add(fragments, MemToBuf(send_peap_message, sizeof(EAP_PEAP) + sz));
+
+ Free(send_peap_message);
+ }
+
+ if (num == 0 && send_empty)
+ {
+ Add(fragments, MemToBuf("\0", 1));
+ }
+
+ // send each of packets
+ for (i = 0;i < LIST_NUM(fragments);i++)
+ {
+ BUF *b = LIST_DATA(fragments, i);
+ RADIUS_AVP *eap_avp;
+ RADIUS_PACKET *response_packet;
+
+ RADIUS_PACKET *send_packet = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(send_packet, e);
+
+ if (e->LastStateSize != 0)
+ {
+ Add(send_packet->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_STATE, 0, 0,
+ e->LastState, e->LastStateSize));
+ }
+
+ if (send_empty == false)
+ {
+ eap_avp = NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, b->Buf, b->Size);
+ }
+ else
+ {
+ EAP_PEAP empty_peap;
+
+ Zero(&empty_peap, sizeof(empty_peap));
+ empty_peap.Code = EAP_CODE_RESPONSE;
+ empty_peap.Id = e->LastRecvEapId;
+ empty_peap.Len = Endian16(sizeof(EAP_PEAP));
+ empty_peap.Type = EAP_TYPE_PEAP;
+
+ eap_avp = NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, &empty_peap, sizeof(EAP_PEAP));
+ }
+
+ Add(send_packet->AvpList, eap_avp);
+
+ response_packet = EapSendPacketAndRecvResponse(e, send_packet);
+
+ if (response_packet != NULL)
+ {
+ e->RecvLastCode = response_packet->Code;
+
+ if (response_packet->Parse_EapMessage != NULL && response_packet->Parse_EapMessage_DataSize >= sizeof(EAP_PEAP))
+ {
+ // Received SSL stream
+ EAP_PEAP *peap_msg = (EAP_PEAP *)response_packet->Parse_EapMessage;
+
+ if (peap_msg->Type == EAP_TYPE_PEAP)
+ {
+ if (peap_msg->TlsFlags & EAP_TLS_FLAGS_LEN)
+ {
+ UINT total_size = READ_UINT(((UCHAR *)peap_msg) + sizeof(EAP_PEAP));
+
+ if (total_size <= (response_packet->Parse_EapMessage_DataSize - sizeof(EAP_PEAP) - sizeof(UINT)))
+ {
+ WriteFifo(e->SslPipe->RawIn->SendFifo, ((UCHAR *)peap_msg) + sizeof(EAP_PEAP) + sizeof(UINT), total_size);
+ }
+ }
+ else
+ {
+ WriteFifo(e->SslPipe->RawIn->SendFifo, ((UCHAR *)peap_msg) + sizeof(EAP_PEAP),
+ response_packet->Parse_EapMessage_DataSize - sizeof(EAP_PEAP));
+ }
+ }
+ }
+ }
+
+ FreeRadiusPacket(send_packet);
+ FreeRadiusPacket(response_packet);
+ }
+
+ FreeBuf(buf);
+
+ if (fragments != NULL)
+ {
+ for (i = 0;i < LIST_NUM(fragments);i++)
+ {
+ BUF *b = LIST_DATA(fragments, i);
+
+ FreeBuf(b);
+ }
+
+ ReleaseList(fragments);
+ }
+
+ SyncSslPipe(e->SslPipe);
+
+ return ret;
+}
+
+// Send an encrypted message of PEAP
+bool SendPeapPacket(EAP_CLIENT *e, void *msg, UINT msg_size)
+{
+ bool ret = false;
+ FIFO *send_fifo;
+ FIFO *recv_fifo;
+ BUF *buf;
+ EAP_MESSAGE tmpmsg;
+ if (e == NULL || msg == NULL || msg_size == 0)
+ {
+ return false;
+ }
+ if (e->SslPipe == NULL)
+ {
+ return false;
+ }
+
+ send_fifo = e->SslPipe->RawOut->RecvFifo;
+ recv_fifo = e->SslPipe->RawIn->SendFifo;
+
+ Zero(&tmpmsg, sizeof(tmpmsg));
+ Copy(&tmpmsg, msg, MIN(msg_size, sizeof(EAP_MESSAGE)));
+
+ WriteFifo(e->SslPipe->SslInOut->SendFifo, &tmpmsg.Type, msg_size - 4);
+
+ SyncSslPipe(e->SslPipe);
+
+ buf = ReadFifoAll(send_fifo);
+
+ while (true)
+ {
+ ret = SendPeapRawPacket(e, buf->Buf, buf->Size);
+ FreeBuf(buf);
+
+ if (send_fifo->size == 0)
+ {
+ break;
+ }
+
+ buf = ReadFifoAll(send_fifo);
+ }
+
+ return !e->SslPipe->IsDisconnected;
+}
+
+// Start a PEAP SSL client
+bool StartPeapSslClient(EAP_CLIENT *e)
+{
+ bool ret = false;
+ FIFO *send_fifo;
+ FIFO *recv_fifo;
+ BUF *buf;
+ if (e == NULL)
+ {
+ return false;
+ }
+ if (e->SslPipe != NULL)
+ {
+ return false;
+ }
+
+ e->SslPipe = NewSslPipe(false, NULL, NULL, NULL);
+ send_fifo = e->SslPipe->RawOut->RecvFifo;
+ recv_fifo = e->SslPipe->RawIn->SendFifo;
+
+ SyncSslPipe(e->SslPipe);
+
+ buf = ReadFifoAll(send_fifo);
+
+ while (true)
+ {
+ ret = SendPeapRawPacket(e, buf->Buf, buf->Size);
+ FreeBuf(buf);
+
+ if (send_fifo->size == 0)
+ {
+ break;
+ }
+
+ buf = ReadFifoAll(send_fifo);
+ }
+
+ SendPeapRawPacket(e, NULL, 0);
+
+ return !e->SslPipe->IsDisconnected;
+}
+
+// Get a received PEAP message (unencrypted)
+bool GetRecvPeapMessage(EAP_CLIENT *e, EAP_MESSAGE *msg)
+{
+ BUF *b;
+ bool ret = false;
+ if (e == NULL)
+ {
+ return false;
+ }
+ if (e->SslPipe == NULL)
+ {
+ return false;
+ }
+
+ b = ReadFifoAll(e->SslPipe->SslInOut->RecvFifo);
+
+ if (b->Size >= 1)
+ {
+ Zero(msg, sizeof(EAP_MESSAGE));
+
+ msg->Len = Endian16(b->Size + 4);
+ Copy(&msg->Type, b->Buf, MIN(b->Size, 1501));
+
+ ret = true;
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Start a PEAP client
+bool StartPeapClient(EAP_CLIENT *e)
+{
+ bool ret = false;
+ RADIUS_PACKET *request1 = NULL;
+ RADIUS_PACKET *response1 = NULL;
+ RADIUS_PACKET *request2 = NULL;
+ RADIUS_PACKET *response2 = NULL;
+ EAP_MESSAGE *eap1 = NULL;
+ EAP_MESSAGE *eap2 = NULL;
+ if (e == NULL)
+ {
+ return false;
+ }
+ if (e->SslPipe != NULL)
+ {
+ return false;
+ }
+
+ request1 = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(request1, e);
+
+ eap1 = ZeroMalloc(sizeof(EAP_MESSAGE));
+ eap1->Code = EAP_CODE_RESPONSE;
+ eap1->Id = e->LastRecvEapId;
+ eap1->Len = Endian16(StrLen(e->Username) + 5);
+ eap1->Type = EAP_TYPE_IDENTITY;
+ Copy(eap1->Data, e->Username, StrLen(e->Username));
+ Add(request1->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, eap1, StrLen(e->Username) + 5));
+
+ response1 = EapSendPacketAndRecvResponse(e, request1);
+
+ if (response1 != NULL)
+ {
+ if (response1->Parse_EapMessage_DataSize != 0 && response1->Parse_EapMessage != NULL)
+ {
+ EAP_MESSAGE *eap = response1->Parse_EapMessage;
+ if (eap->Code == EAP_CODE_REQUEST)
+ {
+ if (eap->Type != EAP_TYPE_PEAP)
+ {
+ // Unsupported auth type. Request PEAP.
+ request2 = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(request2, e);
+
+ if (response1->Parse_StateSize != 0)
+ {
+ Add(request2->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_STATE, 0, 0,
+ response1->Parse_State, response1->Parse_StateSize));
+ }
+
+ eap2 = ZeroMalloc(sizeof(EAP_MESSAGE));
+ eap2->Code = EAP_CODE_RESPONSE;
+ eap2->Id = e->LastRecvEapId;
+ eap2->Len = Endian16(6);
+ eap2->Type = EAP_TYPE_LEGACY_NAK;
+ eap2->Data[0] = EAP_TYPE_PEAP;
+
+ Add(request2->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, eap2, 6));
+
+ response2 = EapSendPacketAndRecvResponse(e, request2);
+
+ if (response2 != NULL && response2->Parse_EapMessage_DataSize != 0 && response2->Parse_EapMessage != NULL)
+ {
+ eap = response2->Parse_EapMessage;
+
+ if (eap->Code == EAP_CODE_REQUEST && eap->Type == EAP_TYPE_PEAP)
+ {
+ goto LABEL_PARSE_PEAP;
+ }
+ }
+ }
+ else
+ {
+ EAP_PEAP *peap;
+LABEL_PARSE_PEAP:
+ peap = (EAP_PEAP *)eap;
+
+ if (peap->TlsFlags == 0x20)
+ {
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+
+ FreeRadiusPacket(request1);
+ FreeRadiusPacket(request2);
+ FreeRadiusPacket(response1);
+ FreeRadiusPacket(response2);
+ Free(eap1);
+ Free(eap2);
+
+ return ret;
+}
+
+// Set RADIUS general attributes
+void EapSetRadiusGeneralAttributes(RADIUS_PACKET *r, EAP_CLIENT *e)
+{
+ UINT ui;
+ char *str;
+ if (r == NULL || e == NULL)
+ {
+ return;
+ }
+
+ ui = Endian32(2);
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_SERVICE_TYPE, 0, 0, &ui, sizeof(UINT)));
+
+ ui = Endian32(1);
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_FRAMED_PROTOCOL, 0, 0, &ui, sizeof(UINT)));
+
+ ui = Endian32(5);
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_NAS_PORT_TYPE, 0, 0, &ui, sizeof(UINT)));
+
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_CALLING_STATION_ID, 0, 0, e->ClientIpStr, StrLen(e->ClientIpStr)));
+
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_TUNNEL_CLIENT_ENDPOINT, 0, 0, e->ClientIpStr, StrLen(e->ClientIpStr)));
+
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_USER_NAME, 0, 0, e->Username, StrLen(e->Username)));
+
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_NAS_ID, 0, 0, CEDAR_SERVER_STR, StrLen(CEDAR_SERVER_STR)));
+
+ ui = Endian32(2);
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC, RADIUS_VENDOR_MICROSOFT,
+ RADIUS_MS_NETWORK_ACCESS_SERVER_TYPE, &ui, sizeof(UINT)));
+
+ ui = Endian32(RADIUS_VENDOR_MICROSOFT);
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC, RADIUS_VENDOR_MICROSOFT,
+ RADIUS_MS_RAS_VENDOR, &ui, sizeof(UINT)));
+
+ str = "MSRASV5.20";
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC, RADIUS_VENDOR_MICROSOFT,
+ RADIUS_MS_VERSION, str, StrLen(str)));
+
+ str = "{5DC53D72-9815-4E97-AC91-339BAFEA6C48}";
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC, RADIUS_VENDOR_MICROSOFT,
+ RADIUS_MS_RAS_CORRELATION, str, StrLen(str)));
+
+ str = "MSRASV5.20";
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC, RADIUS_VENDOR_MICROSOFT,
+ RADIUS_MS_RAS_CLIENT_VERSION, str, StrLen(str)));
+
+ str = "MSRASV5.20";
+ Add(r->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_VENDOR_SPECIFIC, RADIUS_VENDOR_MICROSOFT,
+ RADIUS_MS_RAS_CLIENT_NAME, str, StrLen(str)));
+}
+
+// Send a MSCHAPv2 client auth response1
+bool EapClientSendMsChapv2AuthClientResponse(EAP_CLIENT *e, UCHAR *client_response, UCHAR *client_challenge)
+{
+ bool ret = false;
+ RADIUS_PACKET *request1 = NULL;
+ RADIUS_PACKET *response1 = NULL;
+ RADIUS_PACKET *request2 = NULL;
+ RADIUS_PACKET *response2 = NULL;
+ EAP_MSCHAPV2_RESPONSE *eap1 = NULL;
+ EAP_MSCHAPV2_SUCCESS_CLIENT *eap2 = NULL;
+ if (e == NULL || client_response == NULL || client_challenge == NULL)
+ {
+ return false;
+ }
+
+ request1 = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(request1, e);
+
+ if (e->LastStateSize != 0)
+ {
+ Add(request1->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_STATE, 0, 0,
+ e->LastState, e->LastStateSize));
+ }
+
+ eap1 = ZeroMalloc(sizeof(EAP_MSCHAPV2_RESPONSE));
+ eap1->Code = EAP_CODE_RESPONSE;
+ eap1->Id = e->NextEapId++;
+ eap1->Len = Endian16(59 + StrLen(e->Username));
+ eap1->Type = EAP_TYPE_MS_AUTH;
+ eap1->Chap_Opcode = EAP_MSCHAPV2_OP_RESPONSE;
+ eap1->Chap_Id = e->MsChapV2Challenge.Chap_Id;
+ eap1->Chap_Len = Endian16(54 + StrLen(e->Username));
+ eap1->Chap_ValueSize = 49;
+ Copy(eap1->Chap_PeerChallange, client_challenge, 16);
+ Copy(eap1->Chap_NtResponse, client_response, 24);
+ Copy(eap1->Chap_Name, e->Username, MIN(StrLen(e->Username), 255));
+
+ Add(request1->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, eap1, StrLen(e->Username) + 59));
+
+ response1 = EapSendPacketAndRecvResponse(e, request1);
+
+ if (response1 != NULL)
+ {
+ if (response1->Parse_EapMessage_DataSize != 0 && response1->Parse_EapMessage != NULL)
+ {
+ EAP_MESSAGE *eap = response1->Parse_EapMessage;
+ if (eap->Code == EAP_CODE_REQUEST)
+ {
+ if (eap->Type == EAP_TYPE_MS_AUTH)
+ {
+ if (((EAP_MSCHAPV2_GENERAL *)eap)->Chap_Opcode != EAP_MSCHAPV2_OP_SUCCESS)
+ {
+ // Auth fail
+ }
+ else
+ {
+ // Auth ok
+ EAP_MSCHAPV2_SUCCESS_SERVER *eaps = (EAP_MSCHAPV2_SUCCESS_SERVER *)eap;
+
+ if (StartWith(eaps->Message, "S="))
+ {
+ BUF *buf = StrToBin(eaps->Message + 2);
+
+ if (buf && buf->Size == 20)
+ {
+ Copy(&e->MsChapV2Success, eaps, sizeof(EAP_MSCHAPV2_SUCCESS_SERVER));
+ Copy(e->ServerResponse, buf->Buf, 20);
+
+ if (true)
+ {
+ // Send the final packet
+ request2 = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(request2, e);
+
+ if (e->LastStateSize != 0)
+ {
+ Add(request2->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_STATE, 0, 0,
+ e->LastState, e->LastStateSize));
+ }
+
+ eap2 = ZeroMalloc(sizeof(EAP_MSCHAPV2_SUCCESS_CLIENT));
+ eap2->Code = EAP_CODE_RESPONSE;
+ eap2->Id = e->NextEapId++;
+ eap2->Len = Endian16(6);
+ eap2->Type = EAP_TYPE_MS_AUTH;
+ eap2->Chap_Opcode = EAP_MSCHAPV2_OP_SUCCESS;
+
+ Add(request2->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, eap2, 6));
+
+ response2 = EapSendPacketAndRecvResponse(e, request2);
+
+ if (response2 != NULL)
+ {
+ if (response2->Code == RADIUS_CODE_ACCESS_ACCEPT)
+ {
+ ret = true;
+ }
+ }
+ }
+ }
+
+ FreeBuf(buf);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeRadiusPacket(request1);
+ FreeRadiusPacket(request2);
+ FreeRadiusPacket(response1);
+ FreeRadiusPacket(response2);
+ Free(eap1);
+ Free(eap2);
+
+ return ret;
+}
+
+// Send a MSCHAPv2 client auth request
+bool EapClientSendMsChapv2AuthRequest(EAP_CLIENT *e)
+{
+ bool ret = false;
+ RADIUS_PACKET *request1 = NULL;
+ RADIUS_PACKET *response1 = NULL;
+ RADIUS_PACKET *request2 = NULL;
+ RADIUS_PACKET *response2 = NULL;
+ EAP_MESSAGE *eap1 = NULL;
+ EAP_MESSAGE *eap2 = NULL;
+ if (e == NULL)
+ {
+ return false;
+ }
+
+ request1 = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(request1, e);
+
+ eap1 = ZeroMalloc(sizeof(EAP_MESSAGE));
+ eap1->Code = EAP_CODE_RESPONSE;
+ eap1->Id = e->NextEapId++;
+ eap1->Len = Endian16(StrLen(e->Username) + 5);
+ eap1->Type = EAP_TYPE_IDENTITY;
+ Copy(eap1->Data, e->Username, StrLen(e->Username));
+ Add(request1->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, eap1, StrLen(e->Username) + 5));
+
+ response1 = EapSendPacketAndRecvResponse(e, request1);
+
+ if (response1 != NULL)
+ {
+ if (response1->Parse_EapMessage_DataSize != 0 && response1->Parse_EapMessage != NULL)
+ {
+ EAP_MESSAGE *eap = response1->Parse_EapMessage;
+ if (eap->Code == EAP_CODE_REQUEST)
+ {
+ if (eap->Type != EAP_TYPE_MS_AUTH)
+ {
+ // Unsupported auth type. Request MS-CHAP-v2.
+ request2 = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EapSetRadiusGeneralAttributes(request2, e);
+
+ if (response1->Parse_StateSize != 0)
+ {
+ Add(request2->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_STATE, 0, 0,
+ response1->Parse_State, response1->Parse_StateSize));
+ }
+
+ eap2 = ZeroMalloc(sizeof(EAP_MESSAGE));
+ eap2->Code = EAP_CODE_RESPONSE;
+ eap2->Id = e->NextEapId++;
+ eap2->Len = Endian16(6);
+ eap2->Type = EAP_TYPE_LEGACY_NAK;
+ eap2->Data[0] = EAP_TYPE_MS_AUTH;
+
+ Add(request2->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0, eap2, 6));
+
+ response2 = EapSendPacketAndRecvResponse(e, request2);
+
+ if (response2 != NULL && response2->Parse_EapMessage_DataSize != 0 && response2->Parse_EapMessage != NULL)
+ {
+ eap = response2->Parse_EapMessage;
+
+ if (eap->Code == EAP_CODE_REQUEST && eap->Type == EAP_TYPE_MS_AUTH)
+ {
+ goto LABEL_PARSE_EAP;
+ }
+ }
+ }
+ else
+ {
+ EAP_MSCHAPV2_GENERAL *ms_g;
+LABEL_PARSE_EAP:
+ ms_g = (EAP_MSCHAPV2_GENERAL *)eap;
+
+ if (ms_g->Chap_Opcode == EAP_MSCHAPV2_OP_CHALLENGE)
+ {
+ EAP_MSCHAPV2_CHALLENGE *ms_c = (EAP_MSCHAPV2_CHALLENGE *)eap;
+ if (ms_c->Chap_ValueSize == 16)
+ {
+ Copy(&e->MsChapV2Challenge, ms_c, sizeof(EAP_MSCHAPV2_CHALLENGE));
+
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeRadiusPacket(request1);
+ FreeRadiusPacket(request2);
+ FreeRadiusPacket(response1);
+ FreeRadiusPacket(response2);
+ Free(eap1);
+ Free(eap2);
+
+ return ret;
+}
+
+// Send a packet and recv a response
+RADIUS_PACKET *EapSendPacketAndRecvResponse(EAP_CLIENT *e, RADIUS_PACKET *r)
+{
+ SOCKSET set;
+ UINT64 giveup_tick = 0;
+ UINT64 next_send_tick = 0;
+ bool select_inited = false;
+ bool free_r = false;
+ RADIUS_PACKET *ret = NULL;
+ if (e == NULL || r == NULL)
+ {
+ return NULL;
+ }
+
+ ClearBuf(e->PEAP_CurrentReceivingMsg);
+ e->PEAP_CurrentReceivingTotalSize = 0;
+
+ InitSockSet(&set);
+ AddSockSet(&set, e->UdpSock);
+
+ while (true)
+ {
+ UINT64 now = Tick64();
+ UINT wait_time = INFINITE;
+ bool is_finish = false;
+
+ if (giveup_tick == 0)
+ {
+ giveup_tick = now + (UINT64)e->GiveupTimeout;
+ }
+
+ if (giveup_tick <= now)
+ {
+ break;
+ }
+
+ if (select_inited)
+ {
+ UINT num_error = 0;
+
+ while (true)
+ {
+ IP from_ip;
+ UINT from_port;
+ UINT size;
+ UCHAR *tmp = e->TmpBuffer;
+
+ size = RecvFrom(e->UdpSock, &from_ip, &from_port, tmp, sizeof(e->TmpBuffer));
+ if (size == 0 && e->UdpSock->IgnoreRecvErr == false)
+ {
+ // UDP socket error
+ is_finish = true;
+ break;
+ }
+ else if (size == SOCK_LATER)
+ {
+ break;
+ }
+ if (size == 0 && e->UdpSock->IgnoreRecvErr)
+ {
+ num_error++;
+ if (num_error >= 100)
+ {
+ is_finish = true;
+ break;
+ }
+ }
+
+ // Receive a response packet
+ if (size != SOCK_LATER && size >= 1)
+ {
+ if (CmpIpAddr(&from_ip, &e->ServerIp) == 0 && from_port == e->ServerPort)
+ {
+ RADIUS_PACKET *rp = ParseRadiusPacket(tmp, size);
+ if (rp != NULL)
+ {
+ RADIUS_AVP *eap_msg = GetRadiusAvp(rp, RADIUS_ATTRIBUTE_EAP_MESSAGE);
+ RADIUS_AVP *vlan_avp = GetRadiusAvp(rp, RADIUS_ATTRIBUTE_VLAN_ID);
+ if (eap_msg != NULL)
+ {
+ e->LastRecvEapId = ((EAP_MESSAGE *)(eap_msg->Data))->Id;
+ }
+
+ if (vlan_avp != NULL)
+ {
+ // VLAN ID
+ UINT vlan_id = 0;
+ char tmp[32];
+
+ Zero(tmp, sizeof(tmp));
+
+ Copy(tmp, vlan_avp->Data, MIN(vlan_avp->DataSize, sizeof(tmp) - 1));
+
+ vlan_id = ToInt(tmp);
+
+ e->LastRecvVLanId = vlan_id;
+ }
+
+ // Validate the received packet
+ if (rp->Parse_EapAuthMessagePos != 0 && rp->Parse_AuthenticatorPos != 0)
+ {
+ UCHAR *tmp_buffer = Clone(tmp, size);
+ UCHAR auth1[16];
+ UCHAR auth2[16];
+
+ Copy(auth1, &tmp_buffer[rp->Parse_EapAuthMessagePos], 16);
+
+ Zero(&tmp_buffer[rp->Parse_EapAuthMessagePos], 16);
+ Copy(&tmp_buffer[rp->Parse_AuthenticatorPos], r->Authenticator, 16);
+
+ HMacMd5(auth2, e->SharedSecret, StrLen(e->SharedSecret),
+ tmp_buffer, size);
+
+ if (Cmp(auth1, auth2, 16) == 0)
+ {
+ bool send_ack_packet = false;
+
+ // ok
+ Copy(e->LastState, rp->Parse_State, rp->Parse_StateSize);
+ e->LastStateSize = rp->Parse_StateSize;
+
+ if (rp->Parse_EapMessage_DataSize != 0 && rp->Parse_EapMessage != NULL)
+ {
+ EAP_MESSAGE *eap_msg = (EAP_MESSAGE *)rp->Parse_EapMessage;
+
+ if (eap_msg->Type == EAP_TYPE_PEAP)
+ {
+ EAP_PEAP *peap_message = (EAP_PEAP *)eap_msg;
+
+ if (peap_message->TlsFlags & EAP_TLS_FLAGS_MORE_FRAGMENTS || e->PEAP_CurrentReceivingTotalSize != 0)
+ {
+ // more fragments: reply ack
+ RADIUS_PACKET *ack_packet = NewRadiusPacket(RADIUS_CODE_ACCESS_REQUEST, e->NextRadiusPacketId++);
+ EAP_PEAP *ack_msg = ZeroMalloc(sizeof(EAP_PEAP));
+
+ EapSetRadiusGeneralAttributes(ack_packet, e);
+ if (e->LastStateSize != 0)
+ {
+ Add(ack_packet->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_STATE, 0, 0,
+ e->LastState, e->LastStateSize));
+ }
+
+ ack_msg->Code = EAP_CODE_RESPONSE;
+ ack_msg->Id = e->LastRecvEapId;
+ ack_msg->Len = Endian16(6);
+ ack_msg->Type = EAP_TYPE_PEAP;
+ ack_msg->TlsFlags = 0;
+
+ Add(ack_packet->AvpList, NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_MESSAGE, 0, 0,
+ ack_msg, sizeof(EAP_PEAP)));
+
+ next_send_tick = 0;
+
+ if (free_r)
+ {
+ FreeRadiusPacket(r);
+ }
+
+ r = ack_packet;
+ free_r = true;
+
+ Free(ack_msg);
+
+ send_ack_packet = true;
+
+ if (e->PEAP_CurrentReceivingTotalSize == 0)
+ {
+ if (peap_message->TlsFlags & EAP_TLS_FLAGS_LEN)
+ {
+ if (Endian16(peap_message->Len) >= 9)
+ {
+ UINT total_size = READ_UINT(((UCHAR *)peap_message) + sizeof(EAP_PEAP));
+
+ if (total_size < 65536)
+ {
+ if (rp->Parse_EapMessage_DataSize >= 1)
+ {
+ e->PEAP_CurrentReceivingTotalSize = total_size;
+
+ WriteBuf(e->PEAP_CurrentReceivingMsg,
+ ((UCHAR *)peap_message),
+ rp->Parse_EapMessage_DataSize);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((!(peap_message->TlsFlags & EAP_TLS_FLAGS_LEN)) &&
+ rp->Parse_EapMessage_DataSize >= sizeof(EAP_PEAP))
+ {
+ WriteBuf(e->PEAP_CurrentReceivingMsg,
+ ((UCHAR *)peap_message) + sizeof(EAP_PEAP),
+ rp->Parse_EapMessage_DataSize - sizeof(EAP_PEAP));
+
+ if (e->PEAP_CurrentReceivingTotalSize <= e->PEAP_CurrentReceivingMsg->Size)
+ {
+ // all fragmented segments are arrived
+ send_ack_packet = false;
+
+ is_finish = true;
+
+ Free(rp->Parse_EapMessage);
+ rp->Parse_EapMessage = Clone(e->PEAP_CurrentReceivingMsg->Buf, e->PEAP_CurrentReceivingMsg->Size);
+ rp->Parse_EapMessage_DataSize = e->PEAP_CurrentReceivingMsg->Size;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (send_ack_packet == false)
+ {
+ ret = rp;
+ }
+ }
+
+ Free(tmp_buffer);
+ }
+
+ if (ret != NULL)
+ {
+ is_finish = true;
+ break;
+ }
+ else
+ {
+ FreeRadiusPacket(rp);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (is_finish)
+ {
+ break;
+ }
+
+ if (next_send_tick == 0 || next_send_tick <= now)
+ {
+ next_send_tick = now + (UINT64)e->ResendTimeout;
+
+ if (EapSendPacket(e, r) == false)
+ {
+ is_finish = true;
+ }
+ }
+
+ wait_time = MIN(wait_time, (UINT)(next_send_tick - now));
+ wait_time = MIN(wait_time, (UINT)(giveup_tick - now));
+ wait_time = MAX(wait_time, 1);
+
+ if (is_finish)
+ {
+ break;
+ }
+
+ Select(&set, wait_time, NULL, NULL);
+ select_inited = true;
+ }
+
+ if (free_r)
+ {
+ FreeRadiusPacket(r);
+ }
+
+ return ret;
+}
+
+// Send a RADIUS packet
+bool EapSendPacket(EAP_CLIENT *e, RADIUS_PACKET *r)
+{
+ BUF *b;
+ bool ret = false;
+ if (e == NULL || r == NULL)
+ {
+ return false;
+ }
+
+ b = GenerateRadiusPacket(r, e->SharedSecret);
+ if (b != NULL)
+ {
+ UINT r = SendTo(e->UdpSock, &e->ServerIp, e->ServerPort, b->Buf, b->Size);
+ if (!(r == 0 && e->UdpSock->IgnoreSendErr == false))
+ {
+ ret = true;
+ }
+
+
+ FreeBuf(b);
+ }
+
+ return ret;
+}
+
+// New EAP client
+EAP_CLIENT *NewEapClient(IP *server_ip, UINT server_port, char *shared_secret, UINT resend_timeout, UINT giveup_timeout, char *client_ip_str, char *username)
+{
+ EAP_CLIENT *e;
+ if (server_ip == NULL)
+ {
+ return NULL;
+ }
+ if (resend_timeout == 0)
+ {
+ resend_timeout = RADIUS_RETRY_INTERVAL;
+ }
+ if (giveup_timeout == 0)
+ {
+ giveup_timeout = RADIUS_RETRY_TIMEOUT;
+ }
+
+ e = ZeroMalloc(sizeof(EAP_CLIENT));
+
+ e->Ref = NewRef();
+
+ e->NextRadiusPacketId = 1;
+
+ e->UdpSock = NewUDPEx(0, IsIP6(server_ip));
+ Copy(&e->ServerIp, server_ip, sizeof(IP));
+ e->ServerPort = server_port;
+ e->ResendTimeout = resend_timeout;
+ e->GiveupTimeout = giveup_timeout;
+ StrCpy(e->SharedSecret, sizeof(e->SharedSecret), shared_secret);
+
+ StrCpy(e->ClientIpStr, sizeof(e->ClientIpStr), client_ip_str);
+ StrCpy(e->Username, sizeof(e->Username), username);
+ e->LastRecvEapId = 0;
+
+ e->PEAP_CurrentReceivingMsg = NewBuf();
+
+ return e;
+}
+
+// Free a EAP client
+void ReleaseEapClient(EAP_CLIENT *e)
+{
+ if (e == NULL)
+ {
+ return;
+ }
+
+ if (Release(e->Ref) == 0)
+ {
+ CleanupEapClient(e);
+ }
+}
+void CleanupEapClient(EAP_CLIENT *e)
+{
+ if (e == NULL)
+ {
+ return;
+ }
+
+ Disconnect(e->UdpSock);
+ ReleaseSock(e->UdpSock);
+
+ FreeSslPipe(e->SslPipe);
+
+ FreeBuf(e->PEAP_CurrentReceivingMsg);
+
+ Free(e);
+}
+
+// New RADIUS AVP value
+RADIUS_AVP *NewRadiusAvp(UCHAR type, UINT vendor_id, UCHAR vendor_code, void *data, UINT size)
+{
+ RADIUS_AVP *p = ZeroMalloc(sizeof(RADIUS_AVP));
+
+ p->Type = type;
+ p->VendorId = vendor_id;
+ p->VendorCode = vendor_code;
+ p->DataSize = (UCHAR)size;
+ Copy(p->Data, data, (UCHAR)size);
+
+ if (size >= 256)
+ {
+ Debug("!! size = %u\n", size);
+ }
+
+ return p;
+}
+
+// New RADIUS packet
+RADIUS_PACKET *NewRadiusPacket(UCHAR code, UCHAR packet_id)
+{
+ RADIUS_PACKET *r = ZeroMalloc(sizeof(RADIUS_PACKET));
+
+ r->Code = code;
+ r->PacketId = packet_id;
+
+ r->AvpList = NewListFast(NULL);
+
+ return r;
+}
+
+// Get RADIUS AVP
+RADIUS_AVP *GetRadiusAvp(RADIUS_PACKET *p, UCHAR type)
+{
+ UINT i;
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ RADIUS_AVP *avp = LIST_DATA(p->AvpList, i);
+
+ if (avp->Type == type)
+ {
+ return avp;
+ }
+ }
+
+ return NULL;
+}
+
+// Free a RADIUS packet
+void FreeRadiusPacket(RADIUS_PACKET *p)
+{
+ UINT i;
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->AvpList != NULL)
+ {
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ RADIUS_AVP *a = LIST_DATA(p->AvpList, i);
+
+ Free(a);
+ }
+
+ ReleaseList(p->AvpList);
+ }
+
+ Free(p->Parse_EapMessage);
+
+ Free(p);
+}
+
+// Generate a RADIUS packet
+BUF *GenerateRadiusPacket(RADIUS_PACKET *p, char *shared_secret)
+{
+ BUF *b;
+ UINT i;
+ UCHAR zero16[16];
+ UINT len_pos = 0;
+ UINT eap_auth_pos = 0;
+ bool exist_eap_msg = false;
+ bool exist_eap_auth = false;
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(zero16, sizeof(zero16));
+
+ // Add EAP message auth packet
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ RADIUS_AVP *a = (RADIUS_AVP *)LIST_DATA(p->AvpList, i);
+
+ if (a->Type == RADIUS_ATTRIBUTE_EAP_MESSAGE)
+ {
+ exist_eap_msg = true;
+ }
+ if (a->Type == RADIUS_ATTRIBUTE_EAP_AUTHENTICATOR)
+ {
+ exist_eap_auth = true;
+ }
+ }
+
+ if (exist_eap_msg && exist_eap_auth == false)
+ {
+ RADIUS_AVP *a = NewRadiusAvp(RADIUS_ATTRIBUTE_EAP_AUTHENTICATOR, 0, 0, zero16, sizeof(zero16));
+
+ Add(p->AvpList, a);
+ }
+
+ if (IsZero(p->Authenticator, 16))
+ {
+ UCHAR rand16[16];
+
+ Rand(rand16, sizeof(rand16));
+ Copy(p->Authenticator, rand16, 16);
+ }
+
+ b = NewBuf();
+
+ WriteBufChar(b, p->Code);
+ WriteBufChar(b, p->PacketId);
+ len_pos = b->Current;
+ WriteBufShort(b, 0);
+ WriteBuf(b, p->Authenticator, 16);
+
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ RADIUS_AVP *a = (RADIUS_AVP *)LIST_DATA(p->AvpList, i);
+
+ WriteBufChar(b, a->Type);
+
+ if (a->Type != RADIUS_ATTRIBUTE_VENDOR_SPECIFIC)
+ {
+ WriteBufChar(b, (UCHAR)((UINT)a->DataSize + 2));
+
+ if (a->Type == RADIUS_ATTRIBUTE_EAP_AUTHENTICATOR)
+ {
+ eap_auth_pos = b->Current;
+
+ if (a->DataSize == 16)
+ {
+ Zero(a->Data, sizeof(a->Data));
+ }
+ }
+
+ WriteBuf(b, a->Data, a->DataSize);
+ }
+ else
+ {
+ WriteBufChar(b, (UCHAR)((UINT)a->DataSize + 8));
+ WriteBufInt(b, a->VendorId);
+ WriteBufChar(b, a->VendorCode);
+ WriteBufChar(b, (UCHAR)((UINT)a->DataSize + 2));
+ WriteBuf(b, a->Data, a->DataSize);
+ }
+ }
+
+ WRITE_USHORT(((UCHAR *)b->Buf) + len_pos, b->Size);
+
+ if (eap_auth_pos != 0)
+ {
+ UCHAR eap_auth[16];
+
+ HMacMd5(eap_auth, shared_secret, StrLen(shared_secret), b->Buf, b->Size);
+
+ Copy(((UCHAR *)b->Buf) + eap_auth_pos, eap_auth, 16);
+ }
+
+ SeekBufToBegin(b);
+
+ return b;
+}
+
+// Parse a RADIUS packet
+RADIUS_PACKET *ParseRadiusPacket(void *data, UINT size)
+{
+ RADIUS_PACKET *p = NULL;
+ BUF *buf = NULL;
+ USHORT len;
+ UCHAR auth[16];
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(RADIUS_PACKET));
+
+ p->AvpList = NewListFast(NULL);
+
+ buf = MemToBuf(data, size);
+
+ // Code
+ p->Code = ReadBufChar(buf);
+ p->PacketId = ReadBufChar(buf);
+ len = ReadBufShort(buf);
+
+ p->Parse_AuthenticatorPos = buf->Current;
+ if (ReadBuf(buf, auth, 16) != 16)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if ((UINT)len < 20)
+ {
+ goto LABEL_ERROR;
+ }
+ if ((UINT)len > buf->Size)
+ {
+ goto LABEL_ERROR;
+ }
+ else if ((UINT)len < buf->Size)
+ {
+ buf->Size = len;
+ }
+
+ while (true)
+ {
+ RADIUS_AVP a;
+ UCHAR uc;
+ UINT data_size;
+
+ Zero(&a, sizeof(a));
+
+ if (ReadBuf(buf, &a.Type, 1) == 0)
+ {
+ break;
+ }
+
+ if (a.Type != RADIUS_ATTRIBUTE_VENDOR_SPECIFIC)
+ {
+ if (ReadBuf(buf, &uc, 1) == 0)
+ {
+ break;
+ }
+
+ data_size = (UINT)uc;
+
+ if (data_size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+
+ data_size -= 2;
+
+ a.DataSize = (UCHAR)data_size;
+
+ if (a.Type == RADIUS_ATTRIBUTE_EAP_AUTHENTICATOR && a.DataSize == 16)
+ {
+ p->Parse_EapAuthMessagePos = buf->Current;
+ }
+
+ if (ReadBuf(buf, a.Data, a.DataSize) != a.DataSize)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (a.Type == RADIUS_ATTRIBUTE_EAP_MESSAGE && a.DataSize >= 5 && a.DataSize <= 1500)
+ {
+ UINT sz_tmp = Endian16(((EAP_MESSAGE *)a.Data)->Len);
+
+ if (sz_tmp >= 5 && sz_tmp <= a.DataSize)
+ {
+ if (p->Parse_EapMessage == NULL)
+ {
+ EAP_MESSAGE *eap = Clone(a.Data, a.DataSize);
+
+ p->Parse_EapMessage_DataSize = sz_tmp;
+
+ p->Parse_EapMessage = eap;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ReadBuf(buf, &uc, 1) == 0)
+ {
+ break;
+ }
+
+ data_size = (UINT)uc;
+ if (data_size < 8)
+ {
+ goto LABEL_ERROR;
+ }
+
+ data_size -= 8;
+
+ a.VendorId = ReadBufInt(buf);
+ a.VendorCode = ReadBufChar(buf);
+ if (ReadBuf(buf, &uc, 1) == 0)
+ {
+ break;
+ }
+
+ if (((UINT)uc - 2) != data_size)
+ {
+ goto LABEL_ERROR;
+ }
+
+ a.DataSize = (UINT)data_size;
+
+ if (ReadBuf(buf, a.Data, a.DataSize) != a.DataSize)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ Add(p->AvpList, Clone(&a, sizeof(RADIUS_AVP)));
+ }
+
+ FreeBuf(buf);
+
+ if (true)
+ {
+ UINT num, i;
+ RADIUS_AVP *avp = GetRadiusAvp(p, RADIUS_ATTRIBUTE_STATE);
+
+ if (avp != NULL)
+ {
+ Copy(p->Parse_State, avp->Data, avp->DataSize);
+ p->Parse_StateSize = avp->DataSize;
+ }
+
+ num = 0;
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ RADIUS_AVP *avp = LIST_DATA(p->AvpList, i);
+
+ if (avp->Type == RADIUS_ATTRIBUTE_EAP_MESSAGE)
+ {
+ num++;
+ }
+ }
+
+ if (num >= 2)
+ {
+ // Reassemble multiple EAP messages
+ BUF *b = NewBuf();
+
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ RADIUS_AVP *avp = LIST_DATA(p->AvpList, i);
+
+ if (avp->Type == RADIUS_ATTRIBUTE_EAP_MESSAGE)
+ {
+ WriteBuf(b, avp->Data, avp->DataSize);
+ }
+ }
+
+ if (Endian16(((EAP_MESSAGE *)b->Buf)->Len) <= b->Size)
+ {
+ if (p->Parse_EapMessage != NULL)
+ {
+ Free(p->Parse_EapMessage);
+ }
+
+ p->Parse_EapMessage_DataSize = b->Size;
+ p->Parse_EapMessage_DataSize = MIN(p->Parse_EapMessage_DataSize, 1500);
+ p->Parse_EapMessage = Clone(b->Buf, p->Parse_EapMessage_DataSize);
+ }
+
+ FreeBuf(b);
+ }
+ }
+
+ return p;
+
+LABEL_ERROR:
+
+ if (p != NULL)
+ {
+ FreeRadiusPacket(p);
+ }
+
+ if (buf != NULL)
+ {
+ FreeBuf(buf);
+ }
+
+ return NULL;
+}
+
+
+////////// Classical implementation
+
// Attempts Radius authentication (with specifying retry interval and multiple server)
bool RadiusLogin(CONNECTION *c, char *server, UINT port, UCHAR *secret, UINT secret_size, wchar_t *username, char *password, UINT interval, UCHAR *mschap_v2_server_response_20,
RADIUS_LOGIN_OPTION *opt)
@@ -156,6 +1744,39 @@ bool RadiusLogin(CONNECTION *c, char *server, UINT port, UCHAR *secret, UINT sec
Zero(&mschap, sizeof(mschap));
is_mschap = ParseAndExtractMsChapV2InfoFromPassword(&mschap, password);
+ if (is_mschap && mschap.MsChapV2_EapClient != NULL)
+ {
+ // Try the EAP authentication for RADIUS first
+ EAP_CLIENT *eap = mschap.MsChapV2_EapClient;
+
+ if (eap->PeapMode == false)
+ {
+ ret = EapClientSendMsChapv2AuthClientResponse(eap, mschap.MsChapV2_ClientResponse,
+ mschap.MsChapV2_ClientChallenge);
+ }
+ else
+ {
+ ret = PeapClientSendMsChapv2AuthClientResponse(eap, mschap.MsChapV2_ClientResponse,
+ mschap.MsChapV2_ClientChallenge);
+ }
+
+ if (ret)
+ {
+ Copy(mschap_v2_server_response_20, eap->ServerResponse, 20);
+
+ if (opt->In_CheckVLanId)
+ {
+ opt->Out_VLanId = eap->LastRecvVLanId;
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
// Split the server into tokens
token = ParseToken(server, " ,;\t");
diff --git a/src/Cedar/Radius.h b/src/Cedar/Radius.h
index 3d68e17b..31b041bd 100644
--- a/src/Cedar/Radius.h
+++ b/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
diff --git a/src/Cedar/Sam.c b/src/Cedar/Sam.c
index 2a7c779e..d9872163 100644
--- a/src/Cedar/Sam.c
+++ b/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);
diff --git a/src/Cedar/Server.c b/src/Cedar/Server.c
index 12e6cce9..e5e2aff5 100644
--- a/src/Cedar/Server.c
+++ b/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);
diff --git a/src/Cedar/Virtual.c b/src/Cedar/Virtual.c
index 9f242dfd..01aee77e 100644
--- a/src/Cedar/Virtual.c
+++ b/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?
@@ -1689,6 +1698,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
diff --git a/src/Cedar/Virtual.h b/src/Cedar/Virtual.h
index 3728400b..e638df64 100644
--- a/src/Cedar/Virtual.h
+++ b/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);
diff --git a/src/CurrentBuild.txt b/src/CurrentBuild.txt
index ea4c8a19..34d5f233 100644
--- a/src/CurrentBuild.txt
+++ b/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
diff --git a/src/Mayaqua/MayaType.h b/src/Mayaqua/MayaType.h
index 6476c142..4ca4d90e 100644
--- a/src/Mayaqua/MayaType.h
+++ b/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;
diff --git a/src/Mayaqua/Memory.c b/src/Mayaqua/Memory.c
index 6810884e..2d9bd9f5 100644
--- a/src/Mayaqua/Memory.c
+++ b/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)
{
diff --git a/src/Mayaqua/Memory.h b/src/Mayaqua/Memory.h
index 98f3423f..35066027 100644
--- a/src/Mayaqua/Memory.h
+++ b/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);
diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c
index 42c61f0f..def2f45e 100644
--- a/src/Mayaqua/Network.c
+++ b/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)
diff --git a/src/Mayaqua/Network.h b/src/Mayaqua/Network.h
index 68c06bca..6f51bedf 100644
--- a/src/Mayaqua/Network.h
+++ b/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);
diff --git a/src/Mayaqua/TcpIp.c b/src/Mayaqua/TcpIp.c
index a7e0a0df..45e1624b 100644
--- a/src/Mayaqua/TcpIp.c
+++ b/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;
}
diff --git a/src/Mayaqua/Tick64.c b/src/Mayaqua/Tick64.c
index 0270b779..261c9ab7 100644
--- a/src/Mayaqua/Tick64.c
+++ b/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;
}
}
}
diff --git a/src/Mayaqua/Tick64.h b/src/Mayaqua/Tick64.h
index 5d7a5165..f3aa70e8 100644
--- a/src/Mayaqua/Tick64.h
+++ b/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
diff --git a/src/bin/hamcore/SeLow_x64.sys b/src/bin/hamcore/SeLow_x64.sys
deleted file mode 100644
index 95f91acf..00000000
--- a/src/bin/hamcore/SeLow_x64.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/SeLow_x86.sys b/src/bin/hamcore/SeLow_x86.sys
deleted file mode 100644
index 3e63bac6..00000000
--- a/src/bin/hamcore/SeLow_x86.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/pxwfp_x64.sys b/src/bin/hamcore/pxwfp_x64.sys
deleted file mode 100644
index 5fae09b0..00000000
--- a/src/bin/hamcore/pxwfp_x64.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/pxwfp_x86.sys b/src/bin/hamcore/pxwfp_x86.sys
deleted file mode 100644
index c03635ec..00000000
--- a/src/bin/hamcore/pxwfp_x86.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/see.sys b/src/bin/hamcore/see.sys
deleted file mode 100644
index b59ab4de..00000000
--- a/src/bin/hamcore/see.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/see_x64.sys b/src/bin/hamcore/see_x64.sys
deleted file mode 100644
index 1296fe92..00000000
--- a/src/bin/hamcore/see_x64.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/strtable_cn.stb b/src/bin/hamcore/strtable_cn.stb
index cd79b822..2157ad41 100644
--- a/src/bin/hamcore/strtable_cn.stb
+++ b/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 管理器之后,连接到本机并继续设置进程。
diff --git a/src/bin/hamcore/strtable_en.stb b/src/bin/hamcore/strtable_en.stb
index a549b1db..6a153e27 100644
--- a/src/bin/hamcore/strtable_en.stb
+++ b/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.
diff --git a/src/bin/hamcore/strtable_ja.stb b/src/bin/hamcore/strtable_ja.stb
index 629d223e..fdcc2b49 100644
--- a/src/bin/hamcore/strtable_ja.stb
+++ b/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 に対して接続して、設定を続行してください。
diff --git a/src/bin/hamcore/vpn_driver.sys b/src/bin/hamcore/vpn_driver.sys
deleted file mode 100644
index 3154524b..00000000
--- a/src/bin/hamcore/vpn_driver.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/vpn_driver6.sys b/src/bin/hamcore/vpn_driver6.sys
deleted file mode 100644
index a026b683..00000000
--- a/src/bin/hamcore/vpn_driver6.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/vpn_driver6_x64.sys b/src/bin/hamcore/vpn_driver6_x64.sys
deleted file mode 100644
index 76eee12e..00000000
--- a/src/bin/hamcore/vpn_driver6_x64.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/hamcore/vpn_driver_x64.sys b/src/bin/hamcore/vpn_driver_x64.sys
deleted file mode 100644
index 31700b24..00000000
--- a/src/bin/hamcore/vpn_driver_x64.sys
+++ /dev/null
Binary files differ
diff --git a/src/bin/vpnweb.cab b/src/bin/vpnweb.cab
index 95e474a8..f3a2c61c 100644
--- a/src/bin/vpnweb.cab
+++ b/src/bin/vpnweb.cab
Binary files differ
diff --git a/src/bin/vpnweb.ocx b/src/bin/vpnweb.ocx
index c7f120b1..96ff6111 100644
--- a/src/bin/vpnweb.ocx
+++ b/src/bin/vpnweb.ocx
Binary files differ
diff --git a/src/vpnweb/vpnweb.h b/src/vpnweb/vpnweb.h
index 103c8cda..867297a1 100644
--- a/src/vpnweb/vpnweb.h
+++ b/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)
diff --git a/src/vpnweb/vpnweb_i.c b/src/vpnweb/vpnweb_i.c
index da81ab48..ab07bdc8 100644
--- a/src/vpnweb/vpnweb_i.c
+++ b/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)
diff --git a/src/vpnweb/vpnweb_p.c b/src/vpnweb/vpnweb_p.c
index 66ea52bc..c7183a2f 100644
--- a/src/vpnweb/vpnweb_p.c
+++ b/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)