1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-22 17:39:53 +03:00

Merge pull request #1443 from domosekai/win32

Add IPv6 route management for Windows client
This commit is contained in:
Yihong Wu 2021-09-18 22:12:27 +08:00 committed by GitHub
commit 03859eb515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 263 additions and 330 deletions

View File

@ -162,7 +162,6 @@ void RouteTrackingMain(SESSION *s)
char ip_str2[64]; char ip_str2[64];
Copy(&e->DestIP, &nat_t_ip, sizeof(IP)); Copy(&e->DestIP, &nat_t_ip, sizeof(IP));
e->Metric = e->OldIfMetric;
IPToStr(ip_str, sizeof(ip_str), &e->DestIP); IPToStr(ip_str, sizeof(ip_str), &e->DestIP);
IPToStr(ip_str2, sizeof(ip_str2), &e->GatewayIP); IPToStr(ip_str2, sizeof(ip_str2), &e->GatewayIP);
@ -190,9 +189,12 @@ void RouteTrackingMain(SESSION *s)
{ {
UINT i; UINT i;
bool route_to_server_erased = true; bool route_to_server_erased = true;
bool is_vlan_want_to_be_default_gateway = false; bool is_vlan_want_to_be_default_gateway_v4 = false;
UINT vlan_default_gateway_metric = 0; bool is_vlan_want_to_be_default_gateway_v6 = false;
UINT other_if_default_gateway_metric_min = INFINITE; UINT vlan_default_gateway_metric_v4 = 0;
UINT vlan_default_gateway_metric_v6 = 0;
UINT other_if_default_gateway_metric_min_v4 = INFINITE;
UINT other_if_default_gateway_metric_min_v6 = INFINITE;
// Get whether the routing table have been changed // Get whether the routing table have been changed
if (t->LastRoutingTableHash != table->HashedValue) if (t->LastRoutingTableHash != table->HashedValue)
@ -224,59 +226,77 @@ void RouteTrackingMain(SESSION *s)
} }
// Search for the default gateway // Search for the default gateway
if (IPToUINT(&e->DestIP) == 0 && if (IsZeroIP(&e->DestIP) && IsZeroIP(&e->DestMask))
IPToUINT(&e->DestMask) == 0)
{ {
Debug("e->InterfaceID = %u, t->VLanInterfaceId = %u\n", Debug("e->InterfaceID = %u, t->VLanInterfaceId = %u\n",
e->InterfaceID, t->VLanInterfaceId); e->InterfaceID, t->VLanInterfaceId);
if (e->InterfaceID == t->VLanInterfaceId) if (e->InterfaceID == t->VLanInterfaceId)
{ {
// The virtual LAN card think that he want to be a default gateway if (IsIP4(&e->DestIP))
is_vlan_want_to_be_default_gateway = true;
vlan_default_gateway_metric = e->Metric;
if (vlan_default_gateway_metric >= 2 &&
t->OldDefaultGatewayMetric == (vlan_default_gateway_metric - 1))
{ {
// Restore because the PPP server rewrites // The virtual LAN card think that he want to be a default gateway
// the routing table selfishly is_vlan_want_to_be_default_gateway_v4 = true;
DeleteRouteEntry(e); vlan_default_gateway_metric_v4 = e->Metric;
e->Metric--;
AddRouteEntry(e);
Debug("** Restore metric destroyed by PPP.\n");
any_modified = true; // PPP route fix
if (vlan_default_gateway_metric_v4 >= 2 &&
t->OldDefaultGatewayMetric == (vlan_default_gateway_metric_v4 - 1))
{
// Restore because the PPP server rewrites
// the routing table selfishly
DeleteRouteEntry(e);
e->Metric--;
AddRouteEntry(e);
Debug("** Restore metric destroyed by PPP.\n");
any_modified = true;
}
// Keep this entry
if (t->DefaultGatewayByVLan != NULL)
{
// Delete if there is one added last time
FreeRouteEntry(t->DefaultGatewayByVLan);
}
t->DefaultGatewayByVLan = ZeroMalloc(sizeof(ROUTE_ENTRY));
Copy(t->DefaultGatewayByVLan, e, sizeof(ROUTE_ENTRY));
t->OldDefaultGatewayMetric = vlan_default_gateway_metric_v4;
} }
else
// Keep this entry
if (t->DefaultGatewayByVLan != NULL)
{ {
// Delete if there is one added last time is_vlan_want_to_be_default_gateway_v6 = true;
FreeRouteEntry(t->DefaultGatewayByVLan); vlan_default_gateway_metric_v6 = e->Metric;
} }
t->DefaultGatewayByVLan = ZeroMalloc(sizeof(ROUTE_ENTRY));
Copy(t->DefaultGatewayByVLan, e, sizeof(ROUTE_ENTRY));
t->OldDefaultGatewayMetric = vlan_default_gateway_metric;
} }
else else
{ {
// There are default gateway other than the virtual LAN card if (IsIP4(&e->DestIP))
// Save the metric value of the default gateway
if (other_if_default_gateway_metric_min > e->Metric)
{ {
// Ignore the metric value of all PPP connection in the case of Windows Vista // There are default gateway other than the virtual LAN card
if (e->PPPConnection == false) // Save the metric value of the default gateway
if (other_if_default_gateway_metric_min_v4 > e->Metric)
{ {
other_if_default_gateway_metric_min = e->Metric; // Ignore the metric value of all PPP connection in the case of Windows Vista
if (e->PPPConnection == false)
{
other_if_default_gateway_metric_min_v4 = e->Metric;
}
else
{
// a PPP is used to Connect to the network
// in using Windows Vista
t->VistaAndUsingPPP = true;
}
} }
else }
else
{
if (other_if_default_gateway_metric_min_v6 > e->Metric)
{ {
// a PPP is used to Connect to the network other_if_default_gateway_metric_min_v6 = e->Metric;
// in using Windows Vista
t->VistaAndUsingPPP = true;
} }
} }
} }
@ -287,7 +307,7 @@ void RouteTrackingMain(SESSION *s)
{ {
if (t->DefaultGatewayByVLan != NULL) if (t->DefaultGatewayByVLan != NULL)
{ {
if (is_vlan_want_to_be_default_gateway) if (is_vlan_want_to_be_default_gateway_v4)
{ {
if (t->VistaOldDefaultGatewayByVLan == NULL || Cmp(t->VistaOldDefaultGatewayByVLan, t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)) != 0) if (t->VistaOldDefaultGatewayByVLan == NULL || Cmp(t->VistaOldDefaultGatewayByVLan, t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)) != 0)
{ {
@ -362,8 +382,9 @@ void RouteTrackingMain(SESSION *s)
// to elect the virtual LAN card as the default gateway // to elect the virtual LAN card as the default gateway
// Debug("is_vlan_want_to_be_default_gateway = %u, rs = %u, route_to_server_erased = %u, other_if_default_gateway_metric_min = %u, vlan_default_gateway_metric = %u\n", // Debug("is_vlan_want_to_be_default_gateway = %u, rs = %u, route_to_server_erased = %u, other_if_default_gateway_metric_min = %u, vlan_default_gateway_metric = %u\n",
// is_vlan_want_to_be_default_gateway, rs, route_to_server_erased, other_if_default_gateway_metric_min, vlan_default_gateway_metric); // is_vlan_want_to_be_default_gateway, rs, route_to_server_erased, other_if_default_gateway_metric_min, vlan_default_gateway_metric);
if (is_vlan_want_to_be_default_gateway && (rs != NULL && route_to_server_erased == false) && if ((is_vlan_want_to_be_default_gateway_v4 && other_if_default_gateway_metric_min_v4 >= vlan_default_gateway_metric_v4 ||
other_if_default_gateway_metric_min >= vlan_default_gateway_metric) is_vlan_want_to_be_default_gateway_v6 && other_if_default_gateway_metric_min_v6 >= vlan_default_gateway_metric_v6)
&& rs != NULL && route_to_server_erased == false)
{ {
// Scan the routing table again // Scan the routing table again
for (i = 0;i < table->NumEntry;i++) for (i = 0;i < table->NumEntry;i++)
@ -372,8 +393,7 @@ void RouteTrackingMain(SESSION *s)
if (e->InterfaceID != t->VLanInterfaceId) if (e->InterfaceID != t->VLanInterfaceId)
{ {
if (IPToUINT(&e->DestIP) == 0 && if (IsZeroIP(&e->DestIP) && IsZeroIP(&e->DestMask))
IPToUINT(&e->DestMask) == 0)
{ {
char str[64]; char str[64];
// Default gateway is found // Default gateway is found
@ -486,8 +506,6 @@ void RouteTrackingStart(SESSION *s)
Debug("GetBestRouteEntry() Succeed. [Gateway: %s]\n", tmp); Debug("GetBestRouteEntry() Succeed. [Gateway: %s]\n", tmp);
// Add a route // Add a route
e->Metric = e->OldIfMetric;
if (AddRouteEntryEx(e, &already_exists) == false) if (AddRouteEntryEx(e, &already_exists) == false)
{ {
FreeRouteEntry(e); FreeRouteEntry(e);
@ -549,8 +567,6 @@ void RouteTrackingStart(SESSION *s)
else else
{ {
// Add a route // Add a route
dns->Metric = dns->OldIfMetric;
if (AddRouteEntry(dns) == false) if (AddRouteEntry(dns) == false)
{ {
FreeRouteEntry(dns); FreeRouteEntry(dns);
@ -569,8 +585,6 @@ void RouteTrackingStart(SESSION *s)
if (route_to_real_server_global != NULL) if (route_to_real_server_global != NULL)
{ {
route_to_real_server_global->Metric = route_to_real_server_global->OldIfMetric;
if (AddRouteEntry(route_to_real_server_global) == false) if (AddRouteEntry(route_to_real_server_global) == false)
{ {
FreeRouteEntry(route_to_real_server_global); FreeRouteEntry(route_to_real_server_global);
@ -633,11 +647,6 @@ void RouteTrackingStart(SESSION *s)
MsFreeAdapter(a); MsFreeAdapter(a);
} }
} }
else
{
// For Win9x
Win32RenewDhcp9x(if_id);
}
// Clear the DNS cache // Clear the DNS cache
Win32FlushDnsCache(); Win32FlushDnsCache();
@ -782,12 +791,12 @@ void RouteTrackingStop(SESSION *s, ROUTE_TRACKING *t)
// If the restoring routing entry is a default gateway and // If the restoring routing entry is a default gateway and
// the existing routing table contains another default gateway // the existing routing table contains another default gateway
// on the interface, give up restoring the entry // on the interface, give up restoring the entry
if (IPToUINT(&e->DestIP) == 0 && IPToUINT(&e->DestMask) == 0) if (IsZeroIP(&e->DestIP) && IsZeroIP(&e->DestMask))
{ {
for (i = 0;i < table->NumEntry;i++) for (i = 0;i < table->NumEntry;i++)
{ {
ROUTE_ENTRY *r = table->Entry[i]; ROUTE_ENTRY *r = table->Entry[i];
if (IPToUINT(&r->DestIP) == 0 && IPToUINT(&r->DestMask) == 0) if (IsZeroIP(&r->DestIP) && IsZeroIP(&r->DestMask))
{ {
if (r->InterfaceID == e->InterfaceID) if (r->InterfaceID == e->InterfaceID)
{ {

View File

@ -59,9 +59,9 @@
struct ROUTE_CHANGE_DATA struct ROUTE_CHANGE_DATA
{ {
OVERLAPPED Overlapped;
HANDLE Handle; HANDLE Handle;
UINT NumCalled; UINT NumCalled;
bool Changed;
}; };
#endif #endif
@ -6124,7 +6124,7 @@ ICMP_RESULT *IcmpApiEchoSend(IP *dest_ip, UCHAR ttl, UCHAR *data, UINT size, UIN
ROUTE_CHANGE *NewRouteChange() ROUTE_CHANGE *NewRouteChange()
{ {
#ifdef OS_WIN32 #ifdef OS_WIN32
return Win32NewRouteChange(); return Win32NewRouteChange2(true, true, NULL);
#else // OS_WIN32 #else // OS_WIN32
return NULL; return NULL;
#endif // OS_WIN32 #endif // OS_WIN32
@ -6134,7 +6134,7 @@ ROUTE_CHANGE *NewRouteChange()
void FreeRouteChange(ROUTE_CHANGE *r) void FreeRouteChange(ROUTE_CHANGE *r)
{ {
#ifdef OS_WIN32 #ifdef OS_WIN32
Win32FreeRouteChange(r); Win32FreeRouteChange2(r);
#endif // OS_WIN32 #endif // OS_WIN32
} }
@ -6142,27 +6142,54 @@ void FreeRouteChange(ROUTE_CHANGE *r)
bool IsRouteChanged(ROUTE_CHANGE *r) bool IsRouteChanged(ROUTE_CHANGE *r)
{ {
#ifdef OS_WIN32 #ifdef OS_WIN32
return Win32IsRouteChanged(r); return Win32IsRouteChanged2(r);
#else // OS_WIN32 #else // OS_WIN32
return false; return false;
#endif // OS_WIN32 #endif // OS_WIN32
} }
// Routing table change detector function (Win32)
#ifdef OS_WIN32 #ifdef OS_WIN32
ROUTE_CHANGE *Win32NewRouteChange() void Win32RouteChangeCallback(void *context, MIB_IPFORWARD_ROW2 *row, MIB_NOTIFICATION_TYPE nt)
{
ROUTE_CHANGE_DATA *data = context;
data->Changed = true;
}
// Routing table change detector function (For Vista and later)
ROUTE_CHANGE *Win32NewRouteChange2(bool ipv4, bool ipv6, void *callback)
{ {
ROUTE_CHANGE *r; ROUTE_CHANGE *r;
BOOL ret; BOOL ret;
ADDRESS_FAMILY family;
r = ZeroMalloc(sizeof(ROUTE_CHANGE)); r = ZeroMalloc(sizeof(ROUTE_CHANGE));
r->Data = ZeroMalloc(sizeof(ROUTE_CHANGE_DATA)); r->Data = ZeroMalloc(sizeof(ROUTE_CHANGE_DATA));
r->Data->Overlapped.hEvent = CreateEventA(NULL, false, true, NULL); if (ipv4 && ipv6)
{
family = AF_UNSPEC;
}
else if (ipv6)
{
family = AF_INET6;
}
else
{
family = AF_INET;
}
ret = NotifyRouteChange(&r->Data->Handle, &r->Data->Overlapped); if (callback != NULL)
if (!(ret == NO_ERROR || ret == WSA_IO_PENDING || WSAGetLastError() == WSA_IO_PENDING)) {
ret = NotifyRouteChange2(family, (PIPFORWARD_CHANGE_CALLBACK)callback, r->Data, false, &r->Data->Handle);
}
else
{
// Use default callback if not provided
ret = NotifyRouteChange2(family, (PIPFORWARD_CHANGE_CALLBACK)Win32RouteChangeCallback, r->Data, false, &r->Data->Handle);
}
if (ret != NO_ERROR)
{ {
Free(r->Data); Free(r->Data);
Free(r); Free(r);
@ -6173,7 +6200,7 @@ ROUTE_CHANGE *Win32NewRouteChange()
return r; return r;
} }
void Win32FreeRouteChange(ROUTE_CHANGE *r) void Win32FreeRouteChange2(ROUTE_CHANGE *r)
{ {
// Validate arguments // Validate arguments
if (r == NULL) if (r == NULL)
@ -6181,14 +6208,13 @@ void Win32FreeRouteChange(ROUTE_CHANGE *r)
return; return;
} }
CancelIPChangeNotify(&r->Data->Overlapped); CancelMibChangeNotify2(r->Data->Handle);
CloseHandle(r->Data->Overlapped.hEvent);
Free(r->Data); Free(r->Data);
Free(r); Free(r);
} }
bool Win32IsRouteChanged(ROUTE_CHANGE *r) bool Win32IsRouteChanged2(ROUTE_CHANGE *r)
{ {
// Validate arguments // Validate arguments
if (r == NULL) if (r == NULL)
@ -6201,9 +6227,9 @@ bool Win32IsRouteChanged(ROUTE_CHANGE *r)
return true; return true;
} }
if (WaitForSingleObject(r->Data->Overlapped.hEvent, 0) == WAIT_OBJECT_0) if (r->Data->Changed)
{ {
NotifyRouteChange(&r->Data->Handle, &r->Data->Overlapped); r->Data->Changed = false;
return true; return true;
} }
@ -6481,6 +6507,17 @@ void GenerateEui64Address6(UCHAR *dst, UCHAR *mac)
} }
// Examine whether two IP addresses are in the same network // Examine whether two IP addresses are in the same network
bool IsInSameNetwork(IP *a1, IP *a2, IP *subnet)
{
if (IsIP4(a1))
{
return IsInSameNetwork4(a1, a2, subnet);
}
else
{
return IsInSameNetwork6(a1, a2, subnet);
}
}
bool IsInSameNetwork6ByStr(char *ip1, char *ip2, char *subnet) bool IsInSameNetwork6ByStr(char *ip1, char *ip2, char *subnet)
{ {
IP p1, p2, s; IP p1, p2, s;
@ -8972,118 +9009,6 @@ void Win32FlushDnsCache()
Run("ipconfig.exe", "/flushdns", true, false); Run("ipconfig.exe", "/flushdns", true, false);
} }
// Update the DHCP address of the specified LAN card
void Win32RenewDhcp9x(UINT if_id)
{
IP_INTERFACE_INFO *info;
ULONG size;
int i;
LIST *o;
// Validate arguments
if (if_id == 0)
{
return;
}
size = sizeof(IP_INTERFACE_INFO);
info = ZeroMallocFast(size);
if (GetInterfaceInfo(info, &size) == ERROR_INSUFFICIENT_BUFFER)
{
Free(info);
info = ZeroMallocFast(size);
}
if (GetInterfaceInfo(info, &size) != NO_ERROR)
{
Free(info);
return;
}
o = NewListFast(CompareIpAdapterIndexMap);
for (i = 0; i < info->NumAdapters; i++)
{
IP_ADAPTER_INDEX_MAP *a = &info->Adapter[i];
Add(o, a);
}
Sort(o);
for (i = 0; i < (int)(LIST_NUM(o)); i++)
{
IP_ADAPTER_INDEX_MAP *a = LIST_DATA(o, i);
if (a->Index == if_id)
{
char arg[MAX_PATH];
Format(arg, sizeof(arg), "/renew %u", i);
Run("ipconfig.exe", arg, true, false);
}
}
ReleaseList(o);
Free(info);
}
// Release the DHCP address of the specified LAN card
void Win32ReleaseDhcp9x(UINT if_id, bool wait)
{
IP_INTERFACE_INFO *info;
ULONG size;
int i;
LIST *o;
// Validate arguments
if (if_id == 0)
{
return;
}
size = sizeof(IP_INTERFACE_INFO);
info = ZeroMallocFast(size);
if (GetInterfaceInfo(info, &size) == ERROR_INSUFFICIENT_BUFFER)
{
Free(info);
info = ZeroMallocFast(size);
}
if (GetInterfaceInfo(info, &size) != NO_ERROR)
{
Free(info);
return;
}
o = NewListFast(CompareIpAdapterIndexMap);
for (i = 0; i < info->NumAdapters; i++)
{
IP_ADAPTER_INDEX_MAP *a = &info->Adapter[i];
Add(o, a);
}
Sort(o);
for (i = 0; i < (int)(LIST_NUM(o)); i++)
{
IP_ADAPTER_INDEX_MAP *a = LIST_DATA(o, i);
if (a->Index == if_id)
{
char arg[MAX_PATH];
Format(arg, sizeof(arg), "/release %u", i);
Run("ipconfig.exe", arg, true, wait);
}
}
ReleaseList(o);
Free(info);
}
// Enumerate a list of virtual LAN cards that contains the specified string // Enumerate a list of virtual LAN cards that contains the specified string
char **Win32EnumVLan(char *tag_name) char **Win32EnumVLan(char *tag_name)
{ {
@ -9342,41 +9267,29 @@ bool Win32GetDefaultDns(IP *ip, char *domain, UINT size)
return true; return true;
} }
// IP conversion function for Win32 // Remove a routing entry from the routing table (For Vista and later)
void Win32UINTToIP(IP *ip, UINT i) void Win32DeleteRouteEntry2(ROUTE_ENTRY *e)
{ {
UINTToIP(ip, i); MIB_IPFORWARD_ROW2 *p;
}
// IP conversion function for Win32
UINT Win32IPToUINT(IP *ip)
{
return IPToUINT(ip);
}
// Remove a routing entry from the routing table
void Win32DeleteRouteEntry(ROUTE_ENTRY *e)
{
MIB_IPFORWARDROW *p;
// Validate arguments // Validate arguments
if (e == NULL) if (e == NULL)
{ {
return; return;
} }
p = ZeroMallocFast(sizeof(MIB_IPFORWARDROW)); p = ZeroMallocFast(sizeof(MIB_IPFORWARD_ROW2));
Win32RouteEntryToIpForwardRow(p, e); Win32RouteEntryToIpForwardRow2(p, e);
DeleteIpForwardEntry(p); DeleteIpForwardEntry2(p);
Free(p); Free(p);
} }
// Add a routing entry to the routing table // Add a routing entry to the routing table (For Vista and later)
bool Win32AddRouteEntry(ROUTE_ENTRY *e, bool *already_exists) bool Win32AddRouteEntry2(ROUTE_ENTRY *e, bool *already_exists)
{ {
bool ret = false; bool ret = false;
bool dummy = false; bool dummy = false;
MIB_IPFORWARDROW *p; MIB_IPFORWARD_ROW2 *p;
UINT err = 0; UINT err = 0;
// Validate arguments // Validate arguments
if (e == NULL) if (e == NULL)
@ -9390,21 +9303,21 @@ bool Win32AddRouteEntry(ROUTE_ENTRY *e, bool *already_exists)
*already_exists = false; *already_exists = false;
p = ZeroMallocFast(sizeof(MIB_IPFORWARDROW)); p = ZeroMallocFast(sizeof(MIB_IPFORWARD_ROW2));
Win32RouteEntryToIpForwardRow(p, e); Win32RouteEntryToIpForwardRow2(p, e);
err = CreateIpForwardEntry(p); err = CreateIpForwardEntry2(p);
if (err != 0) if (err != 0)
{ {
if (err == ERROR_OBJECT_ALREADY_EXISTS) if (err == ERROR_OBJECT_ALREADY_EXISTS)
{ {
Debug("CreateIpForwardEntry: Already Exists\n"); Debug("CreateIpForwardEntry2: Already Exists\n");
*already_exists = true; *already_exists = true;
ret = true; ret = true;
} }
else else
{ {
Debug("CreateIpForwardEntry Error: %u\n", err); Debug("CreateIpForwardEntry2 Error: %u\n", err);
ret = false; ret = false;
} }
} }
@ -9418,61 +9331,56 @@ bool Win32AddRouteEntry(ROUTE_ENTRY *e, bool *already_exists)
return ret; return ret;
} }
// Get the routing table // Get the routing table (For Vista and later)
ROUTE_TABLE *Win32GetRouteTable() ROUTE_TABLE *Win32GetRouteTable2(bool ipv4, bool ipv6)
{ {
ROUTE_TABLE *t = ZeroMallocFast(sizeof(ROUTE_TABLE)); ROUTE_TABLE *t = ZeroMallocFast(sizeof(ROUTE_TABLE));
MIB_IPFORWARDTABLE *p; MIB_IPFORWARD_TABLE2 *p = NULL;
UINT ret; UINT ret;
ULONG size_needed;
UINT num_retry = 0; UINT num_retry = 0;
LIST *o; LIST *o;
UINT i; UINT i;
ROUTE_ENTRY *e; ROUTE_ENTRY *e;
ADDRESS_FAMILY family;
if (ipv4 && ipv6)
{
family = AF_UNSPEC;
}
else if (ipv6)
{
family = AF_INET6;
}
else
{
family = AF_INET;
}
RETRY: RETRY:
p = ZeroMallocFast(sizeof(MIB_IFTABLE));
size_needed = 0;
// Examine the needed size
ret = GetIpForwardTable(p, &size_needed, 0);
if (ret == ERROR_INSUFFICIENT_BUFFER)
{
// Re-allocate the memory block of the needed size
Free(p);
p = ZeroMallocFast(size_needed);
}
else if (ret != NO_ERROR)
{
// Acquisition failure
FAILED:
Free(p);
t->Entry = MallocFast(0);
return t;
}
// Actually get // Actually get
ret = GetIpForwardTable(p, &size_needed, FALSE); ret = GetIpForwardTable2(family, &p);
if (ret != NO_ERROR) if (ret != NO_ERROR)
{ {
// Acquisition failure // Acquisition failure
if ((++num_retry) >= 5) if ((++num_retry) >= 5)
{ {
goto FAILED; FreeMibTable(p);
t->Entry = MallocFast(0);
return t;
} }
Free(p); FreeMibTable(p);
goto RETRY; goto RETRY;
} }
// Add to the list along // Add to the list along
o = NewListFast(Win32CompareRouteEntryByMetric); o = NewListFast(Win32CompareRouteEntryByMetric);
for (i = 0; i < p->dwNumEntries; i++) for (i = 0; i < p->NumEntries; i++)
{ {
e = ZeroMallocFast(sizeof(ROUTE_ENTRY)); e = ZeroMallocFast(sizeof(ROUTE_ENTRY));
Win32IpForwardRowToRouteEntry(e, &p->table[i]); Win32IpForwardRow2ToRouteEntry(e, &p->Table[i]);
Add(o, e); Add(o, e);
} }
Free(p); FreeMibTable(p);
// Sort by metric // Sort by metric
Sort(o); Sort(o);
@ -9516,83 +9424,100 @@ int Win32CompareRouteEntryByMetric(void *p1, void *p2)
} }
} }
// Convert the ROUTE_ENTRY to a MIB_IPFORWARDROW // Convert the ROUTE_ENTRY to a MIB_IPFORWARD_ROW2 (For Vista and later)
void Win32RouteEntryToIpForwardRow(void *ip_forward_row, ROUTE_ENTRY *entry) void Win32RouteEntryToIpForwardRow2(void *ip_forward_row, ROUTE_ENTRY *entry)
{ {
MIB_IPFORWARDROW *r; MIB_IPFORWARD_ROW2 *r;
// Validate arguments // Validate arguments
if (entry == NULL || ip_forward_row == NULL) if (entry == NULL || ip_forward_row == NULL)
{ {
return; return;
} }
r = (MIB_IPFORWARDROW *)ip_forward_row; r = (MIB_IPFORWARD_ROW2 *)ip_forward_row;
Zero(r, sizeof(MIB_IPFORWARDROW)); InitializeIpForwardEntry(r);
// IP address if (IsIP4(&entry->DestIP))
r->dwForwardDest = Win32IPToUINT(&entry->DestIP);
// Subnet mask
r->dwForwardMask = Win32IPToUINT(&entry->DestMask);
// Gateway IP address
r->dwForwardNextHop = Win32IPToUINT(&entry->GatewayIP);
// Local routing flag
if (entry->LocalRouting)
{ {
// Local // IP address
r->dwForwardType = 3; r->DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
IPToInAddr(&r->DestinationPrefix.Prefix.Ipv4.sin_addr, &entry->DestIP);
// Subnet mask
r->DestinationPrefix.PrefixLength = SubnetMaskToInt4(&entry->DestMask);
// Gateway IP address
r->NextHop.Ipv4.sin_family = AF_INET;
IPToInAddr(&r->NextHop.Ipv4.sin_addr, &entry->GatewayIP);
} }
else else
{ {
// Remote router // IP address
r->dwForwardType = 4; r->DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
IPToInAddr6(&r->DestinationPrefix.Prefix.Ipv6.sin6_addr, &entry->DestIP);
// Subnet mask
r->DestinationPrefix.PrefixLength = SubnetMaskToInt6(&entry->DestMask);
// Gateway IP address
r->NextHop.Ipv6.sin6_family = AF_INET6;
IPToInAddr6(&r->NextHop.Ipv6.sin6_addr, &entry->GatewayIP);
} }
// Protocol
r->dwForwardProto = r->dwForwardType - 1; // Subtract by 1 in most cases // Metric offset
if (entry->PPPConnection) if (entry->Metric >= entry->IfMetric)
{ {
// Isn't this a PPP? Danger! r->Metric = entry->Metric - entry->IfMetric;
r->dwForwardProto++; }
else
{
r->Metric = 0;
} }
// Metric
r->dwForwardMetric1 = entry->Metric;
r->dwForwardMetric2 = r->dwForwardMetric3 = r->dwForwardMetric4 = r->dwForwardMetric5 = 0;
r->dwForwardAge = 163240;
// Interface ID // Interface ID
r->dwForwardIfIndex = entry->InterfaceID; r->InterfaceIndex = entry->InterfaceID;
Debug("Win32RouteEntryToIpForwardRow()\n"); Debug("Win32RouteEntryToIpForwardRow2()\n");
Debug(" r->dwForwardDest=%X\n", r->dwForwardDest);
Debug(" r->dwForwardMask=%X\n", r->dwForwardMask);
Debug(" r->dwForwardNextHop=%X\n", r->dwForwardNextHop);
Debug(" r->dwForwardType=%u\n", r->dwForwardType);
Debug(" r->dwForwardProto=%u\n", r->dwForwardProto);
Debug(" r->dwForwardMetric1=%u\n", r->dwForwardMetric1);
Debug(" r->dwForwardMetric2=%u\n", r->dwForwardMetric2);
Debug(" r->dwForwardIfIndex=%u\n", r->dwForwardIfIndex);
} }
// Convert the MIB_IPFORWARDROW to a ROUTE_ENTRY // Convert the MIB_IPFORWARD_ROW2 to a ROUTE_ENTRY (For Vista and later)
void Win32IpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row) void Win32IpForwardRow2ToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row)
{ {
MIB_IPFORWARDROW *r; MIB_IPFORWARD_ROW2 *r;
// Validate arguments // Validate arguments
if (entry == NULL || ip_forward_row == NULL) if (entry == NULL || ip_forward_row == NULL)
{ {
return; return;
} }
r = (MIB_IPFORWARDROW *)ip_forward_row; r = (MIB_IPFORWARD_ROW2 *)ip_forward_row;
Zero(entry, sizeof(ROUTE_ENTRY)); Zero(entry, sizeof(ROUTE_ENTRY));
// IP address
Win32UINTToIP(&entry->DestIP, r->dwForwardDest); MIB_IPINTERFACE_ROW *p;
// Subnet mask p = ZeroMallocFast(sizeof(MIB_IPINTERFACE_ROW));
Win32UINTToIP(&entry->DestMask, r->dwForwardMask);
// Gateway IP address if (((struct sockaddr *)&r->DestinationPrefix.Prefix)->sa_family != AF_INET6)
Win32UINTToIP(&entry->GatewayIP, r->dwForwardNextHop); {
// IP address
InAddrToIP(&entry->DestIP, &r->DestinationPrefix.Prefix.Ipv4.sin_addr);
// Subnet mask
IntToSubnetMask4(&entry->DestMask, r->DestinationPrefix.PrefixLength);
// Gateway IP address
InAddrToIP(&entry->GatewayIP, &r->NextHop.Ipv4.sin_addr);
// Interface
p->Family = AF_INET;
}
else
{
// IP address
InAddrToIP6(&entry->DestIP, &r->DestinationPrefix.Prefix.Ipv6.sin6_addr);
// Subnet mask
IntToSubnetMask6(&entry->DestMask, r->DestinationPrefix.PrefixLength);
// Gateway IP address
InAddrToIP6(&entry->GatewayIP, &r->NextHop.Ipv6.sin6_addr);
// Interface
p->Family = AF_INET6;
}
// Local routing flag // Local routing flag
if (r->dwForwardType == 3) if (IsZeroIP(&entry->GatewayIP))
{ {
entry->LocalRouting = true; entry->LocalRouting = true;
} }
@ -9600,15 +9525,27 @@ void Win32IpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row)
{ {
entry->LocalRouting = false; entry->LocalRouting = false;
} }
if (entry->LocalRouting && r->dwForwardProto == 3) if (entry->LocalRouting && r->Protocol == 3)
{ {
// PPP. Danger! // PPP. Danger!
entry->PPPConnection = true; entry->PPPConnection = true;
} }
// Metric // Metric
entry->Metric = r->dwForwardMetric1; p->InterfaceIndex = r->InterfaceIndex;
if (GetIpInterfaceEntry(p) == NO_ERROR)
{
entry->IfMetric = p->Metric;
entry->Metric = r->Metric + p->Metric;
}
else
{
entry->Metric = r->Metric;
}
Free(p);
// Interface ID // Interface ID
entry->InterfaceID = r->dwForwardIfIndex; entry->InterfaceID = r->InterfaceIndex;
} }
// Initializing the socket library // Initializing the socket library
@ -10233,23 +10170,12 @@ ROUTE_ENTRY *GetBestRouteEntryFromRouteTableEx(ROUTE_TABLE *table, IP *ip, UINT
return NULL; return NULL;
} }
if (IsIP6(ip))
{
// IPv6 is not supported
return NULL;
}
// Select routing table entry by following rule // Select routing table entry by following rule
// 1. Largest subnet mask // 1. Largest subnet mask
// 2. Smallest metric value // 2. Smallest metric value
for (i = 0; i < table->NumEntry; i++) for (i = 0; i < table->NumEntry; i++)
{ {
ROUTE_ENTRY *e = table->Entry[i]; ROUTE_ENTRY *e = table->Entry[i];
UINT dest, net, mask;
dest = IPToUINT(ip);
net = IPToUINT(&e->DestIP);
mask = IPToUINT(&e->DestMask);
if (exclude_if_id != 0) if (exclude_if_id != 0)
{ {
@ -10260,10 +10186,10 @@ ROUTE_ENTRY *GetBestRouteEntryFromRouteTableEx(ROUTE_TABLE *table, IP *ip, UINT
} }
// Mask test // Mask test
if ((dest & mask) == (net & mask)) if (IsInSameNetwork(ip, &e->DestIP, &e->DestMask))
{ {
// Calculate the score // Calculate the score
UINT score_high32 = mask; UINT score_high32 = SubnetMaskToInt(&e->DestMask);
UINT score_low32 = 0xFFFFFFFF - e->Metric; UINT score_low32 = 0xFFFFFFFF - e->Metric;
UINT64 score64 = (UINT64)score_high32 * (UINT64)0x80000000 * (UINT64)2 + (UINT64)score_low32; UINT64 score64 = (UINT64)score_high32 * (UINT64)0x80000000 * (UINT64)2 + (UINT64)score_low32;
if (score64 == 0) if (score64 == 0)
@ -10294,24 +10220,24 @@ ROUTE_ENTRY *GetBestRouteEntryFromRouteTableEx(ROUTE_TABLE *table, IP *ip, UINT
if (tmp != NULL) if (tmp != NULL)
{ {
UINT dest, gateway, mask;
// Generate an entry // Generate an entry
ret = ZeroMallocFast(sizeof(ROUTE_ENTRY)); ret = ZeroMallocFast(sizeof(ROUTE_ENTRY));
Copy(&ret->DestIP, ip, sizeof(IP)); Copy(&ret->DestIP, ip, sizeof(IP));
SetIP(&ret->DestMask, 255, 255, 255, 255); if (IsIP4(ip))
{
IntToSubnetMask4(&ret->DestMask, 32);
}
else
{
IntToSubnetMask6(&ret->DestMask, 128);
}
Copy(&ret->GatewayIP, &tmp->GatewayIP, sizeof(IP)); Copy(&ret->GatewayIP, &tmp->GatewayIP, sizeof(IP));
ret->InterfaceID = tmp->InterfaceID; ret->InterfaceID = tmp->InterfaceID;
ret->LocalRouting = tmp->LocalRouting; ret->LocalRouting = tmp->LocalRouting;
ret->OldIfMetric = tmp->Metric; ret->Metric = tmp->Metric;
ret->Metric = 1; ret->IfMetric = tmp->IfMetric;
ret->PPPConnection = tmp->PPPConnection; ret->PPPConnection = tmp->PPPConnection;
// Calculation related to routing control
dest = IPToUINT(&tmp->DestIP);
gateway = IPToUINT(&tmp->GatewayIP);
mask = IPToUINT(&tmp->DestMask);
} }
return ret; return ret;
@ -10468,9 +10394,9 @@ void RouteToStr(char *str, UINT str_size, ROUTE_ENTRY *e)
IPToStr(dest_mask, sizeof(dest_mask), &e->DestMask); IPToStr(dest_mask, sizeof(dest_mask), &e->DestMask);
IPToStr(gateway_ip, sizeof(gateway_ip), &e->GatewayIP); IPToStr(gateway_ip, sizeof(gateway_ip), &e->GatewayIP);
Format(str, str_size, "%s/%s %s m=%u oif=%u if=%u lo=%u p=%u", Format(str, str_size, "%s/%s %s m=%u ifm=%u if=%u lo=%u p=%u",
dest_ip, dest_mask, gateway_ip, dest_ip, dest_mask, gateway_ip,
e->Metric, e->OldIfMetric, e->InterfaceID, e->Metric, e->IfMetric, e->InterfaceID,
e->LocalRouting, e->PPPConnection); e->LocalRouting, e->PPPConnection);
} }
@ -10479,7 +10405,7 @@ void DeleteRouteEntry(ROUTE_ENTRY *e)
{ {
Debug("DeleteRouteEntry();\n"); Debug("DeleteRouteEntry();\n");
#ifdef OS_WIN32 #ifdef OS_WIN32
Win32DeleteRouteEntry(e); Win32DeleteRouteEntry2(e);
#else // OS_WIN32 #else // OS_WIN32
UnixDeleteRouteEntry(e); UnixDeleteRouteEntry(e);
#endif #endif
@ -10496,7 +10422,7 @@ bool AddRouteEntryEx(ROUTE_ENTRY *e, bool *already_exists)
bool ret = false; bool ret = false;
Debug("AddRouteEntryEx();\n"); Debug("AddRouteEntryEx();\n");
#ifdef OS_WIN32 #ifdef OS_WIN32
ret = Win32AddRouteEntry(e, already_exists); ret = Win32AddRouteEntry2(e, already_exists);
#else // OS_WIN32 #else // OS_WIN32
ret = UnixAddRouteEntry(e, already_exists); ret = UnixAddRouteEntry(e, already_exists);
#endif #endif
@ -10512,7 +10438,7 @@ ROUTE_TABLE *GetRouteTable()
UCHAR hash[MD5_SIZE]; UCHAR hash[MD5_SIZE];
#ifdef OS_WIN32 #ifdef OS_WIN32
t = Win32GetRouteTable(); t = Win32GetRouteTable2(true, true);
#else //OS_WIN32 #else //OS_WIN32
t = UnixGetRouteTable(); t = UnixGetRouteTable();
#endif // OS_WIN32 #endif // OS_WIN32

View File

@ -285,7 +285,7 @@ struct ROUTE_ENTRY
bool LocalRouting; bool LocalRouting;
bool PPPConnection; bool PPPConnection;
UINT Metric; UINT Metric;
UINT OldIfMetric; UINT IfMetric;
UINT InterfaceID; UINT InterfaceID;
UINT64 InnerScore; UINT64 InnerScore;
}; };
@ -958,14 +958,12 @@ void Win32Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
void Win32InitAsyncSocket(SOCK *sock); void Win32InitAsyncSocket(SOCK *sock);
void Win32JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event); void Win32JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
void Win32FreeAsyncSocket(SOCK *sock); void Win32FreeAsyncSocket(SOCK *sock);
void Win32IpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row); void Win32IpForwardRow2ToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row);
void Win32RouteEntryToIpForwardRow(void *ip_forward_row, ROUTE_ENTRY *entry); void Win32RouteEntryToIpForwardRow2(void *ip_forward_row, ROUTE_ENTRY *entry);
int Win32CompareRouteEntryByMetric(void *p1, void *p2); int Win32CompareRouteEntryByMetric(void *p1, void *p2);
ROUTE_TABLE *Win32GetRouteTable(); ROUTE_TABLE *Win32GetRouteTable2(bool ipv4, bool ipv6);
bool Win32AddRouteEntry(ROUTE_ENTRY *e, bool *already_exists); bool Win32AddRouteEntry2(ROUTE_ENTRY *e, bool *already_exists);
void Win32DeleteRouteEntry(ROUTE_ENTRY *e); void Win32DeleteRouteEntry2(ROUTE_ENTRY *e);
void Win32UINTToIP(IP *ip, UINT i);
UINT Win32IPToUINT(IP *ip);
UINT Win32GetVLanInterfaceID(char *instance_name); UINT Win32GetVLanInterfaceID(char *instance_name);
char **Win32EnumVLan(char *tag_name); char **Win32EnumVLan(char *tag_name);
void Win32Cancel(CANCEL *c); void Win32Cancel(CANCEL *c);
@ -977,12 +975,11 @@ void Win32CleanupSockEvent(SOCK_EVENT *event);
bool Win32WaitSockEvent(SOCK_EVENT *event, UINT timeout); bool Win32WaitSockEvent(SOCK_EVENT *event, UINT timeout);
bool Win32GetDefaultDns(IP *ip, char *domain, UINT size); bool Win32GetDefaultDns(IP *ip, char *domain, UINT size);
bool Win32GetDnsSuffix(char *domain, UINT size); bool Win32GetDnsSuffix(char *domain, UINT size);
void Win32ReleaseDhcp9x(UINT if_id, bool wait);
void Win32FlushDnsCache(); void Win32FlushDnsCache();
int CompareIpAdapterIndexMap(void *p1, void *p2); int CompareIpAdapterIndexMap(void *p1, void *p2);
ROUTE_CHANGE *Win32NewRouteChange(); ROUTE_CHANGE *Win32NewRouteChange2(bool ipv4, bool ipv6, void *callback);
void Win32FreeRouteChange(ROUTE_CHANGE *r); void Win32FreeRouteChange2(ROUTE_CHANGE *r);
bool Win32IsRouteChanged(ROUTE_CHANGE *r); bool Win32IsRouteChanged2(ROUTE_CHANGE *r);
bool Win32GetAdapterFromGuid(void *a, char *guid); bool Win32GetAdapterFromGuid(void *a, char *guid);
SOCKET Win32Accept(SOCK *sock, SOCKET s, struct sockaddr *addr, int *addrlen, bool ipv6); SOCKET Win32Accept(SOCK *sock, SOCKET s, struct sockaddr *addr, int *addrlen, bool ipv6);
@ -1225,6 +1222,7 @@ void GetLoopbackAddress6(IP *ip);
UINT GetIPAddrType6(IP *ip); UINT GetIPAddrType6(IP *ip);
UINT GetIPv6AddrType(IPV6_ADDR *addr); UINT GetIPv6AddrType(IPV6_ADDR *addr);
void GetPrefixAddress6(IP *dst, IP *ip, IP *subnet); void GetPrefixAddress6(IP *dst, IP *ip, IP *subnet);
bool IsInSameNetwork(IP *a1, IP *a2, IP *subnet);
bool IsInSameNetwork6(IP *a1, IP *a2, IP *subnet); bool IsInSameNetwork6(IP *a1, IP *a2, IP *subnet);
bool IsInSameNetwork6ByStr(char *ip1, char *ip2, char *subnet); bool IsInSameNetwork6ByStr(char *ip1, char *ip2, char *subnet);
void GenerateEui64Address6(UCHAR *dst, UCHAR *mac); void GenerateEui64Address6(UCHAR *dst, UCHAR *mac);