1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-09-18 01:33:00 +03:00

Cedar: DHCP server now assigns static IPv4 address, if present in user note

This works for all VPN protocols.

In SessionMain(): for DHCPDISCOVER and DHCPREQUEST frames, write the static IP address (which is retrieved from the user notes) in the SIADDR field of DHCPHEADER.

In VirtualDhcpServer(): for DHCPDISCOVER and DHCPREQUEST frames, read the static IP address from the SIADDR field of DHCPHEADER and assign it to the client.
This commit is contained in:
PeTeeR 2020-10-12 04:56:30 +02:00 committed by Davide Beatrici
parent 1c4b257a1b
commit b890c7d813
6 changed files with 240 additions and 10 deletions

View File

@ -1318,3 +1318,40 @@ bool GetUserMacAddressFromUserNote(UCHAR *mac, wchar_t *note)
return ret;
}
// Get the static IPv4 address from the user's note string
UINT GetUserIPv4AddressFromUserNote32(wchar_t *note)
{
bool ret = false;
UINT ip32 = 0;
UINT i = UniSearchStrEx(note, USER_IPV4_STR_PREFIX, 0, false);
if (i != INFINITE)
{
wchar_t *ipv4str_start = &note[i + UniStrLen(USER_IPV4_STR_PREFIX)];
wchar_t ipv4str2[MAX_SIZE];
UNI_TOKEN_LIST *tokens;
UniStrCpy(ipv4str2, sizeof(ipv4str2), ipv4str_start);
UniTrim(ipv4str2);
tokens = UniParseToken(ipv4str2, L" ,/()[]");
if (tokens != NULL)
{
if (tokens->NumTokens >= 1)
{
wchar_t *ipv4str = tokens->Token[0];
if (UniIsEmptyStr(ipv4str) == false)
{
char ipv4str_a[MAX_SIZE];
UniToStr(ipv4str_a, sizeof(ipv4str_a), ipv4str);
ip32 = StrToIP32(ipv4str_a);
}
}
UniFreeToken(tokens);
}
}
return ip32;
}

View File

@ -9,6 +9,7 @@
#define ACCOUNT_H
#define USER_MAC_STR_PREFIX L"MAC:"
#define USER_IPV4_STR_PREFIX L"IPv4:"
// Policy item
struct POLICY_ITEM
@ -205,7 +206,6 @@ POLICY_ITEM *GetPolicyItem(UINT id);
void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id);
void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value);
bool GetUserMacAddressFromUserNote(UCHAR *mac, wchar_t *note);
UINT GetUserIPv4AddressFromUserNote32(wchar_t *note);
#endif // ACCOUNT_H

View File

