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