github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/supervisor/daemon/wireguard/wginterface/firewall/rules.go (about)

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