golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/tunnel/firewall/blocker.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 "errors" 10 "net/netip" 11 "unsafe" 12 13 "golang.org/x/sys/windows" 14 ) 15 16 type wfpObjectInstaller func(uintptr) error 17 18 // 19 // Fundamental WireGuard specific WFP objects. 20 // 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 func EnableFirewall(luid uint64, doNotRestrict bool, restrictToDNSServers []netip.Addr) error { 105 if wfpSession != 0 { 106 return errors.New("The firewall has already been enabled") 107 } 108 109 session, err := createWfpSession() 110 if err != nil { 111 return wrapErr(err) 112 } 113 114 objectInstaller := func(session uintptr) error { 115 baseObjects, err := registerBaseObjects(session) 116 if err != nil { 117 return wrapErr(err) 118 } 119 120 err = permitWireGuardService(session, baseObjects, 15) 121 if err != nil { 122 return wrapErr(err) 123 } 124 125 if !doNotRestrict { 126 if len(restrictToDNSServers) > 0 { 127 err = blockDNS(restrictToDNSServers, session, baseObjects, 15, 14) 128 if err != nil { 129 return wrapErr(err) 130 } 131 } 132 133 err = permitLoopback(session, baseObjects, 13) 134 if err != nil { 135 return wrapErr(err) 136 } 137 138 err = permitTunInterface(session, baseObjects, 12, luid) 139 if err != nil { 140 return wrapErr(err) 141 } 142 143 err = permitDHCPIPv4(session, baseObjects, 12) 144 if err != nil { 145 return wrapErr(err) 146 } 147 148 err = permitDHCPIPv6(session, baseObjects, 12) 149 if err != nil { 150 return wrapErr(err) 151 } 152 153 err = permitNdp(session, baseObjects, 12) 154 if err != nil { 155 return wrapErr(err) 156 } 157 158 /* TODO: actually evaluate if this does anything and if we need this. It's layer 2; our other rules are layer 3. 159 * In other words, if somebody complains, try enabling it. For now, keep it off. 160 err = permitHyperV(session, baseObjects, 12) 161 if err != nil { 162 return wrapErr(err) 163 } 164 */ 165 166 err = blockAll(session, baseObjects, 0) 167 if err != nil { 168 return wrapErr(err) 169 } 170 } 171 172 return nil 173 } 174 175 err = runTransaction(session, objectInstaller) 176 if err != nil { 177 fwpmEngineClose0(session) 178 return wrapErr(err) 179 } 180 181 wfpSession = session 182 return nil 183 } 184 185 func DisableFirewall() { 186 if wfpSession != 0 { 187 fwpmEngineClose0(wfpSession) 188 wfpSession = 0 189 } 190 }