mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-23 01:49:53 +03:00
7215 lines
161 KiB
C
7215 lines
161 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Cedar Communication Module
|
|
|
|
|
|
// Hub.c
|
|
// Virtual HUB module
|
|
|
|
#include "CedarPch.h"
|
|
|
|
static UCHAR broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|
static char vgs_ua_str[9] = {0};
|
|
static bool g_vgs_emb_tag = false;
|
|
|
|
// A list of administration options that are currently supported and its default values
|
|
// These names must be shorter than 64 bytes
|
|
ADMIN_OPTION admin_options[] =
|
|
{
|
|
{"allow_hub_admin_change_option", 0},
|
|
{"max_users", 0},
|
|
{"max_multilogins_per_user", 0},
|
|
{"max_groups", 0},
|
|
{"max_accesslists", 0},
|
|
{"max_sessions_client_bridge_apply", 0},
|
|
{"max_sessions", 0},
|
|
{"max_sessions_client", 0},
|
|
{"max_sessions_bridge", 0},
|
|
{"max_bitrates_download", 0},
|
|
{"max_bitrates_upload", 0},
|
|
{"deny_empty_password", 0},
|
|
{"deny_bridge", 0},
|
|
{"deny_routing", 0},
|
|
{"deny_qos", 0},
|
|
{"deny_change_user_password", 0},
|
|
{"no_change_users", 0},
|
|
{"no_change_groups", 0},
|
|
{"no_securenat", 0},
|
|
{"no_securenat_enablenat", 0},
|
|
{"no_securenat_enabledhcp", 0},
|
|
{"no_cascade", 0},
|
|
{"no_online", 0},
|
|
{"no_offline", 0},
|
|
{"no_change_log_config", 0},
|
|
{"no_disconnect_session", 0},
|
|
{"no_delete_iptable", 0},
|
|
{"no_delete_mactable", 0},
|
|
{"no_enum_session", 0},
|
|
{"no_query_session", 0},
|
|
{"no_change_admin_password", 0},
|
|
{"no_change_log_switch_type", 0},
|
|
{"no_change_access_list", 0},
|
|
{"no_change_access_control_list", 0},
|
|
{"no_change_cert_list", 0},
|
|
{"no_change_crl_list", 0},
|
|
{"no_read_log_file", 0},
|
|
{"deny_hub_admin_change_ext_option", 0},
|
|
{"no_delay_jitter_packet_loss", 0},
|
|
{"no_change_msg", 0},
|
|
{"no_access_list_include_file", 0},
|
|
};
|
|
|
|
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, char *vpn_protocol_state_str)
|
|
{
|
|
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, hubname);
|
|
|
|
if (eap != NULL)
|
|
{
|
|
if (IsEmptyStr(vpn_protocol_state_str) == false)
|
|
{
|
|
StrCpy(eap->In_VpnProtocolState, sizeof(eap->In_VpnProtocolState), vpn_protocol_state_str);
|
|
}
|
|
|
|
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()
|
|
{
|
|
LIST *o = NewList(CompareUserList);
|
|
|
|
return o;
|
|
}
|
|
|
|
// Search whether the specified user matches to the user list (with cache expiration)
|
|
bool IsUserMatchInUserListWithCacheExpires(LIST *o, char *filename, UINT64 user_hash, UINT64 lifetime)
|
|
{
|
|
bool ret = false;
|
|
UINT64 now = Tick64();
|
|
// Validate arguments
|
|
if (o == NULL || filename == NULL || user_hash == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LockList(o);
|
|
{
|
|
if (lifetime != 0)
|
|
{
|
|
if (o->Param1 == 0 || (now >= (o->Param1 + lifetime)))
|
|
{
|
|
DeleteAllUserListCache(o);
|
|
|
|
o->Param1 = now;
|
|
}
|
|
}
|
|
|
|
ret = IsUserMatchInUserList(o, filename, user_hash);
|
|
}
|
|
UnlockList(o);
|
|
|
|
return ret;
|
|
}
|
|
bool IsUserMatchInUserListWithCacheExpiresAcl(LIST *o, char *name_in_acl, UINT64 user_hash, UINT64 lifetime)
|
|
{
|
|
char tmp[16];
|
|
bool exclude = false;
|
|
char filename[MAX_SIZE];
|
|
char filename2[MAX_SIZE];
|
|
bool is_full_path = false;
|
|
bool ret = false;
|
|
// Validate arguments
|
|
if (o == NULL || name_in_acl == NULL || user_hash == 0 || StrLen(name_in_acl) < 9)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
StrCpy(tmp, sizeof(tmp), name_in_acl);
|
|
StrLower(tmp);
|
|
|
|
tmp[8] = 0;
|
|
|
|
if (Cmp(tmp, ACCESS_LIST_INCLUDED_PREFIX, 8) == 0)
|
|
{
|
|
// include
|
|
exclude = false;
|
|
}
|
|
else
|
|
{
|
|
// exclude
|
|
exclude = true;
|
|
}
|
|
|
|
// Extract the file name
|
|
StrCpy(filename, sizeof(filename), name_in_acl + 8);
|
|
Trim(filename);
|
|
|
|
// Identify whether the file name is an absolute path
|
|
if (filename[0] == '\\' || filename[0] == '/' || (filename[1] == ':' && filename[2] == '\\'))
|
|
{
|
|
is_full_path = true;
|
|
}
|
|
|
|
if (is_full_path == false)
|
|
{
|
|
// Prepend a '@' if the file name is a relative path
|
|
StrCpy(filename2, sizeof(filename2), "@");
|
|
StrCat(filename2, sizeof(filename2), filename);
|
|
StrCpy(filename, sizeof(filename), filename2);
|
|
}
|
|
|
|
ret = IsUserMatchInUserListWithCacheExpires(o, filename, user_hash, lifetime);
|
|
|
|
if (exclude)
|
|
{
|
|
ret = NEGATIVE_BOOL(ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Search whether the specified user matches to the user list
|
|
bool IsUserMatchInUserList(LIST *o, char *filename, UINT64 user_hash)
|
|
{
|
|
USERLIST *u;
|
|
bool ret = false;
|
|
// Validate arguments
|
|
if (o == NULL || filename == NULL || user_hash == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LockList(o);
|
|
{
|
|
u = FindUserList(o, filename);
|
|
if (u == NULL)
|
|
{
|
|
u = LoadUserList(o, filename);
|
|
}
|
|
|
|
if (u != NULL)
|
|
{
|
|
ret = IsInt64InList(u->UserHashList, user_hash);
|
|
}
|
|
}
|
|
UnlockList(o);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Read the user list
|
|
USERLIST *LoadUserList(LIST *o, char *filename)
|
|
{
|
|
USERLIST *u;
|
|
BUF *b;
|
|
// Validate arguments
|
|
if (o == NULL || filename == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
u = FindUserList(o, filename);
|
|
|
|
if (u != NULL)
|
|
{
|
|
Delete(o, u);
|
|
|
|
FreeUserListEntry(u);
|
|
}
|
|
|
|
u = ZeroMalloc(sizeof(USERLIST));
|
|
|
|
StrCpy(u->Filename, sizeof(u->Filename), filename);
|
|
|
|
u->UserHashList = NewInt64List(false);
|
|
|
|
b = ReadDumpWithMaxSize(filename, ACCESS_LIST_INCLUDE_FILE_MAX_SIZE);
|
|
if (b != NULL)
|
|
{
|
|
while (true)
|
|
{
|
|
char *line = CfgReadNextLine(b);
|
|
UINT64 ui;
|
|
if (line == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Trim(line);
|
|
|
|
if (IsEmptyStr(line) == false)
|
|
{
|
|
if (StartWith(line, "#") == false &&
|
|
StartWith(line, "//") == false &&
|
|
StartWith(line, ";") == false)
|
|
{
|
|
ui = UsernameToInt64(line);
|
|
|
|
AddInt64Distinct(u->UserHashList, ui);
|
|
}
|
|
}
|
|
|
|
Free(line);
|
|
}
|
|
|
|
FreeBuf(b);
|
|
}
|
|
|
|
Add(o, u);
|
|
|
|
return u;
|
|
}
|
|
|
|
// Release the user list entry
|
|
void FreeUserListEntry(USERLIST *u)
|
|
{
|
|
// Validate arguments
|
|
if (u == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ReleaseInt64List(u->UserHashList);
|
|
|
|
Free(u);
|
|
}
|
|
|
|
// Search in user list
|
|
USERLIST *FindUserList(LIST *o, char *filename)
|
|
{
|
|
USERLIST t, *u;
|
|
// Validate arguments
|
|
if (o == NULL || filename == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
|
|
StrCpy(t.Filename, sizeof(t.Filename), filename);
|
|
|
|
u = Search(o, &t);
|
|
|
|
return u;
|
|
}
|
|
|
|
// User list entry comparison function
|
|
int CompareUserList(void *p1, void *p2)
|
|
{
|
|
USERLIST *u1, *u2;
|
|
// Validate arguments
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
u1 = *(USERLIST **)p1;
|
|
u2 = *(USERLIST **)p2;
|
|
if (u1 == NULL || u2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return StrCmpi(u1->Filename, u2->Filename);
|
|
}
|
|
|
|
// Delete the cache of the all user list
|
|
void DeleteAllUserListCache(LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(o);
|
|
{
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
USERLIST *u = LIST_DATA(o, i);
|
|
|
|
FreeUserListEntry(u);
|
|
}
|
|
|
|
DeleteAll(o);
|
|
}
|
|
UnlockList(o);
|
|
}
|
|
|
|
// Release the user list
|
|
void FreeUserList(LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
USERLIST *u = LIST_DATA(o, i);
|
|
|
|
FreeUserListEntry(u);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
}
|
|
|
|
// Get whether the specified message is a URL string
|
|
bool IsURLMsg(wchar_t *str, char *url, UINT url_size)
|
|
{
|
|
UNI_TOKEN_LIST *t;
|
|
bool ret = false;
|
|
UINT i;
|
|
UINT n = 0;
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
t = UniParseToken(str, L"\r\n");
|
|
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
wchar_t *str = t->Token[i];
|
|
|
|
if (IsEmptyUniStr(str) == false)
|
|
{
|
|
n++;
|
|
|
|
UniTrim(str);
|
|
|
|
if (n == 1)
|
|
{
|
|
if (UniStartWith(str, L"http://") ||
|
|
UniStartWith(str, L"https://") ||
|
|
UniStartWith(str, L"ftp://"))
|
|
{
|
|
ret = true;
|
|
|
|
UniToStr(url, url_size, str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (n != 1)
|
|
{
|
|
ret = false;
|
|
}
|
|
|
|
UniFreeToken(t);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Get data from RPC_ADMIN_OPTION
|
|
UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (ao == NULL || name == NULL)
|
|
{
|
|
return INFINITE;
|
|
}
|
|
|
|
for (i = 0;i < ao->NumItem;i++)
|
|
{
|
|
ADMIN_OPTION *a = &ao->Items[i];
|
|
|
|
if (StrCmpi(a->Name, name) == 0)
|
|
{
|
|
return a->Value;
|
|
}
|
|
}
|
|
|
|
return INFINITE;
|
|
}
|
|
void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest)
|
|
{
|
|
UINT value;
|
|
// Validate arguments
|
|
if (ao == NULL || name == NULL || dest == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
value = GetHubAdminOptionData(ao, name);
|
|
if (value == INFINITE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
*dest = value;
|
|
}
|
|
|
|
// Set the contents of the HUB_OPTION based on the data
|
|
void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao)
|
|
{
|
|
// Validate arguments
|
|
if (o == NULL || ao == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv4", &o->NoArpPolling);
|
|
GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv6", &o->NoIPv6AddrPolling);
|
|
GetHubAdminOptionDataAndSet(ao, "NoIpTable", &o->NoIpTable);
|
|
GetHubAdminOptionDataAndSet(ao, "NoMacAddressLog", &o->NoMacAddressLog);
|
|
GetHubAdminOptionDataAndSet(ao, "ManageOnlyPrivateIP", &o->ManageOnlyPrivateIP);
|
|
GetHubAdminOptionDataAndSet(ao, "ManageOnlyLocalUnicastIPv6", &o->ManageOnlyLocalUnicastIPv6);
|
|
GetHubAdminOptionDataAndSet(ao, "DisableIPParsing", &o->DisableIPParsing);
|
|
GetHubAdminOptionDataAndSet(ao, "YieldAfterStorePacket", &o->YieldAfterStorePacket);
|
|
GetHubAdminOptionDataAndSet(ao, "NoSpinLockForPacketDelay", &o->NoSpinLockForPacketDelay);
|
|
GetHubAdminOptionDataAndSet(ao, "BroadcastStormDetectionThreshold", &o->BroadcastStormDetectionThreshold);
|
|
GetHubAdminOptionDataAndSet(ao, "ClientMinimumRequiredBuild", &o->ClientMinimumRequiredBuild);
|
|
GetHubAdminOptionDataAndSet(ao, "FilterPPPoE", &o->FilterPPPoE);
|
|
GetHubAdminOptionDataAndSet(ao, "FilterOSPF", &o->FilterOSPF);
|
|
GetHubAdminOptionDataAndSet(ao, "FilterIPv4", &o->FilterIPv4);
|
|
GetHubAdminOptionDataAndSet(ao, "FilterIPv6", &o->FilterIPv6);
|
|
GetHubAdminOptionDataAndSet(ao, "FilterNonIP", &o->FilterNonIP);
|
|
GetHubAdminOptionDataAndSet(ao, "NoIPv4PacketLog", &o->NoIPv4PacketLog);
|
|
GetHubAdminOptionDataAndSet(ao, "NoIPv6PacketLog", &o->NoIPv6PacketLog);
|
|
GetHubAdminOptionDataAndSet(ao, "FilterBPDU", &o->FilterBPDU);
|
|
GetHubAdminOptionDataAndSet(ao, "NoIPv6DefaultRouterInRAWhenIPv6", &o->NoIPv6DefaultRouterInRAWhenIPv6);
|
|
GetHubAdminOptionDataAndSet(ao, "NoLookBPDUBridgeId", &o->NoLookBPDUBridgeId);
|
|
GetHubAdminOptionDataAndSet(ao, "NoManageVlanId", &o->NoManageVlanId);
|
|
GetHubAdminOptionDataAndSet(ao, "VlanTypeId", &o->VlanTypeId);
|
|
GetHubAdminOptionDataAndSet(ao, "FixForDLinkBPDU", &o->FixForDLinkBPDU);
|
|
GetHubAdminOptionDataAndSet(ao, "RequiredClientId", &o->RequiredClientId);
|
|
GetHubAdminOptionDataAndSet(ao, "AdjustTcpMssValue", &o->AdjustTcpMssValue);
|
|
GetHubAdminOptionDataAndSet(ao, "DisableAdjustTcpMss", &o->DisableAdjustTcpMss);
|
|
GetHubAdminOptionDataAndSet(ao, "NoDhcpPacketLogOutsideHub", &o->NoDhcpPacketLogOutsideHub);
|
|
GetHubAdminOptionDataAndSet(ao, "DisableHttpParsing", &o->DisableHttpParsing);
|
|
GetHubAdminOptionDataAndSet(ao, "DisableUdpAcceleration", &o->DisableUdpAcceleration);
|
|
GetHubAdminOptionDataAndSet(ao, "DisableUdpFilterForLocalBridgeNic", &o->DisableUdpFilterForLocalBridgeNic);
|
|
GetHubAdminOptionDataAndSet(ao, "ApplyIPv4AccessListOnArpPacket", &o->ApplyIPv4AccessListOnArpPacket);
|
|
GetHubAdminOptionDataAndSet(ao, "RemoveDefGwOnDhcpForLocalhost", &o->RemoveDefGwOnDhcpForLocalhost);
|
|
GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxTcpSessionsPerIp", &o->SecureNAT_MaxTcpSessionsPerIp);
|
|
GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxTcpSynSentPerIp", &o->SecureNAT_MaxTcpSynSentPerIp);
|
|
GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxUdpSessionsPerIp", &o->SecureNAT_MaxUdpSessionsPerIp);
|
|
GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxDnsSessionsPerIp", &o->SecureNAT_MaxDnsSessionsPerIp);
|
|
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);
|
|
GetHubAdminOptionDataAndSet(ao, "BroadcastLimiterStrictMode", &o->BroadcastLimiterStrictMode);
|
|
GetHubAdminOptionDataAndSet(ao, "MaxLoggedPacketsPerMinute", &o->MaxLoggedPacketsPerMinute);
|
|
GetHubAdminOptionDataAndSet(ao, "DoNotSaveHeavySecurityLogs", &o->DoNotSaveHeavySecurityLogs);
|
|
GetHubAdminOptionDataAndSet(ao, "DropBroadcastsInPrivacyFilterMode", &o->DropBroadcastsInPrivacyFilterMode);
|
|
GetHubAdminOptionDataAndSet(ao, "DropArpInPrivacyFilterMode", &o->DropArpInPrivacyFilterMode);
|
|
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);
|
|
GetHubAdminOptionDataAndSet(ao, "UseHubNameAsDhcpUserClassOption", &o->UseHubNameAsDhcpUserClassOption);
|
|
GetHubAdminOptionDataAndSet(ao, "UseHubNameAsRadiusNasId", &o->UseHubNameAsRadiusNasId);
|
|
}
|
|
|
|
// Convert the contents of the HUB_OPTION to data
|
|
void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
|
|
{
|
|
LIST *aol;
|
|
UINT i;
|
|
// Validate arguments
|
|
if (ao == NULL || o == NULL || hub_name == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
aol = NewListFast(NULL);
|
|
|
|
Add(aol, NewAdminOption("NoAddressPollingIPv4", o->NoArpPolling));
|
|
Add(aol, NewAdminOption("NoAddressPollingIPv6", o->NoIPv6AddrPolling));
|
|
Add(aol, NewAdminOption("NoIpTable", o->NoIpTable));
|
|
Add(aol, NewAdminOption("NoMacAddressLog", o->NoMacAddressLog));
|
|
Add(aol, NewAdminOption("ManageOnlyPrivateIP", o->ManageOnlyPrivateIP));
|
|
Add(aol, NewAdminOption("ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6));
|
|
Add(aol, NewAdminOption("DisableIPParsing", o->DisableIPParsing));
|
|
Add(aol, NewAdminOption("YieldAfterStorePacket", o->YieldAfterStorePacket));
|
|
Add(aol, NewAdminOption("NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay));
|
|
Add(aol, NewAdminOption("BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold));
|
|
Add(aol, NewAdminOption("ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild));
|
|
Add(aol, NewAdminOption("FilterPPPoE", o->FilterPPPoE));
|
|
Add(aol, NewAdminOption("FilterOSPF", o->FilterOSPF));
|
|
Add(aol, NewAdminOption("FilterIPv4", o->FilterIPv4));
|
|
Add(aol, NewAdminOption("FilterIPv6", o->FilterIPv6));
|
|
Add(aol, NewAdminOption("FilterNonIP", o->FilterNonIP));
|
|
Add(aol, NewAdminOption("NoIPv4PacketLog", o->NoIPv4PacketLog));
|
|
Add(aol, NewAdminOption("NoIPv6PacketLog", o->NoIPv6PacketLog));
|
|
Add(aol, NewAdminOption("FilterBPDU", o->FilterBPDU));
|
|
Add(aol, NewAdminOption("NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6));
|
|
Add(aol, NewAdminOption("NoLookBPDUBridgeId", o->NoLookBPDUBridgeId));
|
|
Add(aol, NewAdminOption("NoManageVlanId", o->NoManageVlanId));
|
|
Add(aol, NewAdminOption("VlanTypeId", o->VlanTypeId));
|
|
Add(aol, NewAdminOption("FixForDLinkBPDU", o->FixForDLinkBPDU));
|
|
Add(aol, NewAdminOption("RequiredClientId", o->RequiredClientId));
|
|
Add(aol, NewAdminOption("AdjustTcpMssValue", o->AdjustTcpMssValue));
|
|
Add(aol, NewAdminOption("DisableAdjustTcpMss", o->DisableAdjustTcpMss));
|
|
Add(aol, NewAdminOption("NoDhcpPacketLogOutsideHub", o->NoDhcpPacketLogOutsideHub));
|
|
Add(aol, NewAdminOption("DisableHttpParsing", o->DisableHttpParsing));
|
|
Add(aol, NewAdminOption("DisableUdpAcceleration", o->DisableUdpAcceleration));
|
|
Add(aol, NewAdminOption("DisableUdpFilterForLocalBridgeNic", o->DisableUdpFilterForLocalBridgeNic));
|
|
Add(aol, NewAdminOption("ApplyIPv4AccessListOnArpPacket", o->ApplyIPv4AccessListOnArpPacket));
|
|
Add(aol, NewAdminOption("RemoveDefGwOnDhcpForLocalhost", o->RemoveDefGwOnDhcpForLocalhost));
|
|
Add(aol, NewAdminOption("SecureNAT_MaxTcpSessionsPerIp", o->SecureNAT_MaxTcpSessionsPerIp));
|
|
Add(aol, NewAdminOption("SecureNAT_MaxTcpSynSentPerIp", o->SecureNAT_MaxTcpSynSentPerIp));
|
|
Add(aol, NewAdminOption("SecureNAT_MaxUdpSessionsPerIp", o->SecureNAT_MaxUdpSessionsPerIp));
|
|
Add(aol, NewAdminOption("SecureNAT_MaxDnsSessionsPerIp", o->SecureNAT_MaxDnsSessionsPerIp));
|
|
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));
|
|
Add(aol, NewAdminOption("BroadcastLimiterStrictMode", o->BroadcastLimiterStrictMode));
|
|
Add(aol, NewAdminOption("MaxLoggedPacketsPerMinute", o->MaxLoggedPacketsPerMinute));
|
|
Add(aol, NewAdminOption("DoNotSaveHeavySecurityLogs", o->DoNotSaveHeavySecurityLogs));
|
|
Add(aol, NewAdminOption("DropBroadcastsInPrivacyFilterMode", o->DropBroadcastsInPrivacyFilterMode));
|
|
Add(aol, NewAdminOption("DropArpInPrivacyFilterMode", o->DropArpInPrivacyFilterMode));
|
|
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));
|
|
Add(aol, NewAdminOption("UseHubNameAsDhcpUserClassOption", o->UseHubNameAsDhcpUserClassOption));
|
|
Add(aol, NewAdminOption("UseHubNameAsRadiusNasId", o->UseHubNameAsRadiusNasId));
|
|
|
|
Zero(ao, sizeof(RPC_ADMIN_OPTION));
|
|
|
|
StrCpy(ao->HubName, sizeof(ao->HubName), hub_name);
|
|
|
|
ao->NumItem = LIST_NUM(aol);
|
|
ao->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * ao->NumItem);
|
|
|
|
for (i = 0;i < LIST_NUM(aol);i++)
|
|
{
|
|
ADMIN_OPTION *a = LIST_DATA(aol, i);
|
|
|
|
UniStrCpy(a->Descrption, sizeof(a->Descrption), GetHubAdminOptionHelpString(a->Name));
|
|
|
|
Copy(&ao->Items[i], a, sizeof(ADMIN_OPTION));
|
|
|
|
Free(a);
|
|
}
|
|
|
|
ReleaseList(aol);
|
|
}
|
|
|
|
// Create a new ADMIN OPTION
|
|
ADMIN_OPTION *NewAdminOption(char *name, UINT value)
|
|
{
|
|
ADMIN_OPTION *a;
|
|
// Validate arguments
|
|
if (name == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
a = ZeroMalloc(sizeof(ADMIN_OPTION));
|
|
StrCpy(a->Name, sizeof(a->Name), name);
|
|
a->Value = value;
|
|
|
|
return a;
|
|
}
|
|
|
|
// Clone the AC list
|
|
LIST *CloneAcList(LIST *o)
|
|
{
|
|
LIST *ret;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ret = NewAcList();
|
|
SetAcList(ret, o);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Set all the AC list
|
|
void SetAcList(LIST *o, LIST *src)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL || src == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DelAllAc(o);
|
|
|
|
for (i = 0;i < LIST_NUM(src);i++)
|
|
{
|
|
AC *ac = LIST_DATA(src, i);
|
|
|
|
AddAc(o, ac);
|
|
}
|
|
}
|
|
|
|
// Remove all AC from the AC list
|
|
void DelAllAc(LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
AC *ac = LIST_DATA(o, i);
|
|
|
|
Free(ac);
|
|
}
|
|
|
|
DeleteAll(o);
|
|
}
|
|
|
|
// Release the AC list
|
|
void FreeAcList(LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
AC *ac = LIST_DATA(o, i);
|
|
|
|
Free(ac);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
}
|
|
|
|
// Generate a string that indicates the contents of the AC
|
|
char *GenerateAcStr(AC *ac)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
char ip[64], mask[64];
|
|
|
|
if (ac == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
IPToStr(ip, sizeof(ip), &ac->IpAddress);
|
|
MaskToStr(mask, sizeof(mask), &ac->SubnetMask);
|
|
|
|
if (ac->Masked == false)
|
|
{
|
|
Format(tmp, sizeof(tmp), "%s", ip);
|
|
}
|
|
else
|
|
{
|
|
Format(tmp, sizeof(tmp), "%s/%s", ip, mask);
|
|
}
|
|
|
|
return CopyStr(tmp);
|
|
}
|
|
|
|
// Calculate whether the specified IP address is rejected by the access list
|
|
bool IsIpDeniedByAcList(IP *ip, LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (ip == NULL || o == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (GetGlobalServerFlag(GSF_DISABLE_AC) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
AC *ac = LIST_DATA(o, i);
|
|
|
|
if (IsIpMaskedByAc(ip, ac))
|
|
{
|
|
if (ac->Deny == false)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Calculate whether the specified IP address is masked by the AC
|
|
bool IsIpMaskedByAc(IP *ip, AC *ac)
|
|
{
|
|
UINT uip, net, mask;
|
|
// Validate arguments
|
|
if (ip == NULL || ac == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (GetGlobalServerFlag(GSF_DISABLE_AC) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsIP4(ip))
|
|
{
|
|
// IPv4
|
|
uip = IPToUINT(ip);
|
|
net = IPToUINT(&ac->IpAddress);
|
|
mask = IPToUINT(&ac->SubnetMask);
|
|
|
|
if (ac->Masked == false)
|
|
{
|
|
if (uip == net)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((uip & mask) == (net & mask))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// IPv6
|
|
if (ac->Masked == false)
|
|
{
|
|
if (CmpIpAddr(ip, &ac->IpAddress) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IP and1, and2;
|
|
|
|
IPAnd6(&and1, ip, &ac->SubnetMask);
|
|
IPAnd6(&and2, &ac->IpAddress, &ac->SubnetMask);
|
|
|
|
if (CmpIpAddr(&and1, &and2) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Set the AC
|
|
void SetAc(LIST *o, UINT id, AC *ac)
|
|
{
|
|
// Validate arguments
|
|
if (o == NULL || id == 0 || ac == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (DelAc(o, id))
|
|
{
|
|
AddAc(o, ac);
|
|
}
|
|
}
|
|
|
|
// Get the AC
|
|
AC *GetAc(LIST *o, UINT id)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL || id == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
AC *ac = LIST_DATA(o, i);
|
|
|
|
if (ac->Id == id)
|
|
{
|
|
return Clone(ac, sizeof(AC));
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Delete the AC
|
|
bool DelAc(LIST *o, UINT id)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL || id == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
AC *ac = LIST_DATA(o, i);
|
|
|
|
if (ac->Id == id)
|
|
{
|
|
if (Delete(o, ac))
|
|
{
|
|
Free(ac);
|
|
|
|
NormalizeAcList(o);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Add an AC to the list
|
|
void AddAc(LIST *o, AC *ac)
|
|
{
|
|
// Validate arguments
|
|
if (o == NULL || ac == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (LIST_NUM(o) < MAX_HUB_ACS)
|
|
{
|
|
Insert(o, Clone(ac, sizeof(AC)));
|
|
|
|
NormalizeAcList(o);
|
|
}
|
|
}
|
|
|
|
// Normalize the AC list
|
|
void NormalizeAcList(LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
AC *ac = LIST_DATA(o, i);
|
|
|
|
if (IsIP6(&ac->IpAddress))
|
|
{
|
|
ac->IpAddress.ipv6_scope_id = 0;
|
|
}
|
|
|
|
ac->Id = (i + 1);
|
|
}
|
|
}
|
|
|
|
// Create a new AC list
|
|
LIST *NewAcList()
|
|
{
|
|
return NewList(CmpAc);
|
|
}
|
|
|
|
// AC comparison
|
|
int CmpAc(void *p1, void *p2)
|
|
{
|
|
AC *a1, *a2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
a1 = *(AC **)p1;
|
|
a2 = *(AC **)p2;
|
|
if (a1 == NULL || a2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if (a1->Priority > a2->Priority)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (a1->Priority < a2->Priority)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (a1->Deny > a2->Deny)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (a1->Deny < a2->Deny)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Copy the CRL
|
|
CRL *CopyCrl(CRL *crl)
|
|
{
|
|
CRL *ret;
|
|
// Validate arguments
|
|
if (crl == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ret = ZeroMalloc(sizeof(CRL));
|
|
|
|
if (crl->Serial != NULL)
|
|
{
|
|
ret->Serial = NewXSerial(crl->Serial->data, crl->Serial->size);
|
|
}
|
|
|
|
ret->Name = CopyName(crl->Name);
|
|
|
|
Copy(ret->DigestMD5, crl->DigestMD5, MD5_SIZE);
|
|
Copy(ret->DigestSHA1, crl->DigestSHA1, SHA1_SIZE);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Release the CRL
|
|
void FreeCrl(CRL *crl)
|
|
{
|
|
// Validate arguments
|
|
if (crl == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (crl->Serial != NULL)
|
|
{
|
|
FreeXSerial(crl->Serial);
|
|
}
|
|
|
|
if (crl->Name != NULL)
|
|
{
|
|
FreeName(crl->Name);
|
|
}
|
|
|
|
Free(crl);
|
|
}
|
|
|
|
// Check whether the certificate has been disabled by searching the CRL list of Virtual HUB
|
|
bool IsValidCertInHub(HUB *h, X *x)
|
|
{
|
|
bool ret;
|
|
// Validate arguments
|
|
if (h == NULL || x == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (h->HubDb == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LockList(h->HubDb->CrlList);
|
|
{
|
|
ret = IsCertMatchCrlList(x, h->HubDb->CrlList);
|
|
}
|
|
UnlockList(h->HubDb->CrlList);
|
|
|
|
if (ret)
|
|
{
|
|
// This is invalid because it was matched
|
|
return false;
|
|
}
|
|
|
|
// This is valid because it wasn't matched
|
|
return true;
|
|
}
|
|
|
|
// Search whether the certificate matches the CRL list
|
|
bool IsCertMatchCrlList(X *x, LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (x == NULL || o == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
CRL *crl = LIST_DATA(o, i);
|
|
|
|
if (IsCertMatchCrl(x, crl))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Convert the CRL to a string
|
|
wchar_t *GenerateCrlStr(CRL *crl)
|
|
{
|
|
wchar_t tmp[2048];
|
|
// Validate arguments
|
|
if (crl == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
UniStrCpy(tmp, sizeof(tmp), L"");
|
|
|
|
if (crl->Name != NULL)
|
|
{
|
|
// Name information
|
|
wchar_t name[MAX_SIZE];
|
|
|
|
UniStrCat(tmp, sizeof(tmp), L"Subject=\"");
|
|
|
|
GetAllNameFromName(name, sizeof(name), crl->Name);
|
|
UniStrCat(tmp, sizeof(tmp), name);
|
|
UniStrCat(tmp, sizeof(tmp), L"\", ");
|
|
}
|
|
|
|
if (crl->Serial != NULL)
|
|
{
|
|
// Serial information
|
|
char str[128];
|
|
wchar_t uni[128];
|
|
|
|
BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
|
|
StrToUni(uni, sizeof(uni), str);
|
|
UniStrCat(tmp, sizeof(tmp), L"Serial=\"");
|
|
UniStrCat(tmp, sizeof(tmp), uni);
|
|
UniStrCat(tmp, sizeof(tmp), L"\", ");
|
|
}
|
|
|
|
if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
|
|
{
|
|
// MD5
|
|
char str[128];
|
|
wchar_t uni[128];
|
|
|
|
BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
|
|
StrToUni(uni, sizeof(uni), str);
|
|
UniStrCat(tmp, sizeof(tmp), L"MD5=\"");
|
|
UniStrCat(tmp, sizeof(tmp), uni);
|
|
UniStrCat(tmp, sizeof(tmp), L"\", ");
|
|
}
|
|
|
|
if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
|
|
{
|
|
// MD5
|
|
char str[128];
|
|
wchar_t uni[128];
|
|
|
|
BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
|
|
StrToUni(uni, sizeof(uni), str);
|
|
UniStrCat(tmp, sizeof(tmp), L"SHA1=\"");
|
|
UniStrCat(tmp, sizeof(tmp), uni);
|
|
UniStrCat(tmp, sizeof(tmp), L"\", ");
|
|
}
|
|
|
|
if (UniEndWith(tmp, L", "))
|
|
{
|
|
tmp[UniStrLen(tmp) - 2] = 0;
|
|
}
|
|
|
|
return CopyUniStr(tmp);
|
|
}
|
|
|
|
// Check whether it matches the Certificate Revocation List entry
|
|
bool IsCertMatchCrl(X *x, CRL *crl)
|
|
{
|
|
bool b = true;
|
|
// Validate arguments
|
|
if (x == NULL || crl == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (crl->Serial != NULL)
|
|
{
|
|
// If a serial number is defined in the CRL
|
|
if (x->serial == NULL || CompareXSerial(x->serial, crl->Serial) == false)
|
|
{
|
|
// Serial number mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (IsZero(crl->DigestMD5, sizeof(crl->DigestMD5)) == false)
|
|
{
|
|
UCHAR test[MD5_SIZE];
|
|
// If a DigestMD5 is defined in the CRL
|
|
GetXDigest(x, test, false);
|
|
|
|
if (Cmp(test, crl->DigestMD5, MD5_SIZE) != 0)
|
|
{
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (IsZero(crl->DigestSHA1, sizeof(crl->DigestSHA1)) == false)
|
|
{
|
|
UCHAR test[SHA1_SIZE];
|
|
// If a DigestSHA1 is defined in the CRL
|
|
GetXDigest(x, test, true);
|
|
|
|
if (Cmp(test, crl->DigestSHA1, SHA1_SIZE) != 0)
|
|
{
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (crl->Name != NULL)
|
|
{
|
|
// If a name is defined in the CRL
|
|
NAME *xn, *cn;
|
|
xn = x->subject_name;
|
|
cn = crl->Name;
|
|
|
|
if (cn->CommonName != NULL && (UniIsEmptyStr(cn->CommonName) == false))
|
|
{
|
|
if (xn->CommonName == NULL || UniSoftStrCmp(xn->CommonName, cn->CommonName) != 0)
|
|
{
|
|
// CommonName mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (cn->Organization != NULL && (UniIsEmptyStr(cn->Organization) == false))
|
|
{
|
|
if (xn->Organization == NULL || UniSoftStrCmp(xn->Organization, cn->Organization) != 0)
|
|
{
|
|
// Organization mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (cn->Unit != NULL && (UniIsEmptyStr(cn->Unit) == false))
|
|
{
|
|
if (xn->Unit == NULL || UniSoftStrCmp(xn->Unit, cn->Unit) != 0)
|
|
{
|
|
// Unit mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (cn->Country != NULL && (UniIsEmptyStr(cn->Country) == false))
|
|
{
|
|
if (xn->Country == NULL || UniSoftStrCmp(xn->Country, cn->Country) != 0)
|
|
{
|
|
// Country mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (cn->State != NULL && (UniIsEmptyStr(cn->State) == false))
|
|
{
|
|
if (xn->State == NULL || UniSoftStrCmp(xn->State, cn->State) != 0)
|
|
{
|
|
// State mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
|
|
if (cn->Local != NULL && (UniIsEmptyStr(cn->Local) == false))
|
|
{
|
|
if (xn->Local == NULL || UniSoftStrCmp(xn->Local, cn->Local) != 0)
|
|
{
|
|
// Local mismatch
|
|
b = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
// Get the help string of administration options
|
|
wchar_t *GetHubAdminOptionHelpString(char *name)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
wchar_t *ret;
|
|
// Validate arguments
|
|
if (name == NULL)
|
|
{
|
|
return L"";
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "HUB_AO_%s", name);
|
|
|
|
ret = _UU(tmp);
|
|
if (UniIsEmptyStr(ret))
|
|
{
|
|
ret = _UU("HUB_AO_UNKNOWN");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Add the default administration options to the Virtual HUB
|
|
void AddHubAdminOptionsDefaults(HUB *h, bool lock)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (lock)
|
|
{
|
|
LockList(h->AdminOptionList);
|
|
}
|
|
|
|
for (i = 0;i < num_admin_options;i++)
|
|
{
|
|
ADMIN_OPTION *e = &admin_options[i];
|
|
ADMIN_OPTION t, *r;
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.Name, sizeof(t.Name), e->Name);
|
|
|
|
r = Search(h->AdminOptionList, &t);
|
|
if (r == NULL)
|
|
{
|
|
ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
|
|
|
|
StrCpy(a->Name, sizeof(a->Name), e->Name);
|
|
a->Value = e->Value;
|
|
|
|
Insert(h->AdminOptionList, a);
|
|
}
|
|
}
|
|
|
|
if (lock)
|
|
{
|
|
UnlockList(h->AdminOptionList);
|
|
}
|
|
}
|
|
|
|
// Delete all administration options of Virtual HUB
|
|
void DeleteAllHubAdminOption(HUB *h, bool lock)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (lock)
|
|
{
|
|
LockList(h->AdminOptionList);
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
|
|
{
|
|
Free(LIST_DATA(h->AdminOptionList, i));
|
|
}
|
|
|
|
DeleteAll(h->AdminOptionList);
|
|
|
|
if (lock)
|
|
{
|
|
UnlockList(h->AdminOptionList);
|
|
}
|
|
}
|
|
|
|
// Get the administration options for the virtual HUB
|
|
UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value)
|
|
{
|
|
UINT ret = default_value;
|
|
// Validate arguments
|
|
if (h == NULL || name == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
LockList(h->AdminOptionList);
|
|
{
|
|
ADMIN_OPTION *a, t;
|
|
|
|
Zero(&t, sizeof(t));
|
|
StrCpy(t.Name, sizeof(t.Name), name);
|
|
Trim(t.Name);
|
|
|
|
a = Search(h->AdminOptionList, &t);
|
|
|
|
if (a != NULL)
|
|
{
|
|
ret = a->Value;
|
|
}
|
|
}
|
|
UnlockList(h->AdminOptionList);
|
|
|
|
return ret;
|
|
}
|
|
UINT GetHubAdminOption(HUB *h, char *name)
|
|
{
|
|
return GetHubAdminOptionEx(h, name, 0);
|
|
}
|
|
|
|
// Administration options
|
|
int CompareAdminOption(void *p1, void *p2)
|
|
{
|
|
ADMIN_OPTION *a1, *a2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
a1 = *(ADMIN_OPTION **)p1;
|
|
a2 = *(ADMIN_OPTION **)p2;
|
|
if (a1 == NULL || a2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
return StrCmpi(a1->Name, a2->Name);
|
|
}
|
|
|
|
// Start the watchdog
|
|
void StartHubWatchDog(HUB *h)
|
|
{
|
|
THREAD *t;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
h->HaltWatchDog = false;
|
|
h->WatchDogEvent = NewEvent();
|
|
|
|
t = NewThread(HubWatchDogThread, h);
|
|
WaitThreadInit(t);
|
|
ReleaseThread(t);
|
|
}
|
|
|
|
// Stop the watchdog
|
|
void StopHubWatchDog(HUB *h)
|
|
{
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
h->HaltWatchDog = true;
|
|
Set(h->WatchDogEvent);
|
|
|
|
WaitThread(h->WatchDogThread, INFINITE);
|
|
ReleaseThread(h->WatchDogThread);
|
|
h->WatchDogThread = NULL;
|
|
h->HaltWatchDog = false;
|
|
|
|
ReleaseEvent(h->WatchDogEvent);
|
|
h->WatchDogEvent = NULL;
|
|
}
|
|
|
|
// Watchdog thread
|
|
void HubWatchDogThread(THREAD *t, void *param)
|
|
{
|
|
UINT num_packets_v4 = 0;
|
|
UINT num_packets_v6 = 0;
|
|
HUB *hub;
|
|
// Validate arguments
|
|
if (t == NULL || param == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
hub = (HUB *)param;
|
|
|
|
hub->WatchDogThread = t;
|
|
AddRef(t->ref);
|
|
|
|
NoticeThreadInit(t);
|
|
|
|
while (true)
|
|
{
|
|
LIST *o;
|
|
LIST *o2;
|
|
UINT i, num;
|
|
UINT interval;
|
|
UINT wait_time = 100;
|
|
if (hub->HaltWatchDog)
|
|
{
|
|
break;
|
|
}
|
|
|
|
o = NewListFast(NULL);
|
|
o2 = NewListFast(NULL);
|
|
|
|
// Send an ARP packet
|
|
LockHashList(hub->MacHashTable);
|
|
{
|
|
num = LIST_NUM(hub->IpTable);
|
|
for (i = 0;i < LIST_NUM(hub->IpTable);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
|
|
|
|
if (e == NULL) continue;
|
|
|
|
if ((e->UpdatedTime + (UINT64)(IP_TABLE_EXPIRE_TIME)) > Tick64())
|
|
{
|
|
if (e->MacAddress[0] != 0xff || e->MacAddress[1] != 0xff || e->MacAddress[2] != 0xff ||
|
|
e->MacAddress[3] != 0xff || e->MacAddress[4] != 0xff || e->MacAddress[5] != 0xff)
|
|
{
|
|
if (hub->Option != NULL && hub->Option->NoArpPolling == false)
|
|
{
|
|
if (IsIP4(&e->Ip))
|
|
{
|
|
// IPv4
|
|
MAC_HEADER *mac = ZeroMalloc(sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
|
|
ARPV4_HEADER *p = (ARPV4_HEADER *)(((UCHAR *)mac) + sizeof(MAC_HEADER));
|
|
|
|
Copy(mac->DestAddress, e->MacAddress, 6);
|
|
Copy(mac->SrcAddress, hub->HubMacAddr, 6);
|
|
mac->Protocol = Endian16(MAC_PROTO_ARPV4);
|
|
|
|
p->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
|
|
p->ProtocolType = Endian16(MAC_PROTO_IPV4);
|
|
p->HardwareSize = 6;
|
|
p->ProtocolSize = 4;
|
|
p->Operation = Endian16(ARP_OPERATION_REQUEST);
|
|
Copy(p->SrcAddress, hub->HubMacAddr, 6);
|
|
p->SrcIP = IPToUINT(&hub->HubIp);
|
|
p->TargetAddress[0] =
|
|
p->TargetAddress[1] =
|
|
p->TargetAddress[2] =
|
|
p->TargetAddress[3] =
|
|
p->TargetAddress[4] =
|
|
p->TargetAddress[5] = 0x00;
|
|
p->TargetIP = IPToUINT(&e->Ip);
|
|
Insert(o, mac);
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->NoIPv6AddrPolling == false)
|
|
{
|
|
if (IsIP6(&e->Ip))
|
|
{
|
|
// IPv6
|
|
BUF *buf;
|
|
IPV6_ADDR ip6addr;
|
|
|
|
if (IPToIPv6Addr(&ip6addr, &e->Ip))
|
|
{
|
|
buf = BuildICMPv6NeighborSoliciation(&hub->HubIpV6,
|
|
&ip6addr,
|
|
hub->HubMacAddr, ++hub->HubIP6Id);
|
|
|
|
if (buf != NULL)
|
|
{
|
|
BUF *buf2 = NewBuf();
|
|
MAC_HEADER mac;
|
|
|
|
Zero(&mac, sizeof(mac));
|
|
|
|
Copy(mac.DestAddress, e->MacAddress, 6);
|
|
Copy(mac.SrcAddress, hub->HubMacAddr, 6);
|
|
mac.Protocol = Endian16(MAC_PROTO_IPV6);
|
|
|
|
WriteBuf(buf2, &mac, sizeof(MAC_HEADER));
|
|
|
|
WriteBuf(buf2, buf->Buf, buf->Size);
|
|
|
|
FreeBuf(buf);
|
|
|
|
Insert(o2, buf2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UnlockHashList(hub->MacHashTable);
|
|
|
|
if ((LIST_NUM(o) + LIST_NUM(o2)) != 0)
|
|
{
|
|
interval = HUB_ARP_SEND_INTERVAL / (LIST_NUM(o) + LIST_NUM(o2));
|
|
}
|
|
else
|
|
{
|
|
interval = HUB_ARP_SEND_INTERVAL;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
PKT *packet;
|
|
void *p = LIST_DATA(o, i);
|
|
|
|
Wait(hub->WatchDogEvent, interval);
|
|
if (hub->HaltWatchDog)
|
|
{
|
|
for (;i < LIST_NUM(o);i++)
|
|
{
|
|
Free(LIST_DATA(o, i));
|
|
}
|
|
ReleaseList(o);
|
|
|
|
for (i = 0;i < LIST_NUM(o2);i++)
|
|
{
|
|
FreeBuf(LIST_DATA(o2, i));
|
|
}
|
|
ReleaseList(o2);
|
|
goto ESCAPE;
|
|
}
|
|
|
|
packet = ParsePacket((UCHAR *)p, sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
|
|
if (packet != NULL)
|
|
{
|
|
StorePacket(hub, NULL, packet);
|
|
num_packets_v4++;
|
|
}
|
|
else
|
|
{
|
|
Free(p);
|
|
}
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o2);i++)
|
|
{
|
|
PKT *packet;
|
|
BUF *buf = LIST_DATA(o2, i);
|
|
|
|
Wait(hub->WatchDogEvent, interval);
|
|
if (hub->HaltWatchDog)
|
|
{
|
|
ReleaseList(o);
|
|
|
|
for (;i < LIST_NUM(o2);i++)
|
|
{
|
|
FreeBuf(LIST_DATA(o2, i));
|
|
}
|
|
ReleaseList(o2);
|
|
goto ESCAPE;
|
|
}
|
|
|
|
packet = ParsePacket(buf->Buf, buf->Size);
|
|
if (packet != NULL)
|
|
{
|
|
StorePacket(hub, NULL, packet);
|
|
num_packets_v6++;
|
|
}
|
|
else
|
|
{
|
|
Free(buf->Buf);
|
|
}
|
|
|
|
Free(buf);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
ReleaseList(o2);
|
|
|
|
if (num == 0)
|
|
{
|
|
wait_time = HUB_ARP_SEND_INTERVAL;
|
|
}
|
|
|
|
Wait(hub->WatchDogEvent, wait_time);
|
|
}
|
|
ESCAPE:
|
|
return;
|
|
}
|
|
|
|
// Enable / disable the SecureNAT
|
|
void EnableSecureNAT(HUB *h, bool enable)
|
|
{
|
|
EnableSecureNATEx(h, enable, false);
|
|
}
|
|
void EnableSecureNATEx(HUB *h, bool enable, bool no_change)
|
|
{
|
|
bool for_cluster = false;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
|
|
{
|
|
if (h->Type == HUB_TYPE_FARM_DYNAMIC)
|
|
{
|
|
for_cluster = true;
|
|
}
|
|
}
|
|
|
|
Lock(h->lock_online);
|
|
{
|
|
if (no_change == false)
|
|
{
|
|
h->EnableSecureNAT = enable;
|
|
}
|
|
|
|
if (h->EnableSecureNAT == false)
|
|
{
|
|
STOP:
|
|
// Stop if it's already started
|
|
if (h->SecureNAT != NULL)
|
|
{
|
|
SnFreeSecureNAT(h->SecureNAT);
|
|
h->SecureNAT = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (for_cluster)
|
|
{
|
|
if ((h->SecureNAT != NULL && LIST_NUM(h->SessionList) <= 1) ||
|
|
(h->SecureNAT == NULL && LIST_NUM(h->SessionList) == 0))
|
|
{
|
|
// It is in a start mode, but stop when there is no other sessions
|
|
// in the case of dynamic Virtual HUB
|
|
goto STOP;
|
|
}
|
|
}
|
|
|
|
// Start if the HUB is online and not started
|
|
if (h->SecureNAT == NULL && h->Offline == false)
|
|
{
|
|
h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
|
|
}
|
|
}
|
|
}
|
|
Unlock(h->lock_online);
|
|
}
|
|
|
|
// Convert an access list to a string
|
|
void GetAccessListStr(char *str, UINT size, ACCESS *a)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
char tmp1[MAX_SIZE];
|
|
char tmp2[MAX_SIZE];
|
|
bool l3 = false;
|
|
bool asterisk = false;
|
|
// Validate arguments
|
|
if (str == NULL || a == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StrCpy(str, size, "");
|
|
|
|
if (a->IsIPv6 == false)
|
|
{
|
|
if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
|
|
{
|
|
IPToStr32(tmp1, sizeof(tmp1), a->SrcIpAddress);
|
|
MaskToStr32(tmp2, sizeof(tmp2), a->SrcSubnetMask);
|
|
Format(tmp, sizeof(tmp), "SrcIPv4=%s/%s, ", tmp1, tmp2);
|
|
StrCat(str, size, tmp);
|
|
|
|
l3 = true;
|
|
}
|
|
|
|
if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
|
|
{
|
|
IPToStr32(tmp1, sizeof(tmp1), a->DestIpAddress);
|
|
MaskToStr32(tmp2, sizeof(tmp2), a->DestSubnetMask);
|
|
Format(tmp, sizeof(tmp), "DstIPv4=%s/%s, ", tmp1, tmp2);
|
|
StrCat(str, size, tmp);
|
|
|
|
l3 = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsZeroIP6Addr(&a->SrcIpAddress6) == false || IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
|
|
{
|
|
IP6AddrToStr(tmp1, sizeof(tmp1), &a->SrcIpAddress6);
|
|
Mask6AddrToStr(tmp2, sizeof(tmp2), &a->SrcSubnetMask6);
|
|
Format(tmp, sizeof(tmp), "SrcIPv6=%s/%s, ", tmp1, tmp2);
|
|
StrCat(str, size, tmp);
|
|
|
|
l3 = true;
|
|
}
|
|
|
|
if (IsZeroIP6Addr(&a->DestIpAddress6) == false || IsZeroIP6Addr(&a->DestSubnetMask6) == false)
|
|
{
|
|
IP6AddrToStr(tmp1, sizeof(tmp1), &a->DestIpAddress6);
|
|
Mask6AddrToStr(tmp2, sizeof(tmp2), &a->DestSubnetMask6);
|
|
Format(tmp, sizeof(tmp), "DstIPv6=%s/%s, ", tmp1, tmp2);
|
|
StrCat(str, size, tmp);
|
|
|
|
l3 = true;
|
|
}
|
|
}
|
|
|
|
if (a->Protocol != 0)
|
|
{
|
|
StrCpy(tmp1, sizeof(tmp1), "");
|
|
switch (a->Protocol)
|
|
{
|
|
case 1:
|
|
StrCpy(tmp1, sizeof(tmp1), "ICMPv4");
|
|
break;
|
|
case 3:
|
|
StrCpy(tmp1, sizeof(tmp1), "GGP");
|
|
break;
|
|
case 6:
|
|
StrCpy(tmp1, sizeof(tmp1), "TCP");
|
|
break;
|
|
case 8:
|
|
StrCpy(tmp1, sizeof(tmp1), "EGP");
|
|
break;
|
|
case 12:
|
|
StrCpy(tmp1, sizeof(tmp1), "PUP");
|
|
break;
|
|
case 17:
|
|
StrCpy(tmp1, sizeof(tmp1), "UDP");
|
|
break;
|
|
case 20:
|
|
StrCpy(tmp1, sizeof(tmp1), "HMP");
|
|
break;
|
|
case 22:
|
|
StrCpy(tmp1, sizeof(tmp1), "XNS-IDP");
|
|
break;
|
|
case 27:
|
|
StrCpy(tmp1, sizeof(tmp1), "RDP");
|
|
break;
|
|
case 58:
|
|
StrCpy(tmp1, sizeof(tmp1), "ICMPv6");
|
|
break;
|
|
case 66:
|
|
StrCpy(tmp1, sizeof(tmp1), "RVD");
|
|
break;
|
|
}
|
|
|
|
if (IsEmptyStr(tmp1))
|
|
{
|
|
Format(tmp, sizeof(tmp), "Protocol=%s(%u), ", tmp1, a->Protocol);
|
|
}
|
|
else
|
|
{
|
|
Format(tmp, sizeof(tmp), "Protocol=%s, ", tmp1);
|
|
}
|
|
|
|
StrCat(str, size, tmp);
|
|
|
|
l3 = true;
|
|
}
|
|
|
|
if (a->SrcPortStart != 0)
|
|
{
|
|
if (a->SrcPortEnd == a->SrcPortStart)
|
|
{
|
|
Format(tmp, sizeof(tmp), "SrcPort=%u, ", a->SrcPortStart);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
else
|
|
{
|
|
Format(tmp, sizeof(tmp), "SrcPort=%u-%u, ", a->SrcPortStart, a->SrcPortEnd);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
l3 = true;
|
|
}
|
|
|
|
if (a->DestPortStart != 0)
|
|
{
|
|
if (a->DestPortEnd == a->DestPortStart)
|
|
{
|
|
Format(tmp, sizeof(tmp), "DstPort=%u, ", a->DestPortStart);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
else
|
|
{
|
|
Format(tmp, sizeof(tmp), "DstPort=%u-%u, ", a->DestPortStart, a->DestPortEnd);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
l3 = true;
|
|
}
|
|
|
|
if (StrLen(a->SrcUsername) != 0)
|
|
{
|
|
Format(tmp, sizeof(tmp), "SrcUser=%s, ", a->SrcUsername);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
if (StrLen(a->DestUsername) != 0)
|
|
{
|
|
Format(tmp, sizeof(tmp), "DstUser=%s, ", a->DestUsername);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
if (a->CheckSrcMac != false)
|
|
{
|
|
char mac[MAX_SIZE], mask[MAX_SIZE];
|
|
MacToStr(mac, sizeof(mac), a->SrcMacAddress);
|
|
MacToStr(mask, sizeof(mask), a->SrcMacMask);
|
|
Format(tmp, sizeof(tmp), "SrcMac=%s/%s, ", mac, mask);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
if (a->CheckDstMac != false)
|
|
{
|
|
char mac[MAX_SIZE], mask[MAX_SIZE];
|
|
MacToStr(mac, sizeof(mac), a->DstMacAddress);
|
|
MacToStr(mask, sizeof(mask), a->DstMacMask);
|
|
Format(tmp, sizeof(tmp), "DstMac=%s/%s, ", mac, mask);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
if (a->CheckTcpState)
|
|
{
|
|
if(a->Established)
|
|
{
|
|
StrCat(str, size, "Established, ");
|
|
}
|
|
else
|
|
{
|
|
StrCat(str, size, "Unestablished, ");
|
|
}
|
|
|
|
l3 = true;
|
|
}
|
|
|
|
if (a->Discard == false)
|
|
{
|
|
if (a->Delay >= 1)
|
|
{
|
|
Format(tmp, sizeof(tmp), "Delay=%u, ", a->Delay);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
if (a->Jitter >= 1)
|
|
{
|
|
Format(tmp, sizeof(tmp), "Jitter=%u, ", a->Jitter);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
if (a->Loss >= 1)
|
|
{
|
|
Format(tmp, sizeof(tmp), "Loss=%u, " , a->Loss);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
}
|
|
|
|
if (IsEmptyStr(a->RedirectUrl) == false)
|
|
{
|
|
Format(tmp, sizeof(tmp), "RedirectUrl=%s, ", a->RedirectUrl);
|
|
StrCat(str, size, tmp);
|
|
}
|
|
|
|
if (StrLen(str) == 0)
|
|
{
|
|
asterisk = true;
|
|
}
|
|
|
|
if (l3)
|
|
{
|
|
if (a->IsIPv6)
|
|
{
|
|
StrCatLeft(str, size, "(ipv6) ");
|
|
}
|
|
else
|
|
{
|
|
StrCatLeft(str, size, "(ipv4) ");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StrCatLeft(str, size, "(ether) ");
|
|
}
|
|
|
|
if (EndWith(str, ", "))
|
|
{
|
|
str[StrLen(str) - 2] = 0;
|
|
}
|
|
|
|
if (asterisk)
|
|
{
|
|
StrCat(str, size, "*");
|
|
}
|
|
}
|
|
|
|
// Determine whether the access list can mask the packet
|
|
bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT64 dest_username, UINT64 dest_groupname, SESSION *dest_session)
|
|
{
|
|
UINT64 src_username;
|
|
UINT64 src_username_simple;
|
|
UINT64 src_groupname;
|
|
HUB_PA *pa;
|
|
IPV4_HEADER *ip = NULL;
|
|
IPV6_HEADER *ip6 = NULL;
|
|
bool is_ipv4_packet = false;
|
|
bool is_ipv6_packet = false;
|
|
bool is_arp_packet = false;
|
|
// Validate arguments
|
|
if (s == NULL || p == NULL || a == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
if (a->Active == false)
|
|
{
|
|
// Access list is inactive
|
|
return false;
|
|
}
|
|
|
|
pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
|
|
// Hash of the source user name
|
|
src_username = pa->UsernameHash;
|
|
src_username_simple = pa->UsernameHashSimple;
|
|
src_groupname = pa->GroupnameHash;
|
|
|
|
// Determine the source and destination MAC address
|
|
if (a->CheckSrcMac != false)
|
|
{
|
|
UINT i;
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if((a->SrcMacAddress[i] & a->SrcMacMask[i]) != (a->SrcMacMask[i] & p->MacAddressSrc[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (a->CheckDstMac != false)
|
|
{
|
|
UINT i;
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if ((a->DstMacAddress[i] & a->DstMacMask[i]) != (a->DstMacMask[i] & p->MacAddressDest[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the source user name / group name
|
|
if (a->SrcUsernameHash != 0)
|
|
{
|
|
if (a->IsSrcUsernameIncludeOrExclude == false)
|
|
{
|
|
// It is specified as a regular user name
|
|
if ((a->SrcUsernameHash != src_username) && (a->SrcUsernameHash != src_groupname))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// It is specified in the form of a exclude:FILENAME or include:FILENAME
|
|
HUB *hub = s->Hub;
|
|
|
|
if (hub != NULL)
|
|
{
|
|
LIST *o = hub->UserList;
|
|
|
|
if (s->NormalClient == false)
|
|
{
|
|
// The internal session don't become target for format exclude: or include:
|
|
return false;
|
|
}
|
|
|
|
if (IsUserMatchInUserListWithCacheExpiresAcl(o, a->SrcUsername, src_username,
|
|
hub->Option->AccessListIncludeFileCacheLifetime * 1000) == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the destination user name / group name
|
|
if (a->DestUsernameHash != 0)
|
|
{
|
|
if (a->IsDestUsernameIncludeOrExclude == false)
|
|
{
|
|
// It is specified as a regular user name
|
|
if ((a->DestUsernameHash != dest_username) && (a->DestUsernameHash != dest_groupname))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// It is specified in the form of a exclude:FILENAME or include:FILENAME
|
|
HUB *hub = s->Hub;
|
|
|
|
if (hub != NULL)
|
|
{
|
|
LIST *o = hub->UserList;
|
|
|
|
if (dest_session != NULL && dest_session->NormalClient == false)
|
|
{
|
|
// The internal session don't become target for format exclude: or include:
|
|
return false;
|
|
}
|
|
|
|
if (IsUserMatchInUserListWithCacheExpiresAcl(o, a->DestUsername, dest_username,
|
|
hub->Option->AccessListIncludeFileCacheLifetime * 1000) == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Determine of the IP packet
|
|
if (p->TypeL3 != L3_IPV4)
|
|
{
|
|
is_ipv4_packet = false;
|
|
}
|
|
else
|
|
{
|
|
is_ipv4_packet = true;
|
|
}
|
|
|
|
if (p->TypeL3 != L3_IPV6)
|
|
{
|
|
is_ipv6_packet = false;
|
|
}
|
|
else
|
|
{
|
|
is_ipv6_packet = true;
|
|
}
|
|
|
|
if (p->TypeL3 == L3_ARPV4)
|
|
{
|
|
is_arp_packet = true;
|
|
}
|
|
|
|
if (is_ipv4_packet)
|
|
{
|
|
ip = p->L3.IPv4Header;
|
|
}
|
|
|
|
if (is_ipv6_packet)
|
|
{
|
|
ip6 = p->L3.IPv6Header;
|
|
}
|
|
|
|
if (a->IsIPv6 == false)
|
|
{
|
|
// IPv4
|
|
|
|
// Check the source IP address
|
|
if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
|
|
{
|
|
if (is_ipv4_packet == false)
|
|
{
|
|
if (p->TypeL3 == L3_ARPV4)
|
|
{
|
|
bool arp_match = false;
|
|
if (p->L3.ARPv4Header->HardwareSize == 6 &&
|
|
Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
|
|
p->L3.ARPv4Header->ProtocolSize == 4 &&
|
|
Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
|
|
{
|
|
UINT uint_ip = p->L3.ARPv4Header->SrcIP;
|
|
|
|
if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
|
|
{
|
|
if ((uint_ip & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
arp_match = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (arp_match == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((ip->SrcIP & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the destination IP address
|
|
if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
|
|
{
|
|
if (is_ipv4_packet == false)
|
|
{
|
|
if (p->TypeL3 == L3_ARPV4)
|
|
{
|
|
bool arp_match = false;
|
|
if (p->L3.ARPv4Header->HardwareSize == 6 &&
|
|
Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
|
|
p->L3.ARPv4Header->ProtocolSize == 4 &&
|
|
Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
|
|
{
|
|
UINT uint_ip = p->L3.ARPv4Header->TargetIP;
|
|
|
|
if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
|
|
{
|
|
if ((uint_ip & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
arp_match = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (arp_match == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((ip->DstIP & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// IPv6
|
|
|
|
// Check the source IP address
|
|
if (IsZeroIP6Addr(&a->SrcIpAddress6) == false ||
|
|
IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
|
|
{
|
|
if (is_ipv6_packet == false)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
IP a_ip, a_subnet, p_ip;
|
|
IP and1, and2;
|
|
|
|
IPv6AddrToIP(&a_ip, &a->SrcIpAddress6);
|
|
IPv6AddrToIP(&a_subnet, &a->SrcSubnetMask6);
|
|
IPv6AddrToIP(&p_ip, &ip6->SrcAddress);
|
|
|
|
IPAnd6(&and1, &a_ip, &a_subnet);
|
|
IPAnd6(&and2, &p_ip, &a_subnet);
|
|
|
|
if (CmpIpAddr(&and1, &and2) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the destination IP address
|
|
if (IsZeroIP6Addr(&a->DestIpAddress6) == false ||
|
|
IsZeroIP6Addr(&a->DestSubnetMask6) == false)
|
|
{
|
|
if (is_ipv6_packet == false)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
IP a_ip, a_subnet, p_ip;
|
|
IP and1, and2;
|
|
|
|
IPv6AddrToIP(&a_ip, &a->DestIpAddress6);
|
|
IPv6AddrToIP(&a_subnet, &a->DestSubnetMask6);
|
|
IPv6AddrToIP(&p_ip, &ip6->DestAddress);
|
|
|
|
IPAnd6(&and1, &a_ip, &a_subnet);
|
|
IPAnd6(&and2, &p_ip, &a_subnet);
|
|
|
|
if (CmpIpAddr(&and1, &and2) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Don't match the packet of non-IPv4 and non-IPv6
|
|
if (is_arp_packet)
|
|
{
|
|
if (s->Hub != NULL && s->Hub->Option != NULL && s->Hub->Option->ApplyIPv4AccessListOnArpPacket)
|
|
{
|
|
// Match the ARP only if ApplyIPv4AccessListOnArpPacket option is enabled
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check the protocol number
|
|
if (a->Protocol != 0)
|
|
{
|
|
if (a->IsIPv6 == false)
|
|
{
|
|
if (is_ipv4_packet == false)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (ip->Protocol != a->Protocol)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (is_ipv6_packet == false)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (p->IPv6HeaderPacketInfo.Protocol != a->Protocol)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the port number
|
|
if (a->SrcPortStart != 0 || a->DestPortStart != 0 ||
|
|
a->SrcPortEnd != 0 || a->DestPortEnd != 0)
|
|
{
|
|
if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
|
|
(a->IsIPv6 && is_ipv6_packet == false))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (p->TypeL4 == L4_TCP)
|
|
{
|
|
TCP_HEADER *tcp = p->L4.TCPHeader;
|
|
// Check the source port
|
|
if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
|
|
{
|
|
UINT src_port = Endian16(tcp->SrcPort);
|
|
if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check the destination port number
|
|
if (a->DestPortStart != 0 || a->DestPortEnd != 0)
|
|
{
|
|
UINT dest_port = Endian16(tcp->DstPort);
|
|
if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else if (p->TypeL4 == L4_UDP)
|
|
{
|
|
UDP_HEADER *udp = p->L4.UDPHeader;
|
|
// Check the source port
|
|
if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
|
|
{
|
|
UINT src_port = Endian16(udp->SrcPort);
|
|
if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check the destination port number
|
|
if (a->DestPortStart != 0 || a->DestPortEnd != 0)
|
|
{
|
|
UINT dest_port = Endian16(udp->DstPort);
|
|
if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// When the port number is specified in the access list,
|
|
// The rule is applied only for UDP or TCP packets
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check the status of the TCP connection
|
|
if (a->CheckTcpState != false)
|
|
{
|
|
if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
|
|
(a->IsIPv6 && is_ipv6_packet == false))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(p->TypeL4 == L4_TCP)
|
|
{
|
|
// by shimizu
|
|
TCP_HEADER *tcp = p->L4.TCPHeader;
|
|
bool est = true;
|
|
|
|
if ((tcp->Flag & TCP_SYN) && (!(tcp->Flag & TCP_ACK)))
|
|
{
|
|
est = false;
|
|
}
|
|
|
|
if((MAKEBOOL(a->Established) ^ MAKEBOOL(est)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Apply the access list for packets to forward
|
|
bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p)
|
|
{
|
|
UINT i;
|
|
bool pass = true; // Pass by default
|
|
bool skip = true;
|
|
// Validate arguments
|
|
if (hub == NULL || src_session == NULL || p == NULL || dest_session == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// The access list is not re-applied for packets that have been already checked
|
|
if (p->AccessChecked)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
LockList(hub->AccessList);
|
|
{
|
|
for (i = 0;i < LIST_NUM(hub->AccessList);i++)
|
|
{
|
|
ACCESS *a = LIST_DATA(hub->AccessList, i);
|
|
|
|
// Scan the entry only after the destination user name is specified.
|
|
if (a->DestUsernameHash != 0)
|
|
{
|
|
skip = false;
|
|
}
|
|
|
|
if (skip == false)
|
|
{
|
|
if (IsPacketMaskedByAccessList(src_session, p, a,
|
|
((HUB_PA *)dest_session->PacketAdapter->Param)->UsernameHash,
|
|
((HUB_PA *)dest_session->PacketAdapter->Param)->GroupnameHash,
|
|
dest_session))
|
|
{
|
|
// Determine the pass or discard the packet
|
|
pass = a->Discard ? false : true;
|
|
|
|
// Complete the scanning of the list here
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UnlockList(hub->AccessList);
|
|
|
|
return pass;
|
|
}
|
|
|
|
// Generate a HTTP payload for redirect
|
|
BUF *BuildRedirectToUrlPayload(HUB *hub, SESSION *s, char *redirect_url)
|
|
{
|
|
char html[MAX_REDIRECT_URL_LEN * 2 + 1 + MAX_SIZE];
|
|
char header[MAX_REDIRECT_URL_LEN * 2 + 1 + MAX_SIZE];
|
|
char redirect_url2[MAX_REDIRECT_URL_LEN * 2];
|
|
BUF *b;
|
|
// Validate arguments
|
|
if (hub == NULL || s == NULL || redirect_url == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
StrCpy(redirect_url2, sizeof(redirect_url2), redirect_url);
|
|
Trim(redirect_url2);
|
|
|
|
if (InStr(redirect_url2, ACCESS_LIST_URL_INFO_TAG))
|
|
{
|
|
// Get the secret key string
|
|
char secret[MAX_SIZE];
|
|
char tmp[MAX_SIZE];
|
|
SYSTEMTIME st;
|
|
UINT i, len, isp;
|
|
|
|
isp = INFINITE;
|
|
|
|
SystemTime(&st);
|
|
ClearStr(secret, sizeof(secret));
|
|
|
|
len = StrLen(redirect_url2);
|
|
|
|
for (i = 0;i < len;i++)
|
|
{
|
|
char c = redirect_url2[i];
|
|
if (c == '|')
|
|
{
|
|
isp = i;
|
|
}
|
|
}
|
|
|
|
if (isp != INFINITE)
|
|
{
|
|
StrCpy(secret, sizeof(secret), redirect_url2 + isp + 1);
|
|
redirect_url2[isp] = 0;
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "%s|%s|%r|%04u%02u%02u%02u%02u%02u%s",
|
|
s->Username, s->Name, &s->Connection->ClientIp,
|
|
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, (IsEmptyStr(secret) ? "" : "|"));
|
|
|
|
if (IsEmptyStr(secret) == false)
|
|
{
|
|
// Calculate the hash
|
|
UCHAR hash[SHA1_SIZE];
|
|
char hash_str[MAX_SIZE];
|
|
BUF *b2 = NewBuf();
|
|
|
|
WriteBuf(b2, tmp, StrLen(tmp));
|
|
WriteBuf(b2, secret, StrLen(secret));
|
|
|
|
Sha1(hash, b2->Buf, b2->Size);
|
|
|
|
BinToStr(hash_str, sizeof(hash_str), hash, sizeof(hash));
|
|
|
|
FreeBuf(b2);
|
|
|
|
StrCat(tmp, sizeof(tmp), hash_str);
|
|
|
|
// Replace
|
|
ReplaceStrEx(redirect_url2, sizeof(redirect_url2), redirect_url2,
|
|
ACCESS_LIST_URL_INFO_TAG, tmp, false);
|
|
}
|
|
}
|
|
|
|
Format(html, sizeof(html),
|
|
"<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved to <a href=\"%s\">here</a>.</h2>\r\n</body></html>\r\n\r\n",
|
|
redirect_url2);
|
|
|
|
Format(header, sizeof(header),
|
|
"HTTP/1.1 302 Found\r\nLocation: %s\r\nCache-Control: private\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %u\r\n\r\n",
|
|
redirect_url2, StrLen(redirect_url2));
|
|
|
|
b = NewBuf();
|
|
|
|
WriteBuf(b, header, StrLen(header));
|
|
WriteBuf(b, html, StrLen(html));
|
|
|
|
return b;
|
|
}
|
|
|
|
// Rpely a TCP response packet to redirect forcibly to the specified URL
|
|
void ForceRedirectToUrl(HUB *hub, SESSION *src_session, PKT *p, char *redirect_url)
|
|
{
|
|
BUF *payload;
|
|
UINT tcp_size;
|
|
TCP_HEADER *tcp_data;
|
|
TCP_HEADER *src_tcp;
|
|
BUF *b;
|
|
// Validate arguments
|
|
if (hub == NULL || src_session == NULL || p == NULL || redirect_url == NULL)
|
|
{
|
|
return;
|
|
}
|
|
if (p->TypeL3 != L3_IPV4 && p->TypeL3 != L3_IPV6)
|
|
{
|
|
return;
|
|
}
|
|
if (p->TypeL4 != L4_TCP)
|
|
{
|
|
return;
|
|
}
|
|
|
|
src_tcp = p->L4.TCPHeader;
|
|
if (src_tcp == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Generate a payload to be sent
|
|
payload = BuildRedirectToUrlPayload(hub, src_session, redirect_url);
|
|
if (payload == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Generate a TCP packet
|
|
tcp_size = sizeof(TCP_HEADER) + payload->Size;
|
|
tcp_data = (TCP_HEADER *)ZeroMalloc(tcp_size);
|
|
tcp_data->SrcPort = src_tcp->DstPort;
|
|
tcp_data->DstPort = src_tcp->SrcPort;
|
|
tcp_data->SeqNumber = src_tcp->AckNumber;
|
|
tcp_data->AckNumber = Endian32(Endian32(src_tcp->SeqNumber) + p->PayloadSize);
|
|
TCP_SET_HEADER_SIZE(tcp_data, 5);
|
|
tcp_data->Flag = TCP_ACK | TCP_PSH;
|
|
tcp_data->WindowSize = Endian16(0xFFFF);
|
|
Copy(((UCHAR *)tcp_data) + sizeof(TCP_HEADER), payload->Buf, payload->Size);
|
|
|
|
// Calculate the TCP checksum
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
// IPv4
|
|
tcp_data->Checksum = CalcChecksumForIPv4(p->L3.IPv4Header->DstIP, p->L3.IPv4Header->SrcIP, IP_PROTO_TCP,
|
|
tcp_data, tcp_size, 0);
|
|
}
|
|
else
|
|
{
|
|
// IPv6
|
|
tcp_data->Checksum = CalcChecksumForIPv6(&p->IPv6HeaderPacketInfo.IPv6Header->DestAddress,
|
|
&p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress, IP_PROTO_TCP, tcp_data, tcp_size, 0);
|
|
}
|
|
|
|
// Generate the Ethernet and IP packet
|
|
b = NewBuf();
|
|
|
|
// Destination MAC address
|
|
WriteBuf(b, p->MacHeader->SrcAddress, 6);
|
|
WriteBuf(b, p->MacHeader->DestAddress, 6);
|
|
WriteBuf(b, &p->MacHeader->Protocol, 2);
|
|
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
// IPv4
|
|
IPV4_HEADER v4;
|
|
|
|
Zero(&v4, sizeof(v4));
|
|
|
|
IPV4_SET_VERSION(&v4, 4);
|
|
IPV4_SET_HEADER_LEN(&v4, 5);
|
|
v4.TotalLength = Endian16((USHORT)(sizeof(IPV4_HEADER) + tcp_size));
|
|
v4.Identification = Endian16(Rand16());
|
|
IPV4_SET_FLAGS(&v4, 0x02);
|
|
v4.TimeToLive = 128;
|
|
v4.Protocol = IP_PROTO_TCP;
|
|
v4.SrcIP = p->L3.IPv4Header->DstIP;
|
|
v4.DstIP = p->L3.IPv4Header->SrcIP;
|
|
v4.Checksum = IpChecksum(&v4, sizeof(v4));
|
|
|
|
WriteBuf(b, &v4, sizeof(v4));
|
|
}
|
|
else
|
|
{
|
|
// IPv6
|
|
IPV6_HEADER v6;
|
|
|
|
Zero(&v6, sizeof(v6));
|
|
|
|
IPV6_SET_VERSION(&v6, 6);
|
|
v6.PayloadLength = Endian16(tcp_size);
|
|
v6.NextHeader = IP_PROTO_TCP;
|
|
v6.HopLimit = 64;
|
|
|
|
Copy(&v6.SrcAddress, &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress, sizeof(IPV6_ADDR));
|
|
Copy(&v6.DestAddress, &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress, sizeof(IPV6_ADDR));
|
|
|
|
WriteBuf(b, &v6, sizeof(v6));
|
|
}
|
|
|
|
WriteBuf(b, tcp_data, tcp_size);
|
|
|
|
// Reply packet
|
|
StorePacketToHubPa((HUB_PA *)src_session->PacketAdapter->Param,
|
|
NULL, b->Buf, b->Size, NULL, false, false);
|
|
|
|
// Release the memory
|
|
Free(tcp_data);
|
|
FreeBuf(payload);
|
|
Free(b);
|
|
}
|
|
|
|
// Apply the access list for packets stored
|
|
bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p)
|
|
{
|
|
UINT i;
|
|
bool pass = true; // Pass by default
|
|
bool use_redirect_url = false;
|
|
char redirect_url[MAX_REDIRECT_URL_LEN + 1];
|
|
// Validate arguments
|
|
if (hub == NULL || s == NULL || p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->FilterPPPoE)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (proto == 0x8863 || proto == 0x8864)
|
|
{
|
|
// PPPoE Filter
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->FilterOSPF)
|
|
{
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
if (p->L3.IPv4Header != NULL)
|
|
{
|
|
if (p->L3.IPv4Header->Protocol == 89)
|
|
{
|
|
// OSPF Filter
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->FilterIPv4)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (proto == 0x0800 || proto == 0x0806)
|
|
{
|
|
// IPv4 Filter
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->FilterIPv6)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (proto == 0x86dd)
|
|
{
|
|
// IPv6 Filter
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->FilterNonIP)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
|
|
{
|
|
// Non-IP Filter
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL && hub->Option->FilterBPDU)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
if (p->TypeL3 == L3_BPDU)
|
|
{
|
|
// BPDU Filter
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
LockList(hub->AccessList);
|
|
{
|
|
for (i = 0;i < LIST_NUM(hub->AccessList);i++)
|
|
{
|
|
ACCESS *a = LIST_DATA(hub->AccessList, i);
|
|
|
|
if (a->DestUsernameHash != 0)
|
|
{
|
|
// If a destination user name is specified, suspend the scanning of the list.
|
|
break;
|
|
}
|
|
|
|
if (IsPacketMaskedByAccessList(s, p, a, 0, 0, NULL))
|
|
{
|
|
// Determine the pass or discard the packet
|
|
pass = a->Discard ? false : true;
|
|
|
|
// Packets determined processing here is not scanned when leaving the HUB.
|
|
p->AccessChecked = true;
|
|
|
|
// Copy of the parameters of the delay jitter packet loss
|
|
p->Delay = a->Delay;
|
|
p->Jitter = a->Jitter;
|
|
p->Loss = a->Loss;
|
|
|
|
if (a->RedirectUrl[0] != 0)
|
|
{
|
|
// There is a setting of URL redirection in the access list
|
|
if ((p->TypeL3 == L3_IPV4 || p->TypeL3 == L3_IPV6) &&
|
|
p->TypeL4 == L4_TCP)
|
|
{
|
|
TCP_HEADER *tcp = p->L4.TCPHeader;
|
|
|
|
// Examine whether this packet is a TCP data packet
|
|
if (tcp != NULL)
|
|
{
|
|
if (tcp->Flag & TCP_ACK)
|
|
{
|
|
if ((tcp->Flag & TCP_SYN) == 0 &&
|
|
(tcp->Flag & TCP_RST) == 0 &&
|
|
(tcp->Flag & TCP_URG) == 0)
|
|
{
|
|
if (p->PayloadSize != 0)
|
|
{
|
|
// Do URL redirection
|
|
use_redirect_url = true;
|
|
StrCpy(redirect_url, sizeof(redirect_url), a->RedirectUrl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Complete the scanning of the list here
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(hub->AccessList);
|
|
|
|
if (pass)
|
|
{
|
|
if (s->FirstTimeHttpRedirect && s->FirstTimeHttpAccessCheckIp != 0)
|
|
{
|
|
if ((p->TypeL3 == L3_IPV4 || p->TypeL3 == L3_IPV6) &&
|
|
p->TypeL4 == L4_TCP)
|
|
{
|
|
TCP_HEADER *tcp = p->L4.TCPHeader;
|
|
|
|
// Examine whether this packet is a TCP data packet
|
|
if (tcp != NULL)
|
|
{
|
|
if (tcp->DstPort == Endian16(80))
|
|
{
|
|
if (p->L3.IPv4Header->DstIP == s->FirstTimeHttpAccessCheckIp)
|
|
{
|
|
s->FirstTimeHttpRedirect = false;
|
|
}
|
|
else if (tcp->Flag & TCP_ACK)
|
|
{
|
|
if ((tcp->Flag & TCP_SYN) == 0 &&
|
|
(tcp->Flag & TCP_RST) == 0 &&
|
|
(tcp->Flag & TCP_URG) == 0)
|
|
{
|
|
if (p->PayloadSize != 0)
|
|
{
|
|
if (IsTcpPacketNcsiHttpAccess(p) == false)
|
|
{
|
|
/* char tmp[4000];
|
|
Zero(tmp, sizeof(tmp));
|
|
Copy(tmp, p->Payload, p->PayloadSize);
|
|
Debug("HTTP: %s\n", tmp);*/
|
|
if (IsEmptyStr(s->FirstTimeHttpRedirectUrl) == false)
|
|
{
|
|
use_redirect_url = true;
|
|
StrCpy(redirect_url, sizeof(redirect_url), s->FirstTimeHttpRedirectUrl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (use_redirect_url)
|
|
{
|
|
if (s->NormalClient)
|
|
{
|
|
// In the case of a normal VPN client (Not a local bridge, a SecureNAT, and not a virtual L3 switch),
|
|
// process URL redirection and discard the packet
|
|
ForceRedirectToUrl(hub, s, p, redirect_url);
|
|
}
|
|
else
|
|
{
|
|
// Discard packets that is sent from the sessions such as local bridge,
|
|
// SecureNAT, virtual L3 switch
|
|
}
|
|
|
|
pass = false;
|
|
}
|
|
|
|
return pass;
|
|
}
|
|
|
|
// Check whether the TCP packet is NCSI accessing
|
|
bool IsTcpPacketNcsiHttpAccess(PKT *p)
|
|
{
|
|
// Validate arguments
|
|
if (p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (p->TypeL4 != L4_TCP)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (p->Payload == NULL || p->PayloadSize == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (SearchBin(p->Payload, 0, p->PayloadSize, "NCSI", 4) != INFINITE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (SearchBin(p->Payload, 0, p->PayloadSize, ".jpeg", 5) != INFINITE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (SearchBin(p->Payload, 0, p->PayloadSize, ".jpg", 4) != INFINITE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (SearchBin(p->Payload, 0, p->PayloadSize, ".gif", 4) != INFINITE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (SearchBin(p->Payload, 0, p->PayloadSize, ".css", 4) != INFINITE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Adding Access List
|
|
void AddAccessList(HUB *hub, ACCESS *a)
|
|
{
|
|
AddAccessListEx(hub, a, false, false);
|
|
}
|
|
void AddAccessListEx(HUB *hub, ACCESS *a, bool no_sort, bool no_reassign_id)
|
|
{
|
|
// Validate arguments
|
|
if (hub == NULL || a == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(hub->AccessList);
|
|
{
|
|
ACCESS *access;
|
|
UINT i;
|
|
|
|
// Check the number of items
|
|
if (LIST_NUM(hub->AccessList) >= MAX_ACCESSLISTS)
|
|
{
|
|
UnlockList(hub->AccessList);
|
|
return;
|
|
}
|
|
|
|
access = Malloc(sizeof(ACCESS));
|
|
Copy(access, a, sizeof(ACCESS));
|
|
|
|
access->IsSrcUsernameIncludeOrExclude = false;
|
|
access->IsDestUsernameIncludeOrExclude = false;
|
|
|
|
// User name correction
|
|
if (IsEmptyStr(access->SrcUsername) == false)
|
|
{
|
|
if (StartWith(access->SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) == false && StartWith(access->SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
|
|
{
|
|
MakeSimpleUsernameRemoveNtDomain(access->SrcUsername, sizeof(access->SrcUsername), access->SrcUsername);
|
|
}
|
|
else
|
|
{
|
|
access->IsSrcUsernameIncludeOrExclude = true;
|
|
}
|
|
}
|
|
if (IsEmptyStr(access->DestUsername) == false)
|
|
{
|
|
if (StartWith(access->DestUsername, ACCESS_LIST_INCLUDED_PREFIX) == false && StartWith(access->DestUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
|
|
{
|
|
MakeSimpleUsernameRemoveNtDomain(access->DestUsername, sizeof(access->DestUsername), access->DestUsername);
|
|
}
|
|
else
|
|
{
|
|
access->IsDestUsernameIncludeOrExclude = true;
|
|
}
|
|
}
|
|
|
|
access->SrcUsernameHash = UsernameToInt64(access->SrcUsername);
|
|
access->DestUsernameHash = UsernameToInt64(access->DestUsername);
|
|
|
|
// Port number correction
|
|
if (access->SrcPortStart != 0)
|
|
{
|
|
access->SrcPortEnd = MAX(access->SrcPortEnd, access->SrcPortStart);
|
|
}
|
|
if (access->DestPortStart != 0)
|
|
{
|
|
access->DestPortEnd = MAX(access->DestPortEnd, access->DestPortStart);
|
|
}
|
|
|
|
// Correct delay, jitter, and packet loss
|
|
access->Delay = MAKESURE(access->Delay, 0, HUB_ACCESSLIST_DELAY_MAX);
|
|
access->Jitter = MAKESURE(access->Jitter, 0, HUB_ACCESSLIST_JITTER_MAX);
|
|
access->Loss = MAKESURE(access->Loss, 0, HUB_ACCESSLIST_LOSS_MAX);
|
|
|
|
if (no_sort == false)
|
|
{
|
|
Insert(hub->AccessList, access);
|
|
}
|
|
else
|
|
{
|
|
Add(hub->AccessList, access);
|
|
}
|
|
|
|
// Reassign the ID
|
|
if (no_reassign_id == false)
|
|
{
|
|
for (i = 0;i < LIST_NUM(hub->AccessList);i++)
|
|
{
|
|
ACCESS *a = LIST_DATA(hub->AccessList, i);
|
|
a->Id = (i + 1);
|
|
}
|
|
}
|
|
}
|
|
UnlockList(hub->AccessList);
|
|
}
|
|
|
|
// Initialize the access list
|
|
void InitAccessList(HUB *hub)
|
|
{
|
|
// Validate arguments
|
|
if (hub == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
hub->AccessList = NewList(CmpAccessList);
|
|
}
|
|
|
|
// Release the access list
|
|
void FreeAccessList(HUB *hub)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (hub == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(hub->AccessList);i++)
|
|
{
|
|
ACCESS *a = LIST_DATA(hub->AccessList, i);
|
|
Free(a);
|
|
}
|
|
|
|
ReleaseList(hub->AccessList);
|
|
hub->AccessList = NULL;
|
|
}
|
|
|
|
// Comparison of the access list entry
|
|
int CmpAccessList(void *p1, void *p2)
|
|
{
|
|
ACCESS *a1, *a2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
a1 = *(ACCESS **)p1;
|
|
a2 = *(ACCESS **)p2;
|
|
if (a1 == NULL || a2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
// Sort by priority
|
|
if (a1->Priority > a2->Priority)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (a1->Priority < a2->Priority)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (a1->Discard > a2->Discard)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (a1->Discard < a2->Discard)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
UINT64 size64 = ((UINT64)(&a1->UniqueId) - (UINT64)(&a1->Active));
|
|
UINT size32 = (UINT)size64;
|
|
|
|
return Cmp(&a1->Active, &a2->Active, size32);
|
|
}
|
|
}
|
|
|
|
// Generate a user name without domain name of the Windows NT
|
|
void MakeSimpleUsernameRemoveNtDomain(char *dst, UINT dst_size, char *src)
|
|
{
|
|
char tmp1[MAX_SIZE];
|
|
char tmp2[MAX_SIZE];
|
|
// Validate arguments
|
|
if (dst == NULL || src == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ParseNtUsername(src, tmp1, sizeof(tmp1), tmp2, sizeof(tmp2), false);
|
|
|
|
StrCpy(dst, dst_size, tmp1);
|
|
}
|
|
|
|
// Convert the user name to UINT
|
|
UINT64 UsernameToInt64(char *name)
|
|
{
|
|
UCHAR hash[SHA1_SIZE];
|
|
UINT64 ret;
|
|
char tmp[MAX_USERNAME_LEN + 1];
|
|
// Validate arguments
|
|
if (name == 0 || IsEmptyStr(name))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (StartWith(name, ACCESS_LIST_INCLUDED_PREFIX) || StartWith(name, ACCESS_LIST_EXCLUDED_PREFIX))
|
|
{
|
|
return Rand64();
|
|
}
|
|
|
|
MakeSimpleUsernameRemoveNtDomain(tmp, sizeof(tmp), name);
|
|
Trim(tmp);
|
|
StrUpper(tmp);
|
|
|
|
if (StrLen(tmp) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
Sha0(hash, tmp, StrLen(tmp));
|
|
Copy(&ret, hash, sizeof(ret));
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Search the session from the session name
|
|
SESSION *GetSessionByName(HUB *hub, char *name)
|
|
{
|
|
// Validate arguments
|
|
if (hub == NULL || name == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
LockList(hub->SessionList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(hub->SessionList);i++)
|
|
{
|
|
SESSION *s = LIST_DATA(hub->SessionList, i);
|
|
if (StrCmpi(s->Name, name) == 0)
|
|
{
|
|
// Found
|
|
AddRef(s->ref);
|
|
UnlockList(hub->SessionList);
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(hub->SessionList);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Sort of the STORM list
|
|
int CompareStormList(void *p1, void *p2)
|
|
{
|
|
STORM *s1, *s2;
|
|
UINT r;
|
|
// Validate arguments
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
s1 = *(STORM **)p1;
|
|
s2 = *(STORM **)p2;
|
|
if (s1 == NULL || s2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if (s1->StrictMode == false && s2->StrictMode == false)
|
|
{
|
|
// Normal mode
|
|
r = CmpIpAddr(&s1->DestIp, &s2->DestIp);
|
|
if (r != 0)
|
|
{
|
|
return r;
|
|
}
|
|
r = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
|
|
if (r != 0)
|
|
{
|
|
return r;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Strict mode
|
|
int r1, r2;
|
|
r1 = CmpIpAddr(&s1->DestIp, &s2->DestIp);
|
|
r2 = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
|
|
if (r1 == 0 || r2 == 0)
|
|
{
|
|
// Either the source IP, and destination IP match
|
|
}
|
|
else
|
|
{
|
|
// Mismatch
|
|
if (r1 != 0)
|
|
{
|
|
return r1;
|
|
}
|
|
|
|
if (r2 != 0)
|
|
{
|
|
return r2;
|
|
}
|
|
}
|
|
}
|
|
r = Cmp(s1->MacAddress, s2->MacAddress, 6);
|
|
return r;
|
|
}
|
|
|
|
// Packet adapter initialization
|
|
bool HubPaInit(SESSION *s)
|
|
{
|
|
// Initialize the packet adapter information
|
|
HUB_PA *pa = ZeroMalloc(sizeof(HUB_PA));
|
|
pa->Cancel = NewCancel();
|
|
pa->PacketQueue = NewQueue();
|
|
pa->Now = Tick64();
|
|
pa->Session = s;
|
|
pa->StormList = NewList(CompareStormList);
|
|
pa->UsernameHash = UsernameToInt64(s->Username);
|
|
pa->GroupnameHash = UsernameToInt64(s->GroupName);
|
|
|
|
s->PacketAdapter->Param = pa;
|
|
|
|
if (s->Policy->MonitorPort)
|
|
{
|
|
// Mark this port as monitoring port
|
|
pa->MonitorPort = true;
|
|
|
|
// Add this session to the list of monitoring port of the HUB
|
|
LockList(s->Hub->MonitorList);
|
|
{
|
|
Insert(s->Hub->MonitorList, s);
|
|
}
|
|
UnlockList(s->Hub->MonitorList);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Release the Packet adapter
|
|
void HubPaFree(SESSION *s)
|
|
{
|
|
HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
HUB *hub = s->Hub;
|
|
|
|
if (pa->MonitorPort)
|
|
{
|
|
// Remove the session from the list of monitor port of the HUB
|
|
LockList(s->Hub->MonitorList);
|
|
{
|
|
Delete(s->Hub->MonitorList, s);
|
|
}
|
|
UnlockList(s->Hub->MonitorList);
|
|
}
|
|
|
|
// Erase MAC address table entries that is associated with this session
|
|
LockHashList(hub->MacHashTable);
|
|
{
|
|
UINT i, num;
|
|
MAC_TABLE_ENTRY **pp;
|
|
LIST *o = NewListFast(NULL);
|
|
|
|
pp = (MAC_TABLE_ENTRY **)HashListToArray(hub->MacHashTable, &num);
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)pp[i];
|
|
if (e->Session == s)
|
|
{
|
|
Add(o, e);
|
|
}
|
|
}
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(o, i);
|
|
DeleteHash(hub->MacHashTable, e);
|
|
Free(e);
|
|
}
|
|
ReleaseList(o);
|
|
Free(pp);
|
|
}
|
|
{
|
|
UINT i, num = LIST_NUM(hub->IpTable);
|
|
LIST *o = NewListFast(NULL);
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
|
|
if (e->Session == s)
|
|
{
|
|
Add(o, e);
|
|
}
|
|
}
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(o, i);
|
|
Delete(hub->IpTable, e);
|
|
Free(e);
|
|
}
|
|
ReleaseList(o);
|
|
}
|
|
UnlockHashList(hub->MacHashTable);
|
|
|
|
// Release the STORM list
|
|
LockList(pa->StormList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(pa->StormList);i++)
|
|
{
|
|
STORM *s = (STORM *)LIST_DATA(pa->StormList, i);
|
|
Free(s);
|
|
}
|
|
DeleteAll(pa->StormList);
|
|
}
|
|
UnlockList(pa->StormList);
|
|
|
|
ReleaseList(pa->StormList);
|
|
|
|
// Release the packets remaining in the queue
|
|
LockQueue(pa->PacketQueue);
|
|
{
|
|
BLOCK *b;
|
|
|
|
while (b = GetNext(pa->PacketQueue))
|
|
{
|
|
// Release the block
|
|
if (b->IsFlooding)
|
|
{
|
|
CedarAddCurrentTcpQueueSize(s->Cedar, -((int)b->Size));
|
|
}
|
|
|
|
FreeBlock(b);
|
|
}
|
|
}
|
|
UnlockQueue(pa->PacketQueue);
|
|
|
|
// Release the queue
|
|
ReleaseQueue(pa->PacketQueue);
|
|
|
|
// Release the cancel object
|
|
ReleaseCancel(pa->Cancel);
|
|
|
|
// Release the packet adapter information
|
|
Free(pa);
|
|
s->PacketAdapter->Param = NULL;
|
|
}
|
|
|
|
// Get the cancel object
|
|
CANCEL *HubPaGetCancel(SESSION *s)
|
|
{
|
|
HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
|
|
AddRef(pa->Cancel->ref);
|
|
return pa->Cancel;
|
|
}
|
|
|
|
// Get the packet to be transmitted next
|
|
UINT HubPaGetNextPacket(SESSION *s, void **data)
|
|
{
|
|
UINT ret = 0;
|
|
HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
|
|
// Get one from the head of the queue
|
|
LockQueue(pa->PacketQueue);
|
|
{
|
|
BLOCK *block = GetNext(pa->PacketQueue);
|
|
if (block == NULL)
|
|
{
|
|
// No queue
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
if (block->IsFlooding)
|
|
{
|
|
CedarAddCurrentTcpQueueSize(s->Cedar, -((int)block->Size));
|
|
}
|
|
|
|
// Found
|
|
*data = block->Buf;
|
|
ret = block->Size;
|
|
// Release the memory of the structure of the block
|
|
Free(block);
|
|
}
|
|
}
|
|
UnlockQueue(pa->PacketQueue);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Receive a packet
|
|
bool HubPaPutPacket(SESSION *s, void *data, UINT size)
|
|
{
|
|
PKT *packet;
|
|
HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
bool b = false;
|
|
HUB *hub;
|
|
bool no_l3 = false;
|
|
bool no_http = false;
|
|
LIST *o = NULL;
|
|
UINT i;
|
|
UINT vlan_type_id = 0;
|
|
bool no_look_bpdu_bridge_id = false;
|
|
bool no_parse_dhcp = false;
|
|
bool no_correct_checksum = false;
|
|
|
|
hub = s->Hub;
|
|
|
|
pa->Now = Tick64();
|
|
|
|
// Processing of Adjust TCP MSS
|
|
if (hub != NULL && hub->Option != NULL && hub->Option->DisableAdjustTcpMss == false && s != NULL)
|
|
{
|
|
UINT target_mss = (hub->Option->AdjustTcpMssValue == 0 ? INFINITE : hub->Option->AdjustTcpMssValue);
|
|
UINT session_mss = (s->AdjustMss == 0 ? INFINITE : s->AdjustMss);
|
|
|
|
target_mss = MIN(target_mss, session_mss);
|
|
|
|
if (s->IsUsingUdpAcceleration && s->UdpAccelMss != 0)
|
|
{
|
|
// If the link is established with UDP acceleration function, use optimum value of the UDP acceleration function
|
|
target_mss = MIN(target_mss, s->UdpAccelMss);
|
|
}
|
|
else if (s->IsRUDPSession && s->RUdpMss != 0)
|
|
{
|
|
// If the link with UDP acceleration is not established, use the optimum value for R-UDP in the case of using R-UDP connection
|
|
target_mss = MIN(target_mss, s->RUdpMss);
|
|
}
|
|
|
|
if (target_mss != INFINITE)
|
|
{
|
|
AdjustTcpMssL2(data, size, target_mss, hub->Option->VlanTypeId);
|
|
}
|
|
}
|
|
|
|
if (data == NULL)
|
|
{
|
|
// Check the delayed packet
|
|
o = NULL;
|
|
LockList(s->DelayedPacketList);
|
|
{
|
|
UINT i;
|
|
if (LIST_NUM(s->DelayedPacketList) >= 1)
|
|
{
|
|
UINT64 now = TickHighres64();
|
|
for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
|
|
{
|
|
PKT *p = LIST_DATA(s->DelayedPacketList, i);
|
|
|
|
if (now >= p->DelayedForwardTick)
|
|
{
|
|
if (o == NULL)
|
|
{
|
|
o = NewListFast(NULL);
|
|
}
|
|
|
|
Add(o, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (o != NULL)
|
|
{
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
PKT *p = LIST_DATA(o, i);
|
|
|
|
Delete(s->DelayedPacketList, p);
|
|
}
|
|
}
|
|
}
|
|
UnlockList(s->DelayedPacketList);
|
|
|
|
// If there is a delayed packet, store it
|
|
if (o != NULL)
|
|
{
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
PKT *p = LIST_DATA(o, i);
|
|
|
|
StorePacket(s->Hub, s, p);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
}
|
|
|
|
// Reception of all packets from this session is complete
|
|
CancelList(s->CancelList);
|
|
|
|
// Yield
|
|
if (hub != NULL)
|
|
{
|
|
if (hub->Option != NULL && hub->Option->YieldAfterStorePacket)
|
|
{
|
|
YieldCpu();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (hub != NULL && hub->Option != NULL)
|
|
{
|
|
no_l3 = hub->Option->DisableIPParsing;
|
|
no_http = hub->Option->DisableHttpParsing;
|
|
vlan_type_id = hub->Option->VlanTypeId;
|
|
no_look_bpdu_bridge_id = hub->Option->NoLookBPDUBridgeId;
|
|
no_correct_checksum = hub->Option->DisableCorrectIpOffloadChecksum;
|
|
}
|
|
|
|
// Insert a VLAN tag
|
|
if (s->VLanId != 0)
|
|
{
|
|
VLanInsertTag(&data, &size, s->VLanId, vlan_type_id);
|
|
}
|
|
|
|
LABEL_TRY_AGAIN:
|
|
// Parse the packet
|
|
packet = ParsePacketEx4(data, size, no_l3, vlan_type_id, !no_look_bpdu_bridge_id, no_http, !no_correct_checksum);
|
|
|
|
if (packet != NULL)
|
|
{
|
|
if (packet->InvalidSourcePacket)
|
|
{
|
|
// Packet which have illegal source
|
|
FreePacket(packet);
|
|
packet = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
if (packet != NULL)
|
|
{
|
|
if (packet->TypeL7 == L7_DHCPV4)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP)
|
|
{
|
|
if (packet->L7.DHCPv4Header != NULL)
|
|
{
|
|
DHCPV4_HEADER *dhcp = packet->L7.DHCPv4Header;
|
|
|
|
if (dhcp->OpCode == 1)
|
|
{
|
|
if (NsIsMacAddressOnLocalhost(dhcp->ClientMacAddress))
|
|
{
|
|
// Filter DHCP requests sent from local kernel-mode virtual NAT
|
|
// not to re-enter it to the virtual HUB along the local bridge
|
|
FreePacket(packet);
|
|
packet = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (no_parse_dhcp == false && packet != NULL)
|
|
{
|
|
if (hub != NULL && hub->Option != NULL && hub->Option->RemoveDefGwOnDhcpForLocalhost)
|
|
{
|
|
// Remove the designation of the DHCP server from the DHCP response packet addressed to localhost
|
|
if (packet->TypeL7 == L7_DHCPV4)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV4)
|
|
{
|
|
if (packet->TypeL4 == L4_UDP)
|
|
{
|
|
if (packet->L7.DHCPv4Header != NULL)
|
|
{
|
|
DHCPV4_HEADER *dhcp = packet->L7.DHCPv4Header;
|
|
|
|
if (dhcp->OpCode == 2)
|
|
{
|
|
if (IsMacAddressLocalFast(dhcp->ClientMacAddress))
|
|
{
|
|
BUF *new_buf;
|
|
DHCP_MODIFY_OPTION m;
|
|
WHERE;
|
|
|
|
Zero(&m, sizeof(m));
|
|
m.RemoveDefaultGatewayOnReply = true;
|
|
|
|
new_buf = DhcpModifyIPv4(&m, data, size);
|
|
|
|
if (new_buf != NULL)
|
|
{
|
|
Free(data);
|
|
|
|
data = new_buf->Buf;
|
|
size = new_buf->Size;
|
|
|
|
Free(new_buf);
|
|
|
|
no_parse_dhcp = true;
|
|
|
|
FreePacket(packet);
|
|
|
|
goto LABEL_TRY_AGAIN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (packet != NULL)
|
|
{
|
|
// Store packet
|
|
StorePacket(s->Hub, s, packet);
|
|
}
|
|
else
|
|
{
|
|
// Release the packet data because it is a bad packet (not a correct MAC frame)
|
|
Free(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Checking algorithm to prevent broadcast-storm
|
|
// If broadcast from a specific endpoint came frequently, filter it
|
|
bool CheckBroadcastStorm(HUB *hub, SESSION *s, PKT *p)
|
|
{
|
|
IP src_ip, dest_ip;
|
|
HUB_PA *pa;
|
|
UINT64 now = Tick64();
|
|
UINT limit_start_count;
|
|
SESSION *sess = s;
|
|
bool ret = true;
|
|
bool strict = false;
|
|
bool no_heavy = false;
|
|
// Validate arguments
|
|
if (s == NULL || p == NULL || hub == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (s->Policy->NoBroadcastLimiter)
|
|
{
|
|
// Unlimited the number of broadcasts
|
|
return true;
|
|
}
|
|
|
|
if (hub->Option != NULL)
|
|
{
|
|
strict = hub->Option->BroadcastLimiterStrictMode;
|
|
no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
|
|
}
|
|
|
|
pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
|
|
Zero(&src_ip, sizeof(IP));
|
|
Zero(&dest_ip, sizeof(IP));
|
|
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
UINTToIP(&src_ip, p->L3.IPv4Header->SrcIP);
|
|
UINTToIP(&dest_ip, p->L3.IPv4Header->DstIP);
|
|
}
|
|
else if (p->TypeL3 == L3_ARPV4)
|
|
{
|
|
UINTToIP(&src_ip, p->L3.ARPv4Header->SrcIP);
|
|
Zero(&dest_ip, sizeof(IP));
|
|
}
|
|
else if (p->TypeL3 == L3_IPV6)
|
|
{
|
|
IPv6AddrToIP(&src_ip, &p->L3.IPv6Header->SrcAddress);
|
|
IPv6AddrToIP(&dest_ip, &p->L3.IPv6Header->DestAddress);
|
|
}
|
|
|
|
// Number of broadcast to start limitation for a single interval
|
|
limit_start_count = 32;
|
|
|
|
if (s->Hub != NULL && s->Hub->Option->BroadcastStormDetectionThreshold != 0)
|
|
{
|
|
limit_start_count = s->Hub->Option->BroadcastStormDetectionThreshold;
|
|
}
|
|
|
|
LockList(pa->StormList);
|
|
{
|
|
STORM *s;
|
|
UINT num;
|
|
s = SearchStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip, strict);
|
|
if (s == NULL)
|
|
{
|
|
s = AddStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip, strict);
|
|
}
|
|
|
|
s->CurrentBroadcastNum++;
|
|
|
|
if ((s->CheckStartTick + STORM_CHECK_SPAN) < now ||
|
|
s->CheckStartTick == 0 || s->CheckStartTick > now)
|
|
{
|
|
// Measure the number of broadcast periodically
|
|
UINT64 diff_time;
|
|
if (s->CheckStartTick < now)
|
|
{
|
|
diff_time = now - s->CheckStartTick;
|
|
}
|
|
else
|
|
{
|
|
diff_time = 0;
|
|
}
|
|
s->CheckStartTick = now;
|
|
num = (UINT)((UINT64)s->CurrentBroadcastNum * (UINT64)1000 / (UINT64)STORM_CHECK_SPAN);
|
|
s->CurrentBroadcastNum = 0;
|
|
if (num >= limit_start_count)
|
|
{
|
|
char ip1[64];
|
|
char ip2[64];
|
|
char mac[MAX_SIZE];
|
|
IPToStr(ip1, sizeof(ip1), &src_ip);
|
|
IPToStr(ip2, sizeof(ip2), &dest_ip);
|
|
ret = false;
|
|
if (s->DiscardValue < STORM_DISCARD_VALUE_END)
|
|
{
|
|
s->DiscardValue = MAX(s->DiscardValue, 1) * 2;
|
|
}
|
|
Debug("s->DiscardValue: %u (%u)\n", s->DiscardValue, num);
|
|
|
|
MacToStr(mac, sizeof(mac), p->MacAddressSrc);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(sess->Hub, "LH_BCAST_STORM", sess->Name, mac, ip1, ip2, num);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (s->DiscardValue >= 1)
|
|
{
|
|
s->DiscardValue = (UINT)((UINT64)s->DiscardValue / MAX((UINT64)2, (UINT64)diff_time / (UINT64)STORM_CHECK_SPAN));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->DiscardValue >= STORM_DISCARD_VALUE_START)
|
|
{
|
|
if (s->DiscardValue >= 128)
|
|
{
|
|
ret = false;
|
|
}
|
|
else if ((rand() % s->DiscardValue) != 0)
|
|
{
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
UnlockList(pa->StormList);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Store packet
|
|
void StorePacket(HUB *hub, SESSION *s, PKT *packet)
|
|
{
|
|
MAC_TABLE_ENTRY *entry = NULL;
|
|
MAC_TABLE_ENTRY t;
|
|
void *data;
|
|
UINT size;
|
|
bool broadcast_mode;
|
|
HUB_PA *dest_pa;
|
|
SESSION *dest_session;
|
|
UINT64 now = Tick64();
|
|
bool no_heavy = false;
|
|
bool drop_broadcast_packet_privacy = false;
|
|
bool drop_arp_packet_privacy = false;
|
|
UINT tcp_queue_quota = 0;
|
|
UINT64 dormant_interval = 0;
|
|
// Validate arguments
|
|
if (hub == NULL || packet == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (s != NULL)
|
|
{
|
|
if (((HUB_PA *)s->PacketAdapter->Param)->MonitorPort)
|
|
{
|
|
// Not to forward packets received from the monitor port
|
|
Free(packet->PacketData);
|
|
FreePacket(packet);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (hub->Option != NULL)
|
|
{
|
|
no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
|
|
drop_broadcast_packet_privacy = hub->Option->DropBroadcastsInPrivacyFilterMode;
|
|
drop_arp_packet_privacy = hub->Option->DropArpInPrivacyFilterMode;
|
|
tcp_queue_quota = hub->Option->FloodingSendQueueBufferQuota;
|
|
if (hub->Option->DetectDormantSessionInterval != 0)
|
|
{
|
|
dormant_interval = (UINT64)hub->Option->DetectDormantSessionInterval * (UINT64)1000;
|
|
}
|
|
}
|
|
|
|
if (dormant_interval != 0)
|
|
{
|
|
if (s != NULL && s->NormalClient)
|
|
{
|
|
if (packet->MacAddressSrc != NULL)
|
|
{
|
|
if (IsHubMacAddress(packet->MacAddressSrc) == false)
|
|
{
|
|
s->LastCommTimeForDormant = now;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lock the entire MAC address table
|
|
LockHashList(hub->MacHashTable);
|
|
{
|
|
// Filtering
|
|
if (s != NULL && (packet->DelayedForwardTick == 0 && StorePacketFilter(s, packet) == false))
|
|
{
|
|
DISCARD_PACKET:
|
|
// Release a packet since passing has been disallowed
|
|
Free(packet->PacketData);
|
|
FreePacket(packet);
|
|
}
|
|
else // Passing is allowed
|
|
{
|
|
bool forward_now = true;
|
|
|
|
if (packet->Loss >= 1)
|
|
{
|
|
// Cause packet loss
|
|
UINT r = rand() % 100;
|
|
if ((packet->Loss >= 100) || (r < packet->Loss))
|
|
{
|
|
// Packet loss
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
|
|
if (packet->Delay >= 1)
|
|
{
|
|
float delay = (float)packet->Delay;
|
|
float jitter;
|
|
UINT delay_uint;
|
|
bool f = Rand1();
|
|
if (packet->Jitter == 0)
|
|
{
|
|
jitter = 0;
|
|
}
|
|
else
|
|
{
|
|
jitter = (float)(Rand32() % (int)((float)packet->Jitter * delay / 100.0f));
|
|
}
|
|
|
|
delay += jitter * (f ? 1 : -1);
|
|
delay_uint = (UINT)delay;
|
|
|
|
if (delay_uint >= 1)
|
|
{
|
|
// Cause delay
|
|
forward_now = false;
|
|
packet->Loss = packet->Jitter = packet->Delay = 0;
|
|
packet->DelayedForwardTick = TickHighres64() + (UINT64)delay_uint;
|
|
packet->DelayedSrcSession = s;
|
|
|
|
LockList(s->DelayedPacketList);
|
|
{
|
|
Add(s->DelayedPacketList, packet);
|
|
}
|
|
UnlockList(s->DelayedPacketList);
|
|
}
|
|
}
|
|
|
|
if (forward_now)
|
|
{
|
|
if (memcmp(packet->MacAddressSrc, hub->HubMacAddr, 6) == 0)
|
|
{
|
|
if (s != NULL)
|
|
{
|
|
// Packets that this HUB itself sent is input from the outside
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
if (s != NULL && (memcmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0))
|
|
{
|
|
// Check whether the source MAC address is registered in the table
|
|
Copy(t.MacAddress, packet->MacAddressSrc, 6);
|
|
if (hub->Option->NoManageVlanId == false)
|
|
{
|
|
t.VlanId = packet->VlanId;
|
|
}
|
|
else
|
|
{
|
|
t.VlanId = 0;
|
|
}
|
|
entry = SearchHash(hub->MacHashTable, &t);
|
|
|
|
if (entry == NULL)
|
|
{
|
|
if (hub->LastFlushTick == 0 || (hub->LastFlushTick + (UINT64)OLD_MAC_ADDRESS_ENTRY_FLUSH_INTERVAL) < now)
|
|
{
|
|
hub->LastFlushTick = now;
|
|
|
|
// Remove old entries
|
|
DeleteExpiredMacTableEntry(hub->MacHashTable);
|
|
}
|
|
|
|
// Register since it is not registered
|
|
if ((s->Policy->MaxMac != 0 || s->Policy->NoBridge) && (s->IsOpenVPNL3Session == false))
|
|
{
|
|
UINT i, num_mac_for_me = 0;
|
|
UINT limited_count;
|
|
MAC_TABLE_ENTRY **pp;
|
|
UINT num_pp;
|
|
|
|
pp = (MAC_TABLE_ENTRY **)HashListToArray(hub->MacHashTable, &num_pp);
|
|
|
|
// Examine a number of MAC addresses that are registered in this current session
|
|
for (i = 0;i < num_pp;i++)
|
|
{
|
|
MAC_TABLE_ENTRY *e = pp[i];
|
|
if (e->Session == s)
|
|
{
|
|
num_mac_for_me++;
|
|
}
|
|
}
|
|
|
|
Free(pp);
|
|
|
|
limited_count = 0xffffffff;
|
|
if (s->Policy->NoBridge)
|
|
{
|
|
limited_count = MIN(limited_count, MAC_MIN_LIMIT_COUNT);
|
|
}
|
|
if (s->Policy->MaxMac != 0)
|
|
{
|
|
limited_count = MIN(limited_count, s->Policy->MaxMac);
|
|
}
|
|
limited_count = MAX(limited_count, MAC_MIN_LIMIT_COUNT);
|
|
|
|
if (num_mac_for_me >= limited_count)
|
|
{
|
|
// Number of MAC addresses that are registered already exceeds the upper limit
|
|
char mac_str[64];
|
|
|
|
if (s != NULL)
|
|
{
|
|
MacToStr(mac_str, sizeof(mac_str), packet->MacAddressSrc);
|
|
if (s->Policy->NoBridge)
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_BRIDGE_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_MAC_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
goto DISCARD_PACKET; // Drop the packet
|
|
}
|
|
}
|
|
|
|
if (HASH_LIST_NUM(hub->MacHashTable) >= MAX_MAC_TABLES)
|
|
{
|
|
// Number of MAC addresses exceeded, discard the packet
|
|
goto DISCARD_PACKET;
|
|
}
|
|
|
|
entry = ZeroMalloc(sizeof(MAC_TABLE_ENTRY));
|
|
entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
|
|
Copy(entry->MacAddress, packet->MacAddressSrc, 6);
|
|
if (hub->Option->NoManageVlanId == false)
|
|
{
|
|
entry->VlanId = packet->VlanId;
|
|
}
|
|
else
|
|
{
|
|
entry->VlanId = 0;
|
|
}
|
|
entry->Session = s;
|
|
entry->UpdatedTime = entry->CreatedTime = now;
|
|
|
|
AddHash(hub->MacHashTable, entry);
|
|
|
|
if (hub->Option->NoMacAddressLog == false)
|
|
{
|
|
// Debug display
|
|
char mac_address[32];
|
|
|
|
if (s != NULL)
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
MacToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc);
|
|
// Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
|
|
|
|
if (packet->VlanId == 0)
|
|
{
|
|
HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
|
|
}
|
|
else
|
|
{
|
|
HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (entry->Session == s)
|
|
{
|
|
// Do not do anything because it is already registered
|
|
entry->UpdatedTime = now;
|
|
}
|
|
else
|
|
{
|
|
// Read the value of the policy CheckMac
|
|
bool check_mac = s->Policy->CheckMac;
|
|
|
|
if (check_mac == false)
|
|
{
|
|
if (s->BridgeMode)
|
|
{
|
|
// Enable the CheckMac policy for the local bridge session forcibly
|
|
check_mac = true;
|
|
|
|
if (hub->Option != NULL && hub->Option->DisableCheckMacOnLocalBridge)
|
|
{
|
|
// Disable if DisableCheckMacOnLocalBridge option is set
|
|
check_mac = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// It's already registered and it's in another session
|
|
if (check_mac && (memcmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0) &&
|
|
((entry->UpdatedTime + MAC_TABLE_EXCLUSIVE_TIME) >= now))
|
|
{
|
|
UCHAR *mac = packet->MacAddressSrc;
|
|
if (hub->Option != NULL && hub->Option->FixForDLinkBPDU &&
|
|
(mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
|
|
(mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
|
|
{
|
|
// Measures for D-Link. Spanning tree packet of D-Link is sent from the above address.
|
|
//CheckMac options for the local bridge may cause an adverse effect. So process this exceptionally.
|
|
UCHAR hash[MD5_SIZE];
|
|
UINT64 tick_diff = Tick64() - s->LastDLinkSTPPacketSendTick;
|
|
|
|
Md5(hash, packet->PacketData, packet->PacketSize);
|
|
|
|
if ((s->LastDLinkSTPPacketSendTick != 0) &&
|
|
(tick_diff < 750ULL) &&
|
|
(memcmp(hash, s->LastDLinkSTPPacketDataHash, MD5_SIZE) == 0))
|
|
{
|
|
// Discard if the same packet sent before 750ms ago
|
|
Debug("D-Link Discard %u\n", (UINT)tick_diff);
|
|
goto DISCARD_PACKET; // Drop the packet
|
|
}
|
|
else
|
|
{
|
|
goto UPDATE_FDB;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0)
|
|
{
|
|
// If the CheckMac policy-enabled, owning same
|
|
// MAC address by other sessions are prohibited
|
|
// (If the second byte is 0xAE, don't perform this check)
|
|
char mac_address[32];
|
|
BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
|
|
}
|
|
}
|
|
|
|
goto DISCARD_PACKET; // Drop the packet
|
|
}
|
|
else
|
|
{
|
|
// Rewrite the session of MAC address table and the HUB_PA
|
|
char mac_address[32];
|
|
UPDATE_FDB:
|
|
BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
|
|
|
|
entry->Session = s;
|
|
entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
|
|
entry->UpdatedTime = entry->CreatedTime = now;
|
|
|
|
if (1)
|
|
{
|
|
// Debug display
|
|
char mac_address[32];
|
|
|
|
if (s != NULL)
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
MacToStr(mac_address, sizeof(mac_address), packet->MacHeader->SrcAddress);
|
|
Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
|
|
if (packet->VlanId == 0)
|
|
{
|
|
HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
|
|
}
|
|
else
|
|
{
|
|
HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
broadcast_mode = false;
|
|
dest_pa = NULL;
|
|
dest_session = NULL;
|
|
|
|
if (packet->BroadcastPacket)
|
|
{
|
|
// Broadcast packet
|
|
broadcast_mode = true;
|
|
}
|
|
else
|
|
{
|
|
// Examine whether the destination MAC address is registered in the table
|
|
Copy(t.MacAddress, packet->MacAddressDest, 6);
|
|
if (hub->Option->NoManageVlanId == false)
|
|
{
|
|
t.VlanId = packet->VlanId;
|
|
}
|
|
else
|
|
{
|
|
t.VlanId = 0;
|
|
}
|
|
entry = SearchHash(hub->MacHashTable, &t);
|
|
|
|
if (entry == NULL)
|
|
{
|
|
// Broadcast because the destination isn't found
|
|
broadcast_mode = true;
|
|
}
|
|
else
|
|
{
|
|
if (entry->Session != s)
|
|
{
|
|
// Destination is found
|
|
dest_pa = entry->HubPa;
|
|
dest_session = entry->Session;
|
|
}
|
|
else
|
|
{
|
|
// Bad packet whose destination is its own
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s != NULL && hub->Option->NoIpTable == false)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6)
|
|
{
|
|
// IPv6 packet
|
|
IP ip;
|
|
bool b = true;
|
|
UINT ip_type;
|
|
bool dhcp_or_ra = false;
|
|
|
|
IPv6AddrToIP(&ip, &packet->L3.IPv6Header->SrcAddress);
|
|
ip_type = GetIPv6AddrType(&packet->L3.IPv6Header->SrcAddress);
|
|
|
|
if (!(ip_type & IPV6_ADDR_UNICAST))
|
|
{
|
|
// Multicast address
|
|
b = false;
|
|
}
|
|
else if ((ip_type & IPV6_ADDR_LOOPBACK) || (ip_type & IPV6_ADDR_ZERO))
|
|
{
|
|
// Loop-back address or all-zero address
|
|
b = false;
|
|
}
|
|
|
|
if (packet->TypeL4 == L4_ICMPV6)
|
|
{
|
|
if (packet->ICMPv6HeaderPacketInfo.Type == 133 ||
|
|
packet->ICMPv6HeaderPacketInfo.Type == 134)
|
|
{
|
|
// ICMPv6 RS/RA
|
|
dhcp_or_ra = true;
|
|
}
|
|
}
|
|
else if (packet->TypeL4 == L4_UDP)
|
|
{
|
|
if (Endian16(packet->L4.UDPHeader->DstPort) == 546 ||
|
|
Endian16(packet->L4.UDPHeader->DstPort) == 547)
|
|
{
|
|
// DHCPv6
|
|
dhcp_or_ra = true;
|
|
}
|
|
}
|
|
|
|
if (IsHubMacAddress(packet->MacAddressSrc) &&
|
|
IsHubIpAddress64(&packet->L3.IPv6Header->SrcAddress))
|
|
{
|
|
// The source address of the Virtual HUB for polling
|
|
b = false;
|
|
}
|
|
|
|
if (b)
|
|
{
|
|
// Other than ICMPv6 RS/RA nor DHCPv6 packet
|
|
IP_TABLE_ENTRY t, *e;
|
|
|
|
Copy(&t.Ip, &ip, sizeof(IP));
|
|
|
|
// Check whether it is registered to an existing table
|
|
e = Search(hub->IpTable, &t);
|
|
|
|
if (e == NULL)
|
|
{
|
|
// Register since it is not registered
|
|
if (s->Policy->NoRoutingV6 || s->Policy->MaxIPv6 != 0)
|
|
{
|
|
UINT i, num_ip_for_me = 0;
|
|
UINT limited_count = 0xffffffff;
|
|
|
|
for (i = 0;i < LIST_NUM(hub->IpTable);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
|
|
|
|
if (e->Session == s)
|
|
{
|
|
if (IsIP6(&e->Ip))
|
|
{
|
|
num_ip_for_me++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->Policy->NoRoutingV6)
|
|
{
|
|
limited_count = MIN(limited_count, IP_LIMIT_WHEN_NO_ROUTING_V6);
|
|
}
|
|
if (s->Policy->MaxIPv6 != 0)
|
|
{
|
|
limited_count = MIN(limited_count, s->Policy->MaxIPv6);
|
|
}
|
|
limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT_V6);
|
|
|
|
if (dhcp_or_ra)
|
|
{
|
|
limited_count = 0xffffffff;
|
|
}
|
|
|
|
if (num_ip_for_me >= limited_count)
|
|
{
|
|
// Discard the packet because it exceeded the
|
|
// upper limit of the IP address that can be used
|
|
char tmp[64];
|
|
IPToStr(tmp, sizeof(tmp), &ip);
|
|
if (s->Policy->NoRoutingV6 == false)
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
|
|
}
|
|
}
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
|
|
if (IsIPManagementTargetForHUB(&ip, hub))
|
|
{
|
|
// Create a entry
|
|
e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
|
|
e->CreatedTime = e->UpdatedTime = now;
|
|
e->DhcpAllocated = false;
|
|
Copy(&e->Ip, &ip, sizeof(IP));
|
|
Copy(e->MacAddress, packet->MacAddressSrc, 6);
|
|
e->Session = s;
|
|
|
|
DeleteExpiredIpTableEntry(hub->IpTable);
|
|
|
|
if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
|
|
{
|
|
// Delete old IP table entries
|
|
DeleteOldIpTableEntry(hub->IpTable);
|
|
}
|
|
|
|
Insert(hub->IpTable, e);
|
|
|
|
if (0)
|
|
{
|
|
char ip_address[64];
|
|
IPToStr(ip_address, sizeof(ip_address), &ip);
|
|
Debug("Registered IP Address %s to Session %X.\n",
|
|
ip_address, s);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (e->Session == s)
|
|
{
|
|
// Do not do anything because it is self session
|
|
// Renew updated time
|
|
e->UpdatedTime = now;
|
|
Copy(e->MacAddress, packet->MacAddressSrc, 6);
|
|
}
|
|
else
|
|
{
|
|
// Another session was using this IP address before
|
|
if ((s->Policy->CheckIPv6) &&
|
|
((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
|
|
{
|
|
// Discard the packet because another session uses this IP address
|
|
char ip_address[32];
|
|
char mac_str[48];
|
|
IPToStr(ip_address, sizeof(ip_address), &ip);
|
|
|
|
Debug("IP Address %s is Already used by Session %X.\n",
|
|
ip_address, s);
|
|
|
|
MacToStr(mac_str, sizeof(mac_str), e->MacAddress);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name, mac_str,
|
|
e->CreatedTime, e->UpdatedTime, e->DhcpAllocated, now);
|
|
}
|
|
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (
|
|
(s != NULL) &&
|
|
(hub->Option->NoIpTable == false) &&
|
|
(
|
|
(packet->TypeL3 == L3_IPV4 ||
|
|
(packet->TypeL3 == L3_ARPV4 && packet->L3.ARPv4Header->HardwareSize == 6 &&
|
|
Endian16(packet->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
|
|
packet->L3.ARPv4Header->ProtocolSize == 4 &&
|
|
Endian16(packet->L3.ARPv4Header->ProtocolType) == 0x0800)
|
|
) &&
|
|
(packet->TypeL7 != L7_DHCPV4)
|
|
)
|
|
) // Other than DHCP packets
|
|
{
|
|
// In the case of the ARP response packet or the IP packet, search in the IP address table
|
|
IP_TABLE_ENTRY t, *e;
|
|
IP ip;
|
|
UINT uint_ip = 0;
|
|
|
|
if (packet->TypeL3 == L3_IPV4)
|
|
{
|
|
uint_ip = packet->L3.IPv4Header->SrcIP;
|
|
}
|
|
else if (packet->TypeL3 == L3_ARPV4)
|
|
{
|
|
uint_ip = packet->L3.ARPv4Header->SrcIP;
|
|
}
|
|
|
|
if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(packet->MacAddressSrc)))
|
|
{
|
|
UINTToIP(&ip, uint_ip);
|
|
Copy(&t.Ip, &ip, sizeof(IP));
|
|
|
|
// Check whether it is registered to an existing table
|
|
e = Search(hub->IpTable, &t);
|
|
|
|
if (e == NULL)
|
|
{
|
|
// Register since it is not registered
|
|
if (s->Policy->DHCPForce)
|
|
{
|
|
char ipstr[MAX_SIZE];
|
|
|
|
// Discard the packet because this IP address isn't
|
|
// assigned by the DHCP server
|
|
IPToStr32(ipstr, sizeof(ipstr), uint_ip);
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
|
|
}
|
|
goto DISCARD_PACKET;
|
|
}
|
|
|
|
// if (packet->TypeL3 == L3_ARPV4)
|
|
{
|
|
// Examine the number that are registered in this session already
|
|
if (s->Policy->NoRouting || s->Policy->MaxIP != 0)
|
|
{
|
|
UINT i, num_ip_for_me = 0;
|
|
UINT limited_count = 0xffffffff;
|
|
|
|
for (i = 0;i < LIST_NUM(hub->IpTable);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
|
|
|
|
if (e->Session == s)
|
|
{
|
|
if (IsIP4(&e->Ip))
|
|
{
|
|
num_ip_for_me++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->Policy->NoRouting)
|
|
{
|
|
limited_count = MIN(limited_count, IP_MIN_LIMIT_COUNT);
|
|
}
|
|
if (s->Policy->MaxIP != 0)
|
|
{
|
|
limited_count = MIN(limited_count, s->Policy->MaxIP);
|
|
}
|
|
limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT);
|
|
|
|
if (num_ip_for_me >= limited_count)
|
|
{
|
|
// Discard the packet because it exceeded the
|
|
// upper limit of the IP address that can be used
|
|
char tmp[64];
|
|
IPToStr32(tmp, sizeof(tmp), uint_ip);
|
|
if (s->Policy->NoRouting == false)
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
|
|
}
|
|
}
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
|
|
if (IsIPManagementTargetForHUB(&ip, hub))
|
|
{
|
|
// Create a entry
|
|
e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
|
|
e->CreatedTime = e->UpdatedTime = now;
|
|
e->DhcpAllocated = false;
|
|
Copy(&e->Ip, &ip, sizeof(IP));
|
|
Copy(e->MacAddress, packet->MacAddressSrc, 6);
|
|
e->Session = s;
|
|
|
|
DeleteExpiredIpTableEntry(hub->IpTable);
|
|
|
|
if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
|
|
{
|
|
// Delete old IP table entries
|
|
DeleteOldIpTableEntry(hub->IpTable);
|
|
}
|
|
|
|
Insert(hub->IpTable, e);
|
|
|
|
if (0)
|
|
{
|
|
char ip_address[64];
|
|
IPToStr(ip_address, sizeof(ip_address), &ip);
|
|
Debug("Registered IP Address %s to Session %X.\n",
|
|
ip_address, s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (e->Session == s)
|
|
{
|
|
// Do not do anything because it is self session
|
|
// Renew update time
|
|
e->UpdatedTime = now;
|
|
Copy(e->MacAddress, packet->MacAddressSrc, 6);
|
|
}
|
|
else
|
|
{
|
|
// Another session was using this IP address before
|
|
if ((s->Policy->CheckIP || s->Policy->DHCPForce) &&
|
|
((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
|
|
{
|
|
// Discard the packet because another session uses
|
|
// this IP address
|
|
char ip_address[32];
|
|
char mac_str[48];
|
|
IPToStr(ip_address, sizeof(ip_address), &ip);
|
|
|
|
Debug("IP Address %s is Already used by Session %X.\n",
|
|
ip_address, s);
|
|
|
|
MacToStr(mac_str, sizeof(mac_str), e->MacAddress);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name, mac_str,
|
|
e->CreatedTime, e->UpdatedTime, e->DhcpAllocated, now);
|
|
}
|
|
|
|
goto DISCARD_PACKET;
|
|
}
|
|
|
|
if (s->Policy->DHCPForce)
|
|
{
|
|
if (e->DhcpAllocated == false)
|
|
{
|
|
char ipstr[MAX_SIZE];
|
|
|
|
// Discard the packet because this IP address
|
|
// isn't assigned by the DHCP server
|
|
IPToStr32(ipstr, sizeof(ipstr), uint_ip);
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
|
|
}
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
|
|
// Overwrite the entry
|
|
e->Session = s;
|
|
e->UpdatedTime = now;
|
|
Copy(e->MacAddress, packet->MacAddressSrc, 6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s != NULL && broadcast_mode)
|
|
{
|
|
// Calling Broadcast Storm avoidance algorithm
|
|
// in order to prevent occurrence of a broadcast packet loop
|
|
// or a large number of broadcast
|
|
if (CheckBroadcastStorm(hub, s, packet) == false)
|
|
{
|
|
goto DISCARD_PACKET;
|
|
}
|
|
}
|
|
|
|
// Broadcast this packet to the monitor port of the HUB
|
|
if (hub->MonitorList->num_item != 0)
|
|
{
|
|
LockList(hub->MonitorList);
|
|
{
|
|
UINT i;
|
|
void *data;
|
|
UINT size = packet->PacketSize;
|
|
for (i = 0;i < LIST_NUM(hub->MonitorList);i++)
|
|
{
|
|
SESSION *monitor_session = (SESSION *)LIST_DATA(hub->MonitorList, i);
|
|
|
|
// Flood the packet
|
|
if (monitor_session->PacketAdapter->Param != NULL)
|
|
{
|
|
data = MallocFast(size);
|
|
Copy(data, packet->PacketData, size);
|
|
StorePacketToHubPa((HUB_PA *)monitor_session->PacketAdapter->Param,
|
|
s, data, size, packet, false, false);
|
|
}
|
|
}
|
|
}
|
|
UnlockList(hub->MonitorList);
|
|
}
|
|
|
|
if (broadcast_mode == false)
|
|
{
|
|
// Unicast packet
|
|
if (dest_pa != NULL)
|
|
{
|
|
if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
|
|
(dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
|
|
(hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
|
|
{
|
|
DeleteIPv6DefaultRouterInRA(packet);
|
|
}
|
|
if (dest_session->Policy->RSandRAFilter)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_ICMPV6 &&
|
|
(packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
|
|
packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
if (dest_session->Policy->DHCPFilter)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV4 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
packet->TypeL7 == L7_DHCPV4)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
if (dest_session->Policy->DHCPv6Filter)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
if (dest_session->Policy->ArpDhcpOnly)
|
|
{
|
|
if (packet->BroadcastPacket)
|
|
{
|
|
bool b = true;
|
|
|
|
if (packet->TypeL3 == L3_IPV4 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
packet->TypeL7 == L7_DHCPV4)
|
|
{
|
|
b = false;
|
|
}
|
|
else if (packet->TypeL3 == L3_ARPV4)
|
|
{
|
|
b = false;
|
|
}
|
|
else if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
|
|
{
|
|
b = false;
|
|
}
|
|
else if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_ICMPV6)
|
|
{
|
|
b = false;
|
|
}
|
|
|
|
if (b)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
}
|
|
if (dest_session->Policy->FilterIPv4)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
if (dest_session->Policy->FilterIPv6)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
if (dest_session->Policy->FilterNonIP)
|
|
{
|
|
if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
|
|
if (s != NULL &&
|
|
((drop_broadcast_packet_privacy || packet->BroadcastPacket == false) &&
|
|
s->Policy->PrivacyFilter &&
|
|
dest_session->Policy->PrivacyFilter)
|
|
)
|
|
{
|
|
// Privacy filter
|
|
if (drop_arp_packet_privacy || packet->TypeL3 != L3_ARPV4)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
|
|
if (s != NULL)
|
|
{
|
|
if (memcmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
|
|
memcmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
|
|
{
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
|
|
// Take a packet log
|
|
if (s != NULL)
|
|
{
|
|
if (PacketLog(s->Hub, s, dest_session, packet, now) == false)
|
|
{
|
|
// The packet drops because it have exceeded the allowable amount
|
|
goto DISCARD_UNICAST_PACKET;
|
|
}
|
|
}
|
|
|
|
// Store to the destination HUB_PA
|
|
StorePacketToHubPa(dest_pa, s, packet->PacketData, packet->PacketSize, packet, false, false);
|
|
}
|
|
else
|
|
{
|
|
DISCARD_UNICAST_PACKET:
|
|
Free(packet->PacketData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Flooding as a broadcast packet
|
|
UINT current_tcp_queue_size = 0;
|
|
|
|
// Take a packet log
|
|
if (s != NULL)
|
|
{
|
|
if (PacketLog(s->Hub, s, NULL, packet, now) == false)
|
|
{
|
|
// The packet drops because It have exceeded the allowable amount
|
|
goto DISCARD_BROADCAST_PACKET;
|
|
}
|
|
}
|
|
|
|
// Store for all sessions
|
|
LockList(hub->SessionList);
|
|
{
|
|
UINT i, num = LIST_NUM(hub->SessionList);
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
SESSION *dest_session = LIST_DATA(hub->SessionList, i);
|
|
HUB_PA *dest_pa = (HUB_PA *)dest_session->PacketAdapter->Param;
|
|
bool discard = false;
|
|
|
|
if (dest_session != s)
|
|
{
|
|
bool delete_default_router_in_ra = false;
|
|
|
|
if (dest_session->IsMonitorMode)
|
|
{
|
|
discard = true;
|
|
}
|
|
|
|
if (dest_session->NormalClient)
|
|
{
|
|
if (dormant_interval != 0)
|
|
{
|
|
if (dest_session->LastCommTimeForDormant == 0 ||
|
|
(dest_session->LastCommTimeForDormant + dormant_interval) < now)
|
|
{
|
|
// This is dormant session
|
|
discard = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tcp_queue_quota != 0)
|
|
{
|
|
current_tcp_queue_size = CedarGetCurrentTcpQueueSize(hub->Cedar);
|
|
|
|
if (current_tcp_queue_size >= tcp_queue_quota)
|
|
{
|
|
// Quota exceeded. Discard the packet for normal session.
|
|
if (dest_session->Connection != NULL &&
|
|
dest_session->Connection->Protocol == CONNECTION_TCP)
|
|
{
|
|
discard = true;
|
|
}
|
|
|
|
if (dest_session->LinkModeServer)
|
|
{
|
|
LINK *k = dest_session->Link;
|
|
|
|
discard = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dest_session->VLanId != 0 && packet->TypeL3 == L3_TAGVLAN &&
|
|
packet->VlanId != dest_session->VLanId)
|
|
{
|
|
discard = true;
|
|
}
|
|
|
|
if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
|
|
(dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
|
|
(hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6 && packet->TypeL4 == L4_ICMPV6 &&
|
|
(packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
|
|
{
|
|
if (packet->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
|
|
{
|
|
delete_default_router_in_ra = true;
|
|
}
|
|
}
|
|
}
|
|
if (dest_session->Policy->RSandRAFilter)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_ICMPV6 &&
|
|
(packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
|
|
packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
|
|
if (dest_session->Policy->DHCPFilter)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV4 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
packet->TypeL7 == L7_DHCPV4)
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
|
|
if (dest_session->Policy->DHCPv6Filter)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
|
|
if (dest_session->Policy->ArpDhcpOnly)
|
|
{
|
|
if (packet->BroadcastPacket)
|
|
{
|
|
bool b = true;
|
|
|
|
if (packet->TypeL3 == L3_IPV4 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
packet->TypeL7 == L7_DHCPV4)
|
|
{
|
|
b = false;
|
|
}
|
|
else if (packet->TypeL3 == L3_ARPV4)
|
|
{
|
|
b = false;
|
|
}
|
|
else if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_UDP &&
|
|
(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
|
|
{
|
|
b = false;
|
|
}
|
|
else if (packet->TypeL3 == L3_IPV6 &&
|
|
packet->TypeL4 == L4_ICMPV6)
|
|
{
|
|
b = false;
|
|
}
|
|
|
|
if (discard == false)
|
|
{
|
|
discard = b;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dest_session->Policy->FilterIPv4)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
if (dest_session->Policy->FilterIPv6)
|
|
{
|
|
if (packet->TypeL3 == L3_IPV6)
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
if (dest_session->Policy->FilterNonIP)
|
|
{
|
|
if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
|
|
if (s != NULL &&
|
|
((drop_broadcast_packet_privacy || packet->BroadcastPacket == false) &&
|
|
s->Policy->PrivacyFilter &&
|
|
dest_session->Policy->PrivacyFilter)
|
|
)
|
|
{
|
|
// Privacy filter
|
|
if (drop_arp_packet_privacy || packet->TypeL3 != L3_ARPV4)
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
|
|
if (s != NULL)
|
|
{
|
|
if (memcmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
|
|
memcmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
|
|
{
|
|
discard = true;
|
|
}
|
|
}
|
|
|
|
if (discard == false && dest_pa != NULL)
|
|
{
|
|
if (s == NULL ||
|
|
ApplyAccessListToForwardPacket(s->Hub, s, dest_pa->Session, packet))
|
|
{
|
|
// Store in session other than its own
|
|
data = MallocFast(packet->PacketSize);
|
|
Copy(data, packet->PacketData, packet->PacketSize);
|
|
size = packet->PacketSize;
|
|
|
|
if (delete_default_router_in_ra)
|
|
{
|
|
PKT *pkt2 = ParsePacket(data, size);
|
|
|
|
DeleteIPv6DefaultRouterInRA(pkt2);
|
|
|
|
FreePacket(pkt2);
|
|
}
|
|
|
|
StorePacketToHubPa(dest_pa, s, data, size, packet, true, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UnlockList(hub->SessionList);
|
|
|
|
DISCARD_BROADCAST_PACKET:
|
|
Free(packet->PacketData);
|
|
}
|
|
FreePacket(packet);
|
|
}
|
|
}
|
|
}
|
|
UnlockHashList(hub->MacHashTable);
|
|
}
|
|
|
|
// Examine the maximum number of logging target packets per minute
|
|
bool CheckMaxLoggedPacketsPerMinute(SESSION *s, UINT max_packets, UINT64 now)
|
|
{
|
|
UINT64 minute = 60 * 1000;
|
|
// Validate arguments
|
|
if (s == NULL || max_packets == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ((s->Policy != NULL && s->Policy->NoBroadcastLimiter) ||
|
|
s->SecureNATMode || s->BridgeMode || s->LinkModeServer || s->LinkModeClient ||
|
|
s->L3SwitchMode)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (s->MaxLoggedPacketsPerMinuteStartTick == 0 ||
|
|
((s->MaxLoggedPacketsPerMinuteStartTick + minute) <= now))
|
|
{
|
|
s->MaxLoggedPacketsPerMinuteStartTick = now;
|
|
s->CurrentNumPackets = 0;
|
|
}
|
|
|
|
s->CurrentNumPackets++;
|
|
if (s->CurrentNumPackets > max_packets)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Confirm whether the specified IP address is managed by Virtual HUB
|
|
bool IsIPManagementTargetForHUB(IP *ip, HUB *hub)
|
|
{
|
|
// Validate arguments
|
|
if (ip == NULL || hub == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (hub->Option == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (IsIP4(ip))
|
|
{
|
|
if (hub->Option->ManageOnlyPrivateIP)
|
|
{
|
|
if (IsIPPrivate(ip) == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hub->Option->ManageOnlyLocalUnicastIPv6)
|
|
{
|
|
UINT ip_type = GetIPAddrType6(ip);
|
|
|
|
if (!(ip_type & IPV6_ADDR_LOCAL_UNICAST))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Delete old IP table entries
|
|
void DeleteOldIpTableEntry(LIST *o)
|
|
{
|
|
UINT i;
|
|
IP_TABLE_ENTRY *old = NULL;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(o, i);
|
|
old = e;
|
|
}
|
|
|
|
if (old != NULL)
|
|
{
|
|
Delete(o, old);
|
|
Free(old);
|
|
}
|
|
}
|
|
|
|
|
|
// Add to Storm list
|
|
STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict)
|
|
{
|
|
STORM *s;
|
|
// Validate arguments
|
|
if (pa == NULL || mac_address == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
s = ZeroMalloc(sizeof(STORM));
|
|
if (src_ip != NULL)
|
|
{
|
|
Copy(&s->SrcIp, src_ip, sizeof(IP));
|
|
}
|
|
if (dest_ip != NULL)
|
|
{
|
|
Copy(&s->DestIp, dest_ip, sizeof(IP));
|
|
}
|
|
Copy(s->MacAddress, mac_address, 6);
|
|
s->StrictMode = strict;
|
|
|
|
Insert(pa->StormList, s);
|
|
|
|
return s;
|
|
}
|
|
|
|
// Search in Storm list
|
|
STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict)
|
|
{
|
|
STORM t, *s;
|
|
// Validate arguments
|
|
if (pa == NULL || mac_address == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
if (src_ip != NULL)
|
|
{
|
|
Copy(&t.SrcIp, src_ip, sizeof(IP));
|
|
}
|
|
if (dest_ip != NULL)
|
|
{
|
|
Copy(&t.DestIp, dest_ip, sizeof(IP));
|
|
}
|
|
Copy(t.MacAddress, mac_address, 6);
|
|
|
|
t.StrictMode = strict;
|
|
|
|
s = Search(pa->StormList, &t);
|
|
|
|
return s;
|
|
}
|
|
|
|
// Store the packet to destination HUB_PA
|
|
void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet, bool is_flooding, bool no_check_acl)
|
|
{
|
|
BLOCK *b;
|
|
// Validate arguments
|
|
if (dest == NULL || data == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (size < 14)
|
|
{
|
|
Free(data);
|
|
return;
|
|
}
|
|
|
|
if (no_check_acl == false)
|
|
{
|
|
if (src != NULL)
|
|
{
|
|
// Apply the access list for forwarding
|
|
if (ApplyAccessListToForwardPacket(src->Hub, src, dest->Session, packet) == false)
|
|
{
|
|
Free(data);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (src != NULL)
|
|
{
|
|
if (dest->Session->Policy->MaxDownload != 0)
|
|
{
|
|
// Traffic limit
|
|
if (packet != NULL && IsMostHighestPriorityPacket(dest->Session, packet) == false)
|
|
{
|
|
TRAFFIC_LIMITER *tr = &dest->DownloadLimiter;
|
|
IntoTrafficLimiter(tr, packet);
|
|
|
|
if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > dest->Session->Policy->MaxDownload)
|
|
{
|
|
// Limit
|
|
Free(data);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (packet != NULL && src != NULL && src->Hub != NULL && src->Hub->Option != NULL && src->Hub->Option->FixForDLinkBPDU)
|
|
{
|
|
// Measures for D-Link bug
|
|
UCHAR *mac = packet->MacAddressSrc;
|
|
if ((mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
|
|
(mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
|
|
{
|
|
SESSION *session = dest->Session;
|
|
|
|
if (session != NULL)
|
|
{
|
|
if (session->Policy != NULL && session->Policy->CheckMac)
|
|
{
|
|
UCHAR hash[MD5_SIZE];
|
|
Md5(hash, packet->PacketData, packet->PacketSize);
|
|
|
|
Copy(session->LastDLinkSTPPacketDataHash, hash, MD5_SIZE);
|
|
session->LastDLinkSTPPacketSendTick = Tick64();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove the VLAN tag
|
|
if (dest->Session != NULL && dest->Session->VLanId != 0)
|
|
{
|
|
UINT vlan_tpid = 0;
|
|
if (src != NULL && src->Hub != NULL && src->Hub->Option != NULL)
|
|
{
|
|
vlan_tpid = src->Hub->Option->VlanTypeId;
|
|
}
|
|
if (VLanRemoveTag(&data, &size, dest->Session->VLanId, vlan_tpid) == false)
|
|
{
|
|
Free(data);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (src != NULL && dest->Session != NULL && src->Hub != NULL && src->Hub->Option != NULL)
|
|
{
|
|
if (dest->Session->AdjustMss != 0 ||
|
|
(dest->Session->IsUsingUdpAcceleration && dest->Session->UdpAccelMss != 0) ||
|
|
(dest->Session->IsRUDPSession && dest->Session->RUdpMss != 0))
|
|
{
|
|
if (src->Hub->Option->DisableAdjustTcpMss == false)
|
|
{
|
|
UINT target_mss = INFINITE;
|
|
|
|
if (dest->Session->AdjustMss != 0)
|
|
{
|
|
target_mss = MIN(target_mss, dest->Session->AdjustMss);
|
|
}
|
|
|
|
if (dest->Session->IsUsingUdpAcceleration && dest->Session->UdpAccelMss != 0)
|
|
{
|
|
target_mss = MIN(target_mss, dest->Session->UdpAccelMss);
|
|
}
|
|
else if (dest->Session->IsRUDPSession && dest->Session->RUdpMss != 0)
|
|
{
|
|
target_mss = MIN(target_mss, dest->Session->RUdpMss);
|
|
}
|
|
|
|
// Processing of Adjust TCP MSS
|
|
if (target_mss != INFINITE)
|
|
{
|
|
AdjustTcpMssL2(data, size, target_mss, src->Hub->Option->VlanTypeId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create a block
|
|
b = NewBlock(data, size, 0);
|
|
|
|
LockQueue(dest->PacketQueue);
|
|
{
|
|
// Measure the length of queue
|
|
if (dest->PacketQueue->num_item < MAX_STORED_QUEUE_NUM)
|
|
{
|
|
// Store
|
|
InsertQueue(dest->PacketQueue, b);
|
|
|
|
if (is_flooding)
|
|
{
|
|
if (src != NULL)
|
|
{
|
|
b->IsFlooding = true;
|
|
CedarAddCurrentTcpQueueSize(src->Cedar, b->Size);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Drop the packet
|
|
FreeBlock(b);
|
|
}
|
|
}
|
|
UnlockQueue(dest->PacketQueue);
|
|
|
|
// Issue of cancellation
|
|
if (src != NULL)
|
|
{
|
|
AddCancelList(src->CancelList, dest->Cancel);
|
|
}
|
|
else
|
|
{
|
|
Cancel(dest->Cancel);
|
|
}
|
|
}
|
|
|
|
// Remove the default router specification from the IPv6 router advertisement
|
|
bool DeleteIPv6DefaultRouterInRA(PKT *p)
|
|
{
|
|
if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
|
|
(p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
|
|
{
|
|
if (p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
|
|
{
|
|
p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime = 0;
|
|
|
|
p->L4.ICMPHeader->Checksum = 0;
|
|
p->L4.ICMPHeader->Checksum =
|
|
CalcChecksumForIPv6(&p->L3.IPv6Header->SrcAddress,
|
|
&p->L3.IPv6Header->DestAddress, IP_PROTO_ICMPV6,
|
|
p->L4.ICMPHeader, p->IPv6HeaderPacketInfo.PayloadSize, 0);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Packet filter by policy
|
|
bool StorePacketFilterByPolicy(SESSION *s, PKT *p)
|
|
{
|
|
POLICY *pol;
|
|
HUB *hub;
|
|
bool no_heavy = false;
|
|
// Validate arguments
|
|
if (s == NULL || p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
hub = s->Hub;
|
|
|
|
if (hub != NULL && hub->Option != NULL)
|
|
{
|
|
no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
|
|
}
|
|
|
|
// Policy
|
|
pol = s->Policy;
|
|
|
|
// To prohibit the operation as a server
|
|
if (pol->NoServer)
|
|
{
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
if (p->TypeL4 == L4_TCP)
|
|
{
|
|
UCHAR flag = p->L4.TCPHeader->Flag;
|
|
if ((flag & TCP_SYN) && (flag & TCP_ACK))
|
|
{
|
|
char ip1[64], ip2[64];
|
|
// Not to send a SYN + ACK packet
|
|
Debug("pol->NoServer: Discard SYN+ACK Packet.\n");
|
|
|
|
IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
|
|
IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
|
|
ip1, p->L4.TCPHeader->SrcPort);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Prohibit the operation as a server (IPv6)
|
|
if (pol->NoServerV6)
|
|
{
|
|
if (p->TypeL3 == L3_IPV6)
|
|
{
|
|
if (p->TypeL4 == L4_TCP)
|
|
{
|
|
UCHAR flag = p->L4.TCPHeader->Flag;
|
|
if ((flag & TCP_SYN) && (flag & TCP_ACK))
|
|
{
|
|
char ip1[128], ip2[128];
|
|
// Not to send a SYN + ACK packet
|
|
Debug("pol->NoServerV6: Discard SYN+ACK Packet.\n");
|
|
|
|
IP6AddrToStr(ip1, sizeof(ip1), &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress);
|
|
IP6AddrToStr(ip2, sizeof(ip2), &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
|
|
ip1, p->L4.TCPHeader->SrcPort);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allow broadcast only DHCP and ARP
|
|
if (pol->ArpDhcpOnly && p->BroadcastPacket)
|
|
{
|
|
bool ok = false;
|
|
|
|
if (p->TypeL3 == L3_ARPV4)
|
|
{
|
|
ok = true;
|
|
}
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
if (p->TypeL4 == L4_UDP)
|
|
{
|
|
if (p->TypeL7 == L7_DHCPV4)
|
|
{
|
|
ok = true;
|
|
}
|
|
}
|
|
}
|
|
if (p->TypeL3 == L3_IPV6)
|
|
{
|
|
if (p->TypeL4 == L4_ICMPV6)
|
|
{
|
|
ok = true;
|
|
}
|
|
}
|
|
|
|
if (p->TypeL3 == L3_IPV6 &&
|
|
p->TypeL4 == L4_UDP &&
|
|
(Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->DstPort) == 547))
|
|
{
|
|
ok = true;
|
|
}
|
|
|
|
if (ok == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Filter IPv4 packets
|
|
if (pol->FilterIPv4)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (proto == 0x0800 || proto == 0x0806)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Filter IPv6 packets
|
|
if (pol->FilterIPv6)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (proto == 0x86dd)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Filter non-IP packets
|
|
if (pol->FilterNonIP)
|
|
{
|
|
if (p->MacHeader != NULL)
|
|
{
|
|
USHORT proto = Endian16(p->MacHeader->Protocol);
|
|
if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Filter DHCP packets
|
|
if (pol->DHCPFilter)
|
|
{
|
|
if (p->TypeL3 == L3_IPV4 &&
|
|
p->TypeL4 == L4_UDP &&
|
|
p->TypeL7 == L7_DHCPV4)
|
|
{
|
|
// Discard the DHCP packet
|
|
Debug("pol->DHCPFilter: Discard DHCP Packet.\n");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// DHCPv6 packet filtering
|
|
if (pol->DHCPv6Filter)
|
|
{
|
|
if (p->TypeL3 == L3_IPV6 &&
|
|
p->TypeL4 == L4_UDP)
|
|
{
|
|
if (Endian16(p->L4.UDPHeader->DstPort) == 546 ||
|
|
Endian16(p->L4.UDPHeader->DstPort) == 547)
|
|
{
|
|
// Discard the DHCPv6 packet
|
|
Debug("pol->DHCPv6Filter: Discard DHCPv6 Packet.\n");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The behavior as a DHCP server is prohibited
|
|
if (pol->DHCPNoServer)
|
|
{
|
|
if (p->TypeL3 == L3_IPV4 &&
|
|
p->TypeL4 == L4_UDP &&
|
|
p->TypeL7 == L7_DHCPV4)
|
|
{
|
|
DHCPV4_HEADER *h = p->L7.DHCPv4Header;
|
|
if (h->OpCode == 2)
|
|
{
|
|
char ip1[64], ip2[64];
|
|
|
|
// Discard the DHCP packet
|
|
IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
|
|
IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
|
|
}
|
|
|
|
// Discard the DHCP response packet
|
|
Debug("pol->DHCPNoServer: Discard DHCP Response Packet.\n");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The behavior as a DHCPv6 server is prohibited
|
|
if (pol->DHCPv6NoServer)
|
|
{
|
|
if (p->TypeL3 == L3_IPV6 &&
|
|
p->TypeL4 == L4_UDP &&
|
|
(Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->SrcPort) == 547))
|
|
{
|
|
char ip1[128], ip2[128];
|
|
|
|
// Discard the DHCP packet
|
|
IP6AddrToStr(ip1, sizeof(ip1), &p->L3.IPv6Header->SrcAddress);
|
|
IP6AddrToStr(ip2, sizeof(ip2), &p->L3.IPv6Header->DestAddress);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
|
|
}
|
|
|
|
// Discard the DHCP response packet
|
|
Debug("pol->DHCPv6NoServer: Discard DHCPv6 Response Packet.\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Filter the Router Solicitation / Advertising packet (IPv6)
|
|
if (pol->RSandRAFilter)
|
|
{
|
|
if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
|
|
(p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
|
|
p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Filter the router advertisement packet (IPv6)
|
|
if (pol->RAFilter)
|
|
{
|
|
if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
|
|
p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Register to the IP table by recording the DHCP response packet
|
|
if (p->TypeL3 == L3_IPV4 &&
|
|
p->TypeL4 == L4_UDP &&
|
|
p->TypeL7 == L7_DHCPV4 &&
|
|
(s->Hub != NULL && s->Hub->Option->NoIpTable == false))
|
|
{
|
|
DHCPV4_HEADER *h = p->L7.DHCPv4Header;
|
|
if (h->OpCode == 2 && p->DhcpOpCode == DHCP_ACK)
|
|
{
|
|
// Register to the IP table by peeking the contents of the DHCP response packet
|
|
if (h->HardwareType == ARP_HARDWARE_TYPE_ETHERNET)
|
|
{
|
|
if (h->HardwareAddressSize == 6)
|
|
{
|
|
if (h->YourIP != 0 && h->YourIP != 0xffffffff)
|
|
{
|
|
UINT ip_uint = h->YourIP;
|
|
IP ip;
|
|
IP_TABLE_ENTRY *e, t;
|
|
MAC_TABLE_ENTRY *mac_table, mt;
|
|
mt.VlanId = 0;
|
|
Copy(&mt.MacAddress, &h->ClientMacAddress, 6);
|
|
mac_table = SearchHash(hub->MacHashTable, &mt);
|
|
|
|
if (mac_table != NULL)
|
|
{
|
|
bool new_entry = true;
|
|
UINTToIP(&ip, ip_uint);
|
|
Copy(&t.Ip, &ip, sizeof(IP));
|
|
|
|
e = Search(hub->IpTable, &t);
|
|
if (e == NULL)
|
|
{
|
|
// Register as a new item
|
|
e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
|
|
UPDATE_DHCP_ALLOC_ENTRY:
|
|
e->CreatedTime = e->UpdatedTime = Tick64();
|
|
e->DhcpAllocated = true;
|
|
Copy(&e->Ip, &ip, sizeof(IP));
|
|
e->Session = mac_table->Session;
|
|
Copy(e->MacAddress, p->MacAddressDest, 6);
|
|
|
|
if (new_entry)
|
|
{
|
|
// Delete the expired IP table entries
|
|
DeleteExpiredIpTableEntry(hub->IpTable);
|
|
if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
|
|
{
|
|
// Remove old entries
|
|
DeleteOldIpTableEntry(hub->IpTable);
|
|
}
|
|
Insert(hub->IpTable, e);
|
|
|
|
|
|
if ((hub->Option != NULL && hub->Option->NoDhcpPacketLogOutsideHub == false) || mac_table->Session != s)
|
|
{
|
|
char dhcp_mac_addr[64];
|
|
char dest_mac_addr[64];
|
|
char dest_ip_addr[64];
|
|
char server_ip_addr[64];
|
|
MacToStr(dhcp_mac_addr, sizeof(dhcp_mac_addr), p->MacAddressSrc);
|
|
MacToStr(dest_mac_addr, sizeof(dest_mac_addr), h->ClientMacAddress);
|
|
IPToStr(dest_ip_addr, sizeof(dest_ip_addr), &ip);
|
|
IPToStr32(server_ip_addr, sizeof(server_ip_addr), p->L3.IPv4Header->SrcIP);
|
|
Debug("DHCP Allocated; dhcp server: %s, client: %s, new_ip: %s\n",
|
|
dhcp_mac_addr, dest_mac_addr, dest_ip_addr);
|
|
|
|
if (no_heavy == false)
|
|
{
|
|
HLog(s->Hub, "LH_REGIST_DHCP", s->Name, dhcp_mac_addr, server_ip_addr,
|
|
mac_table->Session->Name, dest_mac_addr, dest_ip_addr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Update
|
|
new_entry = false;
|
|
goto UPDATE_DHCP_ALLOC_ENTRY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Delete the expired MAC table entries
|
|
void DeleteExpiredMacTableEntry(HASH_LIST *h)
|
|
{
|
|
LIST *o2;
|
|
UINT i;
|
|
MAC_TABLE_ENTRY **pp;
|
|
UINT num;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
o2 = NewListFast(NULL);
|
|
|
|
pp = (MAC_TABLE_ENTRY **)HashListToArray(h, &num);
|
|
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
MAC_TABLE_ENTRY *e = pp[i];
|
|
if ((e->UpdatedTime + (UINT64)MAC_TABLE_EXPIRE_TIME) <= Tick64())
|
|
{
|
|
Add(o2, e);
|
|
}
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o2);i++)
|
|
{
|
|
MAC_TABLE_ENTRY *e = LIST_DATA(o2, i);
|
|
DeleteHash(h, e);
|
|
Free(e);
|
|
}
|
|
|
|
ReleaseList(o2);
|
|
|
|
Free(pp);
|
|
}
|
|
|
|
// Delete the expired IP table entries
|
|
void DeleteExpiredIpTableEntry(LIST *o)
|
|
{
|
|
LIST *o2;
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
o2 = NewListFast(NULL);
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(o, i);
|
|
if ((e->UpdatedTime + (UINT64)(e->DhcpAllocated ? IP_TABLE_EXPIRE_TIME_DHCP : IP_TABLE_EXPIRE_TIME)) <= Tick64())
|
|
{
|
|
Add(o2, e);
|
|
}
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o2);i++)
|
|
{
|
|
IP_TABLE_ENTRY *e = LIST_DATA(o2, i);
|
|
Delete(o, e);
|
|
Free(e);
|
|
}
|
|
|
|
ReleaseList(o2);
|
|
}
|
|
|
|
// Determine whether the packet to be handled with priority
|
|
bool IsMostHighestPriorityPacket(SESSION *s, PKT *p)
|
|
{
|
|
// Validate arguments
|
|
if (s == NULL || p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (p->TypeL3 == L3_ARPV4)
|
|
{
|
|
// ARP packets
|
|
return true;
|
|
}
|
|
|
|
if (p->TypeL3 == L3_IPV4)
|
|
{
|
|
if (p->TypeL4 == L4_ICMPV4)
|
|
{
|
|
// ICMP packets
|
|
return true;
|
|
}
|
|
|
|
if (p->TypeL4 == L4_TCP)
|
|
{
|
|
if ((p->L4.TCPHeader->Flag & TCP_SYN) || (p->L4.TCPHeader->Flag & TCP_FIN)
|
|
|| (p->L4.TCPHeader->Flag & TCP_RST))
|
|
{
|
|
// SYN, FIN, RST packet
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (p->TypeL4 == L4_UDP)
|
|
{
|
|
if (p->TypeL7 == L7_DHCPV4)
|
|
{
|
|
// DHCP packets
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Add a packet to traffic limiter
|
|
void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p)
|
|
{
|
|
UINT64 now = Tick64();
|
|
// Validate arguments
|
|
if (tr == NULL || p == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (tr->LastTime == 0 || tr->LastTime > now ||
|
|
(tr->LastTime + LIMITER_SAMPLING_SPAN) < now)
|
|
{
|
|
// Sampling initialization
|
|
tr->Value = 0;
|
|
tr->LastTime = now;
|
|
}
|
|
|
|
// Value increase
|
|
tr->Value += (UINT64)p->PacketSize * (UINT64)8;
|
|
}
|
|
|
|
// The bandwidth reduction by traffic limiter
|
|
bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p)
|
|
{
|
|
HUB_PA *pa;
|
|
TRAFFIC_LIMITER *tr;
|
|
// Validate arguments
|
|
if (s == NULL || p == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (s->Policy->MaxUpload == 0)
|
|
{
|
|
// Unlimited
|
|
return true;
|
|
}
|
|
|
|
pa = (HUB_PA *)s->PacketAdapter->Param;
|
|
tr = &pa->UploadLimiter;
|
|
|
|
// Restrictions are not applied for priority packets
|
|
if (IsMostHighestPriorityPacket(s, p))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Input packets to the limiter
|
|
IntoTrafficLimiter(tr, p);
|
|
|
|
// Compare the current bandwidth and limit value
|
|
if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > s->Policy->MaxUpload)
|
|
{
|
|
// Discard the packet
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Filtering of packets to store
|
|
bool StorePacketFilter(SESSION *s, PKT *packet)
|
|
{
|
|
// Validate arguments
|
|
if (s == NULL || packet == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// The bandwidth reduction by traffic limiter
|
|
if (StorePacketFilterByTrafficLimiter(s, packet) == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Packet filter by policy
|
|
if (StorePacketFilterByPolicy(s, packet) == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// The packet filter with Access Lists
|
|
if (ApplyAccessListToStoredPacket(s->Hub, s, packet) == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get the packet adapter for the HUB
|
|
PACKET_ADAPTER *GetHubPacketAdapter()
|
|
{
|
|
// Hand over by creating a function list
|
|
PACKET_ADAPTER *pa = NewPacketAdapter(HubPaInit,
|
|
HubPaGetCancel, HubPaGetNextPacket, HubPaPutPacket, HubPaFree);
|
|
|
|
return pa;
|
|
}
|
|
|
|
// Stop all the SESSION of the HUB
|
|
void StopAllSession(HUB *h)
|
|
{
|
|
SESSION **s;
|
|
UINT i, num;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(h->SessionList);
|
|
{
|
|
num = LIST_NUM(h->SessionList);
|
|
s = ToArray(h->SessionList);
|
|
DeleteAll(h->SessionList);
|
|
}
|
|
UnlockList(h->SessionList);
|
|
|
|
for (i = 0;i < num;i++)
|
|
{
|
|
StopSession(s[i]);
|
|
ReleaseSession(s[i]);
|
|
}
|
|
|
|
Free(s);
|
|
}
|
|
|
|
// Remove the SESSION from HUB
|
|
void DelSession(HUB *h, SESSION *s)
|
|
{
|
|
// Validate arguments
|
|
if (h == NULL || s == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(h->SessionList);
|
|
{
|
|
if (Delete(h->SessionList, s))
|
|
{
|
|
Debug("Session %s was Deleted from %s.\n", s->Name, h->Name);
|
|
ReleaseSession(s);
|
|
}
|
|
}
|
|
UnlockList(h->SessionList);
|
|
}
|
|
|
|
// Add a SESSION to the HUB
|
|
void AddSession(HUB *h, SESSION *s)
|
|
{
|
|
// Validate arguments
|
|
if (h == NULL || s == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(h->SessionList);
|
|
{
|
|
Insert(h->SessionList, s);
|
|
AddRef(s->ref);
|
|
Debug("Session %s Inserted to %s.\n", s->Name, h->Name);
|
|
|
|
if (s->InProcMode)
|
|
{
|
|
s->UniqueId = GetNewUniqueId(h);
|
|
}
|
|
}
|
|
UnlockList(h->SessionList);
|
|
}
|
|
|
|
// Create a new unique ID of the HUB
|
|
UINT GetNewUniqueId(HUB *h)
|
|
{
|
|
UINT id;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (id = 1;;id++)
|
|
{
|
|
if (SearchSessionByUniqueId(h, id) == NULL)
|
|
{
|
|
return id;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Search for a session by the unique session ID
|
|
SESSION *SearchSessionByUniqueId(HUB *h, UINT id)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(h->SessionList);i++)
|
|
{
|
|
SESSION *s = LIST_DATA(h->SessionList, i);
|
|
|
|
if (s->UniqueId == id)
|
|
{
|
|
return s;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Stop the operation of the HUB
|
|
void StopHub(HUB *h)
|
|
{
|
|
bool old_status = false;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
old_status = h->Offline;
|
|
h->HubIsOnlineButHalting = true;
|
|
|
|
SetHubOffline(h);
|
|
|
|
if (h->Halt == false)
|
|
{
|
|
SLog(h->Cedar, "LS_HUB_STOP", h->Name);
|
|
h->Halt = true;
|
|
}
|
|
|
|
h->Offline = old_status;
|
|
h->HubIsOnlineButHalting = false;
|
|
}
|
|
|
|
// Online the Virtual HUB
|
|
void SetHubOnline(HUB *h)
|
|
{
|
|
bool for_cluster = false;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
|
|
{
|
|
if (h->Type == HUB_TYPE_FARM_DYNAMIC)
|
|
{
|
|
for_cluster = true;
|
|
}
|
|
}
|
|
|
|
Lock(h->lock_online);
|
|
{
|
|
if (h->Offline == false)
|
|
{
|
|
Unlock(h->lock_online);
|
|
return;
|
|
}
|
|
HLog(h, "LH_ONLINE");
|
|
|
|
// Start all links
|
|
StartAllLink(h);
|
|
|
|
// Start the SecureNAT
|
|
if (h->EnableSecureNAT)
|
|
{
|
|
if (h->SecureNAT == NULL)
|
|
{
|
|
if (for_cluster == false)
|
|
{
|
|
h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start all of the local bridges that is associated with this HUB
|
|
if (h->Type != HUB_TYPE_FARM_DYNAMIC)
|
|
{
|
|
LockList(h->Cedar->LocalBridgeList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
|
|
{
|
|
LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
|
|
|
|
if (StrCmpi(br->HubName, h->Name) == 0)
|
|
{
|
|
if (br->Bridge == NULL)
|
|
{
|
|
br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor,
|
|
br->TapMode, br->TapMacAddress, br->LimitBroadcast, br);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UnlockList(h->Cedar->LocalBridgeList);
|
|
}
|
|
|
|
h->Offline = false;
|
|
}
|
|
Unlock(h->lock_online);
|
|
|
|
if (h->Cedar->Server != NULL)
|
|
{
|
|
SiHubOnlineProc(h);
|
|
}
|
|
}
|
|
|
|
// Offline the Virtual HUB
|
|
void SetHubOffline(HUB *h)
|
|
{
|
|
UINT i;
|
|
bool for_cluster = false;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
|
|
{
|
|
if (h->Type == HUB_TYPE_FARM_DYNAMIC)
|
|
{
|
|
for_cluster = true;
|
|
}
|
|
}
|
|
|
|
h->BeingOffline = true;
|
|
|
|
Lock(h->lock_online);
|
|
{
|
|
if (h->Offline || h->Halt)
|
|
{
|
|
Unlock(h->lock_online);
|
|
h->BeingOffline = false;
|
|
return;
|
|
}
|
|
|
|
HLog(h, "LH_OFFLINE");
|
|
|
|
// Stop all links
|
|
StopAllLink(h);
|
|
|
|
// Stop the SecureNAT
|
|
SnFreeSecureNAT(h->SecureNAT);
|
|
h->SecureNAT = NULL;
|
|
|
|
// Stop all the local bridges that is associated with this HUB
|
|
LockList(h->Cedar->LocalBridgeList);
|
|
{
|
|
for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
|
|
{
|
|
LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
|
|
|
|
if (StrCmpi(br->HubName, h->Name) == 0)
|
|
{
|
|
BrFreeBridge(br->Bridge);
|
|
br->Bridge = NULL;
|
|
}
|
|
}
|
|
}
|
|
UnlockList(h->Cedar->LocalBridgeList);
|
|
|
|
// Offline
|
|
h->Offline = true;
|
|
|
|
// Disconnect all sessions
|
|
StopAllSession(h);
|
|
}
|
|
Unlock(h->lock_online);
|
|
|
|
h->BeingOffline = false;
|
|
|
|
if (h->Cedar->Server != NULL)
|
|
{
|
|
SiHubOfflineProc(h);
|
|
}
|
|
}
|
|
|
|
// Get whether a HUB which have the specified name exists
|
|
bool IsHub(CEDAR *cedar, char *name)
|
|
{
|
|
HUB *h;
|
|
// Validate arguments
|
|
if (cedar == NULL || name == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
h = GetHub(cedar, name);
|
|
if (h == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ReleaseHub(h);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get the HUB
|
|
HUB *GetHub(CEDAR *cedar, char *name)
|
|
{
|
|
HUB *h, t;
|
|
// Validate arguments
|
|
if (cedar == NULL || name == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
LockHubList(cedar);
|
|
|
|
t.Name = name;
|
|
h = Search(cedar->HubList, &t);
|
|
if (h == NULL)
|
|
{
|
|
UnlockHubList(cedar);
|
|
return NULL;
|
|
}
|
|
|
|
AddRef(h->ref);
|
|
|
|
UnlockHubList(cedar);
|
|
|
|
return h;
|
|
}
|
|
|
|
// Lock the HUB list
|
|
void LockHubList(CEDAR *cedar)
|
|
{
|
|
// Validate arguments
|
|
if (cedar == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(cedar->HubList);
|
|
}
|
|
|
|
// Unlock the HUB list
|
|
void UnlockHubList(CEDAR *cedar)
|
|
{
|
|
// Validate arguments
|
|
if (cedar == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UnlockList(cedar->HubList);
|
|
}
|
|
|
|
// Release the HUB
|
|
void ReleaseHub(HUB *h)
|
|
{
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Release(h->ref) == 0)
|
|
{
|
|
CleanupHub(h);
|
|
}
|
|
}
|
|
|
|
// Get the Radius server information
|
|
bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size)
|
|
{
|
|
UINT interval;
|
|
return GetRadiusServerEx(hub, name, size, port, secret, secret_size, &interval);
|
|
}
|
|
bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval)
|
|
{
|
|
return GetRadiusServerEx2(hub, name, size, port, secret, secret_size, interval, NULL, 0);
|
|
}
|
|
bool GetRadiusServerEx2(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval, char *suffix_filter, UINT suffix_filter_size)
|
|
{
|
|
bool ret = false;
|
|
// Validate arguments
|
|
if (hub == NULL || name == NULL || port == NULL || secret == NULL || interval == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Lock(hub->RadiusOptionLock);
|
|
{
|
|
if (hub->RadiusServerName != NULL)
|
|
{
|
|
char *tmp;
|
|
UINT tmp_size;
|
|
StrCpy(name, size, hub->RadiusServerName);
|
|
*port = hub->RadiusServerPort;
|
|
*interval = hub->RadiusRetryInterval;
|
|
|
|
tmp_size = hub->RadiusSecret->Size + 1;
|
|
tmp = ZeroMalloc(tmp_size);
|
|
Copy(tmp, hub->RadiusSecret->Buf, hub->RadiusSecret->Size);
|
|
StrCpy(secret, secret_size, tmp);
|
|
Free(tmp);
|
|
|
|
if (suffix_filter != NULL)
|
|
{
|
|
StrCpy(suffix_filter, suffix_filter_size, hub->RadiusSuffixFilter);
|
|
}
|
|
|
|
ret = true;
|
|
}
|
|
}
|
|
Unlock(hub->RadiusOptionLock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Set the Radius server information
|
|
void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret)
|
|
{
|
|
SetRadiusServerEx(hub, name, port, secret, RADIUS_RETRY_INTERVAL);
|
|
}
|
|
void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval)
|
|
{
|
|
// Validate arguments
|
|
if (hub == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Lock(hub->RadiusOptionLock);
|
|
{
|
|
if (hub->RadiusServerName != NULL)
|
|
{
|
|
Free(hub->RadiusServerName);
|
|
}
|
|
|
|
if (name == NULL)
|
|
{
|
|
hub->RadiusServerName = NULL;
|
|
hub->RadiusServerPort = 0;
|
|
hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
|
|
FreeBuf(hub->RadiusSecret);
|
|
}
|
|
else
|
|
{
|
|
hub->RadiusServerName = CopyStr(name);
|
|
hub->RadiusServerPort = port;
|
|
if (interval == 0)
|
|
{
|
|
hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
|
|
}
|
|
else if (interval > RADIUS_RETRY_TIMEOUT)
|
|
{
|
|
hub->RadiusRetryInterval = RADIUS_RETRY_TIMEOUT;
|
|
}
|
|
else
|
|
{
|
|
hub->RadiusRetryInterval = interval;
|
|
}
|
|
FreeBuf(hub->RadiusSecret);
|
|
|
|
if (secret == NULL)
|
|
{
|
|
hub->RadiusSecret = NewBuf();
|
|
}
|
|
else
|
|
{
|
|
hub->RadiusSecret = NewBuf();
|
|
WriteBuf(hub->RadiusSecret, secret, StrLen(secret));
|
|
SeekBuf(hub->RadiusSecret, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
Unlock(hub->RadiusOptionLock);
|
|
}
|
|
|
|
// Add the traffic information for Virtual HUB
|
|
void IncrementHubTraffic(HUB *h)
|
|
{
|
|
TRAFFIC t;
|
|
// Validate arguments
|
|
if (h == NULL || h->FarmMember == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
|
|
Lock(h->TrafficLock);
|
|
{
|
|
t.Send.BroadcastBytes =
|
|
h->Traffic->Send.BroadcastBytes - h->OldTraffic->Send.BroadcastBytes;
|
|
t.Send.BroadcastCount =
|
|
h->Traffic->Send.BroadcastCount - h->OldTraffic->Send.BroadcastCount;
|
|
t.Send.UnicastBytes =
|
|
h->Traffic->Send.UnicastBytes - h->OldTraffic->Send.UnicastBytes;
|
|
t.Send.UnicastCount =
|
|
h->Traffic->Send.UnicastCount - h->OldTraffic->Send.UnicastCount;
|
|
t.Recv.BroadcastBytes =
|
|
h->Traffic->Recv.BroadcastBytes - h->OldTraffic->Recv.BroadcastBytes;
|
|
t.Recv.BroadcastCount =
|
|
h->Traffic->Recv.BroadcastCount - h->OldTraffic->Recv.BroadcastCount;
|
|
t.Recv.UnicastBytes =
|
|
h->Traffic->Recv.UnicastBytes - h->OldTraffic->Recv.UnicastBytes;
|
|
t.Recv.UnicastCount =
|
|
h->Traffic->Recv.UnicastCount - h->OldTraffic->Recv.UnicastCount;
|
|
Copy(h->OldTraffic, h->Traffic, sizeof(TRAFFIC));
|
|
}
|
|
Unlock(h->TrafficLock);
|
|
|
|
if (IsZero(&t, sizeof(TRAFFIC)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AddTrafficDiff(h, h->Name, TRAFFIC_DIFF_HUB, &t);
|
|
}
|
|
|
|
// Adding Traffic information
|
|
void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic)
|
|
{
|
|
TRAFFIC_DIFF *d;
|
|
// Validate arguments
|
|
if (h == NULL || h->FarmMember == false || name == NULL || traffic == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (LIST_NUM(h->Cedar->TrafficDiffList) > MAX_TRAFFIC_DIFF)
|
|
{
|
|
return;
|
|
}
|
|
|
|
d = ZeroMallocFast(sizeof(TRAFFIC_DIFF));
|
|
d->HubName = CopyStr(h->Name);
|
|
d->Name = CopyStr(name);
|
|
d->Type = type;
|
|
Copy(&d->Traffic, traffic, sizeof(TRAFFIC));
|
|
|
|
LockList(h->Cedar->TrafficDiffList);
|
|
{
|
|
Insert(h->Cedar->TrafficDiffList, d);
|
|
}
|
|
UnlockList(h->Cedar->TrafficDiffList);
|
|
}
|
|
|
|
// Cleanup of HUB
|
|
void CleanupHub(HUB *h)
|
|
{
|
|
UINT i;
|
|
char name[MAX_SIZE];
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StrCpy(name, sizeof(name), h->Name);
|
|
|
|
if (h->WatchDogStarted)
|
|
{
|
|
StopHubWatchDog(h);
|
|
}
|
|
|
|
FreeAccessList(h);
|
|
|
|
if (h->RadiusServerName != NULL)
|
|
{
|
|
Free(h->RadiusServerName);
|
|
FreeBuf(h->RadiusSecret);
|
|
}
|
|
ReleaseAllLink(h);
|
|
DeleteHubDb(h->HubDb);
|
|
ReleaseCedar(h->Cedar);
|
|
DeleteLock(h->lock);
|
|
DeleteLock(h->lock_online);
|
|
Free(h->Name);
|
|
ReleaseList(h->SessionList);
|
|
ReleaseHashList(h->MacHashTable);
|
|
ReleaseList(h->IpTable);
|
|
ReleaseList(h->MonitorList);
|
|
ReleaseList(h->LinkList);
|
|
DeleteCounter(h->NumSessions);
|
|
DeleteCounter(h->NumSessionsClient);
|
|
DeleteCounter(h->NumSessionsBridge);
|
|
DeleteCounter(h->SessionCounter);
|
|
FreeTraffic(h->Traffic);
|
|
FreeTraffic(h->OldTraffic);
|
|
Free(h->Option);
|
|
|
|
Free(h->SecureNATOption);
|
|
|
|
DeleteLock(h->TrafficLock);
|
|
|
|
for (i = 0;i < LIST_NUM(h->TicketList);i++)
|
|
{
|
|
Free(LIST_DATA(h->TicketList, i));
|
|
}
|
|
|
|
ReleaseList(h->TicketList);
|
|
|
|
DeleteLock(h->RadiusOptionLock);
|
|
|
|
FreeLog(h->PacketLogger);
|
|
FreeLog(h->SecurityLogger);
|
|
|
|
for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
|
|
{
|
|
Free(LIST_DATA(h->AdminOptionList, i));
|
|
}
|
|
ReleaseList(h->AdminOptionList);
|
|
|
|
if (h->Msg != NULL)
|
|
{
|
|
Free(h->Msg);
|
|
}
|
|
|
|
FreeUserList(h->UserList);
|
|
|
|
Free(h);
|
|
}
|
|
|
|
// Comparison function of IP table entries
|
|
int CompareIpTable(void *p1, void *p2)
|
|
{
|
|
IP_TABLE_ENTRY *e1, *e2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
e1 = *(IP_TABLE_ENTRY **)p1;
|
|
e2 = *(IP_TABLE_ENTRY **)p2;
|
|
if (e1 == NULL || e2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
return CmpIpAddr(&e1->Ip, &e2->Ip);
|
|
}
|
|
|
|
// Get hash of MAC table entry
|
|
UINT GetHashOfMacTable(void *p)
|
|
{
|
|
UINT v;
|
|
MAC_TABLE_ENTRY *e = p;
|
|
|
|
if (e == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
v = e->MacAddress[0] + e->MacAddress[1] + e->MacAddress[2] +
|
|
e->MacAddress[3] + e->MacAddress[4] + e->MacAddress[5] +
|
|
e->VlanId;
|
|
|
|
return v;
|
|
}
|
|
|
|
// Comparison function of the MAC table entries
|
|
int CompareMacTable(void *p1, void *p2)
|
|
{
|
|
int r;
|
|
MAC_TABLE_ENTRY *e1, *e2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
e1 = *(MAC_TABLE_ENTRY **)p1;
|
|
e2 = *(MAC_TABLE_ENTRY **)p2;
|
|
if (e1 == NULL || e2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
r = memcmp(e1->MacAddress, e2->MacAddress, 6);
|
|
if (r != 0)
|
|
{
|
|
return r;
|
|
}
|
|
if (e1->VlanId > e2->VlanId)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (e1->VlanId < e2->VlanId)
|
|
{
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Comparison function of HUB
|
|
int CompareHub(void *p1, void *p2)
|
|
{
|
|
HUB *h1, *h2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
h1 = *(HUB **)p1;
|
|
h2 = *(HUB **)p2;
|
|
if (h1 == NULL || h2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
return StrCmpi(h1->Name, h2->Name);
|
|
}
|
|
|
|
// Examine whether the MAC address is for the ARP polling of the Virtual HUB
|
|
bool IsHubMacAddress(UCHAR *mac)
|
|
{
|
|
// Validate arguments
|
|
if (mac == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (mac[0] == 0x00 && mac[1] == SE_HUB_MAC_ADDR_SIGN)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Examine whether the IP address is for the ARP polling of the Virtual HUB
|
|
bool IsHubIpAddress32(UINT ip32)
|
|
{
|
|
IP ip;
|
|
|
|
UINTToIP(&ip, ip32);
|
|
|
|
return IsHubIpAddress(&ip);
|
|
}
|
|
bool IsHubIpAddress(IP *ip)
|
|
{
|
|
// Validate arguments
|
|
if (ip == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ip->addr[0] == 172 && ip->addr[1] == 31)
|
|
{
|
|
if (ip->addr[2] >= 1 && ip->addr[2] <= 254)
|
|
{
|
|
if (ip->addr[3] >= 1 && ip->addr[3] <= 254)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool IsHubIpAddress64(IPV6_ADDR *addr)
|
|
{
|
|
// Validate arguments
|
|
if (addr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (addr->Value[0] == 0xfe && addr->Value[1] == 0x80 &&
|
|
addr->Value[2] == 0 &&
|
|
addr->Value[3] == 0 &&
|
|
addr->Value[4] == 0 &&
|
|
addr->Value[5] == 0 &&
|
|
addr->Value[6] == 0 &&
|
|
addr->Value[7] == 0 &&
|
|
addr->Value[8] == 0x02 && addr->Value[9] == 0xae &&
|
|
addr->Value[11] == 0xff && addr->Value[12] == 0xfe)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Generate an IP address for the Virtual HUB
|
|
void GenHubIpAddress(IP *ip, char *name)
|
|
{
|
|
char tmp1[MAX_SIZE];
|
|
char tmp2[MAX_SIZE];
|
|
UCHAR hash[SHA1_SIZE];
|
|
// Validate arguments
|
|
if (ip == NULL || name == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StrCpy(tmp1, sizeof(tmp1), name);
|
|
Trim(tmp1);
|
|
GenerateMachineUniqueHash(hash);
|
|
BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
|
|
StrCat(tmp2, sizeof(tmp2), tmp1);
|
|
StrUpper(tmp2);
|
|
|
|
Sha0(hash, tmp2, StrLen(tmp2));
|
|
|
|
Zero(ip, sizeof(IP));
|
|
ip->addr[0] = 172;
|
|
ip->addr[1] = 31;
|
|
ip->addr[2] = hash[0] % 254 + 1;
|
|
ip->addr[3] = hash[1] % 254 + 1;
|
|
}
|
|
|
|
// Generate a MAC address for the Virtual HUB
|
|
void GenHubMacAddress(UCHAR *mac, char *name)
|
|
{
|
|
char tmp1[MAX_SIZE];
|
|
char tmp2[MAX_SIZE];
|
|
UCHAR hash[SHA1_SIZE];
|
|
// Validate arguments
|
|
if (mac == NULL || name == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StrCpy(tmp1, sizeof(tmp1), name);
|
|
Trim(tmp1);
|
|
GenerateMachineUniqueHash(hash);
|
|
BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
|
|
StrCat(tmp2, sizeof(tmp2), tmp1);
|
|
StrUpper(tmp2);
|
|
|
|
Sha0(hash, tmp2, StrLen(tmp2));
|
|
|
|
mac[0] = 0x00;
|
|
mac[1] = SE_HUB_MAC_ADDR_SIGN;
|
|
mac[2] = hash[0];
|
|
mac[3] = hash[1];
|
|
mac[4] = hash[2];
|
|
mac[5] = hash[3];
|
|
}
|
|
|
|
// Get a message from HUB
|
|
wchar_t *GetHubMsg(HUB *h)
|
|
{
|
|
wchar_t *ret = NULL;
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Lock(h->lock);
|
|
{
|
|
if (h->Msg != NULL)
|
|
{
|
|
ret = CopyUniStr(h->Msg);
|
|
}
|
|
}
|
|
Unlock(h->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Set a message to the HUB
|
|
void SetHubMsg(HUB *h, wchar_t *msg)
|
|
{
|
|
// Validate arguments
|
|
if (h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Lock(h->lock);
|
|
{
|
|
if (h->Msg != NULL)
|
|
{
|
|
Free(h->Msg);
|
|
h->Msg = NULL;
|
|
}
|
|
|
|
if (UniIsEmptyStr(msg) == false)
|
|
{
|
|
h->Msg = UniCopyStr(msg);
|
|
}
|
|
}
|
|
Unlock(h->lock);
|
|
}
|
|
|
|
// Creating a new HUB
|
|
HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option)
|
|
{
|
|
HUB *h;
|
|
char packet_logger_name[MAX_SIZE];
|
|
char tmp[MAX_SIZE];
|
|
char safe_hub_name[MAX_HUBNAME_LEN + 1];
|
|
UCHAR hash[SHA1_SIZE];
|
|
IP ip6;
|
|
// Validate arguments
|
|
if (cedar == NULL || option == NULL || HubName == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
h = ZeroMalloc(sizeof(HUB));
|
|
Sha0(h->HashedPassword, "", 0);
|
|
HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");
|
|
h->lock = NewLock();
|
|
h->lock_online = NewLock();
|
|
h->ref = NewRef();
|
|
h->Cedar = cedar;
|
|
AddRef(h->Cedar->ref);
|
|
h->Type = HUB_TYPE_STANDALONE;
|
|
|
|
ConvertSafeFileName(safe_hub_name, sizeof(safe_hub_name), HubName);
|
|
h->Name = CopyStr(safe_hub_name);
|
|
|
|
|
|
h->AdminOptionList = NewList(CompareAdminOption);
|
|
AddHubAdminOptionsDefaults(h, true);
|
|
|
|
h->LastCommTime = SystemTime64();
|
|
h->LastLoginTime = SystemTime64();
|
|
h->NumLogin = 0;
|
|
|
|
h->TrafficLock = NewLock();
|
|
|
|
h->HubDb = NewHubDb();
|
|
|
|
h->SessionList = NewList(NULL);
|
|
h->SessionCounter = NewCounter();
|
|
h->NumSessions = NewCounter();
|
|
h->NumSessionsClient = NewCounter();
|
|
h->NumSessionsBridge = NewCounter();
|
|
h->MacHashTable = NewHashList(GetHashOfMacTable, CompareMacTable, 8, false);
|
|
h->IpTable = NewList(CompareIpTable);
|
|
h->MonitorList = NewList(NULL);
|
|
h->LinkList = NewList(NULL);
|
|
|
|
h->Traffic = NewTraffic();
|
|
h->OldTraffic = NewTraffic();
|
|
|
|
h->Option = ZeroMalloc(sizeof(HUB_OPTION));
|
|
Copy(h->Option, option, sizeof(HUB_OPTION));
|
|
|
|
if (h->Option->VlanTypeId == 0)
|
|
{
|
|
h->Option->VlanTypeId = MAC_PROTO_TAGVLAN;
|
|
}
|
|
|
|
h->Option->DropBroadcastsInPrivacyFilterMode = true;
|
|
h->Option->DropArpInPrivacyFilterMode = true;
|
|
|
|
Rand(h->HubSignature, sizeof(h->HubSignature));
|
|
|
|
// SecureNAT related
|
|
h->EnableSecureNAT = false;
|
|
h->SecureNAT = NULL;
|
|
h->SecureNATOption = ZeroMalloc(sizeof(VH_OPTION));
|
|
NiSetDefaultVhOption(NULL, h->SecureNATOption);
|
|
|
|
if (h->Cedar != NULL && h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
|
|
{
|
|
NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, true);
|
|
}
|
|
|
|
// Generate a temporary MAC address for the HUB
|
|
GenerateMachineUniqueHash(hash);
|
|
GenHubMacAddress(h->HubMacAddr, h->Name);
|
|
GenHubIpAddress(&h->HubIp, h->Name);
|
|
|
|
// IPv6 address for the HUB
|
|
GenerateEui64LocalAddress(&ip6, h->HubMacAddr);
|
|
IPToIPv6Addr(&h->HubIpV6, &ip6);
|
|
|
|
h->RadiusOptionLock = NewLock();
|
|
h->RadiusServerPort = RADIUS_DEFAULT_PORT;
|
|
|
|
h->TicketList = NewList(NULL);
|
|
|
|
InitAccessList(h);
|
|
|
|
// Create a user list
|
|
h->UserList = NewUserList();
|
|
|
|
// Default logging settings
|
|
h->LogSetting.SavePacketLog = h->LogSetting.SaveSecurityLog = true;
|
|
h->LogSetting.PacketLogConfig[PACKET_LOG_TCP_CONN] =
|
|
h->LogSetting.PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;
|
|
h->LogSetting.SecurityLogSwitchType = LOG_SWITCH_DAY;
|
|
h->LogSetting.PacketLogSwitchType = LOG_SWITCH_DAY;
|
|
|
|
MakeDir(HUB_SECURITY_LOG_DIR_NAME);
|
|
MakeDir(HUB_PACKET_LOG_DIR_NAME);
|
|
|
|
// Start the packet logger
|
|
Format(packet_logger_name, sizeof(packet_logger_name), HUB_PACKET_LOG_FILE_NAME, h->Name);
|
|
h->PacketLogger = NewLog(packet_logger_name, HUB_PACKET_LOG_PREFIX, h->LogSetting.PacketLogSwitchType);
|
|
|
|
// Start the security logger
|
|
Format(tmp, sizeof(tmp), HUB_SECURITY_LOG_FILE_NAME, h->Name);
|
|
h->SecurityLogger = NewLog(tmp, HUB_SECURITY_LOG_PREFIX, h->LogSetting.SecurityLogSwitchType);
|
|
|
|
if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
|
|
{
|
|
h->FarmMember = true;
|
|
}
|
|
|
|
// Start the HUB
|
|
SetHubOnline(h);
|
|
|
|
if (h->Cedar->Bridge)
|
|
{
|
|
h->Option->NoArpPolling = true;
|
|
}
|
|
|
|
if (h->Option->NoArpPolling == false && h->Option->NoIpTable == false)
|
|
{
|
|
StartHubWatchDog(h);
|
|
h->WatchDogStarted = true;
|
|
}
|
|
|
|
SLog(h->Cedar, "LS_HUB_START", h->Name);
|
|
|
|
MacToStr(tmp, sizeof(tmp), h->HubMacAddr);
|
|
SLog(h->Cedar, "LS_HUB_MAC", h->Name, tmp);
|
|
|
|
return h;
|
|
}
|
|
|
|
// Delete the HUBDB
|
|
void DeleteHubDb(HUBDB *d)
|
|
{
|
|
// Validate arguments
|
|
if (d == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LockList(d->UserList);
|
|
{
|
|
LockList(d->GroupList);
|
|
{
|
|
// Release all users and groups
|
|
UINT i;
|
|
USER **users;
|
|
USERGROUP **groups;
|
|
|
|
users = ToArray(d->UserList);
|
|
groups = ToArray(d->GroupList);
|
|
|
|
for (i = 0;i < LIST_NUM(d->UserList);i++)
|
|
{
|
|
ReleaseUser(users[i]);
|
|
}
|
|
for (i = 0;i < LIST_NUM(d->GroupList);i++)
|
|
{
|
|
ReleaseGroup(groups[i]);
|
|
}
|
|
|
|
Free(users);
|
|
Free(groups);
|
|
}
|
|
UnlockList(d->GroupList);
|
|
}
|
|
UnlockList(d->UserList);
|
|
|
|
// Release the root certificate list
|
|
LockList(d->RootCertList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(d->RootCertList);i++)
|
|
{
|
|
X *x = LIST_DATA(d->RootCertList, i);
|
|
FreeX(x);
|
|
}
|
|
}
|
|
UnlockList(d->RootCertList);
|
|
|
|
// Release the CRL
|
|
LockList(d->CrlList);
|
|
{
|
|
UINT i;
|
|
for (i = 0;i < LIST_NUM(d->CrlList);i++)
|
|
{
|
|
CRL *crl = LIST_DATA(d->CrlList, i);
|
|
FreeCrl(crl);
|
|
}
|
|
}
|
|
UnlockList(d->CrlList);
|
|
|
|
// Release the AC list
|
|
FreeAcList(d->AcList);
|
|
|
|
ReleaseList(d->GroupList);
|
|
ReleaseList(d->UserList);
|
|
ReleaseList(d->RootCertList);
|
|
ReleaseList(d->CrlList);
|
|
Free(d);
|
|
}
|
|
|
|
// Get a log setting of the HUB
|
|
void GetHubLogSetting(HUB *h, HUB_LOG *setting)
|
|
{
|
|
// Validate arguments
|
|
if (setting == NULL || h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Copy(setting, &h->LogSetting, sizeof(HUB_LOG));
|
|
}
|
|
|
|
// Update the log settings of the HUB
|
|
void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type)
|
|
{
|
|
UINT i1, i2;
|
|
// Validate arguments
|
|
if (setting == NULL || h == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
i1 = h->LogSetting.PacketLogSwitchType;
|
|
i2 = h->LogSetting.SecurityLogSwitchType;
|
|
|
|
Copy(&h->LogSetting, setting, sizeof(HUB_LOG));
|
|
|
|
if (no_change_switch_type)
|
|
{
|
|
h->LogSetting.PacketLogSwitchType = i1;
|
|
h->LogSetting.SecurityLogSwitchType = i2;
|
|
}
|
|
|
|
// Packet logger configuration
|
|
SetLogSwitchType(h->PacketLogger, setting->PacketLogSwitchType);
|
|
SetLogSwitchType(h->SecurityLogger, setting->SecurityLogSwitchType);
|
|
}
|
|
void SetHubLogSetting(HUB *h, HUB_LOG *setting)
|
|
{
|
|
SetHubLogSettingEx(h, setting, false);
|
|
}
|
|
|
|
// Add the trusted root certificate to the HUB
|
|
void AddRootCert(HUB *hub, X *x)
|
|
{
|
|
HUBDB *db;
|
|
// Validate arguments
|
|
if (hub == NULL || x == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
db = hub->HubDb;
|
|
if (db != NULL)
|
|
{
|
|
LockList(db->RootCertList);
|
|
{
|
|
if (LIST_NUM(db->RootCertList) < MAX_HUB_CERTS)
|
|
{
|
|
UINT i;
|
|
bool ok = true;
|
|
|
|
for (i = 0;i < LIST_NUM(db->RootCertList);i++)
|
|
{
|
|
X *exist_x = LIST_DATA(db->RootCertList, i);
|
|
if (CompareX(exist_x, x))
|
|
{
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
Insert(db->RootCertList, CloneX(x));
|
|
}
|
|
}
|
|
}
|
|
UnlockList(db->RootCertList);
|
|
}
|
|
}
|
|
|
|
// Compare the list of certificates
|
|
int CompareCert(void *p1, void *p2)
|
|
{
|
|
X *x1, *x2;
|
|
wchar_t tmp1[MAX_SIZE];
|
|
wchar_t tmp2[MAX_SIZE];
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
x1 = *(X **)p1;
|
|
x2 = *(X **)p2;
|
|
if (x1 == NULL || x2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
GetPrintNameFromX(tmp1, sizeof(tmp1), x1);
|
|
GetPrintNameFromX(tmp2, sizeof(tmp2), x2);
|
|
|
|
return UniStrCmpi(tmp1, tmp2);
|
|
}
|
|
|
|
// Creating a new HUBDB
|
|
HUBDB *NewHubDb()
|
|
{
|
|
HUBDB *d = ZeroMalloc(sizeof(HUBDB));
|
|
|
|
d->GroupList = NewList(CompareGroupName);
|
|
d->UserList = NewList(CompareUserName);
|
|
d->RootCertList = NewList(CompareCert);
|
|
d->CrlList = NewList(NULL);
|
|
d->AcList = NewAcList();
|
|
|
|
return d;
|
|
}
|
|
|
|
|