mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2025-07-06 07:44:57 +03:00
v4.12-9514-beta
This commit is contained in:
@ -229,6 +229,8 @@ static LOCK *host_ip_address_list_cache_lock = NULL;
|
||||
static UINT64 host_ip_address_list_cache_last = 0;
|
||||
static LIST *host_ip_address_cache = NULL;
|
||||
static bool disable_gethostname_by_accept = false;
|
||||
static COUNTER *getip_thread_counter = NULL;
|
||||
static UINT max_getip_thread = 0;
|
||||
|
||||
|
||||
static char *cipher_list = "RC4-MD5 RC4-SHA AES128-SHA AES256-SHA DES-CBC-SHA DES-CBC3-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA";
|
||||
@ -2005,6 +2007,17 @@ bool RUDPIsIpInValidateList(RUDP_STACK *r, IP *ip)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always allow private IP addresses
|
||||
if (IsIPPrivate(ip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsIPAddressInSameLocalNetwork(ip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0;i < LIST_NUM(r->NatT_SourceIpList);i++)
|
||||
{
|
||||
RUDP_SOURCE_IP *s = (RUDP_SOURCE_IP *)LIST_DATA(r->NatT_SourceIpList, i);
|
||||
@ -4350,6 +4363,7 @@ void RUDPIpQueryThread(THREAD *thread, void *param)
|
||||
void *route_change_poller = NULL;
|
||||
char current_hostname[MAX_SIZE];
|
||||
bool last_time_ip_changed = false;
|
||||
UINT num_retry = 0;
|
||||
// Validate arguments
|
||||
if (thread == NULL || param == NULL)
|
||||
{
|
||||
@ -4429,7 +4443,9 @@ void RUDPIpQueryThread(THREAD *thread, void *param)
|
||||
|
||||
if (IsZeroIp(&r->NatT_IP))
|
||||
{
|
||||
next_getip_tick = now + (UINT64)UDP_NAT_T_GET_IP_INTERVAL;
|
||||
num_retry++;
|
||||
|
||||
next_getip_tick = now + MIN((UINT64)UDP_NAT_T_GET_IP_INTERVAL * (UINT64)num_retry, (UINT64)UDP_NAT_T_GET_IP_INTERVAL_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6730,6 +6746,46 @@ bool IsInSameNetwork4(IP *a1, IP *a2, IP *subnet)
|
||||
|
||||
return false;
|
||||
}
|
||||
bool IsInSameNetwork4Standard(IP *a1, IP *a2)
|
||||
{
|
||||
IP subnet;
|
||||
|
||||
SetIP(&subnet, 255, 255, 0, 0);
|
||||
|
||||
return IsInSameNetwork4(a1, a2, &subnet);
|
||||
}
|
||||
bool IsInSameLocalNetworkToMe4(IP *a)
|
||||
{
|
||||
IP g1, g2;
|
||||
|
||||
Zero(&g1, sizeof(g1));
|
||||
Zero(&g2, sizeof(g2));
|
||||
|
||||
GetCurrentGlobalIPGuess(&g1, false);
|
||||
|
||||
if (IsZeroIp(&g1) == false)
|
||||
{
|
||||
if (IsInSameNetwork4Standard(&g1, a))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetCurrentGlobalIP(&g2, false))
|
||||
{
|
||||
if (IsInSameNetwork4Standard(&g2, a))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsIPAddressInSameLocalNetwork(a))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether it is a network address prefix
|
||||
bool IsNetworkAddress6(IP *ip, IP *subnet)
|
||||
@ -10926,6 +10982,20 @@ void InitHostCache()
|
||||
HostCacheList = NewList(CompareHostCache);
|
||||
}
|
||||
|
||||
// Get the number of wait threads
|
||||
UINT GetNumWaitThread()
|
||||
{
|
||||
UINT ret = 0;
|
||||
|
||||
LockList(WaitThreadList);
|
||||
{
|
||||
ret = LIST_NUM(WaitThreadList);
|
||||
}
|
||||
UnlockList(WaitThreadList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Add the thread to the thread waiting list
|
||||
void AddWaitThread(THREAD *t)
|
||||
{
|
||||
@ -16631,6 +16701,8 @@ void GetIP4Ex6ExThread(THREAD *t, void *param)
|
||||
ReleaseGetIPThreadParam(p);
|
||||
|
||||
DelWaitThread(t);
|
||||
|
||||
Dec(getip_thread_counter);
|
||||
}
|
||||
|
||||
// Perform a forward DNS query (with timeout)
|
||||
@ -16645,9 +16717,13 @@ bool GetIP4Ex6Ex2(IP *ip, char *hostname_arg, UINT timeout, bool ipv6, bool *can
|
||||
bool ret = false;
|
||||
UINT64 start_tick = 0;
|
||||
UINT64 end_tick = 0;
|
||||
UINT64 spent_time = 0;
|
||||
UINT64 now;
|
||||
UINT n;
|
||||
bool use_dns_proxy = false;
|
||||
char hostname[260];
|
||||
UINT i;
|
||||
bool timed_out;
|
||||
// Validate arguments
|
||||
if (ip == NULL || hostname_arg == NULL)
|
||||
{
|
||||
@ -16718,6 +16794,89 @@ bool GetIP4Ex6Ex2(IP *ip, char *hostname_arg, UINT timeout, bool ipv6, bool *can
|
||||
}
|
||||
|
||||
|
||||
// check the quota
|
||||
start_tick = Tick64();
|
||||
end_tick = start_tick + (UINT64)timeout;
|
||||
|
||||
n = 0;
|
||||
|
||||
timed_out = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
UINT64 now = Tick64();
|
||||
UINT64 remain;
|
||||
UINT remain32;
|
||||
|
||||
if (GetGetIpThreadMaxNum() > GetCurrentGetIpThreadNum())
|
||||
{
|
||||
// below the quota
|
||||
break;
|
||||
}
|
||||
|
||||
if (now >= end_tick)
|
||||
{
|
||||
// timeouted
|
||||
timed_out = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cancel != NULL && (*cancel))
|
||||
{
|
||||
// cancelled
|
||||
timed_out = true;
|
||||
break;
|
||||
}
|
||||
|
||||
remain = end_tick - now;
|
||||
remain32 = MIN((UINT)remain, 100);
|
||||
|
||||
SleepThread(remain32);
|
||||
n++;
|
||||
}
|
||||
|
||||
now = Tick64();
|
||||
spent_time = now - start_tick;
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
spent_time = 0;
|
||||
}
|
||||
|
||||
if ((UINT)spent_time >= timeout)
|
||||
{
|
||||
timed_out = true;
|
||||
}
|
||||
|
||||
if (timed_out)
|
||||
{
|
||||
IP ip2;
|
||||
|
||||
// timed out, cancelled
|
||||
if (QueryDnsCache(&ip2, hostname))
|
||||
{
|
||||
ret = true;
|
||||
|
||||
Copy(ip, &ip2, sizeof(IP));
|
||||
}
|
||||
|
||||
Debug("GetIP4Ex6Ex2: Worker thread quota exceeded: max=%u current=%u\n",
|
||||
GetGetIpThreadMaxNum(), GetCurrentGetIpThreadNum());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Increment the counter
|
||||
Inc(getip_thread_counter);
|
||||
|
||||
if (spent_time != 0)
|
||||
{
|
||||
Debug("GetIP4Ex6Ex2: Waited for %u msecs to create a worker thread.\n",
|
||||
spent_time);
|
||||
}
|
||||
|
||||
timeout -= (UINT)spent_time;
|
||||
|
||||
p = ZeroMalloc(sizeof(GETIP_THREAD_PARAM));
|
||||
p->Ref = NewRef();
|
||||
StrCpy(p->HostName, sizeof(p->HostName), hostname);
|
||||
@ -16774,6 +16933,7 @@ bool GetIP4Ex6Ex2(IP *ip, char *hostname_arg, UINT timeout, bool ipv6, bool *can
|
||||
{
|
||||
IP ip2;
|
||||
|
||||
#if 0
|
||||
if (only_direct_dns == false)
|
||||
{
|
||||
if (ipv6)
|
||||
@ -16802,6 +16962,7 @@ bool GetIP4Ex6Ex2(IP *ip, char *hostname_arg, UINT timeout, bool ipv6, bool *can
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (QueryDnsCache(&ip2, hostname))
|
||||
{
|
||||
@ -17457,6 +17618,27 @@ void FreeSSLCtx(struct ssl_ctx_st *ctx)
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
|
||||
// The number of get ip threads
|
||||
void SetGetIpThreadMaxNum(UINT num)
|
||||
{
|
||||
max_getip_thread = num;
|
||||
}
|
||||
UINT GetGetIpThreadMaxNum()
|
||||
{
|
||||
UINT ret = max_getip_thread;
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
UINT GetCurrentGetIpThreadNum()
|
||||
{
|
||||
return Count(getip_thread_counter);
|
||||
}
|
||||
|
||||
// Initialize the network communication module
|
||||
void InitNetwork()
|
||||
{
|
||||
@ -17471,6 +17653,8 @@ void InitNetwork()
|
||||
|
||||
num_tcp_connections = NewCounter();
|
||||
|
||||
getip_thread_counter = NewCounter();
|
||||
|
||||
// Initialization of client list
|
||||
InitIpClientList();
|
||||
|
||||
@ -17515,6 +17699,8 @@ void InitNetwork()
|
||||
dh_1024 = DhNewGroup2();
|
||||
|
||||
Zero(rand_port_numbers, sizeof(rand_port_numbers));
|
||||
|
||||
SetGetIpThreadMaxNum(DEFAULT_GETIP_THREAD_MAX_NUM);
|
||||
}
|
||||
|
||||
// Enable the network name cache
|
||||
@ -17770,6 +17956,45 @@ void FreePrivateIPFile()
|
||||
g_use_privateip_file = false;
|
||||
}
|
||||
|
||||
// Check whether the specified IP address is in the same network to this computer
|
||||
bool IsIPAddressInSameLocalNetwork(IP *a)
|
||||
{
|
||||
bool ret = false;
|
||||
LIST *o;
|
||||
UINT i;
|
||||
// Validate arguments
|
||||
if (a == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
o = GetHostIPAddressList();
|
||||
|
||||
if (o != NULL)
|
||||
{
|
||||
for (i = 0;i < LIST_NUM(o);i++)
|
||||
{
|
||||
IP *p = LIST_DATA(o, i);
|
||||
|
||||
if (IsIP4(p))
|
||||
{
|
||||
if (IsZeroIp(p) == false && p->addr[0] != 127)
|
||||
{
|
||||
if (IsInSameNetwork4Standard(p, a))
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeHostIPAddressList(o);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Guess the IPv4, IPv6 global address from the IP address list of the current interface
|
||||
void GetCurrentGlobalIPGuess(IP *ip, bool ipv6)
|
||||
{
|
||||
@ -17950,6 +18175,9 @@ void FreeNetwork()
|
||||
|
||||
FreeDynList();
|
||||
|
||||
DeleteCounter(getip_thread_counter);
|
||||
getip_thread_counter = NULL;
|
||||
|
||||
}
|
||||
|
||||
// Add a socket to socket list
|
||||
@ -19114,6 +19342,46 @@ int CmpIpAddressList(void *p1, void *p2)
|
||||
return r;
|
||||
}
|
||||
|
||||
// Get the IP address list hash of the host
|
||||
UINT64 GetHostIPAddressListHash()
|
||||
{
|
||||
UINT i;
|
||||
LIST *o;
|
||||
BUF *buf = NewBuf();
|
||||
UCHAR hash[SHA1_SIZE];
|
||||
UINT64 ret = 0;
|
||||
|
||||
o = GetHostIPAddressList();
|
||||
|
||||
if (o != NULL)
|
||||
{
|
||||
for (i = 0;i < LIST_NUM(o);i++)
|
||||
{
|
||||
IP *ip = LIST_DATA(o, i);
|
||||
char tmp[128];
|
||||
|
||||
Zero(tmp, sizeof(tmp));
|
||||
IPToStr(tmp, sizeof(tmp), ip);
|
||||
|
||||
WriteBufStr(buf, tmp);
|
||||
}
|
||||
|
||||
FreeHostIPAddressList(o);
|
||||
}
|
||||
|
||||
WriteBufStr(buf, "test");
|
||||
|
||||
HashSha1(hash, buf->Buf, buf->Size);
|
||||
|
||||
FreeBuf(buf);
|
||||
|
||||
Copy(&ret, hash, sizeof(UINT64));
|
||||
|
||||
ret = Endian64(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the IP address list of the host (using cache)
|
||||
LIST *GetHostIPAddressList()
|
||||
{
|
||||
|
@ -147,6 +147,13 @@ struct DYN_VALUE
|
||||
|
||||
#define MAX_NUM_IGNORE_ERRORS 1024
|
||||
|
||||
#ifndef USE_STRATEGY_LOW_MEMORY
|
||||
#define DEFAULT_GETIP_THREAD_MAX_NUM 512
|
||||
#else // USE_STRATEGY_LOW_MEMORY
|
||||
#define DEFAULT_GETIP_THREAD_MAX_NUM 64
|
||||
#endif // USE_STRATEGY_LOW_MEMORY
|
||||
|
||||
|
||||
// SSL logging function
|
||||
//#define ENABLE_SSL_LOGGING
|
||||
#define SSL_LOGGING_DIRNAME "@ssl_log"
|
||||
@ -748,6 +755,7 @@ struct RUDP_SESSION
|
||||
|
||||
// Related to processing to get the IP address of the NAT-T server
|
||||
#define UDP_NAT_T_GET_IP_INTERVAL DYN32(UDP_NAT_T_GET_IP_INTERVAL, (5 * 1000)) // IP address acquisition interval of NAT-T server (before success)
|
||||
#define UDP_NAT_T_GET_IP_INTERVAL_MAX DYN32(UDP_NAT_T_GET_IP_INTERVAL, (150 * 1000)) // IP address acquisition interval of NAT-T server (before success)
|
||||
#define UDP_NAT_T_GET_IP_INTERVAL_AFTER DYN32(UDP_NAT_T_GET_IP_INTERVAL_AFTER, (5 * 60 * 1000)) // IP address acquisition interval of NAT-T server (after success)
|
||||
|
||||
// Related to process to get the private IP address of itself with making a TCP connection to the NAT-T server
|
||||
@ -1418,6 +1426,7 @@ void RouteToStr(char *str, UINT str_size, ROUTE_ENTRY *e);
|
||||
void DebugPrintRoute(ROUTE_ENTRY *e);
|
||||
void DebugPrintRouteTable(ROUTE_TABLE *r);
|
||||
bool IsIPv6LocalNetworkAddress(IP *ip);
|
||||
UINT GetNumWaitThread();
|
||||
|
||||
#ifdef ENABLE_SSL_LOGGING
|
||||
void SockEnableSslLogging(SOCK *s);
|
||||
@ -1484,6 +1493,8 @@ void IPNot4(IP *dst, IP *a);
|
||||
void IPOr4(IP *dst, IP *a, IP *b);
|
||||
void IPAnd4(IP *dst, IP *a, IP *b);
|
||||
bool IsInSameNetwork4(IP *a1, IP *a2, IP *subnet);
|
||||
bool IsInSameNetwork4Standard(IP *a1, IP *a2);
|
||||
bool IsInSameLocalNetworkToMe4(IP *a);
|
||||
|
||||
bool ParseIpAndSubnetMask4(char *src, UINT *ip, UINT *mask);
|
||||
bool ParseIpAndSubnetMask6(char *src, IP *ip, IP *mask);
|
||||
@ -1539,6 +1550,7 @@ bool IsMyIPAddress(IP *ip);
|
||||
void FreeHostIPAddressList(LIST *o);
|
||||
void AddHostIPAddressToList(LIST *o, IP *ip);
|
||||
int CmpIpAddressList(void *p1, void *p2);
|
||||
UINT64 GetHostIPAddressListHash();
|
||||
|
||||
UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param);
|
||||
void UdpListenerThread(THREAD *thread, void *param);
|
||||
@ -1599,6 +1611,7 @@ bool SslBioSync(SSL_BIO *b, bool sync_send, bool sync_recv);
|
||||
void SetCurrentGlobalIP(IP *ip, bool ipv6);
|
||||
bool GetCurrentGlobalIP(IP *ip, bool ipv6);
|
||||
void GetCurrentGlobalIPGuess(IP *ip, bool ipv6);
|
||||
bool IsIPAddressInSameLocalNetwork(IP *a);
|
||||
|
||||
bool IsIPPrivate(IP *ip);
|
||||
bool IsIPMyHost(IP *ip);
|
||||
@ -1631,6 +1644,11 @@ QUERYIPTHREAD *NewQueryIpThread(char *hostname, UINT interval_last_ok, UINT inte
|
||||
bool GetQueryIpThreadResult(QUERYIPTHREAD *t, IP *ip);
|
||||
void FreeQueryIpThread(QUERYIPTHREAD *t);
|
||||
|
||||
void SetGetIpThreadMaxNum(UINT num);
|
||||
UINT GetGetIpThreadMaxNum();
|
||||
UINT GetCurrentGetIpThreadNum();
|
||||
|
||||
|
||||
|
||||
bool IsIpInStrList(IP *ip, char *ip_list);
|
||||
bool IsInStrByStrList(char *str, char *str_list);
|
||||
|
@ -3304,11 +3304,44 @@ BUF *BuildDhcpOptionsBuf(LIST *o)
|
||||
for (i = 0;i < LIST_NUM(o);i++)
|
||||
{
|
||||
DHCP_OPTION *d = LIST_DATA(o, i);
|
||||
UINT current_size = d->Size;
|
||||
UINT current_pos = 0;
|
||||
|
||||
id = (UCHAR)d->Id;
|
||||
sz = (UCHAR)d->Size;
|
||||
if (d->Size <= 255)
|
||||
{
|
||||
sz = (UCHAR)d->Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = 0xFF;
|
||||
}
|
||||
WriteBuf(b, &id, 1);
|
||||
WriteBuf(b, &sz, 1);
|
||||
WriteBuf(b, d->Data, d->Size);
|
||||
WriteBuf(b, d->Data, sz);
|
||||
|
||||
current_size -= sz;
|
||||
current_pos += sz;
|
||||
|
||||
while (current_size != 0)
|
||||
{
|
||||
id = DHCP_ID_PRIVATE;
|
||||
if (current_size <= 255)
|
||||
{
|
||||
sz = (UCHAR)current_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = 0xFF;
|
||||
}
|
||||
WriteBuf(b, &id, 1);
|
||||
WriteBuf(b, &sz, 1);
|
||||
WriteBuf(b, ((UCHAR *)d->Data) + current_pos, sz);
|
||||
|
||||
current_size -= sz;
|
||||
current_pos += sz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
id = 0xff;
|
||||
@ -3755,27 +3788,24 @@ BUF *DhcpBuildClasslessRouteData(DHCP_CLASSLESS_ROUTE_TABLE *t)
|
||||
|
||||
if (r->Exists && r->SubnetMaskLen <= 32)
|
||||
{
|
||||
if (b->Size <= (255 - 9))
|
||||
{
|
||||
UCHAR c;
|
||||
UINT data_len;
|
||||
UINT ip32;
|
||||
UCHAR tmp[4];
|
||||
UCHAR c;
|
||||
UINT data_len;
|
||||
UINT ip32;
|
||||
UCHAR tmp[4];
|
||||
|
||||
// Width of subnet mask
|
||||
c = (UCHAR)r->SubnetMaskLen;
|
||||
WriteBuf(b, &c, 1);
|
||||
// Width of subnet mask
|
||||
c = (UCHAR)r->SubnetMaskLen;
|
||||
WriteBuf(b, &c, 1);
|
||||
|
||||
// Number of significant octets
|
||||
data_len = (r->SubnetMaskLen + 7) / 8;
|
||||
Zero(tmp, sizeof(tmp));
|
||||
Copy(tmp, &r->Network, data_len);
|
||||
WriteBuf(b, tmp, data_len);
|
||||
// Number of significant octets
|
||||
data_len = (r->SubnetMaskLen + 7) / 8;
|
||||
Zero(tmp, sizeof(tmp));
|
||||
Copy(tmp, &r->Network, data_len);
|
||||
WriteBuf(b, tmp, data_len);
|
||||
|
||||
// Gateway
|
||||
ip32 = IPToUINT(&r->Gateway);
|
||||
WriteBuf(b, &ip32, sizeof(UINT));
|
||||
}
|
||||
// Gateway
|
||||
ip32 = IPToUINT(&r->Gateway);
|
||||
WriteBuf(b, &ip32, sizeof(UINT));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3965,6 +3995,7 @@ LIST *ParseDhcpOptions(void *data, UINT size)
|
||||
{
|
||||
BUF *b;
|
||||
LIST *o;
|
||||
DHCP_OPTION *last_opt;
|
||||
// Validate arguments
|
||||
if (data == NULL)
|
||||
{
|
||||
@ -3977,6 +4008,8 @@ LIST *ParseDhcpOptions(void *data, UINT size)
|
||||
|
||||
o = NewListFast(NULL);
|
||||
|
||||
last_opt = NULL;
|
||||
|
||||
while (true)
|
||||
{
|
||||
UCHAR c = 0;
|
||||
@ -3995,12 +4028,27 @@ LIST *ParseDhcpOptions(void *data, UINT size)
|
||||
break;
|
||||
}
|
||||
|
||||
opt = ZeroMalloc(sizeof(DHCP_OPTION));
|
||||
opt->Id = (UINT)c;
|
||||
opt->Size = (UINT)sz;
|
||||
opt->Data = ZeroMalloc((UINT)sz);
|
||||
ReadBuf(b, opt->Data, sz);
|
||||
Add(o, opt);
|
||||
if (c == DHCP_ID_PRIVATE && last_opt != NULL)
|
||||
{
|
||||
UINT new_size = last_opt->Size + (UINT)sz;
|
||||
UCHAR *new_buf = ZeroMalloc(new_size);
|
||||
Copy(new_buf, last_opt->Data, last_opt->Size);
|
||||
ReadBuf(b, new_buf + last_opt->Size, sz);
|
||||
Free(last_opt->Data);
|
||||
last_opt->Data = new_buf;
|
||||
last_opt->Size = new_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt = ZeroMalloc(sizeof(DHCP_OPTION));
|
||||
opt->Id = (UINT)c;
|
||||
opt->Size = (UINT)sz;
|
||||
opt->Data = ZeroMalloc((UINT)sz);
|
||||
ReadBuf(b, opt->Data, sz);
|
||||
Add(o, opt);
|
||||
|
||||
last_opt = opt;
|
||||
}
|
||||
}
|
||||
|
||||
FreeBuf(b);
|
||||
|
@ -625,6 +625,7 @@ struct ICMPV6_HEADER_INFO
|
||||
#define DHCP_ID_REQ_PARAM_LIST 0x37
|
||||
#define DHCP_ID_CLASSLESS_ROUTE 0x79
|
||||
#define DHCP_ID_MS_CLASSLESS_ROUTE 0xF9
|
||||
#define DHCP_ID_PRIVATE 0xFA
|
||||
|
||||
|
||||
// DHCP client action
|
||||
|
Reference in New Issue
Block a user