aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/service/firewall/blocker.go
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2019-05-03 16:50:42 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-03 16:52:41 +0200
commitf4b0bd49027c833219cc7f357a96d317dccfab2f (patch)
tree9eb2a8125f81fa878f592965e9a7d215ea1778f3 /service/firewall/blocker.go
parentui: add toolbar after adding it to the tabs (diff)
downloadwireguard-windows-f4b0bd49027c833219cc7f357a96d317dccfab2f.tar.xz
wireguard-windows-f4b0bd49027c833219cc7f357a96d317dccfab2f.zip
firewall: introduce incomplete untested prototype
This doesn't support NDP yet, and some major things are still left to be decided, but this is the beginning of something that can be debugged into shape. Signed-off-by: Odd Stranne <odd@mullvad.net> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> Signed-off-by: Aleksandar Pesic <peske.nis@gmail.com>
Diffstat (limited to 'service/firewall/blocker.go')
-rw-r--r--service/firewall/blocker.go232
1 files changed, 232 insertions, 0 deletions
diff --git a/service/firewall/blocker.go b/service/firewall/blocker.go
new file mode 100644
index 00000000..66162448
--- /dev/null
+++ b/service/firewall/blocker.go
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+package firewall
+
+import (
+ "errors"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type wfpObjectInstaller func(uintptr) error
+
+//
+// Fundamental WireGuard specific WFP objects.
+//
+type baseObjects struct {
+ provider windows.GUID
+ whitelist windows.GUID
+ blacklist windows.GUID
+}
+
+var wfpSession uintptr
+
+func createWfpSession() (uintptr, error) {
+ sessionDisplayData, err := createWtFwpmDisplayData0("WireGuard", "WireGuard dynamic session")
+ if err != nil {
+ return 0, err
+ }
+
+ session := wtFwpmSession0{
+ displayData: *sessionDisplayData,
+ flags: cFWPM_SESSION_FLAG_DYNAMIC,
+ txnWaitTimeoutInMSec: windows.INFINITE,
+ }
+
+ sessionHandle := uintptr(0)
+
+ err = fwpmEngineOpen0(nil, cRPC_C_AUTHN_WINNT, nil, &session, unsafe.Pointer(&sessionHandle))
+ if err != nil {
+ return 0, err
+ }
+
+ return sessionHandle, nil
+}
+
+func registerBaseObjects(session uintptr) (*baseObjects, error) {
+ // {48E29F38-7492-4436-8F92-29D78A8D29D3}
+ providerGuid := windows.GUID{
+ Data1: 0x48e29f38,
+ Data2: 0x7492,
+ Data3: 0x4436,
+ Data4: [8]byte{0x8f, 0x92, 0x29, 0xd7, 0x8a, 0x8d, 0x29, 0xd3},
+ }
+ // {FE3DB7F8-4658-4DE5-8DA9-CE5086A8266B}
+ whitelistGuid := windows.GUID{
+ Data1: 0xfe3db7f8,
+ Data2: 0x4658,
+ Data3: 0x4de5,
+ Data4: [8]byte{0x8d, 0xa9, 0xce, 0x50, 0x86, 0xa8, 0x26, 0x6b},
+ }
+ // {CE1DD58F-A7BF-46BD-B048-9C5518346CE9}
+ blacklistGuid := windows.GUID{
+ Data1: 0xce1dd58f,
+ Data2: 0xa7bf,
+ Data3: 0x46bd,
+ Data4: [8]byte{0xb0, 0x48, 0x9c, 0x55, 0x18, 0x34, 0x6c, 0xe9},
+ }
+
+ //
+ // Register provider.
+ //
+ {
+ displayData, err := createWtFwpmDisplayData0("WireGuard", "The WireGuard provider")
+ if err != nil {
+ return nil, err
+ }
+ provider := wtFwpmProvider0{
+ providerKey: providerGuid,
+ displayData: *displayData,
+ }
+ err = fwpmProviderAdd0(session, &provider, 0)
+ if err != nil {
+ //TODO: cleanup entire call chain of these if failure?
+ return nil, err
+ }
+ }
+
+ //
+ // Register whitelist sublayer.
+ //
+ {
+ displayData, err := createWtFwpmDisplayData0("WireGuard whitelist", "Permissive filters")
+ if err != nil {
+ return nil, err
+ }
+ sublayer := wtFwpmSublayer0{
+ subLayerKey: whitelistGuid,
+ displayData: *displayData,
+ providerKey: &providerGuid,
+ weight: ^uint16(0),
+ }
+ err = fwpmSubLayerAdd0(session, &sublayer, 0)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ //
+ // Register blacklist sublayer.
+ //
+ {
+ displayData, err := createWtFwpmDisplayData0("WireGuard blacklist", "Blocking filters")
+ if err != nil {
+ return nil, err
+ }
+ sublayer := wtFwpmSublayer0{
+ subLayerKey: blacklistGuid,
+ displayData: *displayData,
+ providerKey: &providerGuid,
+ weight: (^uint16(0)) - 1,
+ }
+ err = fwpmSubLayerAdd0(session, &sublayer, 0)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return &baseObjects{
+ providerGuid,
+ whitelistGuid,
+ blacklistGuid,
+ }, nil
+}
+
+func EnableFirewall(luid uint64, restrictDNS bool, restrictAll bool) error {
+ if wfpSession != 0 {
+ return errors.New("The firewall has already been enabled")
+ }
+
+ session, err := createWfpSession()
+ if err != nil {
+ return err
+ }
+
+ objectInstaller := func(session uintptr) error {
+ baseObjects, err := registerBaseObjects(session)
+ if err != nil {
+ return err
+ }
+
+ err = permitTunInterface(session, baseObjects, luid)
+ if err != nil {
+ return err
+ }
+
+ err = permitWireGuardService(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ err = permitLoopback(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ /* We actually don't want to allow lan explicitly. This is controlled by the restrictAll rule.
+ * TODO: consider removing those functions or just rethinking about how this all works.
+
+ err = permitLanIpv4(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ err = permitLanIpv6(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ */
+
+ err = permitDhcpIpv4(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ err = permitDhcpIpv6(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ err = permitNdp(session, baseObjects)
+ if err != nil {
+ return err
+ }
+
+ if restrictDNS {
+ err = blockDnsUnmatched(session, baseObjects)
+ if err != nil {
+ return err
+ }
+ }
+
+ if restrictAll {
+ err = blockAllUnmatched(session, baseObjects)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+ }
+
+ err = runTransaction(session, objectInstaller)
+ if err != nil {
+ fwpmEngineClose0(session)
+ return err
+ }
+
+ wfpSession = session
+ return nil
+}
+
+func DisableFirewall() {
+ if wfpSession != 0 {
+ fwpmEngineClose0(wfpSession)
+ wfpSession = 0
+ }
+}