diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-20 14:18:01 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-20 14:18:01 +0200 |
commit | cdb8c53cdea8d8ac6e6f2112e4a5e844bffd01a4 (patch) | |
tree | db88ec568dfc508da863e67164de909448c66742 /tunnel/firewall/rules.go | |
parent | service: move route monitor and account for changing index (diff) | |
download | wireguard-windows-cdb8c53cdea8d8ac6e6f2112e4a5e844bffd01a4.tar.xz wireguard-windows-cdb8c53cdea8d8ac6e6f2112e4a5e844bffd01a4.zip |
service: split into tunnel and manager
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'tunnel/firewall/rules.go')
-rw-r--r-- | tunnel/firewall/rules.go | 1240 |
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 +} |