golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/tunnel/firewall/rules.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package firewall
     7  
     8  import (
     9  	"encoding/binary"
    10  	"errors"
    11  	"net/netip"
    12  	"runtime"
    13  	"unsafe"
    14  
    15  	"golang.org/x/sys/windows"
    16  )
    17  
    18  //
    19  // Known addresses.
    20  //
    21  var (
    22  	linkLocal = wtFwpV6AddrAndMask{[16]uint8{0xfe, 0x80}, 10}
    23  
    24  	linkLocalDHCPMulticast = wtFwpByteArray16{[16]uint8{0xFF, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2}}
    25  	siteLocalDHCPMulticast = wtFwpByteArray16{[16]uint8{0xFF, 0x05, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3}}
    26  
    27  	linkLocalRouterMulticast = wtFwpByteArray16{[16]uint8{0xFF, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}
    28  )
    29  
    30  func permitTunInterface(session uintptr, baseObjects *baseObjects, weight uint8, ifLUID uint64) error {
    31  	ifaceCondition := wtFwpmFilterCondition0{
    32  		fieldKey:  cFWPM_CONDITION_IP_LOCAL_INTERFACE,
    33  		matchType: cFWP_MATCH_EQUAL,
    34  		conditionValue: wtFwpConditionValue0{
    35  			_type: cFWP_UINT64,
    36  			value: (uintptr)(unsafe.Pointer(&ifLUID)),
    37  		},
    38  	}
    39  
    40  	filter := wtFwpmFilter0{
    41  		providerKey:         &baseObjects.provider,
    42  		subLayerKey:         baseObjects.filters,
    43  		weight:              filterWeight(weight),
    44  		numFilterConditions: 1,
    45  		filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&ifaceCondition)),
    46  		action: wtFwpmAction0{
    47  			_type: cFWP_ACTION_PERMIT,
    48  		},
    49  	}
    50  
    51  	filterID := uint64(0)
    52  
    53  	//
    54  	// #1 Permit outbound IPv4 traffic.
    55  	//
    56  	{
    57  		displayData, err := createWtFwpmDisplayData0("Permit outbound IPv4 traffic on TUN", "")
    58  		if err != nil {
    59  			return wrapErr(err)
    60  		}
    61  
    62  		filter.displayData = *displayData
    63  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4
    64  
    65  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
    66  		if err != nil {
    67  			return wrapErr(err)
    68  		}
    69  	}
    70  
    71  	//
    72  	// #2 Permit inbound IPv4 traffic.
    73  	//
    74  	{
    75  		displayData, err := createWtFwpmDisplayData0("Permit inbound IPv4 traffic on TUN", "")
    76  		if err != nil {
    77  			return wrapErr(err)
    78  		}
    79  
    80  		filter.displayData = *displayData
    81  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
    82  
    83  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
    84  		if err != nil {
    85  			return wrapErr(err)
    86  		}
    87  	}
    88  
    89  	//
    90  	// #3 Permit outbound IPv6 traffic.
    91  	//
    92  	{
    93  		displayData, err := createWtFwpmDisplayData0("Permit outbound IPv6 traffic on TUN", "")
    94  		if err != nil {
    95  			return wrapErr(err)
    96  		}
    97  
    98  		filter.displayData = *displayData
    99  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6
   100  
   101  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   102  		if err != nil {
   103  			return wrapErr(err)
   104  		}
   105  	}
   106  
   107  	//
   108  	// #4 Permit inbound IPv6 traffic.
   109  	//
   110  	{
   111  		displayData, err := createWtFwpmDisplayData0("Permit inbound IPv6 traffic on TUN", "")
   112  		if err != nil {
   113  			return wrapErr(err)
   114  		}
   115  
   116  		filter.displayData = *displayData
   117  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
   118  
   119  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   120  		if err != nil {
   121  			return wrapErr(err)
   122  		}
   123  	}
   124  
   125  	return nil
   126  }
   127  
   128  func permitWireGuardService(session uintptr, baseObjects *baseObjects, weight uint8) error {
   129  	var conditions [2]wtFwpmFilterCondition0
   130  
   131  	//
   132  	// First condition is the exe path of the current process.
   133  	//
   134  	appID, err := getCurrentProcessAppID()
   135  	if err != nil {
   136  		return wrapErr(err)
   137  	}
   138  	defer fwpmFreeMemory0(unsafe.Pointer(&appID))
   139  
   140  	conditions[0] = wtFwpmFilterCondition0{
   141  		fieldKey:  cFWPM_CONDITION_ALE_APP_ID,
   142  		matchType: cFWP_MATCH_EQUAL,
   143  		conditionValue: wtFwpConditionValue0{
   144  			_type: cFWP_BYTE_BLOB_TYPE,
   145  			value: uintptr(unsafe.Pointer(appID)),
   146  		},
   147  	}
   148  
   149  	//
   150  	// Second condition is the SECURITY_DESCRIPTOR of the current process.
   151  	// This prevents other processes hosted in the same exe from matching this filter.
   152  	//
   153  	sd, err := getCurrentProcessSecurityDescriptor()
   154  	if err != nil {
   155  		return wrapErr(err)
   156  	}
   157  
   158  	conditions[1] = wtFwpmFilterCondition0{
   159  		fieldKey:  cFWPM_CONDITION_ALE_USER_ID,
   160  		matchType: cFWP_MATCH_EQUAL,
   161  		conditionValue: wtFwpConditionValue0{
   162  			_type: cFWP_SECURITY_DESCRIPTOR_TYPE,
   163  			value: uintptr(unsafe.Pointer(&wtFwpByteBlob{sd.Length(), (*byte)(unsafe.Pointer(sd))})),
   164  		},
   165  	}
   166  
   167  	//
   168  	// Assemble the filter.
   169  	//
   170  	filter := wtFwpmFilter0{
   171  		providerKey:         &baseObjects.provider,
   172  		subLayerKey:         baseObjects.filters,
   173  		weight:              filterWeight(weight),
   174  		flags:               cFWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT,
   175  		numFilterConditions: uint32(len(conditions)),
   176  		filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)),
   177  		action: wtFwpmAction0{
   178  			_type: cFWP_ACTION_PERMIT,
   179  		},
   180  	}
   181  
   182  	filterID := uint64(0)
   183  
   184  	//
   185  	// #1 Permit outbound IPv4 traffic.
   186  	//
   187  	{
   188  		displayData, err := createWtFwpmDisplayData0("Permit unrestricted outbound traffic for WireGuard service (IPv4)", "")
   189  		if err != nil {
   190  			return wrapErr(err)
   191  		}
   192  
   193  		filter.displayData = *displayData
   194  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4
   195  
   196  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   197  		if err != nil {
   198  			return wrapErr(err)
   199  		}
   200  	}
   201  
   202  	//
   203  	// #2 Permit inbound IPv4 traffic.
   204  	//
   205  	{
   206  		displayData, err := createWtFwpmDisplayData0("Permit unrestricted inbound traffic for WireGuard service (IPv4)", "")
   207  		if err != nil {
   208  			return wrapErr(err)
   209  		}
   210  
   211  		filter.displayData = *displayData
   212  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
   213  
   214  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   215  		if err != nil {
   216  			return wrapErr(err)
   217  		}
   218  	}
   219  
   220  	//
   221  	// #3 Permit outbound IPv6 traffic.
   222  	//
   223  	{
   224  		displayData, err := createWtFwpmDisplayData0("Permit unrestricted outbound traffic for WireGuard service (IPv6)", "")
   225  		if err != nil {
   226  			return wrapErr(err)
   227  		}
   228  
   229  		filter.displayData = *displayData
   230  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6
   231  
   232  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   233  		if err != nil {
   234  			return wrapErr(err)
   235  		}
   236  	}
   237  
   238  	//
   239  	// #4 Permit inbound IPv6 traffic.
   240  	//
   241  	{
   242  		displayData, err := createWtFwpmDisplayData0("Permit unrestricted inbound traffic for WireGuard service (IPv6)", "")
   243  		if err != nil {
   244  			return wrapErr(err)
   245  		}
   246  
   247  		filter.displayData = *displayData
   248  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
   249  
   250  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   251  		if err != nil {
   252  			return wrapErr(err)
   253  		}
   254  	}
   255  
   256  	return nil
   257  }
   258  
   259  func permitLoopback(session uintptr, baseObjects *baseObjects, weight uint8) error {
   260  	condition := wtFwpmFilterCondition0{
   261  		fieldKey:  cFWPM_CONDITION_FLAGS,
   262  		matchType: cFWP_MATCH_FLAGS_ALL_SET,
   263  		conditionValue: wtFwpConditionValue0{
   264  			_type: cFWP_UINT32,
   265  			value: uintptr(cFWP_CONDITION_FLAG_IS_LOOPBACK),
   266  		},
   267  	}
   268  
   269  	filter := wtFwpmFilter0{
   270  		providerKey:         &baseObjects.provider,
   271  		subLayerKey:         baseObjects.filters,
   272  		weight:              filterWeight(weight),
   273  		numFilterConditions: 1,
   274  		filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&condition)),
   275  		action: wtFwpmAction0{
   276  			_type: cFWP_ACTION_PERMIT,
   277  		},
   278  	}
   279  
   280  	filterID := uint64(0)
   281  
   282  	//
   283  	// #1 Permit outbound IPv4 on loopback.
   284  	//
   285  	{
   286  		displayData, err := createWtFwpmDisplayData0("Permit outbound on loopback (IPv4)", "")
   287  		if err != nil {
   288  			return wrapErr(err)
   289  		}
   290  
   291  		filter.displayData = *displayData
   292  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4
   293  
   294  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   295  		if err != nil {
   296  			return wrapErr(err)
   297  		}
   298  	}
   299  
   300  	//
   301  	// #2 Permit inbound IPv4 on loopback.
   302  	//
   303  	{
   304  		displayData, err := createWtFwpmDisplayData0("Permit inbound on loopback (IPv4)", "")
   305  		if err != nil {
   306  			return wrapErr(err)
   307  		}
   308  
   309  		filter.displayData = *displayData
   310  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
   311  
   312  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   313  		if err != nil {
   314  			return wrapErr(err)
   315  		}
   316  	}
   317  
   318  	//
   319  	// #3 Permit outbound IPv6 on loopback.
   320  	//
   321  	{
   322  		displayData, err := createWtFwpmDisplayData0("Permit outbound on loopback (IPv6)", "")
   323  		if err != nil {
   324  			return wrapErr(err)
   325  		}
   326  
   327  		filter.displayData = *displayData
   328  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6
   329  
   330  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   331  		if err != nil {
   332  			return wrapErr(err)
   333  		}
   334  	}
   335  
   336  	//
   337  	// #4 Permit inbound IPv6 on loopback.
   338  	//
   339  	{
   340  		displayData, err := createWtFwpmDisplayData0("Permit inbound on loopback (IPv6)", "")
   341  		if err != nil {
   342  			return wrapErr(err)
   343  		}
   344  
   345  		filter.displayData = *displayData
   346  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
   347  
   348  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   349  		if err != nil {
   350  			return wrapErr(err)
   351  		}
   352  	}
   353  
   354  	return nil
   355  }
   356  
   357  func permitDHCPIPv4(session uintptr, baseObjects *baseObjects, weight uint8) error {
   358  	//
   359  	// #1 Outbound DHCP request on IPv4.
   360  	//
   361  	{
   362  		var conditions [4]wtFwpmFilterCondition0
   363  
   364  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   365  		conditions[0].matchType = cFWP_MATCH_EQUAL
   366  		conditions[0].conditionValue._type = cFWP_UINT8
   367  		conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP)
   368  
   369  		conditions[1].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT
   370  		conditions[1].matchType = cFWP_MATCH_EQUAL
   371  		conditions[1].conditionValue._type = cFWP_UINT16
   372  		conditions[1].conditionValue.value = uintptr(68)
   373  
   374  		conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT
   375  		conditions[2].matchType = cFWP_MATCH_EQUAL
   376  		conditions[2].conditionValue._type = cFWP_UINT16
   377  		conditions[2].conditionValue.value = uintptr(67)
   378  
   379  		conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   380  		conditions[3].matchType = cFWP_MATCH_EQUAL
   381  		conditions[3].conditionValue._type = cFWP_UINT32
   382  		conditions[3].conditionValue.value = uintptr(0xffffffff)
   383  
   384  		displayData, err := createWtFwpmDisplayData0("Permit outbound DHCP request (IPv4)", "")
   385  		if err != nil {
   386  			return wrapErr(err)
   387  		}
   388  
   389  		filter := wtFwpmFilter0{
   390  			displayData:         *displayData,
   391  			providerKey:         &baseObjects.provider,
   392  			layerKey:            cFWPM_LAYER_ALE_AUTH_CONNECT_V4,
   393  			subLayerKey:         baseObjects.filters,
   394  			weight:              filterWeight(weight),
   395  			numFilterConditions: uint32(len(conditions)),
   396  			filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)),
   397  			action: wtFwpmAction0{
   398  				_type: cFWP_ACTION_PERMIT,
   399  			},
   400  		}
   401  
   402  		filterID := uint64(0)
   403  
   404  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   405  		if err != nil {
   406  			return wrapErr(err)
   407  		}
   408  	}
   409  
   410  	//
   411  	// #2 Inbound DHCP response on IPv4.
   412  	//
   413  	{
   414  		var conditions [3]wtFwpmFilterCondition0
   415  
   416  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   417  		conditions[0].matchType = cFWP_MATCH_EQUAL
   418  		conditions[0].conditionValue._type = cFWP_UINT8
   419  		conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP)
   420  
   421  		conditions[1].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT
   422  		conditions[1].matchType = cFWP_MATCH_EQUAL
   423  		conditions[1].conditionValue._type = cFWP_UINT16
   424  		conditions[1].conditionValue.value = uintptr(68)
   425  
   426  		conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT
   427  		conditions[2].matchType = cFWP_MATCH_EQUAL
   428  		conditions[2].conditionValue._type = cFWP_UINT16
   429  		conditions[2].conditionValue.value = uintptr(67)
   430  
   431  		displayData, err := createWtFwpmDisplayData0("Permit inbound DHCP response (IPv4)", "")
   432  		if err != nil {
   433  			return wrapErr(err)
   434  		}
   435  
   436  		filter := wtFwpmFilter0{
   437  			displayData:         *displayData,
   438  			providerKey:         &baseObjects.provider,
   439  			layerKey:            cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
   440  			subLayerKey:         baseObjects.filters,
   441  			weight:              filterWeight(weight),
   442  			numFilterConditions: uint32(len(conditions)),
   443  			filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)),
   444  			action: wtFwpmAction0{
   445  				_type: cFWP_ACTION_PERMIT,
   446  			},
   447  		}
   448  
   449  		filterID := uint64(0)
   450  
   451  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   452  		if err != nil {
   453  			return wrapErr(err)
   454  		}
   455  	}
   456  
   457  	return nil
   458  }
   459  
   460  func permitDHCPIPv6(session uintptr, baseObjects *baseObjects, weight uint8) error {
   461  	//
   462  	// #1 Outbound DHCP request on IPv6.
   463  	//
   464  	{
   465  		var conditions [6]wtFwpmFilterCondition0
   466  
   467  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   468  		conditions[0].matchType = cFWP_MATCH_EQUAL
   469  		conditions[0].conditionValue._type = cFWP_UINT8
   470  		conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP)
   471  
   472  		conditions[1].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   473  		conditions[1].matchType = cFWP_MATCH_EQUAL
   474  		conditions[1].conditionValue._type = cFWP_BYTE_ARRAY16_TYPE
   475  		conditions[1].conditionValue.value = uintptr(unsafe.Pointer(&linkLocalDHCPMulticast))
   476  
   477  		// Repeat the condition type for logical OR.
   478  		conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   479  		conditions[2].matchType = cFWP_MATCH_EQUAL
   480  		conditions[2].conditionValue._type = cFWP_BYTE_ARRAY16_TYPE
   481  		conditions[2].conditionValue.value = uintptr(unsafe.Pointer(&siteLocalDHCPMulticast))
   482  
   483  		conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT
   484  		conditions[3].matchType = cFWP_MATCH_EQUAL
   485  		conditions[3].conditionValue._type = cFWP_UINT16
   486  		conditions[3].conditionValue.value = uintptr(547)
   487  
   488  		conditions[4].fieldKey = cFWPM_CONDITION_IP_LOCAL_ADDRESS
   489  		conditions[4].matchType = cFWP_MATCH_EQUAL
   490  		conditions[4].conditionValue._type = cFWP_V6_ADDR_MASK
   491  		conditions[4].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal))
   492  
   493  		conditions[5].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT
   494  		conditions[5].matchType = cFWP_MATCH_EQUAL
   495  		conditions[5].conditionValue._type = cFWP_UINT16
   496  		conditions[5].conditionValue.value = uintptr(546)
   497  
   498  		displayData, err := createWtFwpmDisplayData0("Permit outbound DHCP request (IPv6)", "")
   499  		if err != nil {
   500  			return wrapErr(err)
   501  		}
   502  
   503  		filter := wtFwpmFilter0{
   504  			displayData:         *displayData,
   505  			providerKey:         &baseObjects.provider,
   506  			layerKey:            cFWPM_LAYER_ALE_AUTH_CONNECT_V6,
   507  			subLayerKey:         baseObjects.filters,
   508  			weight:              filterWeight(weight),
   509  			numFilterConditions: uint32(len(conditions)),
   510  			filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)),
   511  			action: wtFwpmAction0{
   512  				_type: cFWP_ACTION_PERMIT,
   513  			},
   514  		}
   515  
   516  		filterID := uint64(0)
   517  
   518  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   519  		if err != nil {
   520  			return wrapErr(err)
   521  		}
   522  	}
   523  
   524  	//
   525  	// #2 Inbound DHCP response on IPv6.
   526  	//
   527  	{
   528  		var conditions [5]wtFwpmFilterCondition0
   529  
   530  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   531  		conditions[0].matchType = cFWP_MATCH_EQUAL
   532  		conditions[0].conditionValue._type = cFWP_UINT8
   533  		conditions[0].conditionValue.value = uintptr(cIPPROTO_UDP)
   534  
   535  		conditions[1].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   536  		conditions[1].matchType = cFWP_MATCH_EQUAL
   537  		conditions[1].conditionValue._type = cFWP_V6_ADDR_MASK
   538  		conditions[1].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal))
   539  
   540  		conditions[2].fieldKey = cFWPM_CONDITION_IP_REMOTE_PORT
   541  		conditions[2].matchType = cFWP_MATCH_EQUAL
   542  		conditions[2].conditionValue._type = cFWP_UINT16
   543  		conditions[2].conditionValue.value = uintptr(547)
   544  
   545  		conditions[3].fieldKey = cFWPM_CONDITION_IP_LOCAL_ADDRESS
   546  		conditions[3].matchType = cFWP_MATCH_EQUAL
   547  		conditions[3].conditionValue._type = cFWP_V6_ADDR_MASK
   548  		conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal))
   549  
   550  		conditions[4].fieldKey = cFWPM_CONDITION_IP_LOCAL_PORT
   551  		conditions[4].matchType = cFWP_MATCH_EQUAL
   552  		conditions[4].conditionValue._type = cFWP_UINT16
   553  		conditions[4].conditionValue.value = uintptr(546)
   554  
   555  		displayData, err := createWtFwpmDisplayData0("Permit inbound DHCP response (IPv6)", "")
   556  		if err != nil {
   557  			return wrapErr(err)
   558  		}
   559  
   560  		filter := wtFwpmFilter0{
   561  			displayData:         *displayData,
   562  			providerKey:         &baseObjects.provider,
   563  			layerKey:            cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
   564  			subLayerKey:         baseObjects.filters,
   565  			weight:              filterWeight(weight),
   566  			numFilterConditions: uint32(len(conditions)),
   567  			filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&conditions)),
   568  			action: wtFwpmAction0{
   569  				_type: cFWP_ACTION_PERMIT,
   570  			},
   571  		}
   572  
   573  		filterID := uint64(0)
   574  
   575  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   576  		if err != nil {
   577  			return wrapErr(err)
   578  		}
   579  	}
   580  
   581  	return nil
   582  }
   583  
   584  func permitNdp(session uintptr, baseObjects *baseObjects, weight uint8) error {
   585  	/* TODO: actually handle the hop limit somehow! The rules should vaguely be:
   586  	 *  - icmpv6 133: must be outgoing, dst must be FF02::2/128, hop limit must be 255
   587  	 *  - icmpv6 134: must be incoming, src must be FE80::/10, hop limit must be 255
   588  	 *  - icmpv6 135: either incoming or outgoing, hop limit must be 255
   589  	 *  - icmpv6 136: either incoming or outgoing, hop limit must be 255
   590  	 *  - icmpv6 137: must be incoming, src must be FE80::/10, hop limit must be 255
   591  	 */
   592  
   593  	type filterDefinition struct {
   594  		displayData *wtFwpmDisplayData0
   595  		conditions  []wtFwpmFilterCondition0
   596  		layer       windows.GUID
   597  	}
   598  
   599  	var defs []filterDefinition
   600  
   601  	//
   602  	// Router Solicitation Message
   603  	// ICMP type 133, code 0. Outgoing.
   604  	//
   605  	{
   606  		conditions := make([]wtFwpmFilterCondition0, 4)
   607  
   608  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   609  		conditions[0].matchType = cFWP_MATCH_EQUAL
   610  		conditions[0].conditionValue._type = cFWP_UINT8
   611  		conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6)
   612  
   613  		conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE
   614  		conditions[1].matchType = cFWP_MATCH_EQUAL
   615  		conditions[1].conditionValue._type = cFWP_UINT16
   616  		conditions[1].conditionValue.value = uintptr(133)
   617  
   618  		conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE
   619  		conditions[2].matchType = cFWP_MATCH_EQUAL
   620  		conditions[2].conditionValue._type = cFWP_UINT16
   621  		conditions[2].conditionValue.value = uintptr(0)
   622  
   623  		conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   624  		conditions[3].matchType = cFWP_MATCH_EQUAL
   625  		conditions[3].conditionValue._type = cFWP_BYTE_ARRAY16_TYPE
   626  		conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocalRouterMulticast))
   627  
   628  		displayData, err := createWtFwpmDisplayData0("Permit NDP type 133", "")
   629  		if err != nil {
   630  			return wrapErr(err)
   631  		}
   632  
   633  		defs = append(defs, filterDefinition{
   634  			displayData: displayData,
   635  			conditions:  conditions,
   636  			layer:       cFWPM_LAYER_ALE_AUTH_CONNECT_V6,
   637  		})
   638  	}
   639  
   640  	//
   641  	// Router Advertisement Message
   642  	// ICMP type 134, code 0. Incoming.
   643  	//
   644  	{
   645  		conditions := make([]wtFwpmFilterCondition0, 4)
   646  
   647  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   648  		conditions[0].matchType = cFWP_MATCH_EQUAL
   649  		conditions[0].conditionValue._type = cFWP_UINT8
   650  		conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6)
   651  
   652  		conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE
   653  		conditions[1].matchType = cFWP_MATCH_EQUAL
   654  		conditions[1].conditionValue._type = cFWP_UINT16
   655  		conditions[1].conditionValue.value = uintptr(134)
   656  
   657  		conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE
   658  		conditions[2].matchType = cFWP_MATCH_EQUAL
   659  		conditions[2].conditionValue._type = cFWP_UINT16
   660  		conditions[2].conditionValue.value = uintptr(0)
   661  
   662  		conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   663  		conditions[3].matchType = cFWP_MATCH_EQUAL
   664  		conditions[3].conditionValue._type = cFWP_V6_ADDR_MASK
   665  		conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal))
   666  
   667  		displayData, err := createWtFwpmDisplayData0("Permit NDP type 134", "")
   668  		if err != nil {
   669  			return wrapErr(err)
   670  		}
   671  
   672  		defs = append(defs, filterDefinition{
   673  			displayData: displayData,
   674  			conditions:  conditions,
   675  			layer:       cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
   676  		})
   677  	}
   678  
   679  	//
   680  	// Neighbor Solicitation Message
   681  	// ICMP type 135, code 0. Bi-directional.
   682  	//
   683  	{
   684  		conditions := make([]wtFwpmFilterCondition0, 3)
   685  
   686  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   687  		conditions[0].matchType = cFWP_MATCH_EQUAL
   688  		conditions[0].conditionValue._type = cFWP_UINT8
   689  		conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6)
   690  
   691  		conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE
   692  		conditions[1].matchType = cFWP_MATCH_EQUAL
   693  		conditions[1].conditionValue._type = cFWP_UINT16
   694  		conditions[1].conditionValue.value = uintptr(135)
   695  
   696  		conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE
   697  		conditions[2].matchType = cFWP_MATCH_EQUAL
   698  		conditions[2].conditionValue._type = cFWP_UINT16
   699  		conditions[2].conditionValue.value = uintptr(0)
   700  
   701  		displayData, err := createWtFwpmDisplayData0("Permit NDP type 135", "")
   702  		if err != nil {
   703  			return wrapErr(err)
   704  		}
   705  
   706  		defs = append(defs, filterDefinition{
   707  			displayData: displayData,
   708  			conditions:  conditions,
   709  			layer:       cFWPM_LAYER_ALE_AUTH_CONNECT_V6,
   710  		})
   711  
   712  		defs = append(defs, filterDefinition{
   713  			displayData: displayData,
   714  			conditions:  conditions,
   715  			layer:       cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
   716  		})
   717  	}
   718  
   719  	//
   720  	// Neighbor Advertisement Message
   721  	// ICMP type 136, code 0. Bi-directional.
   722  	//
   723  	{
   724  		conditions := make([]wtFwpmFilterCondition0, 3)
   725  
   726  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   727  		conditions[0].matchType = cFWP_MATCH_EQUAL
   728  		conditions[0].conditionValue._type = cFWP_UINT8
   729  		conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6)
   730  
   731  		conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE
   732  		conditions[1].matchType = cFWP_MATCH_EQUAL
   733  		conditions[1].conditionValue._type = cFWP_UINT16
   734  		conditions[1].conditionValue.value = uintptr(136)
   735  
   736  		conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE
   737  		conditions[2].matchType = cFWP_MATCH_EQUAL
   738  		conditions[2].conditionValue._type = cFWP_UINT16
   739  		conditions[2].conditionValue.value = uintptr(0)
   740  
   741  		displayData, err := createWtFwpmDisplayData0("Permit NDP type 136", "")
   742  		if err != nil {
   743  			return wrapErr(err)
   744  		}
   745  
   746  		defs = append(defs, filterDefinition{
   747  			displayData: displayData,
   748  			conditions:  conditions,
   749  			layer:       cFWPM_LAYER_ALE_AUTH_CONNECT_V6,
   750  		})
   751  
   752  		defs = append(defs, filterDefinition{
   753  			displayData: displayData,
   754  			conditions:  conditions,
   755  			layer:       cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
   756  		})
   757  	}
   758  
   759  	//
   760  	// Redirect Message
   761  	// ICMP type 137, code 0. Incoming.
   762  	//
   763  	{
   764  		conditions := make([]wtFwpmFilterCondition0, 4)
   765  
   766  		conditions[0].fieldKey = cFWPM_CONDITION_IP_PROTOCOL
   767  		conditions[0].matchType = cFWP_MATCH_EQUAL
   768  		conditions[0].conditionValue._type = cFWP_UINT8
   769  		conditions[0].conditionValue.value = uintptr(cIPPROTO_ICMPV6)
   770  
   771  		conditions[1].fieldKey = cFWPM_CONDITION_ICMP_TYPE
   772  		conditions[1].matchType = cFWP_MATCH_EQUAL
   773  		conditions[1].conditionValue._type = cFWP_UINT16
   774  		conditions[1].conditionValue.value = uintptr(137)
   775  
   776  		conditions[2].fieldKey = cFWPM_CONDITION_ICMP_CODE
   777  		conditions[2].matchType = cFWP_MATCH_EQUAL
   778  		conditions[2].conditionValue._type = cFWP_UINT16
   779  		conditions[2].conditionValue.value = uintptr(0)
   780  
   781  		conditions[3].fieldKey = cFWPM_CONDITION_IP_REMOTE_ADDRESS
   782  		conditions[3].matchType = cFWP_MATCH_EQUAL
   783  		conditions[3].conditionValue._type = cFWP_V6_ADDR_MASK
   784  		conditions[3].conditionValue.value = uintptr(unsafe.Pointer(&linkLocal))
   785  
   786  		displayData, err := createWtFwpmDisplayData0("Permit NDP type 137", "")
   787  		if err != nil {
   788  			return wrapErr(err)
   789  		}
   790  
   791  		defs = append(defs, filterDefinition{
   792  			displayData: displayData,
   793  			conditions:  conditions,
   794  			layer:       cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
   795  		})
   796  	}
   797  
   798  	filter := wtFwpmFilter0{
   799  		providerKey: &baseObjects.provider,
   800  		subLayerKey: baseObjects.filters,
   801  		weight:      filterWeight(weight),
   802  		action: wtFwpmAction0{
   803  			_type: cFWP_ACTION_PERMIT,
   804  		},
   805  	}
   806  
   807  	filterID := uint64(0)
   808  
   809  	for _, definition := range defs {
   810  		filter.displayData = *definition.displayData
   811  		filter.layerKey = definition.layer
   812  		filter.numFilterConditions = uint32(len(definition.conditions))
   813  		filter.filterCondition = (*wtFwpmFilterCondition0)(unsafe.Pointer(&definition.conditions[0]))
   814  
   815  		err := fwpmFilterAdd0(session, &filter, 0, &filterID)
   816  		if err != nil {
   817  			return wrapErr(err)
   818  		}
   819  	}
   820  
   821  	return nil
   822  }
   823  
   824  func permitHyperV(session uintptr, baseObjects *baseObjects, weight uint8) error {
   825  	//
   826  	// Only applicable on Win8+.
   827  	//
   828  	{
   829  		major, minor, _ := windows.RtlGetNtVersionNumbers()
   830  		win8plus := major > 6 || (major == 6 && minor >= 3)
   831  
   832  		if !win8plus {
   833  			return nil
   834  		}
   835  	}
   836  
   837  	condition := wtFwpmFilterCondition0{
   838  		fieldKey:  cFWPM_CONDITION_L2_FLAGS,
   839  		matchType: cFWP_MATCH_EQUAL,
   840  		conditionValue: wtFwpConditionValue0{
   841  			_type: cFWP_UINT32,
   842  			value: uintptr(cFWP_CONDITION_L2_IS_VM2VM),
   843  		},
   844  	}
   845  
   846  	filter := wtFwpmFilter0{
   847  		providerKey:         &baseObjects.provider,
   848  		subLayerKey:         baseObjects.filters,
   849  		weight:              filterWeight(weight),
   850  		numFilterConditions: 1,
   851  		filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&condition)),
   852  		action: wtFwpmAction0{
   853  			_type: cFWP_ACTION_PERMIT,
   854  		},
   855  	}
   856  
   857  	filterID := uint64(0)
   858  
   859  	//
   860  	// #1 Outbound.
   861  	//
   862  	{
   863  		displayData, err := createWtFwpmDisplayData0("Permit Hyper-V => Hyper-V outbound", "")
   864  		if err != nil {
   865  			return wrapErr(err)
   866  		}
   867  
   868  		filter.displayData = *displayData
   869  		filter.layerKey = cFWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE
   870  
   871  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   872  		if err != nil {
   873  			return wrapErr(err)
   874  		}
   875  	}
   876  
   877  	//
   878  	// #2 Inbound.
   879  	//
   880  	{
   881  		displayData, err := createWtFwpmDisplayData0("Permit Hyper-V => Hyper-V inbound", "")
   882  		if err != nil {
   883  			return wrapErr(err)
   884  		}
   885  
   886  		filter.displayData = *displayData
   887  		filter.layerKey = cFWPM_LAYER_INBOUND_MAC_FRAME_NATIVE
   888  
   889  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   890  		if err != nil {
   891  			return wrapErr(err)
   892  		}
   893  	}
   894  
   895  	return nil
   896  }
   897  
   898  // Block all traffic except what is explicitly permitted by other rules.
   899  func blockAll(session uintptr, baseObjects *baseObjects, weight uint8) error {
   900  	filter := wtFwpmFilter0{
   901  		providerKey: &baseObjects.provider,
   902  		subLayerKey: baseObjects.filters,
   903  		weight:      filterWeight(weight),
   904  		action: wtFwpmAction0{
   905  			_type: cFWP_ACTION_BLOCK,
   906  		},
   907  	}
   908  
   909  	filterID := uint64(0)
   910  
   911  	//
   912  	// #1 Block outbound traffic on IPv4.
   913  	//
   914  	{
   915  		displayData, err := createWtFwpmDisplayData0("Block all outbound (IPv4)", "")
   916  		if err != nil {
   917  			return wrapErr(err)
   918  		}
   919  
   920  		filter.displayData = *displayData
   921  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4
   922  
   923  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   924  		if err != nil {
   925  			return wrapErr(err)
   926  		}
   927  	}
   928  
   929  	//
   930  	// #2 Block inbound traffic on IPv4.
   931  	//
   932  	{
   933  		displayData, err := createWtFwpmDisplayData0("Block all inbound (IPv4)", "")
   934  		if err != nil {
   935  			return wrapErr(err)
   936  		}
   937  
   938  		filter.displayData = *displayData
   939  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
   940  
   941  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   942  		if err != nil {
   943  			return wrapErr(err)
   944  		}
   945  	}
   946  
   947  	//
   948  	// #3 Block outbound traffic on IPv6.
   949  	//
   950  	{
   951  		displayData, err := createWtFwpmDisplayData0("Block all outbound (IPv6)", "")
   952  		if err != nil {
   953  			return wrapErr(err)
   954  		}
   955  
   956  		filter.displayData = *displayData
   957  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6
   958  
   959  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   960  		if err != nil {
   961  			return wrapErr(err)
   962  		}
   963  	}
   964  
   965  	//
   966  	// #4 Block inbound traffic on IPv6.
   967  	//
   968  	{
   969  		displayData, err := createWtFwpmDisplayData0("Block all inbound (IPv6)", "")
   970  		if err != nil {
   971  			return wrapErr(err)
   972  		}
   973  
   974  		filter.displayData = *displayData
   975  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
   976  
   977  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
   978  		if err != nil {
   979  			return wrapErr(err)
   980  		}
   981  	}
   982  
   983  	return nil
   984  }
   985  
   986  // Block all DNS traffic except towards specified DNS servers.
   987  func blockDNS(except []netip.Addr, session uintptr, baseObjects *baseObjects, weightAllow, weightDeny uint8) error {
   988  	if weightDeny >= weightAllow {
   989  		return errors.New("The allow weight must be greater than the deny weight")
   990  	}
   991  
   992  	denyConditions := []wtFwpmFilterCondition0{
   993  		{
   994  			fieldKey:  cFWPM_CONDITION_IP_REMOTE_PORT,
   995  			matchType: cFWP_MATCH_EQUAL,
   996  			conditionValue: wtFwpConditionValue0{
   997  				_type: cFWP_UINT16,
   998  				value: uintptr(53),
   999  			},
  1000  		},
  1001  		{
  1002  			fieldKey:  cFWPM_CONDITION_IP_PROTOCOL,
  1003  			matchType: cFWP_MATCH_EQUAL,
  1004  			conditionValue: wtFwpConditionValue0{
  1005  				_type: cFWP_UINT8,
  1006  				value: uintptr(cIPPROTO_UDP),
  1007  			},
  1008  		},
  1009  		// Repeat the condition type for logical OR.
  1010  		{
  1011  			fieldKey:  cFWPM_CONDITION_IP_PROTOCOL,
  1012  			matchType: cFWP_MATCH_EQUAL,
  1013  			conditionValue: wtFwpConditionValue0{
  1014  				_type: cFWP_UINT8,
  1015  				value: uintptr(cIPPROTO_TCP),
  1016  			},
  1017  		},
  1018  	}
  1019  
  1020  	filter := wtFwpmFilter0{
  1021  		providerKey:         &baseObjects.provider,
  1022  		subLayerKey:         baseObjects.filters,
  1023  		weight:              filterWeight(weightDeny),
  1024  		numFilterConditions: uint32(len(denyConditions)),
  1025  		filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&denyConditions[0])),
  1026  		action: wtFwpmAction0{
  1027  			_type: cFWP_ACTION_BLOCK,
  1028  		},
  1029  	}
  1030  
  1031  	filterID := uint64(0)
  1032  
  1033  	//
  1034  	// #1 Block IPv4 outbound DNS.
  1035  	//
  1036  	{
  1037  		displayData, err := createWtFwpmDisplayData0("Block DNS outbound (IPv4)", "")
  1038  		if err != nil {
  1039  			return wrapErr(err)
  1040  		}
  1041  
  1042  		filter.displayData = *displayData
  1043  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4
  1044  
  1045  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1046  		if err != nil {
  1047  			return wrapErr(err)
  1048  		}
  1049  	}
  1050  
  1051  	//
  1052  	// #2 Block IPv4 inbound DNS.
  1053  	//
  1054  	{
  1055  		displayData, err := createWtFwpmDisplayData0("Block DNS inbound (IPv4)", "")
  1056  		if err != nil {
  1057  			return wrapErr(err)
  1058  		}
  1059  
  1060  		filter.displayData = *displayData
  1061  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
  1062  
  1063  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1064  		if err != nil {
  1065  			return wrapErr(err)
  1066  		}
  1067  	}
  1068  
  1069  	//
  1070  	// #3 Block IPv6 outbound DNS.
  1071  	//
  1072  	{
  1073  		displayData, err := createWtFwpmDisplayData0("Block DNS outbound (IPv6)", "")
  1074  		if err != nil {
  1075  			return wrapErr(err)
  1076  		}
  1077  
  1078  		filter.displayData = *displayData
  1079  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6
  1080  
  1081  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1082  		if err != nil {
  1083  			return wrapErr(err)
  1084  		}
  1085  	}
  1086  
  1087  	//
  1088  	// #4 Block IPv6 inbound DNS.
  1089  	//
  1090  	{
  1091  		displayData, err := createWtFwpmDisplayData0("Block DNS inbound (IPv6)", "")
  1092  		if err != nil {
  1093  			return wrapErr(err)
  1094  		}
  1095  
  1096  		filter.displayData = *displayData
  1097  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
  1098  
  1099  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1100  		if err != nil {
  1101  			return wrapErr(err)
  1102  		}
  1103  	}
  1104  
  1105  	allowConditionsV4 := make([]wtFwpmFilterCondition0, 0, len(denyConditions)+len(except))
  1106  	allowConditionsV4 = append(allowConditionsV4, denyConditions...)
  1107  	for _, ip := range except {
  1108  		if !ip.Is4() {
  1109  			continue
  1110  		}
  1111  		allowConditionsV4 = append(allowConditionsV4, wtFwpmFilterCondition0{
  1112  			fieldKey:  cFWPM_CONDITION_IP_REMOTE_ADDRESS,
  1113  			matchType: cFWP_MATCH_EQUAL,
  1114  			conditionValue: wtFwpConditionValue0{
  1115  				_type: cFWP_UINT32,
  1116  				value: uintptr(binary.BigEndian.Uint32(ip.AsSlice())),
  1117  			},
  1118  		})
  1119  	}
  1120  
  1121  	storedPointers := make([]*wtFwpByteArray16, 0, len(except))
  1122  	allowConditionsV6 := make([]wtFwpmFilterCondition0, 0, len(denyConditions)+len(except))
  1123  	allowConditionsV6 = append(allowConditionsV6, denyConditions...)
  1124  	for _, ip := range except {
  1125  		if !ip.Is6() {
  1126  			continue
  1127  		}
  1128  		address := wtFwpByteArray16{byteArray16: ip.As16()}
  1129  		allowConditionsV6 = append(allowConditionsV6, wtFwpmFilterCondition0{
  1130  			fieldKey:  cFWPM_CONDITION_IP_REMOTE_ADDRESS,
  1131  			matchType: cFWP_MATCH_EQUAL,
  1132  			conditionValue: wtFwpConditionValue0{
  1133  				_type: cFWP_BYTE_ARRAY16_TYPE,
  1134  				value: uintptr(unsafe.Pointer(&address)),
  1135  			},
  1136  		})
  1137  		storedPointers = append(storedPointers, &address)
  1138  	}
  1139  
  1140  	filter = wtFwpmFilter0{
  1141  		providerKey:         &baseObjects.provider,
  1142  		subLayerKey:         baseObjects.filters,
  1143  		weight:              filterWeight(weightAllow),
  1144  		numFilterConditions: uint32(len(allowConditionsV4)),
  1145  		filterCondition:     (*wtFwpmFilterCondition0)(unsafe.Pointer(&allowConditionsV4[0])),
  1146  		action: wtFwpmAction0{
  1147  			_type: cFWP_ACTION_PERMIT,
  1148  		},
  1149  	}
  1150  
  1151  	filterID = uint64(0)
  1152  
  1153  	//
  1154  	// #5 Allow IPv4 outbound DNS.
  1155  	//
  1156  	if len(allowConditionsV4) > len(denyConditions) {
  1157  		displayData, err := createWtFwpmDisplayData0("Allow DNS outbound (IPv4)", "")
  1158  		if err != nil {
  1159  			return wrapErr(err)
  1160  		}
  1161  
  1162  		filter.displayData = *displayData
  1163  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V4
  1164  
  1165  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1166  		if err != nil {
  1167  			return wrapErr(err)
  1168  		}
  1169  	}
  1170  
  1171  	//
  1172  	// #6 Allow IPv4 inbound DNS.
  1173  	//
  1174  	if len(allowConditionsV4) > len(denyConditions) {
  1175  		displayData, err := createWtFwpmDisplayData0("Allow DNS inbound (IPv4)", "")
  1176  		if err != nil {
  1177  			return wrapErr(err)
  1178  		}
  1179  
  1180  		filter.displayData = *displayData
  1181  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
  1182  
  1183  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1184  		if err != nil {
  1185  			return wrapErr(err)
  1186  		}
  1187  	}
  1188  
  1189  	filter.filterCondition = (*wtFwpmFilterCondition0)(unsafe.Pointer(&allowConditionsV6[0]))
  1190  	filter.numFilterConditions = uint32(len(allowConditionsV6))
  1191  
  1192  	//
  1193  	// #7 Allow IPv6 outbound DNS.
  1194  	//
  1195  	if len(allowConditionsV6) > len(denyConditions) {
  1196  		displayData, err := createWtFwpmDisplayData0("Allow DNS outbound (IPv6)", "")
  1197  		if err != nil {
  1198  			return wrapErr(err)
  1199  		}
  1200  
  1201  		filter.displayData = *displayData
  1202  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_CONNECT_V6
  1203  
  1204  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1205  		if err != nil {
  1206  			return wrapErr(err)
  1207  		}
  1208  	}
  1209  
  1210  	//
  1211  	// #8 Allow IPv6 inbound DNS.
  1212  	//
  1213  	if len(allowConditionsV6) > len(denyConditions) {
  1214  		displayData, err := createWtFwpmDisplayData0("Allow DNS inbound (IPv6)", "")
  1215  		if err != nil {
  1216  			return wrapErr(err)
  1217  		}
  1218  
  1219  		filter.displayData = *displayData
  1220  		filter.layerKey = cFWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
  1221  
  1222  		err = fwpmFilterAdd0(session, &filter, 0, &filterID)
  1223  		if err != nil {
  1224  			return wrapErr(err)
  1225  		}
  1226  	}
  1227  
  1228  	runtime.KeepAlive(storedPointers)
  1229  
  1230  	return nil
  1231  }