@ -33,6 +33,8 @@ void SessionMain(SESSION *s)
SOCK *nicinfo_sock = NULL;
bool is_server_session = false;
bool lock_receive_blocks_queue = false;
UINT static_ip = 0;
// Validate arguments
if (s == NULL)
{
@ -300,6 +302,13 @@ void SessionMain(SESSION *s)
if (b->Size >= 14)
{
UINT ip;
if( (ip = PrepareDHCPRequestForStaticIPv4( s, b )) != 0 )
{
// Remember the static IP address to remove it from the leased IP address list later
static_ip = ip;
}
if (b->Buf[0] & 0x01)
{
if (is_server_session == false)
@ -603,6 +612,9 @@ CLEANUP:
// Update the user information
IncrementUserTraffic(s->Hub, s->UserNameReal, s);
// Clear the DHCP lease record if assigned as a static client IP address
ClearDHCPLeaseRecordForIPv4(s, static_ip);
DelSession(s->Hub, s);
}
@ -2309,3 +2321,140 @@ void Notify(SESSION *s, UINT code)
}
UINT PrepareDHCPRequestForStaticIPv4(SESSION *s, BLOCK *b)
{
PKT *pkt = NULL;
DHCPV4_HEADER *dhcp = NULL;
UCHAR *data = NULL;
UINT size = 0;
UINT dhcp_header_size = 0;
UINT dhcp_data_offset = 0;
UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
DHCP_OPTION_LIST *opt = NULL;
USER *user = NULL;
UINT ret_ip = 0;
if ((s->Username == NULL) || (StrLen(s->Username) == 0) || (StrCmpi(s->Username, SNAT_USER_NAME_PRINT) == 0) ||
(StrCmpi( s->Username, BRIDGE_USER_NAME_PRINT) == 0) || (StrCmpi(s->Username, LINK_USER_NAME_PRINT) == 0))
{
return ret_ip;
}
pkt = ParsePacket(b->Buf, b->Size);
if (pkt == NULL)
{
return ret_ip;
}
if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP && pkt->TypeL7 == L7_DHCPV4)
{
if (pkt->L7.DHCPv4Header->OpCode != 1)
{
goto CLEANUP_TP;
}
dhcp = pkt->L7.DHCPv4Header;
dhcp_header_size = sizeof(DHCPV4_HEADER);
dhcp_data_offset = (UINT)(((UCHAR *)pkt->L7.DHCPv4Header) - ((UCHAR *)pkt->MacHeader) + dhcp_header_size);
data = ((UCHAR *)dhcp) + dhcp_header_size;
size = pkt->PacketSize - dhcp_data_offset;
if (dhcp_header_size < 5)
{
goto CLEANUP_TP;
}
// Search for Magic Cookie
while (size >= 5)
{
if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
{
// Found
data += 4;
size -= 4;
opt = ParseDhcpOptionList(data, size);
break;
}
++data;
--size;
}
if (opt == NULL)
{
goto CLEANUP_TP;
}
if (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST)
{
if (s->Hub != NULL)
{
user = AcGetUser( s->Hub, s->Username );
if (user != NULL)
{
dhcp->ServerIP = GetUserIPv4AddressFromUserNote32(user->Note);
ReleaseUser(user);
if (s->Hub->SecureNAT != NULL && s->Hub->SecureNAT->Nat != NULL)
{
VH *v = s->Hub->SecureNAT->Nat->Virtual;
if (v != NULL && v->UseDhcp == true && v->DhcpLeaseList != NULL)
{
DHCP_LEASE *d = SearchDhcpLeaseByIp(v, dhcp->ServerIP);
// The given static IP address is not used - it's OK
if (d == NULL)
{
ret_ip = dhcp->ServerIP;
}
}
}
}
}
}
}
CLEANUP_TP:
if (opt != NULL)
{
Free(opt);
}
if (pkt != NULL)
{
FreePacket(pkt);
}
return ret_ip;
}
void ClearDHCPLeaseRecordForIPv4(SESSION *s, UINT static_ip)
{
if (s == NULL || static_ip == 0)
{
return;
}
if (s->Hub == NULL || s->Hub->SecureNAT == NULL || s->Hub->SecureNAT->Nat == NULL)
{
return;
}
VH *v = s->Hub->SecureNAT->Nat->Virtual;
if (v == NULL || v->DhcpLeaseList == NULL)
{
return;
}
DHCP_LEASE *d = SearchDhcpLeaseByIp(v, static_ip);
if (d == NULL)
{
return;
}
LockList(v->DhcpLeaseList);
{
FreeDhcpLease(d);
Delete(v->DhcpLeaseList, d);
}
UnlockList( v->DhcpLeaseList);
}

View File

@ -339,6 +339,9 @@ void CancelList(LIST *o);
bool IsPriorityHighestPacketForQoS(void *data, UINT size);
UINT GetNextDelayedPacketTickDiff(SESSION *s);
UINT PrepareDHCPRequestForStaticIPv4(SESSION *s, BLOCK *b);
void ClearDHCPLeaseRecordForIPv4(SESSION *s, UINT static_ip);
#endif // SESSION_H

View File

