Merge pull request #37 from safing/feature/firefox-doh

Add support for firefox canary domain for disabling DoH
This commit is contained in:
Daniel 2020-04-17 12:43:45 +02:00 committed by GitHub
commit c7c2908151
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 8 deletions

19
firewall/bypassing.go Normal file
View file

@ -0,0 +1,19 @@
package firewall
import (
"strings"
"github.com/safing/portmaster/network"
"github.com/safing/portmaster/profile/endpoints"
)
// PreventBypassing checks if the connection should be denied or permitted
// based on some bypass protection checks.
func PreventBypassing(conn *network.Connection) (endpoints.EPResult, string) {
// Block firefox canary domain to disable DoH
if strings.ToLower(conn.Entity.Domain) == "use-application-dns.net." {
return endpoints.Denied, "blocked canary domain to prevent enabling DNS-over-HTTPs"
}
return endpoints.NoMatch, ""
}

View file

@ -141,9 +141,24 @@ func DecideOnConnection(conn *network.Connection, pkt packet.Packet) { //nolint:
} }
} }
// check endpoints list
var result endpoints.EPResult var result endpoints.EPResult
var reason string var reason string
if p.PreventBypassing() {
// check for bypass protection
result, reason := PreventBypassing(conn)
switch result {
case endpoints.Denied:
conn.Block("bypass prevention: " + reason)
return
case endpoints.Permitted:
conn.Accept("bypass prevention: " + reason)
return
case endpoints.NoMatch:
}
}
// check endpoints list
if conn.Inbound { if conn.Inbound {
result, reason = p.MatchServiceEndpoint(conn.Entity) result, reason = p.MatchServiceEndpoint(conn.Entity)
} else { } else {

View file

@ -151,7 +151,6 @@ func (e *Entity) getLocation() {
e.fetchLocationOnce.Do(func() { e.fetchLocationOnce.Do(func() {
// need IP! // need IP!
if e.IP == nil { if e.IP == nil {
log.Warningf("intel: cannot get location for %s data without IP", e.Domain)
return return
} }
@ -224,11 +223,11 @@ func (e *Entity) getDomainLists() {
var domains = []string{domain} var domains = []string{domain}
if e.resolveSubDomainLists { if e.resolveSubDomainLists {
domains = splitDomain(domain) domains = splitDomain(domain)
log.Debugf("intel: subdomain list resolving is enabled, checking %v", domains) log.Tracef("intel: subdomain list resolving is enabled, checking %v", domains)
} }
for _, d := range domains { for _, d := range domains {
log.Debugf("intel: loading domain list for %s", d) log.Tracef("intel: loading domain list for %s", d)
list, err := filterlists.LookupDomain(d) list, err := filterlists.LookupDomain(d)
if err != nil { if err != nil {
log.Errorf("intel: failed to get domain blocklists for %s: %s", d, err) log.Errorf("intel: failed to get domain blocklists for %s: %s", d, err)
@ -278,7 +277,7 @@ func (e *Entity) getASNLists() {
return return
} }
log.Debugf("intel: loading ASN list for %d", asn) log.Tracef("intel: loading ASN list for %d", asn)
e.loadAsnListOnce.Do(func() { e.loadAsnListOnce.Do(func() {
list, err := filterlists.LookupASNString(fmt.Sprintf("%d", asn)) list, err := filterlists.LookupASNString(fmt.Sprintf("%d", asn))
if err != nil { if err != nil {
@ -302,7 +301,7 @@ func (e *Entity) getCountryLists() {
return return
} }
log.Debugf("intel: loading country list for %s", country) log.Tracef("intel: loading country list for %s", country)
e.loadCoutryListOnce.Do(func() { e.loadCoutryListOnce.Do(func() {
list, err := filterlists.LookupCountry(country) list, err := filterlists.LookupCountry(country)
if err != nil { if err != nil {
@ -335,7 +334,7 @@ func (e *Entity) getIPLists() {
return return
} }
log.Debugf("intel: loading IP list for %s", ip) log.Tracef("intel: loading IP list for %s", ip)
e.loadIPListOnce.Do(func() { e.loadIPListOnce.Do(func() {
list, err := filterlists.LookupIP(ip) list, err := filterlists.LookupIP(ip)

View file

@ -53,6 +53,9 @@ var (
CfgOptionRemoveBlockedDNSKey = "filter/removeBlockedDNS" CfgOptionRemoveBlockedDNSKey = "filter/removeBlockedDNS"
cfgOptionRemoveBlockedDNS config.IntOption // security level option cfgOptionRemoveBlockedDNS config.IntOption // security level option
CfgOptionPreventBypassingKey = "filter/preventBypassing"
cfgOptionPreventBypassing config.IntOption // security level option
) )
func registerConfiguration() error { func registerConfiguration() error {
@ -325,5 +328,22 @@ Examples:
cfgOptionRemoveBlockedDNS = config.Concurrent.GetAsInt(CfgOptionRemoveBlockedDNSKey, int64(status.SecurityLevelsAll)) cfgOptionRemoveBlockedDNS = config.Concurrent.GetAsInt(CfgOptionRemoveBlockedDNSKey, int64(status.SecurityLevelsAll))
cfgIntOptions[CfgOptionRemoveBlockedDNSKey] = cfgOptionRemoveBlockedDNS cfgIntOptions[CfgOptionRemoveBlockedDNSKey] = cfgOptionRemoveBlockedDNS
err = config.Register(&config.Option{
Name: "Prevent Bypassing",
Key: CfgOptionPreventBypassingKey,
Description: "Prevent apps from bypassing the privacy filter: Firefox by disabling DNS-over-HTTPs",
OptType: config.OptTypeInt,
ExpertiseLevel: config.ExpertiseLevelUser,
ReleaseLevel: config.ReleaseLevelBeta,
ExternalOptType: "security level",
DefaultValue: status.SecurityLevelsAll,
ValidationRegex: "^(7|6|4)",
})
if err != nil {
return err
}
cfgOptionPreventBypassing = config.Concurrent.GetAsInt((CfgOptionPreventBypassingKey), int64(status.SecurityLevelsAll))
cfgIntOptions[CfgOptionPreventBypassingKey] = cfgOptionPreventBypassing
return nil return nil
} }

View file

@ -43,6 +43,7 @@ type LayeredProfile struct {
RemoveOutOfScopeDNS config.BoolOption RemoveOutOfScopeDNS config.BoolOption
RemoveBlockedDNS config.BoolOption RemoveBlockedDNS config.BoolOption
FilterSubDomains config.BoolOption FilterSubDomains config.BoolOption
PreventBypassing config.BoolOption
} }
// NewLayeredProfile returns a new layered profile based on the given local profile. // NewLayeredProfile returns a new layered profile based on the given local profile.
@ -98,6 +99,10 @@ func NewLayeredProfile(localProfile *Profile) *LayeredProfile {
CfgOptionFilterSubDomainsKey, CfgOptionFilterSubDomainsKey,
cfgOptionFilterSubDomains, cfgOptionFilterSubDomains,
) )
new.PreventBypassing = new.wrapSecurityLevelOption(
CfgOptionPreventBypassingKey,
cfgOptionPreventBypassing,
)
// TODO: load linked profiles. // TODO: load linked profiles.
@ -224,7 +229,7 @@ func (lp *LayeredProfile) MatchServiceEndpoint(entity *intel.Entity) (result end
// MatchFilterLists matches the entity against the set of filter // MatchFilterLists matches the entity against the set of filter
// lists. // lists.
func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (result endpoints.EPResult, reason string) { func (lp *LayeredProfile) MatchFilterLists(entity *intel.Entity) (endpoints.EPResult, string) {
entity.ResolveSubDomainLists(lp.FilterSubDomains()) entity.ResolveSubDomainLists(lp.FilterSubDomains())
lookupMap, hasLists := entity.GetListsMap() lookupMap, hasLists := entity.GetListsMap()