aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tunnel/firewall/rules.go
diff options
context:
space:
mode:
Diffstat (limited to 'tunnel/firewall/rules.go')
-rw-r--r--tunnel/firewall/rules.go1240
1 files changed, 1240 insertions, 0 deletions
diff --git a/tunnel/firewall/rules.go b/tunnel/firewall/rules.go
new file mode 100644
index 00000000..76e2a85b
--- /dev/null
+++ b/tunnel/firewall/rules.go
@@ -0,0 +1,1240 @@
+/* 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 low privileged applications 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
+}