mirror of
https://github.com/safing/portmaster
synced 2025-09-01 10:09:11 +00:00
Add debug interfaces for wfp and iptables
This commit is contained in:
parent
b0b2fff5d7
commit
45339ce0c2
9 changed files with 56957 additions and 1 deletions
10
compat/debug_default.go
Normal file
10
compat/debug_default.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
//go:build !windows && !linux
|
||||
|
||||
package compat
|
||||
|
||||
import "github.com/safing/portbase/utils/debug"
|
||||
|
||||
// AddToDebugInfo adds compatibility data to the given debug.Info.
|
||||
func AddToDebugInfo(di *debug.Info) {
|
||||
// Not yet implemented on this platform.
|
||||
}
|
28
compat/debug_linux.go
Normal file
28
compat/debug_linux.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package compat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/safing/portbase/utils/debug"
|
||||
)
|
||||
|
||||
// AddToDebugInfo adds compatibility data to the given debug.Info.
|
||||
func AddToDebugInfo(di *debug.Info) {
|
||||
// Get iptables state and add error info if it fails.
|
||||
chains, err := GetIPTablesChains()
|
||||
if err != nil {
|
||||
di.AddSection(
|
||||
"Compatibility: IPTables Chains (failed)",
|
||||
debug.UseCodeSection,
|
||||
err.Error(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Add data as section.
|
||||
di.AddSection(
|
||||
fmt.Sprintf("Compatibility: IPTables Chains (%d)", len(chains)-10),
|
||||
debug.UseCodeSection|debug.AddContentLineBreaks,
|
||||
chains...,
|
||||
)
|
||||
}
|
30
compat/debug_windows.go
Normal file
30
compat/debug_windows.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package compat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/safing/portbase/utils/debug"
|
||||
)
|
||||
|
||||
// AddToDebugInfo adds compatibility data to the given debug.Info.
|
||||
func AddToDebugInfo(di *debug.Info) {
|
||||
// Get WFP state and add error info if it fails.
|
||||
wfp, err := GetWFPState()
|
||||
if err != nil {
|
||||
di.AddSection(
|
||||
"Compatibility: WFP State (failed)",
|
||||
debug.UseCodeSection,
|
||||
err.Error(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Add data as section.
|
||||
wfpTable := wfp.AsTable()
|
||||
di.AddSection(
|
||||
fmt.Sprintf("Compatibility: WFP State (%d)", strings.Count(wfpTable, "\n")),
|
||||
debug.UseCodeSection,
|
||||
wfpTable,
|
||||
)
|
||||
}
|
60
compat/iptables.go
Normal file
60
compat/iptables.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
//go:build linux
|
||||
|
||||
package compat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/go-iptables/iptables"
|
||||
)
|
||||
|
||||
var (
|
||||
iptProtocols = []iptables.Protocol{
|
||||
iptables.ProtocolIPv4,
|
||||
iptables.ProtocolIPv6,
|
||||
}
|
||||
iptTables = []string{
|
||||
"filter",
|
||||
"nat",
|
||||
"mangle",
|
||||
"raw",
|
||||
}
|
||||
)
|
||||
|
||||
// GetIPTablesChains returns the chain names currently in ip(6)tables.
|
||||
func GetIPTablesChains() ([]string, error) {
|
||||
chains := make([]string, 0, 100)
|
||||
|
||||
// Iterate over protocols.
|
||||
for _, protocol := range iptProtocols {
|
||||
if protocol == iptables.ProtocolIPv4 {
|
||||
chains = append(chains, "v4")
|
||||
} else {
|
||||
chains = append(chains, "v6")
|
||||
}
|
||||
|
||||
// Get iptables access for protocol.
|
||||
tbls, err := iptables.NewWithProtocol(protocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Iterate over tables.
|
||||
for _, table := range iptTables {
|
||||
chains = append(chains, " "+table)
|
||||
|
||||
// Get chain names
|
||||
chainNames, err := tbls.ListChains(table)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get chains of table %s: %w", table, err)
|
||||
}
|
||||
|
||||
// Add chain names to list.
|
||||
for _, name := range chainNames {
|
||||
chains = append(chains, " "+name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chains, nil
|
||||
}
|
24
compat/iptables_test.go
Normal file
24
compat/iptables_test.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
//go:build linux
|
||||
|
||||
package compat
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIPTablesChains(t *testing.T) {
|
||||
// Skip in CI.
|
||||
if testing.Short() {
|
||||
t.Skip()
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
chain, err := GetIPTablesChains()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(chain) < 35 {
|
||||
t.Errorf("Expected at least 35 output lines, not %d", len(chain))
|
||||
}
|
||||
}
|
528
compat/wfpstate.go
Normal file
528
compat/wfpstate.go
Normal file
|
@ -0,0 +1,528 @@
|
|||
package compat
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
)
|
||||
|
||||
// GetWFPState queries the system for the WFP state and returns a simplified
|
||||
// and cleaned version.
|
||||
func GetWFPState() (*SimplifiedWFPState, error) {
|
||||
// Use a file to get the wfp state, as the terminal isn't able to return the
|
||||
// data encoded in UTF-8.
|
||||
tmpDir, err := os.MkdirTemp("", "portmaster-debug-data-wfpstate")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create tmp dir for wfpstate: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
}()
|
||||
tmpFile := filepath.Join(tmpDir, "wfpstate.xml")
|
||||
|
||||
// Get wfp state and write it to the tmp file.
|
||||
_, err = osdetail.RunCmd(
|
||||
"netsh.exe",
|
||||
"wfp",
|
||||
"show",
|
||||
"state",
|
||||
tmpFile,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to write wfp state to tmp file: %w", err)
|
||||
}
|
||||
|
||||
// Get tmp file contents.
|
||||
output, err := ioutil.ReadFile(tmpFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read wfp state to tmp file: %w", err)
|
||||
}
|
||||
if len(output) == 0 {
|
||||
return nil, errors.New("wfp state tmp file was empty")
|
||||
}
|
||||
|
||||
// Parse wfp state.
|
||||
parsedState, err := parseWFPState(output)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse wfpstate: %w", err)
|
||||
}
|
||||
|
||||
// Return simplified and cleaned state.
|
||||
return parsedState.simplified(), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Interesting data is found at:
|
||||
|
||||
providers->item[]
|
||||
->displayData->name
|
||||
->displayData->description
|
||||
->providerKey
|
||||
|
||||
subLayers->item[]
|
||||
->displayData->name
|
||||
->displayData->description
|
||||
->subLayerKey
|
||||
|
||||
layers->item[]->callouts->item[]
|
||||
->displayData->name
|
||||
->displayData->description
|
||||
->calloutKey
|
||||
->providerKey
|
||||
->applicableLayer
|
||||
|
||||
layers->item[]->filters->item[]
|
||||
->displayData->name
|
||||
->displayData->description
|
||||
->filterKey
|
||||
->providerKey
|
||||
->layerKey
|
||||
->subLayerKey
|
||||
*/
|
||||
|
||||
// SimplifiedWFPState is a simplified version of the full WFP state.
|
||||
type SimplifiedWFPState struct {
|
||||
Providers []*WFPProvider
|
||||
SubLayers []*WFPSubLayer
|
||||
Callouts []*WFPCallout
|
||||
Filters []*WFPFilter
|
||||
}
|
||||
|
||||
// WFPProvider represents a WFP Provider.
|
||||
type WFPProvider struct {
|
||||
Name string
|
||||
Description string
|
||||
ProviderKey string
|
||||
}
|
||||
|
||||
// WFPSubLayer represents a WFP SubLayer.
|
||||
type WFPSubLayer struct {
|
||||
Name string
|
||||
Description string
|
||||
SubLayerKey string
|
||||
}
|
||||
|
||||
// WFPCallout represents a WFP Callout.
|
||||
type WFPCallout struct {
|
||||
Name string
|
||||
Description string
|
||||
CalloutKey string
|
||||
ProviderKey string
|
||||
ApplicableLayer string
|
||||
}
|
||||
|
||||
// WFPFilter represents a WFP Filter.
|
||||
type WFPFilter struct {
|
||||
Name string
|
||||
Description string
|
||||
FilterKey string
|
||||
ProviderKey string
|
||||
LayerKey string
|
||||
SubLayerKey string
|
||||
}
|
||||
|
||||
// Keys returns all keys found in the WFP state.
|
||||
func (sw *SimplifiedWFPState) Keys() map[string]struct{} {
|
||||
lookupMap := make(map[string]struct{}, len(sw.Providers)+len(sw.SubLayers)+len(sw.Callouts)+len(sw.Filters))
|
||||
|
||||
// Collect keys.
|
||||
for _, provider := range sw.Providers {
|
||||
lookupMap[provider.ProviderKey] = struct{}{}
|
||||
}
|
||||
for _, subLayer := range sw.SubLayers {
|
||||
lookupMap[subLayer.SubLayerKey] = struct{}{}
|
||||
}
|
||||
for _, callout := range sw.Callouts {
|
||||
lookupMap[callout.CalloutKey] = struct{}{}
|
||||
}
|
||||
for _, filter := range sw.Filters {
|
||||
lookupMap[filter.FilterKey] = struct{}{}
|
||||
}
|
||||
|
||||
return lookupMap
|
||||
}
|
||||
|
||||
// AsTable formats the simplified WFP state as a table.
|
||||
func (sw *SimplifiedWFPState) AsTable() string {
|
||||
rows := make([]string, 0, len(sw.Providers)+len(sw.SubLayers)+len(sw.Callouts)+len(sw.Filters))
|
||||
|
||||
// Collect data and put it into rows.
|
||||
for _, provider := range sw.Providers {
|
||||
rows = append(rows, strings.Join([]string{
|
||||
provider.Name,
|
||||
"Provider",
|
||||
provider.Description,
|
||||
provider.ProviderKey,
|
||||
}, "\t"))
|
||||
}
|
||||
for _, subLayer := range sw.SubLayers {
|
||||
rows = append(rows, strings.Join([]string{
|
||||
subLayer.Name,
|
||||
"SubLayer",
|
||||
subLayer.Description,
|
||||
subLayer.SubLayerKey,
|
||||
}, "\t"))
|
||||
}
|
||||
for _, callout := range sw.Callouts {
|
||||
rows = append(rows, strings.Join([]string{
|
||||
callout.Name,
|
||||
"Callout",
|
||||
callout.Description,
|
||||
callout.CalloutKey,
|
||||
callout.ProviderKey,
|
||||
callout.ApplicableLayer,
|
||||
}, "\t"))
|
||||
}
|
||||
for _, filter := range sw.Filters {
|
||||
rows = append(rows, strings.Join([]string{
|
||||
filter.Name,
|
||||
"Filter",
|
||||
filter.Description,
|
||||
filter.FilterKey,
|
||||
filter.ProviderKey,
|
||||
filter.LayerKey,
|
||||
filter.SubLayerKey,
|
||||
}, "\t"))
|
||||
}
|
||||
|
||||
// Sort and build table.
|
||||
sort.Strings(rows)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
tabWriter := tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)
|
||||
for _, row := range rows {
|
||||
fmt.Fprint(tabWriter, row)
|
||||
fmt.Fprint(tabWriter, "\n")
|
||||
}
|
||||
_ = tabWriter.Flush()
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// wfpState is the WFP state as returned by `netsh.exe wfp show state -`.
|
||||
type wfpState struct {
|
||||
XMLName xml.Name `xml:"wfpstate"`
|
||||
Text string `xml:",chardata"`
|
||||
TimeStamp string `xml:"timeStamp"`
|
||||
Providers struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
ProviderKey string `xml:"providerKey"`
|
||||
DisplayData struct {
|
||||
Text string `xml:",chardata"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
} `xml:"displayData"`
|
||||
Flags struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item string `xml:"item"`
|
||||
} `xml:"flags"`
|
||||
ProviderData string `xml:"providerData"`
|
||||
ServiceName string `xml:"serviceName"`
|
||||
} `xml:"item"`
|
||||
} `xml:"providers"`
|
||||
SubLayers struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
SubLayerKey string `xml:"subLayerKey"`
|
||||
DisplayData struct {
|
||||
Text string `xml:",chardata"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
} `xml:"displayData"`
|
||||
Flags struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item string `xml:"item"`
|
||||
} `xml:"flags"`
|
||||
ProviderKey string `xml:"providerKey"`
|
||||
ProviderData string `xml:"providerData"`
|
||||
Weight string `xml:"weight"`
|
||||
} `xml:"item"`
|
||||
} `xml:"subLayers"`
|
||||
Layers struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
Layer struct {
|
||||
Text string `xml:",chardata"`
|
||||
LayerKey string `xml:"layerKey"`
|
||||
DisplayData struct {
|
||||
Text string `xml:",chardata"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
} `xml:"displayData"`
|
||||
Flags struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []string `xml:"item"`
|
||||
} `xml:"flags"`
|
||||
Field struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
FieldKey string `xml:"fieldKey"`
|
||||
Type string `xml:"type"`
|
||||
DataType string `xml:"dataType"`
|
||||
} `xml:"item"`
|
||||
} `xml:"field"`
|
||||
DefaultSubLayerKey string `xml:"defaultSubLayerKey"`
|
||||
LayerID string `xml:"layerId"`
|
||||
} `xml:"layer"`
|
||||
Callouts struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
CalloutKey string `xml:"calloutKey"`
|
||||
DisplayData struct {
|
||||
Text string `xml:",chardata"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
} `xml:"displayData"`
|
||||
Flags struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []string `xml:"item"`
|
||||
} `xml:"flags"`
|
||||
ProviderKey string `xml:"providerKey"`
|
||||
ProviderData string `xml:"providerData"`
|
||||
ApplicableLayer string `xml:"applicableLayer"`
|
||||
CalloutID string `xml:"calloutId"`
|
||||
} `xml:"item"`
|
||||
} `xml:"callouts"`
|
||||
Filters struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
FilterKey string `xml:"filterKey"`
|
||||
DisplayData struct {
|
||||
Text string `xml:",chardata"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
} `xml:"displayData"`
|
||||
Flags struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []string `xml:"item"`
|
||||
} `xml:"flags"`
|
||||
ProviderKey string `xml:"providerKey"`
|
||||
ProviderData struct {
|
||||
Text string `xml:",chardata"`
|
||||
Data string `xml:"data"`
|
||||
AsString string `xml:"asString"`
|
||||
} `xml:"providerData"`
|
||||
LayerKey string `xml:"layerKey"`
|
||||
SubLayerKey string `xml:"subLayerKey"`
|
||||
Weight struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type"`
|
||||
Uint8 string `xml:"uint8"`
|
||||
Uint64 string `xml:"uint64"`
|
||||
} `xml:"weight"`
|
||||
FilterCondition struct {
|
||||
Text string `xml:",chardata"`
|
||||
NumItems string `xml:"numItems,attr"`
|
||||
Item []struct {
|
||||
Text string `xml:",chardata"`
|
||||
FieldKey string `xml:"fieldKey"`
|
||||
MatchType string `xml:"matchType"`
|
||||
ConditionValue struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type"`
|
||||
Uint32 string `xml:"uint32"`
|
||||
Uint16 string `xml:"uint16"`
|
||||
RangeValue struct {
|
||||
Text string `xml:",chardata"`
|
||||
ValueLow struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type"`
|
||||
Uint16 string `xml:"uint16"`
|
||||
Uint32 string `xml:"uint32"`
|
||||
ByteArray16 string `xml:"byteArray16"`
|
||||
} `xml:"valueLow"`
|
||||
ValueHigh struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type"`
|
||||
Uint16 string `xml:"uint16"`
|
||||
Uint32 string `xml:"uint32"`
|
||||
ByteArray16 string `xml:"byteArray16"`
|
||||
} `xml:"valueHigh"`
|
||||
} `xml:"rangeValue"`
|
||||
Uint8 string `xml:"uint8"`
|
||||
ByteBlob struct {
|
||||
Text string `xml:",chardata"`
|
||||
Data string `xml:"data"`
|
||||
AsString string `xml:"asString"`
|
||||
} `xml:"byteBlob"`
|
||||
Sd string `xml:"sd"`
|
||||
Sid string `xml:"sid"`
|
||||
Uint64 string `xml:"uint64"`
|
||||
} `xml:"conditionValue"`
|
||||
} `xml:"item"`
|
||||
} `xml:"filterCondition"`
|
||||
Action struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type"`
|
||||
FilterType string `xml:"filterType"`
|
||||
} `xml:"action"`
|
||||
RawContext string `xml:"rawContext"`
|
||||
Reserved string `xml:"reserved"`
|
||||
FilterID string `xml:"filterId"`
|
||||
EffectiveWeight struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type"`
|
||||
Uint64 string `xml:"uint64"`
|
||||
} `xml:"effectiveWeight"`
|
||||
ProviderContextKey string `xml:"providerContextKey"`
|
||||
} `xml:"item"`
|
||||
} `xml:"filters"`
|
||||
} `xml:"item"`
|
||||
} `xml:"layers"`
|
||||
}
|
||||
|
||||
func parseWFPState(data []byte) (*wfpState, error) {
|
||||
w := &wfpState{}
|
||||
err := xml.Unmarshal(data, w)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *wfpState) simplified() *SimplifiedWFPState {
|
||||
sw := &SimplifiedWFPState{
|
||||
Providers: make([]*WFPProvider, 0, len(w.Providers.Item)),
|
||||
SubLayers: make([]*WFPSubLayer, 0, len(w.SubLayers.Item)),
|
||||
Callouts: make([]*WFPCallout, 0, len(w.Layers.Item)),
|
||||
Filters: make([]*WFPFilter, 0, len(w.Layers.Item)),
|
||||
}
|
||||
|
||||
// Collect data.
|
||||
for _, provider := range w.Providers.Item {
|
||||
if isIgnoredProvider(provider.DisplayData.Name, provider.ProviderKey) {
|
||||
continue
|
||||
}
|
||||
|
||||
sw.Providers = append(sw.Providers, &WFPProvider{
|
||||
Name: defaultTo(provider.DisplayData.Name, "[no name]"),
|
||||
Description: defaultTo(provider.DisplayData.Description, "[no description]"),
|
||||
ProviderKey: defaultTo(provider.ProviderKey, "[no provider key]"),
|
||||
})
|
||||
}
|
||||
for _, subLayer := range w.SubLayers.Item {
|
||||
if isIgnoredProvider(subLayer.DisplayData.Name, "") {
|
||||
continue
|
||||
}
|
||||
|
||||
sw.SubLayers = append(sw.SubLayers, &WFPSubLayer{
|
||||
Name: defaultTo(subLayer.DisplayData.Name, "[no name]"),
|
||||
Description: defaultTo(subLayer.DisplayData.Description, "[no description]"),
|
||||
SubLayerKey: defaultTo(subLayer.SubLayerKey, "[no sublayer key]"),
|
||||
})
|
||||
}
|
||||
for _, layer := range w.Layers.Item {
|
||||
for _, callout := range layer.Callouts.Item {
|
||||
if isIgnoredProvider(callout.DisplayData.Name, callout.ProviderKey) {
|
||||
continue
|
||||
}
|
||||
|
||||
sw.Callouts = append(sw.Callouts, &WFPCallout{
|
||||
Name: defaultTo(callout.DisplayData.Name, "[no name]"),
|
||||
Description: defaultTo(callout.DisplayData.Description, "[no description]"),
|
||||
CalloutKey: defaultTo(callout.CalloutKey, "[no callout key]"),
|
||||
ProviderKey: defaultTo(callout.ProviderKey, "[no provider key]"),
|
||||
ApplicableLayer: defaultTo(callout.ApplicableLayer, "[no applicable layer]"),
|
||||
})
|
||||
}
|
||||
for _, filter := range layer.Filters.Item {
|
||||
if isIgnoredProvider(filter.DisplayData.Name, filter.ProviderKey) {
|
||||
continue
|
||||
}
|
||||
|
||||
sw.Filters = append(sw.Filters, &WFPFilter{
|
||||
Name: defaultTo(filter.DisplayData.Name, "[no name]"),
|
||||
Description: defaultTo(filter.DisplayData.Description, "[no description]"),
|
||||
FilterKey: defaultTo(filter.FilterKey, "[no filter key]"),
|
||||
ProviderKey: defaultTo(filter.ProviderKey, "[no provider key]"),
|
||||
LayerKey: defaultTo(filter.LayerKey, "[no layer key]"),
|
||||
SubLayerKey: defaultTo(filter.SubLayerKey, "[no sublayer key]"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return sw
|
||||
}
|
||||
|
||||
func isIgnoredProvider(name, key string) bool {
|
||||
// Check provider key.
|
||||
if key != "" {
|
||||
matched := true
|
||||
switch key {
|
||||
case "{1bebc969-61a5-4732-a177-847a0817862a}": // Microsoft Windows Defender Firewall IPsec Provider.
|
||||
case "{4b153735-1049-4480-aab4-d1b9bdc03710}": // Microsoft Windows Defender Firewall Provider.
|
||||
case "{893a4f22-9bba-49b7-8c66-3d40929c8fd5}": // Microsoft Windows Teredo firewall provider.
|
||||
case "{8e44982a-f477-11df-85ce-78e7d1810190}": // Windows Network Data Usage (NDU) Provider.
|
||||
case "{9c2532b4-0314-434f-8274-0cbaebdbda56}": // Microsoft Windows edge traversal socket option authorization provider.
|
||||
case "{aa6a7d87-7f8f-4d2a-be53-fda555cd5fe3}": // Microsoft Windows Defender Firewall IPsec Provider.
|
||||
case "{c698301d-9129-450c-937c-f4b834bfb374}": // Microsoft Windows edge traversal socket option authorization provider.
|
||||
case "{decc16ca-3f33-4346-be1e-8fb4ae0f3d62}": // Microsoft Windows Defender Firewall Provider.
|
||||
case "FWPM_PROVIDER_IKEEXT": // Microsoft Windows WFP Built-in IKEEXT provider used to identify filters added by IKE/AuthIP.
|
||||
case "FWPM_PROVIDER_IPSEC_DOSP_CONFIG": // Microsoft Windows WFP Built-in IPsec DoS Protection configuration provider used to identify filters added by IPsec Denial of Service Protection.
|
||||
case "FWPM_PROVIDER_MPSSVC_APP_ISOLATION": // Microsoft Windows WFP Built-in MPSSVC App Isolation provider.
|
||||
case "FWPM_PROVIDER_MPSSVC_EDP": // Microsoft Windows WFP Built-in MPSSVC Enterprise Data Protection provider.
|
||||
case "FWPM_PROVIDER_MPSSVC_TENANT_RESTRICTIONS": // Microsoft Windows WFP Built-in MPSSVC Tenant Restrictions provider.
|
||||
case "FWPM_PROVIDER_MPSSVC_WF": // Microsoft Windows WFP Built-in MPSSVC Windows Firewall provider.
|
||||
case "FWPM_PROVIDER_MPSSVC_WSH": // Microsoft Windows WFP Built-in MPSSVC Windows Service Hardening and Quarantine provider.
|
||||
case "FWPM_PROVIDER_TCP_CHIMNEY_OFFLOAD": // Microsoft Windows WFP Built-in TCP Chimney Offload provider used to identify filters added by TCP Chimney Offload.
|
||||
case "FWPM_PROVIDER_TCP_TEMPLATES": // Microsoft Windows WFP Built-in TCP Templates provider used to identify filters added by TCP Template based configuration.
|
||||
default:
|
||||
matched = false
|
||||
}
|
||||
if matched {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Some entries don't have a provider key (set).
|
||||
// These are pretty generic, but the output strings are localized.
|
||||
if name != "" {
|
||||
switch {
|
||||
case strings.Contains(name, "Microsoft Corporation"):
|
||||
return true
|
||||
case strings.Contains(name, "windefend"):
|
||||
return true
|
||||
case strings.Contains(name, "WFP"):
|
||||
return true
|
||||
case strings.Contains(name, "RPC"):
|
||||
return true
|
||||
case strings.Contains(name, "NDU"):
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func defaultTo(a, b string) string {
|
||||
if a != "" {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
56270
compat/wfpstate_test.go
Normal file
56270
compat/wfpstate_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -4,12 +4,15 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/safing/portbase/api"
|
||||
"github.com/safing/portbase/config"
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/modules"
|
||||
"github.com/safing/portbase/utils/debug"
|
||||
"github.com/safing/portmaster/compat"
|
||||
"github.com/safing/portmaster/resolver"
|
||||
"github.com/safing/portmaster/status"
|
||||
"github.com/safing/portmaster/updates"
|
||||
"github.com/safing/spn/captain"
|
||||
)
|
||||
|
||||
func registerAPIEndpoints() error {
|
||||
|
@ -85,7 +88,10 @@ func debugInfo(ar *api.Request) (data []byte, err error) {
|
|||
di.AddVersionInfo()
|
||||
di.AddPlatformInfo(ar.Context())
|
||||
status.AddToDebugInfo(di)
|
||||
config.AddToDebugInfo(di)
|
||||
resolver.AddToDebugInfo(di)
|
||||
captain.AddToDebugInfo(di)
|
||||
compat.AddToDebugInfo(di)
|
||||
di.AddLastReportedModuleError()
|
||||
di.AddLastUnexpectedLogs()
|
||||
di.AddGoroutineStack()
|
||||
|
|
|
@ -110,7 +110,7 @@ func getDefaultInterface() *defaultNetInterface {
|
|||
newIf := &defaultNetInterface{}
|
||||
|
||||
// Scan data for needed fields.
|
||||
scanner := bufio.NewScanner(bytes.NewBufferString(interfaceData))
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(interfaceData))
|
||||
scanner.Split(bufio.ScanLines)
|
||||
var segmentKey, segmentValue, previousKey string
|
||||
for scanner.Scan() {
|
||||
|
|
Loading…
Add table
Reference in a new issue