/* * Add a persistent sublayer with specified uuid. */ static DWORD add_sublayer(GUID uuid) { FWPM_SESSION0 session; HANDLE engine = NULL; DWORD err = 0; FWPM_SUBLAYER0 sublayer; memset(&session, 0, sizeof(session)); memset(&sublayer, 0, sizeof(sublayer)); err = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine); if (err != ERROR_SUCCESS) { goto out; } sublayer.subLayerKey = uuid; sublayer.displayData.name = FIREWALL_NAME; sublayer.displayData.description = FIREWALL_NAME; sublayer.flags = 0; sublayer.weight = 0x100; /* Add sublayer to the session */ err = FwpmSubLayerAdd0(engine, &sublayer, NULL); out: if (engine) { FwpmEngineClose0(engine); } return err; }
void DDProxyUnregisterCallouts() { FwpmEngineClose0(gEngineHandle); gEngineHandle = NULL; FwpsCalloutUnregisterById0(gCalloutIdV6); FwpsCalloutUnregisterById0(gCalloutIdV4); FwpsCalloutUnregisterById0(gFlowEstablishedCalloutIdV6); FwpsCalloutUnregisterById0(gFlowEstablishedCalloutIdV4); }
DWORD delete_block_dns_filters(HANDLE engine_handle) { DWORD err = 0; /* * For dynamic sessions closing the engine removes all filters added in the session */ if (engine_handle) { err = FwpmEngineClose0(engine_handle); } return err; }
void monitor_destroy(void) { monitor_stop(); if (g.session) { FWP_VALUE0 val = {0}; val.type = FWP_UINT32; val.uint32 = 0; FwpmEngineSetOption0(g.session, FWPM_ENGINE_COLLECT_NET_EVENTS, &val); FwpmEngineClose0(g.session); } SecureZeroMemory(&g, sizeof(g)); }
void TLInspectUnregisterCallouts() { FwpmEngineClose0(gEngineHandle); gEngineHandle = NULL; FwpsCalloutUnregisterById0(gOutboundTlCalloutIdV6); FwpsCalloutUnregisterById0(gOutboundTlCalloutIdV4); FwpsCalloutUnregisterById0(gInboundTlCalloutIdV6); FwpsCalloutUnregisterById0(gInboundTlCalloutIdV4); FwpsCalloutUnregisterById0(gAleConnectCalloutIdV6); FwpsCalloutUnregisterById0(gAleConnectCalloutIdV4); FwpsCalloutUnregisterById0(gAleRecvAcceptCalloutIdV6); FwpsCalloutUnregisterById0(gAleRecvAcceptCalloutIdV4); }
NTSTATUS DDProxyRegisterCallouts( IN void* deviceObject ) /* ++ This function registers dynamic callouts and filters that intercept UDP or non-error ICMP traffic at WFP FWPM_LAYER_DATAGRAM_DATA_V{4|6} and FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4|6} layers. Callouts and filters will be removed during DriverUnload. -- */ { NTSTATUS status = STATUS_SUCCESS; FWPM_SUBLAYER0 DDProxySubLayer; BOOLEAN engineOpened = FALSE; BOOLEAN inTransaction = FALSE; FWPM_SESSION0 session = {0}; session.flags = FWPM_SESSION_FLAG_DYNAMIC; status = FwpmEngineOpen0( NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle ); if (!NT_SUCCESS(status)) { goto Exit; } engineOpened = TRUE; status = FwpmTransactionBegin0(gEngineHandle, 0); if (!NT_SUCCESS(status)) { goto Exit; } inTransaction = TRUE; RtlZeroMemory(&DDProxySubLayer, sizeof(FWPM_SUBLAYER0)); DDProxySubLayer.subLayerKey = DD_PROXY_SUBLAYER; DDProxySubLayer.displayData.name = L"Datagram-Data Proxy Sub-Layer"; DDProxySubLayer.displayData.description = L"Sub-Layer for use by Datagram-Data Proxy callouts"; DDProxySubLayer.flags = 0; DDProxySubLayer.weight = FWP_EMPTY; // auto-weight.; status = FwpmSubLayerAdd0(gEngineHandle, &DDProxySubLayer, NULL); if (!NT_SUCCESS(status)) { goto Exit; } status = DDProxyRegisterFlowEstablishedCallouts( &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4, &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4, deviceObject, &gFlowEstablishedCalloutIdV4 ); if (!NT_SUCCESS(status)) { goto Exit; } status = DDProxyRegisterFlowEstablishedCallouts( &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6, &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6, deviceObject, &gFlowEstablishedCalloutIdV6 ); if (!NT_SUCCESS(status)) { goto Exit; } status = DDProxyRegisterDatagramDataCallouts( &FWPM_LAYER_DATAGRAM_DATA_V4, &DD_PROXY_CALLOUT_V4, deviceObject, &gCalloutIdV4 ); if (!NT_SUCCESS(status)) { goto Exit; } status = DDProxyRegisterDatagramDataCallouts( &FWPM_LAYER_DATAGRAM_DATA_V6, &DD_PROXY_CALLOUT_V6, deviceObject, &gCalloutIdV6 ); if (!NT_SUCCESS(status)) { goto Exit; } status = FwpmTransactionCommit0(gEngineHandle); if (!NT_SUCCESS(status)) { goto Exit; } inTransaction = FALSE; Exit: if (!NT_SUCCESS(status)) { if (inTransaction) { FwpmTransactionAbort0(gEngineHandle); } if (engineOpened) { FwpmEngineClose0(gEngineHandle); gEngineHandle = NULL; } } return status; }
DWORD GetMatchingEvents( __in UINT32 mins, __in ADDRESS_FAMILY version, __in_opt SOCKADDR_STORAGE* remoteAddr, __out FWPM_NET_EVENT0*** matchedEvents, __out UINT32* numMatchedEvents ) /*++ Routine Description: This routine creates and fills an event enumeration template, and retrieve events matching the template using WFP API. The diagnostic events API is used only in this function Arguments: mins - period in minutes for which events should be retrieved going back from current time. version - IP version remoteAddr - pointer to IP address which should match the remote address in events. matchedEvents - pointer to an array of pointers to events that have period and/or remote address matching those specified. numMatchedEvents - pointer to the number of events matching the criterion. Return Value: DWORD - If the function succeeds, the return value is ERROR_SUCCESS. --*/ { DWORD result = ERROR_SUCCESS; UINT32 filterCondCount = 0; FWPM_NET_EVENT_ENUM_TEMPLATE0 eventTemplate; FWPM_FILTER_CONDITION0 filterConditions[NUM_FILTER_CONDITIONS] = {0}; HANDLE fwpEngineHandle = NULL; HANDLE enumHandle = NULL; BOOLEAN engineOpen = FALSE; SYSTEMTIME curTimeSys; //----------------------------------------- // The period in which the event happened is set to current sytem time. GetSystemTime(&curTimeSys); if (!(SystemTimeToFileTime(&curTimeSys, &(eventTemplate.endTime)))) { wprintf(L"Error in converting system time to file time.\n"); result = GetLastError(); CHECK_RESULT(result); } //----------------------------------------- // Set the lower end of the period in which events are of interest if (0 == mins) { eventTemplate.startTime.dwLowDateTime = 0; eventTemplate.startTime.dwHighDateTime = 0; } else { ULARGE_INTEGER filetime; ULONGLONG period; filetime.LowPart = eventTemplate.endTime.dwLowDateTime; filetime.HighPart = eventTemplate.endTime.dwHighDateTime; period = ((ULONGLONG)mins)*MIN_FACTOR; if (filetime.QuadPart > period) { filetime.QuadPart -= period; } else { filetime.QuadPart = 0; } eventTemplate.startTime.dwLowDateTime = filetime.LowPart; eventTemplate.startTime.dwHighDateTime = filetime.HighPart; } //----------------------------------------- // Set the filter condition to look for events matching the remote address if (remoteAddr) { if (AF_INET == version) { SOCKADDR_IN* ipV4Addr = (SOCKADDR_IN*)remoteAddr; filterConditions[filterCondCount].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS; filterConditions[filterCondCount].matchType = FWP_MATCH_EQUAL; filterConditions[filterCondCount].conditionValue.type = FWP_UINT32; filterConditions[filterCondCount].conditionValue.uint32 = ntohl(ipV4Addr->sin_addr.s_addr); filterCondCount++; } else if (AF_INET6 == version) { SOCKADDR_IN6* ipV6Addr = (SOCKADDR_IN6*)remoteAddr; filterConditions[filterCondCount].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS; filterConditions[filterCondCount].matchType = FWP_MATCH_EQUAL; filterConditions[filterCondCount].conditionValue.type = FWP_BYTE_ARRAY16_TYPE; filterConditions[filterCondCount].conditionValue.byteArray16 = (FWP_BYTE_ARRAY16 *)(ipV6Addr->sin6_addr.s6_bytes); filterCondCount++; } } //----------------------------------------- // Fill the event enumeration template eventTemplate.numFilterConditions = filterCondCount; eventTemplate.filterCondition = filterConditions; //----------------------------------------- // Open a session to the filter engine result = FwpmEngineOpen0( NULL, RPC_C_AUTHN_WINNT, NULL, NULL, &fwpEngineHandle ); CHECK_RESULT(result); //----------------------------------------- // Create an enumeration handle based on event template result = FwpmNetEventCreateEnumHandle0( fwpEngineHandle, &eventTemplate, &enumHandle ); CHECK_RESULT(result); //----------------------------------------- // Get the events from enumeration result = FwpmNetEventEnum0( fwpEngineHandle, enumHandle, INFINITE, matchedEvents, numMatchedEvents ); CHECK_RESULT(result); // // fallthrough // cleanup: //----------------------------------------- // Destroy enumeration handle if (enumHandle) { FwpmNetEventDestroyEnumHandle0(fwpEngineHandle, enumHandle); } //----------------------------------------- // Close session after destroying enumeration handle if (fwpEngineHandle) { FwpmEngineClose0(fwpEngineHandle); } return result; }
NTSTATUS TLInspectRegisterCallouts( IN void* deviceObject ) /* ++ This function registers dynamic callouts and filters that intercept transport traffic at ALE AUTH_CONNECT/AUTH_RECV_ACCEPT and INBOUND/OUTBOUND transport layers. Callouts and filters will be removed during DriverUnload. -- */ { NTSTATUS status = STATUS_SUCCESS; FWPM_SUBLAYER0 TLInspectSubLayer; BOOLEAN engineOpened = FALSE; BOOLEAN inTransaction = FALSE; FWPM_SESSION0 session = {0}; session.flags = FWPM_SESSION_FLAG_DYNAMIC; status = FwpmEngineOpen0( NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle ); if (!NT_SUCCESS(status)) { goto Exit; } engineOpened = TRUE; status = FwpmTransactionBegin0(gEngineHandle, 0); if (!NT_SUCCESS(status)) { goto Exit; } inTransaction = TRUE; RtlZeroMemory(&TLInspectSubLayer, sizeof(FWPM_SUBLAYER0)); TLInspectSubLayer.subLayerKey = TL_INSPECT_SUBLAYER; TLInspectSubLayer.displayData.name = L"Transport Inspect Sub-Layer"; TLInspectSubLayer.displayData.description = L"Sub-Layer for use by Transport Inspect callouts"; TLInspectSubLayer.flags = 0; TLInspectSubLayer.weight = 0; // must be less than the weight of // FWPM_SUBLAYER_UNIVERSAL to be // compatible with Vista's IpSec // implementation. status = FwpmSubLayerAdd0(gEngineHandle, &TLInspectSubLayer, NULL); if (!NT_SUCCESS(status)) { goto Exit; } //if (configInspectRemoteAddrV4 != NULL) { /* status = TLInspectRegisterALEClassifyCallouts( &FWPM_LAYER_ALE_AUTH_CONNECT_V4, &TL_INSPECT_ALE_CONNECT_CALLOUT_V4, deviceObject, &gAleConnectCalloutIdV4 ); if (!NT_SUCCESS(status)) { goto Exit; } status = TLInspectRegisterALEClassifyCallouts( &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, &TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V4, deviceObject, &gAleRecvAcceptCalloutIdV4 ); if (!NT_SUCCESS(status)) { goto Exit; } */ status = TLInspectRegisterTransportCallouts( &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, &TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V4, deviceObject, &gOutboundTlCalloutIdV4 ); if (!NT_SUCCESS(status)) { goto Exit; } status = TLInspectRegisterTransportCallouts( &FWPM_LAYER_INBOUND_TRANSPORT_V4, &TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V4, deviceObject, &gInboundTlCalloutIdV4 ); if (!NT_SUCCESS(status)) { goto Exit; } } /* if (configInspectRemoteAddrV6 != NULL) { status = TLInspectRegisterALEClassifyCallouts( &FWPM_LAYER_ALE_AUTH_CONNECT_V6, &TL_INSPECT_ALE_CONNECT_CALLOUT_V6, deviceObject, &gAleConnectCalloutIdV6 ); if (!NT_SUCCESS(status)) { goto Exit; } status = TLInspectRegisterALEClassifyCallouts( &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, &TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V6, deviceObject, &gAleRecvAcceptCalloutIdV6 ); if (!NT_SUCCESS(status)) { goto Exit; } status = TLInspectRegisterTransportCallouts( &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, &TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V6, deviceObject, &gOutboundTlCalloutIdV6 ); if (!NT_SUCCESS(status)) { goto Exit; } status = TLInspectRegisterTransportCallouts( &FWPM_LAYER_INBOUND_TRANSPORT_V6, &TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V6, deviceObject, &gInboundTlCalloutIdV6 ); if (!NT_SUCCESS(status)) { goto Exit; } } */ status = FwpmTransactionCommit0(gEngineHandle); if (!NT_SUCCESS(status)) { goto Exit; } inTransaction = FALSE; Exit: if (!NT_SUCCESS(status)) { if (inTransaction) { FwpmTransactionAbort0(gEngineHandle); } if (engineOpened) { FwpmEngineClose0(gEngineHandle); gEngineHandle = NULL; } } return status; }
DWORD add_block_dns_filters(HANDLE *engine_handle, int index, const WCHAR *exe_path, block_dns_msg_handler_t msg_handler ) { FWPM_SESSION0 session = {0}; FWPM_SUBLAYER0 *sublayer_ptr = NULL; NET_LUID tapluid; UINT64 filterid; FWP_BYTE_BLOB *openvpnblob = NULL; FWPM_FILTER0 Filter = {0}; FWPM_FILTER_CONDITION0 Condition[2] = {0}; DWORD err = 0; if (!msg_handler) { msg_handler = default_msg_handler; } /* Add temporary filters which don't survive reboots or crashes. */ session.flags = FWPM_SESSION_FLAG_DYNAMIC; *engine_handle = NULL; err = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, engine_handle); CHECK_ERROR(err, "FwpEngineOpen: open fwp session failed"); msg_handler(0, "Block_DNS: WFP engine opened"); /* Check sublayer exists and add one if it does not. */ if (FwpmSubLayerGetByKey0(*engine_handle, &OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, &sublayer_ptr) == ERROR_SUCCESS) { msg_handler(0, "Block_DNS: Using existing sublayer"); FwpmFreeMemory0((void **)&sublayer_ptr); } else { /* Add a new sublayer -- as another process may add it in the meantime, * do not treat "already exists" as an error */ err = add_sublayer(OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER); if (err == FWP_E_ALREADY_EXISTS || err == ERROR_SUCCESS) { msg_handler(0, "Block_DNS: Added a persistent sublayer with pre-defined UUID"); } else { CHECK_ERROR(err, "add_sublayer: failed to add persistent sublayer"); } } err = ConvertInterfaceIndexToLuid(index, &tapluid); CHECK_ERROR(err, "Convert interface index to luid failed"); err = FwpmGetAppIdFromFileName0(exe_path, &openvpnblob); CHECK_ERROR(err, "Get byte blob for openvpn executable name failed"); /* Prepare filter. */ Filter.subLayerKey = OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER; Filter.displayData.name = FIREWALL_NAME; Filter.weight.type = FWP_UINT8; Filter.weight.uint8 = 0xF; Filter.filterCondition = Condition; Filter.numFilterConditions = 2; /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; Filter.action.type = FWP_ACTION_PERMIT; Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; Condition[0].matchType = FWP_MATCH_EQUAL; Condition[0].conditionValue.type = FWP_UINT16; Condition[0].conditionValue.uint16 = 53; Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; Condition[1].matchType = FWP_MATCH_EQUAL; Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; Condition[1].conditionValue.byteBlob = openvpnblob; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR(err, "Add filter to permit IPv4 port 53 traffic from OpenVPN failed"); /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR(err, "Add filter to permit IPv6 port 53 traffic from OpenVPN failed"); msg_handler(0, "Block_DNS: Added permit filters for exe_path"); /* Third filter. Block all IPv4 DNS queries. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; Filter.action.type = FWP_ACTION_BLOCK; Filter.weight.type = FWP_EMPTY; Filter.numFilterConditions = 1; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR(err, "Add filter to block IPv4 DNS traffic failed"); /* Forth filter. Block all IPv6 DNS queries. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR(err, "Add filter to block IPv6 DNS traffic failed"); msg_handler(0, "Block_DNS: Added block filters for all interfaces"); /* Fifth filter. Permit IPv4 DNS queries from TAP. * Use a non-zero weight so that the permit filters get higher priority * over the block filter added with automatic weighting */ Filter.weight.type = FWP_UINT8; Filter.weight.uint8 = 0xE; Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; Filter.action.type = FWP_ACTION_PERMIT; Filter.numFilterConditions = 2; Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; Condition[1].matchType = FWP_MATCH_EQUAL; Condition[1].conditionValue.type = FWP_UINT64; Condition[1].conditionValue.uint64 = &tapluid.Value; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR(err, "Add filter to permit IPv4 DNS traffic through TAP failed"); /* Sixth filter. Permit IPv6 DNS queries from TAP. * Use same weight as IPv4 filter */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR(err, "Add filter to permit IPv6 DNS traffic through TAP failed"); msg_handler(0, "Block_DNS: Added permit filters for TAP interface"); out: if (openvpnblob) { FwpmFreeMemory0((void **)&openvpnblob); } if (err && *engine_handle) { FwpmEngineClose0(*engine_handle); *engine_handle = NULL; } return err; }