防火牆動態關鍵字
您可以使用防火牆動態關鍵字 API 來管理Microsoft Defender防火牆中的動態關鍵字位址。 動態關鍵字位址可用來建立一組 IP 位址,其中一或多個防火牆規則可以參考。 動態關鍵字位址同時支援 IPv4 和 IPv6。
注意
如需本主題仲介紹之 API 的 API 參考內容,請參閱 防火牆動態關鍵字參考。
動態關鍵字位址的作業
使用防火牆動態關鍵字 API,您可以執行下列作業。
- 新增動態關鍵字位址
- 刪除動態關鍵字位址
- 依識別碼或類型列舉動態關鍵字位址
- 更新動態關鍵字位址
- 訂閱及處理動態關鍵字位址變更通知
本主題稍後會針對所有這些作業提供程式碼範例。
新增動態關鍵字位址之後,它會在重新開機時持續存在。 使用 物件完成之後,您必須刪除動態關鍵字位址。
動態關鍵字位址有兩個類別,如下兩節所述。
AutoResolve 動態關鍵字位址
第一個類型是 AutoResolve,其中 關鍵字 欄位代表可解析的名稱,而且建立時不會定義 IP 位址。
這些物件旨在讓其 IP 位址自動解析。 也就是說,不是在物件建立時透過系統管理員;或透過作業系統 (作業系統本身) 。 防火牆服務外部的元件必須針對這些物件執行 IP 位址解析,並適當地加以更新。 這類元件的實作超出此內容的範圍。
呼叫FWAddDynamicKeywordAddress0函式時,動態關鍵字位址會在 物件中設定FW_DYNAMIC_KEYWORD_ADDRESS_FLAGS_AUTO_RESOLVE旗標來表示為AutoResolve。 關鍵字欄位應該用來表示正在解析的值,也就是 FQDN) 或主機名稱 (完整功能變數名稱。 這些物件的位址欄位一開始必須是 Null。 這些物件不會在其開機週期之間保存其 IP 位址,而且您應該在下一個開機週期期間重新評估/重新填入其位址。
注意
AutoResolve 動態關鍵字位址物件會在 FWAddDynamicKeywordAddress0 和 FWDeleteDynamicKeywordAddress0上觸發通知,但不會觸發 FWUpdateDynamicKeywordAddress0的通知。
非 AutoResolve 動態關鍵字位址
第二種類型是 非 AutoResolve,其中 關鍵字 欄位是任何字串,而且位址會在建立時定義。
這些物件可用來儲存一組 IP 位址、子網或範圍。 這裡的 關鍵字 欄位用於管理便利性,而且可以設定為任何字串。 建立時,位址欄位必須是非 Null。 這些物件的位址會在重新開機時保存。
注意
非 AutoResolve 動態關鍵字位址物件會在 FWAddDynamicKeywordAddress0、 FWDeleteDynamicKeywordAddress0上觸發通知,以及 FWUpdateDynamicKeywordAddress0。
深入瞭解動態關鍵字位址
所有動態關鍵字位址都必須有唯一 的 GUID 識別碼來表示它們。
當動態關鍵字位址變更時 ,FwpmDynamicKeywordSubscribe0 API 會將通知傳遞給用戶端。 不會將承載傳遞至用戶端,描述系統上變更的確切內容。 如果您需要知道哪些物件已變更,則應該使用 FWEnumDynamicKeywordAddressById0 或 FWEnumDynamicKeywordAddressesByType0 API 查詢系統上物件的目前狀態。 您可以使用各種旗標,只要求物件子集的通知。 如果您沒有使用旗標,則會為所有物件傳遞變更通知。
防火牆規則可以使用動態關鍵字位址,而不是明確定義其遠端位址條件的 IP 位址。 防火牆規則可以使用動態關鍵字位址和靜態定義的遠端位址範圍。 單一動態關鍵字位址物件可以跨多個防火牆規則重複使用。 如果防火牆規則沒有任何設定的遠端位址 (,請只設定尚未解析) 的 AutoResolve 物件,則不會強制執行規則。 此外,如果規則使用多個動態關鍵字位址,則即使尚未解析其他物件,也會對所有目前解析的位址強制執行規則。 更新動態關鍵字位址時,所有相關聯的規則物件也會更新其遠端位址。
作業系統 (OS) 本身不會強制執行規則與動態關鍵字位址之間的任何相依性。 這表示可以先建立任一個物件—規則可以參考尚未存在的動態關鍵字位址識別碼 (在此情況下,規則將不會強制執行) 。 此外,即使動態關鍵字位址正在使用防火牆規則,您也可以刪除該位址。 本主題概述系統管理員如何設定規則以使用動態關鍵字位址。
程式碼範例
若要試用這些程式碼範例,請先啟動 Visual Studio,並根據 主控台應用程式 專案範本建立新的專案。 您可以只將 的內容 main.cpp
取代為程式代碼清單。
大部分的程式碼範例都會使用 WINDOWS 實作程式庫 (WIL) 。 安裝 WIL 的便利方式是移至 Visual Studio,按一下 [專案>管理 NuGet 套件...>流覽、在搜尋方塊中輸入或貼上Microsoft.Windows.ImplementationLibrary,選取搜尋結果中的專案,然後按一下 [安裝] 以安裝該專案的套件。
注意
NetFw 免費函式的指標類型是透過 NetFw.h
發佈,但不會發佈靜態程式庫。 使用LoadLibraryExW/GetProcAddress模式來呼叫這些函式,如這些程式碼範例所示。
新增動態關鍵字位址
此範例示範如何使用 FWAddDynamicKeywordAddress0 函式。
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
// {e9d5c993-9369-4a96-8228-9c5c37aac51a}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_2 =
{
0xe9d5c993,
0x9369,
0x4a96,
{0x82,0x28,0x9c,0x5c,0x37,0xaa,0xc5,0x1a}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWADDDYNAMICKEYWORDADDRESS0 addDynamicKeywordAddressFn = NULL;
HMODULE moduleHandle = NULL;
FW_DYNAMIC_KEYWORD_ADDRESS0 autoResolveKeywordAddress = { 0 };
FW_DYNAMIC_KEYWORD_ADDRESS0 nonAutoResolveKeywordAddress = { 0 };
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
addDynamicKeywordAddressFn = (PFN_FWADDDYNAMICKEYWORDADDRESS0)GetProcAddress(
moduleHandle,
"FWAddDynamicKeywordAddress0"
);
}
if (addDynamicKeywordAddressFn == NULL)
{
error = GetLastError();
return error;
}
// Ensure the ID is unique. If not, the add operation will fail with ERROR_ALREADY_EXISTS
// and you should invoke the API with a new ID.
// Initialize and add an auto-resolve dynamic keyword address
autoResolveKeywordAddress.id = DYNAMIC_KEYWORD_ADDRESS_ID_1;
autoResolveKeywordAddress.keyword = L"bing.com";
autoResolveKeywordAddress.flags = FW_DYNAMIC_KEYWORD_ADDRESS_FLAGS_AUTO_RESOLVE;
// must be NULL as we have set the auto resolve flag
autoResolveKeywordAddress.addresses = NULL;
error = addDynamicKeywordAddressFn(&autoResolveKeywordAddress);
if (error != ERROR_SUCCESS)
{
return error;
}
// Initialize and add a non auto-resolve dynamic keyword address
nonAutoResolveKeywordAddress.id = DYNAMIC_KEYWORD_ADDRESS_ID_2;
nonAutoResolveKeywordAddress.keyword = L"myServerIPs";
nonAutoResolveKeywordAddress.flags = 0;
nonAutoResolveKeywordAddress.addresses = L"10.0.0.5,20.0.0.0/24,30.0.0.0-40.0.0.0";
error = addDynamicKeywordAddressFn(&nonAutoResolveKeywordAddress);
if (error != ERROR_SUCCESS)
{
return error;
}
return error;
}
刪除動態關鍵字位址
此範例示範如何使用 FWDeleteDynamicKeywordAddress0 函式。
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
// {e9d5c993-9369-4a96-8228-9c5c37aac51a}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_2 =
{
0xe9d5c993,
0x9369,
0x4a96,
{0x82,0x28,0x9c,0x5c,0x37,0xaa,0xc5,0x1a}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWDELETEDYNAMICKEYWORDADDRESS0 deleteDynamicKeywordAddressFn = NULL;
HMODULE moduleHandle = NULL;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
deleteDynamicKeywordAddressFn = (PFN_FWDELETEDYNAMICKEYWORDADDRESS0)GetProcAddress(
moduleHandle,
"FWDeleteDynamicKeywordAddress0"
);
}
if (deleteDynamicKeywordAddressFn == NULL)
{
error = GetLastError();
return error;
}
// Invoke the functions
error = deleteDynamicKeywordAddressFn(DYNAMIC_KEYWORD_ADDRESS_ID_1);
if (error != ERROR_SUCCESS)
{
wprintf(L"Failed to delete object with ID 1, err=[%d]", error);
}
error = deleteDynamicKeywordAddressFn(DYNAMIC_KEYWORD_ADDRESS_ID_2);
if (error != ERROR_SUCCESS)
{
wprintf(L"Failed to delete object with ID 2, err=[%d]", error);
}
return error;
}
依識別碼列舉和釋放動態關鍵字位址
此範例示範如何使用 FWEnumDynamicKeywordAddressById0 和 FWFreeDynamicKeywordAddressData0 函式。
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
// {e9d5c993-9369-4a96-8228-9c5c37aac51a}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_2 =
{
0xe9d5c993,
0x9369,
0x4a96,
{0x82,0x28,0x9c,0x5c,0x37,0xaa,0xc5,0x1a}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWENUMDYNAMICKEYWORDADDRESSBYID0 enumDynamicKeywordAddressByIdFn = NULL;
PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0 freeDynamicKeywordAddressDataFn = NULL;
HMODULE moduleHandle = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 dynamicKeywordAddressData = NULL;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
enumDynamicKeywordAddressByIdFn = (PFN_FWENUMDYNAMICKEYWORDADDRESSBYID0)GetProcAddress(
moduleHandle,
"FWEnumDynamicKeywordAddressById0"
);
freeDynamicKeywordAddressDataFn = (PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0)GetProcAddress(
moduleHandle,
"FWFreeDynamicKeywordAddressData0"
);
}
if (enumDynamicKeywordAddressByIdFn == NULL ||
freeDynamicKeywordAddressDataFn == NULL)
{
error = GetLastError();
return error;
}
error = enumDynamicKeywordAddressByIdFn(
DYNAMIC_KEYWORD_ADDRESS_ID_1,
&dynamicKeywordAddressData
);
if (error != ERROR_SUCCESS)
{
return error;
}
if (dynamicKeywordAddressData != NULL)
{
// Process this dynamic keyword address
}
// Free the dynamic keyword address
freeDynamicKeywordAddressDataFn(dynamicKeywordAddressData);
return error;
}
依類型列舉和釋放動態關鍵字位址
此範例示範如何使用 FWEnumDynamicKeywordAddressesByType0 和 FWFreeDynamicKeywordAddressData0 函式。
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0 enumDynamicKeywordAddressesByTypeFn = NULL;
PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0 freeDynamicKeywordAddressDataFn = NULL;
HMODULE moduleHandle = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 dynamicKeywordAddressData = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 currDynamicKeywordAddressData = NULL;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
enumDynamicKeywordAddressesByTypeFn = (PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0)GetProcAddress(
moduleHandle,
"FWEnumDynamicKeywordAddressesByType0"
);
freeDynamicKeywordAddressDataFn = (PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0)GetProcAddress(
moduleHandle,
"FWFreeDynamicKeywordAddressData0"
);
}
if (enumDynamicKeywordAddressesByTypeFn == NULL ||
freeDynamicKeywordAddressDataFn == NULL)
{
error = GetLastError();
return error;
}
// Invoke enum for ALL dynamic keyword addresses
error = enumDynamicKeywordAddressesByTypeFn(
FW_DYNAMIC_KEYWORD_ADDRESS_ENUM_FLAGS_ALL,
&dynamicKeywordAddressData
);
if (error != ERROR_SUCCESS)
{
return error;
}
currDynamicKeywordAddressData = dynamicKeywordAddressData;
while (currDynamicKeywordAddressData != NULL)
{
// Process this dynamic keyword address
// iterate to the next one in the list
currDynamicKeywordAddressData = currDynamicKeywordAddressData->next;
}
// Free the dynamic keyword addresses
freeDynamicKeywordAddressDataFn(dynamicKeywordAddressData);
return error;
}
更新動態關鍵字位址
此範例示範如何使用 FWUpdateDynamicKeywordAddress0 函式。
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWUPDATEDYNAMICKEYWORDADDRESS0 updateDynamicKeywordAddressFn = NULL;
HMODULE moduleHandle = NULL;
BOOL appendToCurrentAddresses = TRUE;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
updateDynamicKeywordAddressFn = (PFN_FWUPDATEDYNAMICKEYWORDADDRESS0)GetProcAddress(
moduleHandle,
"FWUpdateDynamicKeywordAddress0"
);
}
if (updateDynamicKeywordAddressFn == NULL)
{
error = GetLastError();
return error;
}
// Invoke the function
error = updateDynamicKeywordAddressFn(
DYNAMIC_KEYWORD_ADDRESS_ID_1,
L"20.0.0.5",
appendToCurrentAddresses);
return error;
}
訂閱及處理動態關鍵字位址變更通知
此範例示範如何使用 FwpmDynamicKeywordSubscribe0 和 FwpmDynamicKeywordUnsubscribe0 函式,以及 FWPM_DYNAMIC_KEYWORD_CALLBACK0 回呼。
// main.cpp in a Console App project.
#include <windows.h>
#include <netfw.h>
#include <fwpmu.h>
#pragma comment(lib, "Fwpuclnt")
void CALLBACK TestCallback(_Inout_ VOID* /*pNotification*/, _Inout_ VOID* pContext)
{
DWORD error = ERROR_SUCCESS;
PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0 enumDynamicKeywordAddressesByTypeFn = NULL;
PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0 freeDynamicKeywordAddressDataFn = NULL;
HMODULE moduleHandle = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 dynamicKeywordAddressData = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 currDynamicKeywordAddressData = NULL;
HANDLE* waitHandle = (HANDLE*)pContext;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryW(L"firewallapi.dll");
if (moduleHandle != NULL)
{
enumDynamicKeywordAddressesByTypeFn = (PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0)GetProcAddress(
moduleHandle,
"FWEnumDynamicKeywordAddressesByType0"
);
freeDynamicKeywordAddressDataFn = (PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0)GetProcAddress(
moduleHandle,
"FWFreeDynamicKeywordAddressData0"
);
}
if (enumDynamicKeywordAddressesByTypeFn == NULL ||
freeDynamicKeywordAddressDataFn == NULL)
{
return;
}
// Invoke enum for ALL AutoResolve dynamic keyword addresses
error = enumDynamicKeywordAddressesByTypeFn(
FW_DYNAMIC_KEYWORD_ADDRESS_ENUM_FLAGS_AUTO_RESOLVE,
&dynamicKeywordAddressData
);
if (error != ERROR_SUCCESS)
{
return;
}
currDynamicKeywordAddressData = dynamicKeywordAddressData;
while (currDynamicKeywordAddressData != NULL)
{
// Process this dynamic keyword address
currDynamicKeywordAddressData = currDynamicKeywordAddressData->next;
}
// Free the dynamic keyword addresses
freeDynamicKeywordAddressDataFn(dynamicKeywordAddressData);
SetEvent(*waitHandle);
}
int main()
{
DWORD error = ERROR_SUCCESS;
HANDLE notifyHandle;
HANDLE waitHandle;
waitHandle = CreateEventW(
NULL,
TRUE,
FALSE,
L"subscriptionWaitEvent"
);
// Subscribe for change notifications
error = FwpmDynamicKeywordSubscribe0(
FWPM_NOTIFY_ADDRESSES_AUTO_RESOLVE,
TestCallback,
&waitHandle,
¬ifyHandle);
if (error != ERROR_SUCCESS)
{
return error;
}
WaitForSingleObject(waitHandle, INFINITE);
// When client is ready to unsubscribe
error = FwpmDynamicKeywordUnsubscribe0(notifyHandle);
return error;
}