github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/supervisor/daemon/wireguard/wginterface/firewall/blocker.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  	"errors"
    12  	"net"
    13  	"unsafe"
    14  
    15  	"golang.org/x/sys/windows"
    16  )
    17  
    18  type wfpObjectInstaller func(uintptr) error
    19  
    20  // Fundamental WireGuard specific WFP objects.
    21  type baseObjects struct {
    22  	provider windows.GUID
    23  	filters  windows.GUID
    24  }
    25  
    26  var wfpSession uintptr
    27  
    28  func createWfpSession() (uintptr, error) {
    29  	sessionDisplayData, err := createWtFwpmDisplayData0("WireGuard", "WireGuard dynamic session")
    30  	if err != nil {
    31  		return 0, wrapErr(err)
    32  	}
    33  
    34  	session := wtFwpmSession0{
    35  		displayData:          *sessionDisplayData,
    36  		flags:                cFWPM_SESSION_FLAG_DYNAMIC,
    37  		txnWaitTimeoutInMSec: windows.INFINITE,
    38  	}
    39  
    40  	sessionHandle := uintptr(0)
    41  
    42  	err = fwpmEngineOpen0(nil, cRPC_C_AUTHN_WINNT, nil, &session, unsafe.Pointer(&sessionHandle))
    43  	if err != nil {
    44  		return 0, wrapErr(err)
    45  	}
    46  
    47  	return sessionHandle, nil
    48  }
    49  
    50  func registerBaseObjects(session uintptr) (*baseObjects, error) {
    51  	bo := &baseObjects{}
    52  	var err error
    53  	bo.provider, err = windows.GenerateGUID()
    54  	if err != nil {
    55  		return nil, wrapErr(err)
    56  	}
    57  	bo.filters, err = windows.GenerateGUID()
    58  	if err != nil {
    59  		return nil, wrapErr(err)
    60  	}
    61  
    62  	//
    63  	// Register provider.
    64  	//
    65  	{
    66  		displayData, err := createWtFwpmDisplayData0("WireGuard", "WireGuard provider")
    67  		if err != nil {
    68  			return nil, wrapErr(err)
    69  		}
    70  		provider := wtFwpmProvider0{
    71  			providerKey: bo.provider,
    72  			displayData: *displayData,
    73  		}
    74  		err = fwpmProviderAdd0(session, &provider, 0)
    75  		if err != nil {
    76  			// TODO: cleanup entire call chain of these if failure?
    77  			return nil, wrapErr(err)
    78  		}
    79  	}
    80  
    81  	//
    82  	// Register filters sublayer.
    83  	//
    84  	{
    85  		displayData, err := createWtFwpmDisplayData0("WireGuard filters", "Permissive and blocking filters")
    86  		if err != nil {
    87  			return nil, wrapErr(err)
    88  		}
    89  		sublayer := wtFwpmSublayer0{
    90  			subLayerKey: bo.filters,
    91  			displayData: *displayData,
    92  			providerKey: &bo.provider,
    93  			weight:      ^uint16(0),
    94  		}
    95  		err = fwpmSubLayerAdd0(session, &sublayer, 0)
    96  		if err != nil {
    97  			return nil, wrapErr(err)
    98  		}
    99  	}
   100  
   101  	return bo, nil
   102  }
   103  
   104  // EnableFirewall enable firewall
   105  func EnableFirewall(luid uint64, doNotRestrict bool, restrictToDNSServers []net.IP) error {
   106  	if wfpSession != 0 {
   107  		return errors.New("The firewall has already been enabled")
   108  	}
   109  
   110  	session, err := createWfpSession()
   111  	if err != nil {
   112  		return wrapErr(err)
   113  	}
   114  
   115  	objectInstaller := func(session uintptr) error {
   116  		baseObjects, err := registerBaseObjects(session)
   117  		if err != nil {
   118  			return wrapErr(err)
   119  		}
   120  
   121  		err = permitSupervisorWireGuardService(session, baseObjects, 15)
   122  		if err != nil {
   123  			return wrapErr(err)
   124  		}
   125  
   126  		err = permitMystWireGuardService(session, baseObjects, 15)
   127  		if err != nil {
   128  			return wrapErr(err)
   129  		}
   130  
   131  		if !doNotRestrict {
   132  			if len(restrictToDNSServers) > 0 {
   133  				err = blockDNS(restrictToDNSServers, session, baseObjects, 15, 14)
   134  				if err != nil {
   135  					return wrapErr(err)
   136  				}
   137  			}
   138  
   139  			err = permitLoopback(session, baseObjects, 13)
   140  			if err != nil {
   141  				return wrapErr(err)
   142  			}
   143  
   144  			err = permitTunInterface(session, baseObjects, 12, luid)
   145  			if err != nil {
   146  				return wrapErr(err)
   147  			}
   148  
   149  			err = permitDHCPIPv4(session, baseObjects, 12)
   150  			if err != nil {
   151  				return wrapErr(err)
   152  			}
   153  
   154  			err = permitDHCPIPv6(session, baseObjects, 12)
   155  			if err != nil {
   156  				return wrapErr(err)
   157  			}
   158  
   159  			err = permitNdp(session, baseObjects, 12)
   160  			if err != nil {
   161  				return wrapErr(err)
   162  			}
   163  
   164  			/* TODO: actually evaluate if this does anything and if we need this. It's layer 2; our other rules are layer 3.
   165  			 *  In other words, if somebody complains, try enabling it. For now, keep it off.
   166  			err = permitHyperV(session, baseObjects, 12)
   167  			if err != nil {
   168  				return wrapErr(err)
   169  			}
   170  			*/
   171  
   172  			err = blockAll(session, baseObjects, 0)
   173  			if err != nil {
   174  				return wrapErr(err)
   175  			}
   176  		}
   177  
   178  		return nil
   179  	}
   180  
   181  	err = runTransaction(session, objectInstaller)
   182  	if err != nil {
   183  		fwpmEngineClose0(session)
   184  		return wrapErr(err)
   185  	}
   186  
   187  	wfpSession = session
   188  	return nil
   189  }
   190  
   191  // DisableFirewall disable firewall
   192  func DisableFirewall() {
   193  	if wfpSession != 0 {
   194  		fwpmEngineClose0(wfpSession)
   195  		wfpSession = 0
   196  	}
   197  }