mirror of
https://github.com/safing/portmaster
synced 2025-09-04 19:49:15 +00:00
Add support for fast-tracking connections within the OS integration
This commit is contained in:
parent
995e924b15
commit
c3d94efab9
6 changed files with 63 additions and 16 deletions
|
@ -161,6 +161,12 @@ func getConnection(pkt packet.Packet) (*network.Connection, error) {
|
||||||
func fastTrackedPermit(pkt packet.Packet) (handled bool) {
|
func fastTrackedPermit(pkt packet.Packet) (handled bool) {
|
||||||
meta := pkt.Info()
|
meta := pkt.Info()
|
||||||
|
|
||||||
|
// Check if packed was already fast-tracked by the OS integration.
|
||||||
|
if pkt.FastTrackedByIntegration() {
|
||||||
|
log.Debugf("filter: fast-tracked by OS integration: %s", pkt)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Check if connection was already blocked.
|
// Check if connection was already blocked.
|
||||||
if meta.Dst.Equal(blockedIPv4) || meta.Dst.Equal(blockedIPv6) {
|
if meta.Dst.Equal(blockedIPv4) || meta.Dst.Equal(blockedIPv6) {
|
||||||
_ = pkt.PermanentBlock()
|
_ = pkt.PermanentBlock()
|
||||||
|
|
|
@ -86,7 +86,7 @@ func (pkt *packet) mark(mark int) (err error) {
|
||||||
return pkt.setMark(mark)
|
return pkt.setMark(mark)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("verdict set")
|
return errors.New("verdict already set")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *packet) setMark(mark int) error {
|
func (pkt *packet) setMark(mark int) error {
|
||||||
|
@ -113,12 +113,12 @@ func (pkt *packet) setMark(mark int) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Errorf("nfqueue: failed to set verdict %s for %s (%s -> %s): %s", markToString(mark), pkt.ID(), pkt.Info().Src, pkt.Info().Dst, err)
|
log.Tracer(pkt.Ctx()).Errorf("nfqueue: failed to set verdict %s for %s (%s -> %s): %s", markToString(mark), pkt.ID(), pkt.Info().Src, pkt.Info().Dst, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Tracef("nfqueue: marking packet %s (%s -> %s) on queue %d with %s after %s", pkt.ID(), pkt.Info().Src, pkt.Info().Dst, pkt.queue.id, markToString(mark), time.Since(pkt.received))
|
log.Tracer(pkt.Ctx()).Tracef("nfqueue: marking packet %s (%s -> %s) on queue %d with %s after %s", pkt.ID(), pkt.Info().Src, pkt.Info().Dst, pkt.queue.id, markToString(mark), time.Since(pkt.received))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,18 @@ import (
|
||||||
"github.com/safing/portmaster/network/packet"
|
"github.com/safing/portmaster/network/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// VerdictRequestFlagFastTrackPermitted is set on packets that have been
|
||||||
|
// already permitted by the kernel extension and the verdict request is only
|
||||||
|
// informational.
|
||||||
|
VerdictRequestFlagFastTrackPermitted = 1
|
||||||
|
|
||||||
|
// VerdictRequestFlagSocketAuth indicates that the verdict request is for a
|
||||||
|
// connection that was intercepted on an ALE layer instead of in the network
|
||||||
|
// stack itself. Thus, no packet data is available.
|
||||||
|
VerdictRequestFlagSocketAuth = 2
|
||||||
|
)
|
||||||
|
|
||||||
// VerdictRequest is the request structure from the Kext.
|
// VerdictRequest is the request structure from the Kext.
|
||||||
type VerdictRequest struct {
|
type VerdictRequest struct {
|
||||||
id uint32 // ID from RegisterPacket
|
id uint32 // ID from RegisterPacket
|
||||||
|
@ -20,7 +32,7 @@ type VerdictRequest struct {
|
||||||
direction uint8
|
direction uint8
|
||||||
ipV6 uint8 // True: IPv6, False: IPv4
|
ipV6 uint8 // True: IPv6, False: IPv4
|
||||||
protocol uint8 // Protocol
|
protocol uint8 // Protocol
|
||||||
_ uint8
|
flags uint8 // Flags
|
||||||
localIP [4]uint32 // Source Address
|
localIP [4]uint32 // Source Address
|
||||||
remoteIP [4]uint32 // Destination Address
|
remoteIP [4]uint32 // Destination Address
|
||||||
localPort uint16 // Source Port
|
localPort uint16 // Source Port
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
// Package errors
|
// Package errors
|
||||||
var (
|
var (
|
||||||
ErrKextNotReady = errors.New("the windows kernel extension (driver) is not ready to accept commands")
|
ErrKextNotReady = errors.New("the windows kernel extension (driver) is not ready to accept commands")
|
||||||
|
ErrNoPacketID = errors.New("the packet has no ID, possibly because it was fast-tracked by the kernel extension")
|
||||||
|
|
||||||
winErrInvalidData = uintptr(windows.ERROR_INVALID_DATA)
|
winErrInvalidData = uintptr(windows.ERROR_INVALID_DATA)
|
||||||
|
|
||||||
|
@ -178,22 +179,29 @@ func RecvVerdictRequest() (*VerdictRequest, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVerdict sets the verdict for a packet and/or connection.
|
// SetVerdict sets the verdict for a packet and/or connection.
|
||||||
func SetVerdict(packetID uint32, verdict network.Verdict) error {
|
func SetVerdict(pkt *Packet, verdict network.Verdict) error {
|
||||||
|
if pkt.verdictRequest.id == 0 {
|
||||||
|
log.Tracer(pkt.Ctx()).Errorf("kext: failed to set verdict %s: no packet ID", verdict)
|
||||||
|
return ErrNoPacketID
|
||||||
|
}
|
||||||
|
|
||||||
kextLock.RLock()
|
kextLock.RLock()
|
||||||
defer kextLock.RUnlock()
|
defer kextLock.RUnlock()
|
||||||
if !ready.IsSet() {
|
if !ready.IsSet() {
|
||||||
|
log.Tracer(pkt.Ctx()).Errorf("kext: failed to set verdict %s: kext not ready", verdict)
|
||||||
return ErrKextNotReady
|
return ErrKextNotReady
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic.AddInt32(urgentRequests, 1)
|
atomic.AddInt32(urgentRequests, 1)
|
||||||
// timestamp := time.Now()
|
// timestamp := time.Now()
|
||||||
rc, _, lastErr := kext.setVerdict.Call(
|
rc, _, lastErr := kext.setVerdict.Call(
|
||||||
uintptr(packetID),
|
uintptr(pkt.verdictRequest.id),
|
||||||
uintptr(verdict),
|
uintptr(verdict),
|
||||||
)
|
)
|
||||||
// log.Tracef("winkext: settings verdict for packetID %d took %s", packetID, time.Now().Sub(timestamp))
|
// log.Tracef("winkext: settings verdict for packetID %d took %s", packetID, time.Now().Sub(timestamp))
|
||||||
atomic.AddInt32(urgentRequests, -1)
|
atomic.AddInt32(urgentRequests, -1)
|
||||||
if rc != windows.NO_ERROR {
|
if rc != windows.NO_ERROR {
|
||||||
|
log.Tracer(pkt.Ctx()).Errorf("kext: failed to set verdict %s on packet %d", verdict, pkt.verdictRequest.id)
|
||||||
return formatErr(lastErr, rc)
|
return formatErr(lastErr, rc)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -201,6 +209,10 @@ func SetVerdict(packetID uint32, verdict network.Verdict) error {
|
||||||
|
|
||||||
// GetPayload returns the payload of a packet.
|
// GetPayload returns the payload of a packet.
|
||||||
func GetPayload(packetID uint32, packetSize uint32) ([]byte, error) {
|
func GetPayload(packetID uint32, packetSize uint32) ([]byte, error) {
|
||||||
|
if packetID == 0 {
|
||||||
|
return nil, ErrNoPacketID
|
||||||
|
}
|
||||||
|
|
||||||
kextLock.RLock()
|
kextLock.RLock()
|
||||||
defer kextLock.RUnlock()
|
defer kextLock.RUnlock()
|
||||||
if !ready.IsSet() {
|
if !ready.IsSet() {
|
||||||
|
|
|
@ -23,11 +23,21 @@ type Packet struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FastTrackedByIntegration returns whether the packet has been fast-track
|
||||||
|
// accepted by the OS integration.
|
||||||
|
func (pkt *Packet) FastTrackedByIntegration() bool {
|
||||||
|
return pkt.verdictRequest.flags&VerdictRequestFlagFastTrackPermitted > 0
|
||||||
|
}
|
||||||
|
|
||||||
// GetPayload returns the full raw packet.
|
// GetPayload returns the full raw packet.
|
||||||
func (pkt *Packet) LoadPacketData() error {
|
func (pkt *Packet) LoadPacketData() error {
|
||||||
pkt.lock.Lock()
|
pkt.lock.Lock()
|
||||||
defer pkt.lock.Unlock()
|
defer pkt.lock.Unlock()
|
||||||
|
|
||||||
|
if pkt.verdictRequest.id == 0 {
|
||||||
|
return packet.ErrNoPacketID
|
||||||
|
}
|
||||||
|
|
||||||
if !pkt.payloadLoaded {
|
if !pkt.payloadLoaded {
|
||||||
pkt.payloadLoaded = true
|
pkt.payloadLoaded = true
|
||||||
|
|
||||||
|
@ -53,7 +63,7 @@ func (pkt *Packet) LoadPacketData() error {
|
||||||
// Accept accepts the packet.
|
// Accept accepts the packet.
|
||||||
func (pkt *Packet) Accept() error {
|
func (pkt *Packet) Accept() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, -network.VerdictAccept)
|
return SetVerdict(pkt, -network.VerdictAccept)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -61,7 +71,7 @@ func (pkt *Packet) Accept() error {
|
||||||
// Block blocks the packet.
|
// Block blocks the packet.
|
||||||
func (pkt *Packet) Block() error {
|
func (pkt *Packet) Block() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, -network.VerdictBlock)
|
return SetVerdict(pkt, -network.VerdictBlock)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -69,7 +79,7 @@ func (pkt *Packet) Block() error {
|
||||||
// Drop drops the packet.
|
// Drop drops the packet.
|
||||||
func (pkt *Packet) Drop() error {
|
func (pkt *Packet) Drop() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, -network.VerdictDrop)
|
return SetVerdict(pkt, -network.VerdictDrop)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -77,7 +87,7 @@ func (pkt *Packet) Drop() error {
|
||||||
// PermanentAccept permanently accepts connection (and the current packet).
|
// PermanentAccept permanently accepts connection (and the current packet).
|
||||||
func (pkt *Packet) PermanentAccept() error {
|
func (pkt *Packet) PermanentAccept() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, network.VerdictAccept)
|
return SetVerdict(pkt, network.VerdictAccept)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -85,7 +95,7 @@ func (pkt *Packet) PermanentAccept() error {
|
||||||
// PermanentBlock permanently blocks connection (and the current packet).
|
// PermanentBlock permanently blocks connection (and the current packet).
|
||||||
func (pkt *Packet) PermanentBlock() error {
|
func (pkt *Packet) PermanentBlock() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, network.VerdictBlock)
|
return SetVerdict(pkt, network.VerdictBlock)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -93,7 +103,7 @@ func (pkt *Packet) PermanentBlock() error {
|
||||||
// PermanentDrop permanently drops connection (and the current packet).
|
// PermanentDrop permanently drops connection (and the current packet).
|
||||||
func (pkt *Packet) PermanentDrop() error {
|
func (pkt *Packet) PermanentDrop() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, network.VerdictDrop)
|
return SetVerdict(pkt, network.VerdictDrop)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -101,7 +111,7 @@ func (pkt *Packet) PermanentDrop() error {
|
||||||
// RerouteToNameserver permanently reroutes the connection to the local nameserver (and the current packet).
|
// RerouteToNameserver permanently reroutes the connection to the local nameserver (and the current packet).
|
||||||
func (pkt *Packet) RerouteToNameserver() error {
|
func (pkt *Packet) RerouteToNameserver() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, network.VerdictRerouteToNameserver)
|
return SetVerdict(pkt, network.VerdictRerouteToNameserver)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -109,7 +119,7 @@ func (pkt *Packet) RerouteToNameserver() error {
|
||||||
// RerouteToTunnel permanently reroutes the connection to the local tunnel entrypoint (and the current packet).
|
// RerouteToTunnel permanently reroutes the connection to the local tunnel entrypoint (and the current packet).
|
||||||
func (pkt *Packet) RerouteToTunnel() error {
|
func (pkt *Packet) RerouteToTunnel() error {
|
||||||
if pkt.verdictSet.SetToIf(false, true) {
|
if pkt.verdictSet.SetToIf(false, true) {
|
||||||
return SetVerdict(pkt.verdictRequest.id, network.VerdictRerouteToTunnel)
|
return SetVerdict(pkt, network.VerdictRerouteToTunnel)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,12 @@ type Base struct {
|
||||||
layer5Data []byte
|
layer5Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FastTrackedByIntegration returns whether the packet has been fast-track
|
||||||
|
// accepted by the OS integration.
|
||||||
|
func (pkt *Base) FastTrackedByIntegration() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// SetCtx sets the packet context.
|
// SetCtx sets the packet context.
|
||||||
func (pkt *Base) SetCtx(ctx context.Context) {
|
func (pkt *Base) SetCtx(ctx context.Context) {
|
||||||
pkt.ctx = ctx
|
pkt.ctx = ctx
|
||||||
|
@ -222,6 +228,7 @@ type Packet interface {
|
||||||
PermanentDrop() error
|
PermanentDrop() error
|
||||||
RerouteToNameserver() error
|
RerouteToNameserver() error
|
||||||
RerouteToTunnel() error
|
RerouteToTunnel() error
|
||||||
|
FastTrackedByIntegration() bool
|
||||||
|
|
||||||
// INFO
|
// INFO
|
||||||
SetCtx(context.Context)
|
SetCtx(context.Context)
|
||||||
|
|
Loading…
Add table
Reference in a new issue