Fix handling of connectivity / captive portal domains

Also, improve handling of queries during being captive.
This commit is contained in:
Daniel
2020-07-17 16:09:46 +02:00
parent a6e161e0a1
commit 68c2d23c1b
15 changed files with 223 additions and 63 deletions

View File

@@ -1,9 +1,11 @@
package firewall
import (
"context"
"net"
"os"
"strings"
"time"
"github.com/miekg/dns"
"github.com/safing/portbase/database"
@@ -77,18 +79,13 @@ func filterDNSSection(entries []dns.RR, p *profile.LayeredProfile, scope int8) (
}
func filterDNSResponse(conn *network.Connection, rrCache *resolver.RRCache) *resolver.RRCache {
p := conn.Process().Profile()
// do not modify own queries
if conn.Process().Pid == os.Getpid() {
return rrCache
}
// get profile
p := conn.Process().Profile()
if p == nil {
conn.Block("no profile")
return nil
}
// check if DNS response filtering is completely turned off
if !p.RemoveOutOfScopeDNS() && !p.RemoveBlockedDNS() {
return rrCache
@@ -112,6 +109,31 @@ func filterDNSResponse(conn *network.Connection, rrCache *resolver.RRCache) *res
rrCache.Filtered = true
if validIPs == 0 {
conn.Block("no addresses returned for this domain are permitted")
// If all entries are filtered, this could mean that these are broken/bogus resource records.
if rrCache.Expired() {
// If the entry is expired, force delete it.
err := resolver.DeleteNameRecord(rrCache.Domain, rrCache.Question.String())
if err != nil && err != database.ErrNotFound {
log.Warningf(
"filter: failed to delete fully filtered name cache for %s: %s",
rrCache.ID(),
err,
)
}
} else if rrCache.TTL > time.Now().Add(10*time.Second).Unix() {
// Set a low TTL of 10 seconds if TTL is higher than that.
rrCache.TTL = time.Now().Add(10 * time.Second).Unix()
err := rrCache.Save()
if err != nil {
log.Debugf(
"filter: failed to set shorter TTL on fully filtered name cache for %s: %s",
rrCache.ID(),
err,
)
}
}
return nil
}
@@ -122,7 +144,25 @@ func filterDNSResponse(conn *network.Connection, rrCache *resolver.RRCache) *res
}
// DecideOnResolvedDNS filters a dns response according to the application profile and settings.
func DecideOnResolvedDNS(conn *network.Connection, q *resolver.Query, rrCache *resolver.RRCache) *resolver.RRCache {
func DecideOnResolvedDNS(
ctx context.Context,
conn *network.Connection,
q *resolver.Query,
rrCache *resolver.RRCache,
) *resolver.RRCache {
// check profile
if checkProfileExists(ctx, conn, nil) {
// returns true if check triggered
return nil
}
// special grant for connectivity domains
if checkConnectivityDomain(ctx, conn, nil) {
// returns true if check triggered
return rrCache
}
updatedRR := filterDNSResponse(conn, rrCache)
if updatedRR == nil {
return nil

View File

@@ -52,7 +52,7 @@ func DecideOnConnection(ctx context.Context, conn *network.Connection, pkt packe
checkSelfCommunication,
checkProfileExists,
checkConnectionType,
checkCaptivePortal,
checkConnectivityDomain,
checkConnectionScope,
checkEndpointLists,
checkBypassPrevention,
@@ -181,10 +181,17 @@ func checkConnectionType(ctx context.Context, conn *network.Connection, _ packet
return false
}
func checkCaptivePortal(_ context.Context, conn *network.Connection, _ packet.Packet) bool {
if netenv.GetOnlineStatus() == netenv.StatusPortal &&
conn.Entity.Domain == netenv.GetCaptivePortal().Domain {
conn.Accept("captive portal access permitted")
func checkConnectivityDomain(_ context.Context, conn *network.Connection, _ packet.Packet) bool {
p := conn.Process().Profile()
if !p.BlockScopeInternet() {
// Special grant only applies if application is allowed to connect to the Internet.
return false
}
if netenv.GetOnlineStatus() <= netenv.StatusPortal &&
netenv.IsConnectivityDomain(conn.Entity.Domain) {
conn.Accept("special grant for connectivity domain during network bootstrap")
return true
}