📄 mngprfx.c
字号:
DWORD dwType;
DWORD dwVal;
DWORD dwValSize;
DWORD i;
// At least name of upstream interface needs to be provided
if (UpIfName == NULL) goto cleanup;
// Convert names of interfaces
_sntprintf(szDownIfName, MAX_REG_STR, TEXT("%hs"), DownIfName != NULL ? DownIfName : "\0");
szDownIfName[MAX_REG_STR - 1] = TEXT('\0');
// Open the key containing settings of the up-stream interface
_sntprintf(szRegValue, MAX_REG_STR, TEXT("%s\\%hs"), DHCPV6_REGKEY_BASE, UpIfName);
szRegValue[MAX_REG_STR - 1] = TEXT('\0');
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegValue, 0,
0, &hKey)) {
hKey = INVALID_HANDLE_VALUE;
goto cleanup;
}
// Check whether the upstream interface should participate in PD
dwValSize = sizeof(dwVal);
dwType = REG_DWORD;
if (ERROR_SUCCESS != RegQueryValueEx(hKey, DHCPV6_REGVAL_ACCEPT_PD, NULL,
&dwType, (LPBYTE)&dwVal, &dwValSize)
|| dwType != REG_DWORD)
goto cleanup;
if (dwVal == 0) {
// This interface is not supposed to participate in PD
goto cleanup;
}
if (dwVal == 1 && szDownIfName[0] == TEXT('\0')) {
// This interface is supposed to participate in PD; no need to check
// downstream interface because it is not provided
fRet = TRUE;
goto cleanup;
}
// Check list of downstream interfaces
dwValSize = MAX_REG_STR * sizeof(TCHAR);
dwType = REG_MULTI_SZ;
if (ERROR_SUCCESS != RegQueryValueEx(hKey, DHCPV6_REGVAL_DOWNSTREAM_IFS, NULL,
&dwType, (LPBYTE)szRegValue, &dwValSize)
|| dwType != REG_MULTI_SZ)
goto cleanup;
// Try to find the downstream interface in the list
for (i = 0; i < MAX_REG_STR;) {
if (! _tcscmp(&szRegValue[i], szDownIfName))
// Found it!
break;
i += _tcslen(&szRegValue[i]) + 1;
if (szRegValue[i] == TEXT('\0'))
// End of list; didn't find the interface
goto cleanup;
}
fRet = TRUE;
cleanup:
if (hKey != INVALID_HANDLE_VALUE) RegCloseKey(hKey);
return fRet;
}
//
// Install new (or refresh) prefix on the system. This function will assign (refresh)
// given prefix on all applicable interfaces.
//
BOOL DHCPv6ManagePrefix(
UINT OrigIfIdx, // Interface on which prefix was received
IPv6Addr Prefix, // The prefix
UINT PrefixLen, // Length
UINT ValidLifetime, // Valid lifetime; Note: can use INFINITE_LIFETIME
UINT PreferredLifetime // Preferred lifetime; Note: can use INFINITE_LIFETIME
) {
BOOL fRet = FALSE; // Be pessimistic
PIP_ADAPTER_ADDRESSES pAADownStreamIfArray[MAX_DOWNSTREAM_IFS];
PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL;
PIP_ADAPTER_ADDRESSES pAAIncomingIf = NULL;
PIP_ADAPTER_ADDRESSES pAA;
USHORT DownStreamIfCount;
ULONG ulFlags;
ULONG ulBufferLength;
USHORT usAttempts;
UINT i;
ASSERT(g_hIPv6Stack != INVALID_HANDLE_VALUE);
// The passed-in prefix may actually be longer than required
TrimPrefix(&Prefix, PrefixLen);
// Get a list of all interfaces in the system
ulFlags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_INCLUDE_PREFIX;
pAdapterAddresses = NULL;
ulBufferLength = 0;
usAttempts = 0;
for (;;) {
DWORD dwError;
dwError = GetAdaptersAddresses(AF_UNSPEC, ulFlags, NULL,
pAdapterAddresses, &ulBufferLength);
if (dwError == ERROR_SUCCESS)
break;
else if (dwError == ERROR_BUFFER_OVERFLOW
&& ++usAttempts < 4) {
if (pAdapterAddresses != NULL)
free(pAdapterAddresses);
pAdapterAddresses = (PIP_ADAPTER_ADDRESSES)malloc(ulBufferLength);
} else
goto cleanup;
}
// Find the interface on which we received the Prefix delegation
for (pAA = pAdapterAddresses, pAAIncomingIf = NULL;
pAA != NULL; pAA = pAA->Next) {
if (pAA->Ipv6IfIndex == OrigIfIdx) {
pAAIncomingIf = pAA;
break;
}
}
if (pAAIncomingIf == NULL)
// We couldn't find the incoming interface; just give up
goto cleanup;
// Consult with registry to determine whether the interface on which
// we recieved PD is a valid upstream interface
if (! IsPDEnabledInterface(pAAIncomingIf->AdapterName, NULL))
goto cleanup;
// Find interfaces that are eligible for prefix assignment
DownStreamIfCount = 0;
for (pAA = pAdapterAddresses;
pAA != NULL && DownStreamIfCount < MAX_DOWNSTREAM_IFS;
pAA = pAA->Next) {
// Accept only Ethernet interfaces
if (pAA->IfType != IF_TYPE_ETHERNET_CSMACD) continue;
// Cannot be the same interface on which we recieved the prefix
if (pAA->Ipv6IfIndex == OrigIfIdx) continue;
// Consult with registry to determine whether this is one of the
// valid downstream interfaces
if (! IsPDEnabledInterface(pAAIncomingIf->AdapterName, pAA->AdapterName))
continue;
// This interface is eligible for prefix assignment, remember it
pAADownStreamIfArray[DownStreamIfCount++] = pAA;
DEBUGMSG(1,
(TEXT("DHCPv6ManagePrefix: IF# [%d] is eligible for prefix assignment\r\n"),
pAA->Ipv6IfIndex));
}
// Given number of eligible interfaces for prefix assignment, if:
// a) no interfaces, then ignore the prefix
// b) one or more interface, then subnet prefix between interfaces
// on interface index number.
//
// Note: We could handle (b) to not to subnet prefix if we have
// only one downstream interface, but handling dynamic interface
// creation would be more complicated.
//
if (DownStreamIfCount == 0) goto cleanup;
for (i = 0; i < DownStreamIfCount; i+=1) {
PIP_ADAPTER_PREFIX pAP;
IPv6Addr NewPrefix;
UINT NewPrefixLen;
pAA = pAADownStreamIfArray[i];
// Check whether the interface already has the prefix
for (pAP = pAA->FirstPrefix; pAP != NULL; pAP = pAP->Next) {
IPv6Addr ThisPrefix;
if (pAP->PrefixLength == 0 || pAP->PrefixLength == 128) continue;
ThisPrefix = *GetIpFromSockAddr(&pAP->Address);
TrimPrefix(&ThisPrefix, PrefixLen);
if (IN6_ADDR_EQUAL(&ThisPrefix, &Prefix)) {
NewPrefix = *GetIpFromSockAddr(&pAP->Address);
NewPrefixLen = pAP->PrefixLength;
break;
}
}
if (pAP == NULL) {
// The Prefix has never been assigned to this interface; generate one.
if (! CreateSubnetPrefix(&Prefix, PrefixLen, (USHORT)pAA->Ipv6IfIndex,
&NewPrefix, &NewPrefixLen))
goto cleanup;
}
DEBUGMSG(1,
(TEXT("DHCPv6ManagePrefix: %s prefix for IF# [%d]\r\n"),
pAP == NULL ? TEXT("Creating") : TEXT("Refreshing"),
pAA->Ipv6IfIndex));
if (! SetOrRefreshPrefix(pAAIncomingIf,
pAA,
&NewPrefix,
NewPrefixLen,
ValidLifetime,
PreferredLifetime)) {
goto cleanup;
}
}
fRet = TRUE;
cleanup:
if (pAdapterAddresses != NULL)
free(pAdapterAddresses);
return fRet;
}
//
// Intended to be called periodically to clean-up expired routes.
//
BOOL DHCPv6ManagePrefixPeriodicCleanup() {
// Cleanup routes
IPV6_QUERY_ROUTE_TABLE Query, NextQuery;
IPV6_INFO_ROUTE_TABLE Route;
UINT BytesReturned;
ASSERT(g_hIPv6Stack != INVALID_HANDLE_VALUE);
NextQuery.Neighbor.IF.Index = 0;
for (;;) {
Query = NextQuery;
if (! DeviceIoControl(g_hIPv6Stack,
IOCTL_IPV6_QUERY_ROUTE_TABLE,
&Query, sizeof Query,
&Route, sizeof Route,
&BytesReturned, NULL)) {
return FALSE;
}
NextQuery = Route.Next;
if (Query.Neighbor.IF.Index != 0) {
Route.This = Query;
if (Route.Type == RTE_TYPE_AUTOCONF &&
Route.ValidLifetime == 0 &&
Route.Publish) {
// This route has been configured by DHCPv6 earlier, but is
// no longer valid. We'll stop publishing it so that it can
// be cleaned-up by the stack.
//
UpdateRoute(Route.This.Neighbor.IF.Index,
&Route.This.Neighbor.Address,
&Route.This.Prefix, Route.This.PrefixLength,
Route.ValidLifetime, Route.PreferredLifetime,
Route.Preference, FALSE);
}
}
if (NextQuery.Neighbor.IF.Index == 0)
break;
}
return TRUE;
}
BOOL DHCPv6ManagePrefixInit() {
ASSERT(g_hIPv6Stack == INVALID_HANDLE_VALUE);
if (g_hIPv6Stack == INVALID_HANDLE_VALUE) {
// Get handle to IPv6 stack for DeviceIoControl calls
g_hIPv6Stack = CreateFileW(L"IP60:",
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // security attributes
OPEN_EXISTING,
0, // flags & attributes
NULL); // template file
if (g_hIPv6Stack == INVALID_HANDLE_VALUE) {
ASSERT(FALSE);
return FALSE;
}
}
return TRUE;
}
void DHCPv6ManagePrefixDeinit() {
if (g_hIPv6Stack != INVALID_HANDLE_VALUE) CloseHandle(g_hIPv6Stack);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -