Merge pull request #411 from safing/feature/routing-options

Add routing options
This commit is contained in:
Daniel
2021-10-12 16:35:43 +02:00
committed by GitHub
6 changed files with 63 additions and 128 deletions

View File

@@ -322,39 +322,34 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) {
func initialHandler(conn *network.Connection, pkt packet.Packet) {
log.Tracer(pkt.Ctx()).Trace("filter: handing over to connection-based handler")
// Check for pre-authenticated port.
if !conn.Inbound && localPortIsPreAuthenticated(conn.Entity.Protocol, conn.LocalPort) {
switch {
case !conn.Inbound && localPortIsPreAuthenticated(conn.Entity.Protocol, conn.LocalPort):
// Approve connection.
conn.Accept("connection by Portmaster", noReasonOptionKey)
conn.Internal = true
// Finalize connection.
conn.StopFirewallHandler()
issueVerdict(conn, pkt, 0, true)
return
}
// Redirect rogue dns requests to the Portmaster.
if pkt.IsOutbound() &&
// Set tunnel options.
setCustomTunnelOptionsForPortmaster(conn)
case pkt.IsOutbound() &&
pkt.Info().DstPort == 53 &&
conn.Process().Pid != ownPID &&
nameserverIPMatcherReady.IsSet() &&
!nameserverIPMatcher(pkt.Info().Dst) {
!nameserverIPMatcher(pkt.Info().Dst):
// Reroute rogue dns queries back to Portmaster.
conn.Verdict = network.VerdictRerouteToNameserver
conn.Reason.Msg = "redirecting rogue dns query"
conn.Internal = true
// End directly, as no other processing is necessary.
conn.StopFirewallHandler()
issueVerdict(conn, pkt, 0, true)
return
}
// TODO: enable inspecting again
conn.Inspecting = false
// Filter, if enabled.
if filterEnabled() {
case filterEnabled():
log.Tracer(pkt.Ctx()).Trace("filter: starting decision process")
DecideOnConnection(pkt.Ctx(), conn, pkt)
} else {
default:
conn.Accept("privacy filter disabled", noReasonOptionKey)
}
@@ -366,6 +361,8 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
// Exclude requests of the SPN itself.
if !captain.IsExcepted(conn.Entity.IP) {
conn.Tunneled = true
// Check if client is ready.
if captain.ClientReady() {
// Queue request in sluice.
@@ -385,6 +382,9 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
}
}
// TODO: enable inspecting again
conn.Inspecting = false
switch {
case conn.Inspecting:
log.Tracer(pkt.Ctx()).Trace("filter: start inspecting")

View File

@@ -141,6 +141,10 @@ func checkPortmasterConnection(ctx context.Context, conn *network.Connection, _
log.Tracer(ctx).Infof("filter: granting own connection %s", conn)
conn.Accept("connection by Portmaster", noReasonOptionKey)
conn.Internal = true
// Set tunnel options.
setCustomTunnelOptionsForPortmaster(conn)
return true
}

View File

@@ -1,111 +1,23 @@
package firewall
// var (
// TunnelNet4 *net.IPNet
// TunnelNet6 *net.IPNet
// TunnelEntry4 = net.IPv4(127, 0, 0, 17)
// TunnelEntry6 = net.ParseIP("fd17::17")
//
// ipToDomainMap = make(map[string]*TunnelInfo)
// ipToDomainMapLock sync.RWMutex
// )
//
// func init() {
// var err error
// _, TunnelNet4, err = net.ParseCIDR("127.17.0.0/16")
// if err != nil {
// log.Fatalf("portmaster: could not parse 127.17.0.0/16: %s", err)
// }
// _, TunnelNet6, err = net.ParseCIDR("fd17::/64")
// if err != nil {
// log.Fatalf("portmaster: could not parse fd17::/64: %s", err)
// }
//
// go tunnelInfoCleaner()
// }
//
// type TunnelInfo struct {
// IP net.IP
// Domain string
// RRCache *intel.RRCache
// Expires int64
// }
//
// func (ti *TunnelInfo) ExportTunnelIP() *intel.RRCache {
// return &intel.RRCache{
// Answer: []dns.RR{
// &dns.A{
// Hdr: dns.RR_Header{
// Name: ti.Domain,
// Rrtype: 1,
// Class: 1,
// Ttl: 17,
// Rdlength: 8,
// },
// A: ti.IP,
// },
// },
// }
// }
//
// func AssignTunnelIP(domain string) (*TunnelInfo, error) {
// ipToDomainMapLock.Lock()
// defer ipToDomainMapLock.Unlock()
//
// for i := 0; i < 100; i++ {
// // get random IP
// r, err := random.Bytes(2)
// if err != nil {
// return nil, err
// }
// randomIP := net.IPv4(127, 17, r[0], r[1])
//
// // clean after every 20 tries
// if i > 0 && i%20 == 0 {
// cleanExpiredTunnelInfos()
// }
//
// // if it does not exist yet, set and return
// _, ok := ipToDomainMap[randomIP.String()]
// if !ok {
// tunnelInfo := &TunnelInfo{
// IP: randomIP,
// Domain: domain,
// Expires: time.Now().Add(5 * time.Minute).Unix(),
// }
// ipToDomainMap[randomIP.String()] = tunnelInfo
// return tunnelInfo, nil
// }
// }
//
// return nil, errors.New("could not find available tunnel IP, please retry later")
// }
//
// func GetTunnelInfo(tunnelIP net.IP) (tunnelInfo *TunnelInfo) {
// ipToDomainMapLock.RLock()
// defer ipToDomainMapLock.RUnlock()
// var ok bool
// tunnelInfo, ok = ipToDomainMap[tunnelIP.String()]
// if ok && tunnelInfo.Expires >= time.Now().Unix() {
// return tunnelInfo
// }
// return nil
// }
//
// func tunnelInfoCleaner() {
// for {
// time.Sleep(5 * time.Minute)
// ipToDomainMapLock.Lock()
// cleanExpiredTunnelInfos()
// ipToDomainMapLock.Unlock()
// }
// }
//
// func cleanExpiredTunnelInfos() {
// now := time.Now().Unix()
// for domain, tunnelInfo := range ipToDomainMap {
// if tunnelInfo.Expires < now {
// delete(ipToDomainMap, domain)
// }
// }
// }
import (
"github.com/safing/portmaster/network"
"github.com/safing/portmaster/resolver"
"github.com/safing/spn/navigator"
)
func setCustomTunnelOptionsForPortmaster(conn *network.Connection) {
switch {
case !tunnelEnabled():
// Ignore when tunneling is not enabled.
return
case !conn.Entity.IPScope.IsGlobal():
// Ignore if destination is not in global address space.
return
case resolver.IsResolverAddress(conn.Entity.IP, conn.Entity.Port):
// Set custom tunnel options for DNS servers.
conn.TunnelOpts = &navigator.Options{
RoutingProfile: navigator.RoutingProfileHomeName,
}
}
}

2
go.sum
View File

@@ -480,6 +480,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tannerryan/ring v1.1.2 h1:iXayOjqHQOLzuy9GwSKuG3nhWfzQkldMlQivcgIr7gQ=
@@ -1000,6 +1001,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -7,15 +7,15 @@ import (
"sync"
"time"
"github.com/safing/portmaster/netenv"
"github.com/safing/portbase/database/record"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/intel"
"github.com/safing/portmaster/netenv"
"github.com/safing/portmaster/network/netutils"
"github.com/safing/portmaster/network/packet"
"github.com/safing/portmaster/process"
"github.com/safing/portmaster/resolver"
"github.com/safing/spn/navigator"
)
// FirewallHandler defines the function signature for a firewall
@@ -137,6 +137,8 @@ type Connection struct { //nolint:maligned // TODO: fix alignment
Tunneled bool
// Encrypted is currently unused and MUST be ignored.
Encrypted bool
// TunnelOpts holds options for tunneling the connection.
TunnelOpts *navigator.Options
// ProcessContext holds additional information about the process
// that iniated the connection. It is set once when the connection
// object is created and is considered immutable afterwards.

View File

@@ -395,3 +395,18 @@ func checkSearchScope(searchDomain string) (ok bool) {
return true
}
// IsResolverAddress returns whether the given ip and port match a configured resolver.
func IsResolverAddress(ip net.IP, port uint16) bool {
resolversLock.RLock()
defer resolversLock.RUnlock()
// Check if the given IP and port matches a resolver.
for _, r := range globalResolvers {
if port == r.Info.Port && r.Info.IP.Equal(ip) {
return true
}
}
return false
}