@ -9198,6 +9198,11 @@ PENDING_LIST_CLEANUP:
// Correspond to the DHCP REQUEST
UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip)
{
return ServeDhcpRequestEx(v, mac, request_ip, false);
}
UINT ServeDhcpRequestEx(VH *v, UCHAR *mac, UINT request_ip, bool is_static_ip)
{
UINT ret;
// Validate arguments
@ -9206,7 +9211,7 @@ UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip)
return 0;
}
ret = ServeDhcpDiscover(v, mac, request_ip);
ret = ServeDhcpDiscoverEx(v, mac, request_ip, is_static_ip);
if (ret != request_ip)
{
if (request_ip != 0)
@ -9309,6 +9314,34 @@ UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip)
return ret;
}
UINT ServeDhcpDiscoverEx(VH *v, UCHAR *mac, UINT request_ip, bool is_static_ip)
{
if (is_static_ip == false)
{
return ServeDhcpDiscover(v, mac, request_ip );
}
if (v == NULL || mac == NULL || request_ip == 0)
{
return 0;
}
DHCP_LEASE *d = SearchDhcpLeaseByIp(v, request_ip);
if (d != NULL)
{
// The requested IP address is used already
return 0;
}
// For static IP, the requested IP address must NOT be within the range of the DHCP pool
if (Endian32(request_ip) < Endian32(v->DhcpIpStart) || Endian32(request_ip) > Endian32(v->DhcpIpEnd))
{
return request_ip;
}
return 0;
}
// Take an appropriate IP addresses that can be assigned newly
UINT GetFreeDhcpIpAddress(VH *v)
{
@ -9469,21 +9502,30 @@ void VirtualDhcpServer(VH *v, PKT *p)
if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST || opt->Opcode == DHCP_INFORM))
{
// Operate as the server
UINT ip = 0;
UINT ip = 0, ip_static = dhcp->ServerIP;
dhcp->ServerIP = 0;
if (opt->RequestedIp == 0)
{
opt->RequestedIp = p->L3.IPv4Header->SrcIP;
opt->RequestedIp = (ip_static ? ip_static : p->L3.IPv4Header->SrcIP);
}
if (opt->Opcode == DHCP_DISCOVER)
{
// Return an IP address that can be used
ip = ServeDhcpDiscover(v, p->MacAddressSrc, opt->RequestedIp);
ip = ServeDhcpDiscoverEx(v, p->MacAddressSrc, opt->RequestedIp, ip_static);
}
else if (opt->Opcode == DHCP_REQUEST)
{
// Determine the IP address
ip = ServeDhcpRequest(v, p->MacAddressSrc, opt->RequestedIp);
if (ip_static && opt->RequestedIp != ip_static)
{
// Don't allow opt->RequestedIp other than the IP written in user's note
ip = 0;
}
else
{
ip = ServeDhcpRequestEx(v, p->MacAddressSrc, opt->RequestedIp, ip_static);
}
}
if (ip != 0 || opt->Opcode == DHCP_INFORM)

View File

@ -514,9 +514,11 @@ DHCP_LEASE *SearchDhcpPendingLeaseByMac(VH *v, UCHAR *mac);
DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip);
DHCP_LEASE *SearchDhcpPendingLeaseByIp(VH *v, UINT ip);
UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip);
UINT ServeDhcpDiscoverEx(VH *v, UCHAR *mac, UINT request_ip, bool is_static_ip);
UINT GetFreeDhcpIpAddress(VH *v);
UINT GetFreeDhcpIpAddressByRandom(VH *v, UCHAR *mac);
UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip);
UINT ServeDhcpRequestEx(VH *v, UCHAR *mac, UINT request_ip, bool is_static_ip);
void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
UINT new_ip, UCHAR *client_mac, BUF *b, UINT hw_type, UINT hw_addr_size);
void VLog(VH *v, char *str);
@ -587,7 +589,4 @@ void NnDeleteOldestNatSessionIfNecessary(NATIVE_NAT *t, UINT ip, UINT protocol);
void NnSetSecureNatTargetHostname(char *name);
#endif // VIRTUAL_H