Динамические ключевые слова брандмауэра

Api динамических ключевых слов брандмауэра используются для управления динамическими адресами ключевое слово в брандмауэре Microsoft Defender. Адрес на основе динамического ключевого слова используется для создания набора IP-адресов, на которые может ссылаться одно или несколько правил брандмауэра. Адреса на основе динамического ключевого слова поддерживают как IPv4, так и IPv6.

Примечание

Справочные материалы по API, представленные в этом разделе, см. в справочнике по динамическим ключевым словам брандмауэра.

Операции с динамическими адресами ключевое слово

С помощью API динамических ключевых слов брандмауэра можно выполнять следующие операции.

  • Добавление динамических адресов ключевое слово
  • Удаление динамических адресов ключевое слово
  • Перечисление динамических ключевое слово адресов по идентификатору или типу
  • Обновление динамических адресов ключевое слово
  • Подписка и обработка уведомлений об изменении динамических ключевое слово адресов

Ниже приведены примеры кода для всех этих операций.

После добавления динамического адреса ключевое слово он сохраняется при перезагрузке. После завершения работы с объектом необходимо удалить динамический адрес ключевое слово.

Существует два класса динамических адресов ключевое слово, как описано в следующих двух разделах.

Автоматическое заполнение динамических адресов ключевое слово

Первый тип — AutoResolve, где поле ключевое слово представляет разрешаемое имя, а IP-адреса не определяются при создании.

Эти объекты предназначены для автоматического разрешения IP-адресов. То есть не через администратора во время создания объекта; не через саму операционную систему (ОС). Компонент за пределами службы брандмауэра должен выполнять разрешение IP-адресов для этих объектов и соответствующим образом обновлять их. Реализация такого компонента выходит за рамки область этого содержимого.

Динамический адрес ключевое слово указывается как autoResolve путем установки флага FW_DYNAMIC_KEYWORD_ADDRESS_FLAGS_AUTO_RESOLVE в объекте при вызове функции FWAddDynamicKeywordAddress0. Поле ключевое слово должно использоваться для представления разрешаемого значения, то есть полного доменного имени (FQDN) или имени узла. Поле адресов должно изначально иметь значение NULL для этих объектов. Эти объекты не будут сохранять СВОИ IP-адреса в течение циклов загрузки, и вам следует повторно оценить или повторно заполнить их адреса во время следующего цикла загрузки.

Примечание

Автоматическое удаление динамических объектов ключевое слово адресов активирует уведомления на FWAddDynamicKeywordAddress0 и FWDeleteDynamicKeywordAddress0, но не FWUpdateDynamicKeywordAddress0.

Динамические адреса ключевое слово без автоматического разрешения

Второй тип — не AutoResolve, где поле ключевое слово представляет собой любую строку, а адреса определяются во время создания.

Эти объекты используются для хранения набора IP-адресов, подсетей или диапазонов. Поле ключевое слово здесь используется для удобства управления, и для него можно задать любую строку. Поле адреса должно иметь значение, отличное от NULL, после создания. Адреса для этих объектов сохраняются во время перезагрузки.

Примечание

Динамические объекты ключевое слово адресов, не относящиеся к AutoResolve, активируют уведомления на FWAddDynamicKeywordAddress0, FWDeleteDynamicKeywordAddress0, а также FWUpdateDynamicKeywordAddress0.

Дополнительные сведения о динамических адресах ключевое слово

Все динамические адреса ключевое слово должны иметь уникальный идентификатор GUID для их представления.

API FwpmDynamicKeywordSubscribe0 предоставляет клиенту уведомления при изменении динамических ключевое слово адресов. Нет полезных данных, доставляемых клиенту, описывающих, что именно изменилось в системе. Если необходимо знать, какие объекты изменились, следует запросить текущее состояние объектов в системе с помощью API FWEnumDynamicKeywordAddressById0 или FWEnumDynamicKeywordAddressesByType0 . Различные флаги можно использовать для запроса уведомлений только для подмножества объектов. Если вы не используете флаги, уведомления об изменениях будут доставляться для всех объектов.

Правило брандмауэра может использовать динамические адреса ключевое слово вместо явного определения IP-адресов в качестве условия удаленного адреса. Правило брандмауэра может использовать как динамические ключевое слово адреса, так и статически определенные диапазоны удаленных адресов. Один динамический объект адреса ключевое слово можно повторно использовать в нескольких правилах брандмауэра. Если правило брандмауэра не имеет настроенных удаленных адресов (то есть настроено только для объектов AutoResolve, которые еще не разрешены), это правило не будет применено. Кроме того, если правило использует несколько динамических ключевое слово адресов, оно будет применяться ко всем адресам, которые в настоящее время разрешены, даже если есть другие объекты, которые еще не разрешены. При обновлении динамического адреса ключевое слово все связанные объекты правил также будут обновлять свои удаленные адреса.

Сама операционная система (ОС) не применяет зависимости между правилом и динамическим адресом ключевое слово. Это означает, что сначала можно создать любой объект— правило может ссылаться на динамические идентификаторы адресов ключевое слово, которые еще не существуют (в этом случае правило не будет применяться). Кроме того, вы можете удалить динамический адрес ключевое слово, даже если он используется правилом брандмауэра. В этом разделе описывается, как администратор может настроить правила для использования динамического адреса ключевое слово.

Примеры кода

Чтобы опробовать каждый из этих примеров кода, сначала запустите 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,
        &notifyHandle);
    if (error != ERROR_SUCCESS)
    {
        return error;
    }

    WaitForSingleObject(waitHandle, INFINITE);

    // When client is ready to unsubscribe
    error = FwpmDynamicKeywordUnsubscribe0(notifyHandle);

    return error;
}