/* SPDX-License-Identifier: MIT * * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. */ package firewall import ( "encoding/binary" "errors" "net" "runtime" "unsafe" "golang.org/x/sys/windows" "golang.zx2c4.com/wireguard/windows/version" ) // // Known addresses. // var ( linkLocal = wtFwpV6AddrAndMask{[16]uint8{0xfe, 0x80}, 10} linkLocalDHCPMulticast = wtFwpByteArray16{[16]uint8{0xFF, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2}} siteLocalDHCPMulticast = wtFwpByteArray16{[16]uint8{0xFF, 0x05, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3}} linkLocalRouterMulticast = wtFwpByteArray16{[16]uint8{0xFF, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}} ) func permitTunInterface(session uintptr, baseObjects *baseObjects, weight uint8, ifLUID uint64) error { ifaceCondition := wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_IP_LOCAL_INTERFACE, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT64, value: (uintptr)(unsafe.Pointer(&ifLUID)), }, } filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: 1, filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&ifaceCondition)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) // // #1 Permit outbound IPv4 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit outbound IPv4 traffic on TUN", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Permit inbound IPv4 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit inbound IPv4 traffic on TUN", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #3 Permit outbound IPv6 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit outbound IPv6 traffic on TUN", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #4 Permit inbound IPv6 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit inbound IPv6 traffic on TUN", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } func permitWireGuardService(session uintptr, baseObjects *baseObjects, weight uint8) error { var conditions [2]wtFwpmFilterCondition0 // // First condition is the exe path of the current process. // appID, err := getCurrentProcessAppID() if err != nil { return wrapErr(err) } defer fwpmFreeMemory0(unsafe.Pointer(&appID)) conditions[0] = wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_ALE_APP_ID, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_BYTE_BLOB_TYPE, value: uintptr(unsafe.Pointer(appID)), }, } // // Second condition is the SECURITY_DESCRIPTOR of the current process. // This prevents other processes hosted in the same exe from matching this filter. // sd, err := getCurrentProcessSecurityDescriptor() if err != nil { return wrapErr(err) } defer windows.LocalFree(windows.Handle(unsafe.Pointer(sd.data))) conditions[1] = wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_ALE_USER_ID, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_SECURITY_DESCRIPTOR_TYPE, value: uintptr(unsafe.Pointer(sd)), }, } // // Assemble the filter. // filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weight), flags: cFWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT, numFilterConditions: uint32(len(conditions)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) // // #1 Permit outbound IPv4 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit unrestricted outbound traffic for WireGuard service (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Permit inbound IPv4 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit unrestricted inbound traffic for WireGuard service (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #3 Permit outbound IPv6 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit unrestricted outbound traffic for WireGuard service (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #4 Permit inbound IPv6 traffic. // { displayData, err := createWtFwpmDisplayData0("Permit unrestricted inbound traffic for WireGuard service (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } func permitLoopback(session uintptr, baseObjects *baseObjects, weight uint8) error { condition := wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_INTERFACE_TYPE, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT32, value: uintptr(cIF_TYPE_SOFTWARE_LOOPBACK), }, } filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: 1, filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&condition)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) // // #1 Permit outbound IPv4 on loopback. // { displayData, err := createWtFwpmDisplayData0("Permit outbound on loopback (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Permit inbound IPv4 on loopback. // { displayData, err := createWtFwpmDisplayData0("Permit inbound on loopback (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #3 Permit outbound IPv6 on loopback. // { displayData, err := createWtFwpmDisplayData0("Permit outbound on loopback (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #4 Permit inbound IPv6 on loopback. // { displayData, err := createWtFwpmDisplayData0("Permit inbound on loopback (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } func permitDHCPIPv4(session uintptr, baseObjects *baseObjects, weight uint8) error { // // #1 Outbound DHCP request on IPv4. // { var conditions [4]wtFwpmFilterCondition0 conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP) conditions[1].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(68) conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(67) conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[3].matchType = cFWP_MATCH_EQUAL conditions[3].conditionValue._type = cFWP_UINT32 conditions[3].conditionValue.value = uintptr(0xffffffff) displayData, err := createWtFwpmDisplayData0("Permit outbound DHCP request (IPv4)", "") if err != nil { return wrapErr(err) } filter := wtFwpmFilter0{ displayData: *displayData, providerKey: &baseObjects.provider, layerKey: cFWPM_LAYER_ALE_AUTH_CONNECT_V4, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: uint32(len(conditions)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Inbound DHCP response on IPv4. // { var conditions [3]wtFwpmFilterCondition0 conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP) conditions[1].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(68) conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(67) displayData, err := createWtFwpmDisplayData0("Permit inbound DHCP response (IPv4)", "") if err != nil { return wrapErr(err) } filter := wtFwpmFilter0{ displayData: *displayData, providerKey: &baseObjects.provider, layerKey: cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: uint32(len(conditions)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } func permitDHCPIPv6(session uintptr, baseObjects *baseObjects, weight uint8) error { // // #1 Outbound DHCP request on IPv6. // { var conditions [6]wtFwpmFilterCondition0 conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP) conditions[1].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_BYTE_ARRAY16_TYPE conditions[1].conditionValue.value = uintptr(unsafe.Pointer(&linkLocalDHCPMulticast)) // Repeat the condition type for logical OR. conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_BYTE_ARRAY16_TYPE conditions[2].conditionValue.value = uintptr(unsafe.Pointer(&siteLocalDHCPMulticast)) conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT conditions[3].matchType = cFWP_MATCH_EQUAL conditions[3].conditionValue._type = cFWP_UINT16 conditions[3].conditionValue.value = uintptr(547) conditions[4].fieldKey = cFWPM_CONDITION_IP_LOCAL_ADDRESS conditions[4].matchType = cFWP_MATCH_EQUAL conditions[4].conditionValue._type = cFWP_V6_ADDR_MASK conditions[4].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal)) conditions[5].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT conditions[5].matchType = cFWP_MATCH_EQUAL conditions[5].conditionValue._type = cFWP_UINT16 conditions[5].conditionValue.value = uintptr(546) displayData, err := createWtFwpmDisplayData0("Permit outbound DHCP request (IPv6)", "") if err != nil { return wrapErr(err) } filter := wtFwpmFilter0{ displayData: *displayData, providerKey: &baseObjects.provider, layerKey: cFWPM_LAYER_ALE_AUTH_CONNECT_V6, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: uint32(len(conditions)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Inbound DHCP response on IPv6. // { var conditions [5]wtFwpmFilterCondition0 conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP) conditions[1].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_V6_ADDR_MASK conditions[1].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal)) conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(547) conditions[3].fieldKey = cFWPM_CONDITION_IP_LOCAL_ADDRESS conditions[3].matchType = cFWP_MATCH_EQUAL conditions[3].conditionValue._type = cFWP_V6_ADDR_MASK conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal)) conditions[4].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT conditions[4].matchType = cFWP_MATCH_EQUAL conditions[4].conditionValue._type = cFWP_UINT16 conditions[4].conditionValue.value = uintptr(546) displayData, err := createWtFwpmDisplayData0("Permit inbound DHCP response (IPv6)", "") if err != nil { return wrapErr(err) } filter := wtFwpmFilter0{ displayData: *displayData, providerKey: &baseObjects.provider, layerKey: cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: uint32(len(conditions)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } func permitNdp(session uintptr, baseObjects *baseObjects, weight uint8) error { /* TODO: actually handle the hop limit somehow! The rules should vaguely be: * - icmpv6 133: must be outgoing, dst must be FF02::2/128, hop limit must be 255 * - icmpv6 134: must be incoming, src must be FE80::/10, hop limit must be 255 * - icmpv6 135: either incoming or outgoing, hop limit must be 255 * - icmpv6 136: either incoming or outgoing, hop limit must be 255 * - icmpv6 137: must be incoming, src must be FE80::/10, hop limit must be 255 */ type filterDefinition struct { displayData *wtFwpmDisplayData0 conditions []wtFwpmFilterCondition0 layer windows.GUID } var defs []filterDefinition // // Router Solicitation Message // ICMP type 133, code 0. Outgoing. // { conditions := make([]wtFwpmFilterCondition0, 4) conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6) conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(133) conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(0) conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[3].matchType = cFWP_MATCH_EQUAL conditions[3].conditionValue._type = cFWP_BYTE_ARRAY16_TYPE conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocalRouterMulticast)) displayData, err := createWtFwpmDisplayData0("Permit NDP type 133", "") if err != nil { return wrapErr(err) } defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_CONNECT_V6, }) } // // Router Advertisement Message // ICMP type 134, code 0. Incoming. // { conditions := make([]wtFwpmFilterCondition0, 4) conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6) conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(134) conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(0) conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[3].matchType = cFWP_MATCH_EQUAL conditions[3].conditionValue._type = cFWP_V6_ADDR_MASK conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal)) displayData, err := createWtFwpmDisplayData0("Permit NDP type 134", "") if err != nil { return wrapErr(err) } defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, }) } // // Neighbor Solicitation Message // ICMP type 135, code 0. Bi-directional. // { conditions := make([]wtFwpmFilterCondition0, 3) conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6) conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(135) conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(0) displayData, err := createWtFwpmDisplayData0("Permit NDP type 135", "") if err != nil { return wrapErr(err) } defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_CONNECT_V6, }) defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, }) } // // Neighbor Advertisement Message // ICMP type 136, code 0. Bi-directional. // { conditions := make([]wtFwpmFilterCondition0, 3) conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6) conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(136) conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(0) displayData, err := createWtFwpmDisplayData0("Permit NDP type 136", "") if err != nil { return wrapErr(err) } defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_CONNECT_V6, }) defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, }) } // // Redirect Message // ICMP type 137, code 0. Incoming. // { conditions := make([]wtFwpmFilterCondition0, 4) conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL conditions[0].matchType = cFWP_MATCH_EQUAL conditions[0].conditionValue._type = cFWP_UINT8 conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6) conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE conditions[1].matchType = cFWP_MATCH_EQUAL conditions[1].conditionValue._type = cFWP_UINT16 conditions[1].conditionValue.value = uintptr(137) conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE conditions[2].matchType = cFWP_MATCH_EQUAL conditions[2].conditionValue._type = cFWP_UINT16 conditions[2].conditionValue.value = uintptr(0) conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS conditions[3].matchType = cFWP_MATCH_EQUAL conditions[3].conditionValue._type = cFWP_V6_ADDR_MASK conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal)) displayData, err := createWtFwpmDisplayData0("Permit NDP type 137", "") if err != nil { return wrapErr(err) } defs = append(defs, filterDefinition{ displayData: displayData, conditions: conditions, layer: cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, }) } filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weight), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) for _, definition := range defs { filter.displayData = *definition.displayData filter.layerKey = definition.layer filter.numFilterConditions = uint32(len(definition.conditions)) filter.filterCondition = (*wtFwpmFilterCondition0)(unsafe.Pointer(&definition.conditions[0])) err := fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } func permitHyperV(session uintptr, baseObjects *baseObjects, weight uint8) error { // // Only applicable on Win8+. // { v, err := version.OsVersion() if err != nil { panic(err) } win8plus := v.MajorVersion > 6 || (v.MajorVersion == 6 && v.MinorVersion >= 3) if !win8plus { return nil } } condition := wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_L2_FLAGS, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT32, value: uintptr(cFWP_CONDITION_L2_IS_VM2VM), }, } filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weight), numFilterConditions: 1, filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&condition)), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID := uint64(0) // // #1 Outbound. // { displayData, err := createWtFwpmDisplayData0("Permit Hyper-V => Hyper-V outbound", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Inbound. // { displayData, err := createWtFwpmDisplayData0("Permit Hyper-V => Hyper-V inbound", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_INBOUND_MAC_FRAME_NATIVE err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } // Block all traffic except what is explicitly permitted by other rules. func blockAll(session uintptr, baseObjects *baseObjects, weight uint8) error { filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weight), action: wtFwpmAction0{ _type: cFWP_ACTION_BLOCK, }, } filterID := uint64(0) // // #1 Block outbound traffic on IPv4. // { displayData, err := createWtFwpmDisplayData0("Block all outbound (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Block inbound traffic on IPv4. // { displayData, err := createWtFwpmDisplayData0("Block all inbound (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #3 Block outbound traffic on IPv6. // { displayData, err := createWtFwpmDisplayData0("Block all outbound (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #4 Block inbound traffic on IPv6. // { displayData, err := createWtFwpmDisplayData0("Block all inbound (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } return nil } // Block all DNS traffic except towards specified DNS servers. func blockDNS(except []net.IP, session uintptr, baseObjects *baseObjects, weightAllow uint8, weightDeny uint8) error { if weightDeny >= weightAllow { return errors.New("The allow weight must be greater than the deny weight") } denyConditions := []wtFwpmFilterCondition0{ { fieldKey: cFWPM_CONDITION_IP_REMOTE_PORT, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT16, value: uintptr(53), }, }, { fieldKey: cFWPM_CONDITION_IP_PROTOCOL, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT8, value: uintptr(cIPPROTO_UDP), }, }, // Repeat the condition type for logical OR. { fieldKey: cFWPM_CONDITION_IP_PROTOCOL, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT8, value: uintptr(cIPPROTO_TCP), }, }, } filter := wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weightDeny), numFilterConditions: uint32(len(denyConditions)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&denyConditions[0])), action: wtFwpmAction0{ _type: cFWP_ACTION_BLOCK, }, } filterID := uint64(0) // // #1 Block IPv4 outbound DNS. // { displayData, err := createWtFwpmDisplayData0("Block DNS outbound (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #2 Block IPv4 inbound DNS. // { displayData, err := createWtFwpmDisplayData0("Block DNS inbound (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #3 Block IPv6 outbound DNS. // { displayData, err := createWtFwpmDisplayData0("Block DNS outbound (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #4 Block IPv6 inbound DNS. // { displayData, err := createWtFwpmDisplayData0("Block DNS inbound (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } allowConditionsV4 := make([]wtFwpmFilterCondition0, 0, len(denyConditions)+len(except)) allowConditionsV4 = append(allowConditionsV4, denyConditions...) for _, ip := range except { ip4 := ip.To4() if ip4 == nil { continue } allowConditionsV4 = append(allowConditionsV4, wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_IP_REMOTE_ADDRESS, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_UINT32, value: uintptr(binary.BigEndian.Uint32(ip4)), }, }) } storedPointers := make([]*wtFwpByteArray16, 0, len(except)) allowConditionsV6 := make([]wtFwpmFilterCondition0, 0, len(denyConditions)+len(except)) allowConditionsV6 = append(allowConditionsV6, denyConditions...) for _, ip := range except { if ip.To4() != nil { continue } var address wtFwpByteArray16 copy(address.byteArray16[:], ip) allowConditionsV6 = append(allowConditionsV6, wtFwpmFilterCondition0{ fieldKey: cFWPM_CONDITION_IP_REMOTE_ADDRESS, matchType: cFWP_MATCH_EQUAL, conditionValue: wtFwpConditionValue0{ _type: cFWP_BYTE_ARRAY16_TYPE, value: uintptr(unsafe.Pointer(&address)), }, }) storedPointers = append(storedPointers, &address) } filter = wtFwpmFilter0{ providerKey: &baseObjects.provider, subLayerKey: baseObjects.filters, weight: filterWeight(weightAllow), numFilterConditions: uint32(len(allowConditionsV4)), filterCondition: (*wtFwpmFilterCondition0)(unsafe.Pointer(&allowConditionsV4[0])), action: wtFwpmAction0{ _type: cFWP_ACTION_PERMIT, }, } filterID = uint64(0) // // #5 Allow IPv4 outbound DNS. // if len(allowConditionsV4) > len(denyConditions) { displayData, err := createWtFwpmDisplayData0("Allow DNS outbound (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #6 Allow IPv4 inbound DNS. // if len(allowConditionsV4) > len(denyConditions) { displayData, err := createWtFwpmDisplayData0("Allow DNS inbound (IPv4)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } filter.filterCondition = (*wtFwpmFilterCondition0)(unsafe.Pointer(&allowConditionsV6[0])) filter.numFilterConditions = uint32(len(allowConditionsV6)) // // #7 Allow IPv6 outbound DNS. // if len(allowConditionsV6) > len(denyConditions) { displayData, err := createWtFwpmDisplayData0("Allow DNS outbound (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } // // #8 Allow IPv6 inbound DNS. // if len(allowConditionsV6) > len(denyConditions) { displayData, err := createWtFwpmDisplayData0("Allow DNS inbound (IPv6)", "") if err != nil { return wrapErr(err) } filter.displayData = *displayData filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6 err = fwpmFilterAdd0(session, &filter, 0, &filterID) if err != nil { return wrapErr(err) } } runtime.KeepAlive(storedPointers) return nil }