mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
// +build linux
|
|
|
|
package nfqexp
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/florianl/go-nfqueue"
|
|
"github.com/mdlayher/netlink"
|
|
"github.com/safing/portbase/log"
|
|
pmpacket "github.com/safing/portmaster/network/packet"
|
|
)
|
|
|
|
// Firewalling marks used by the Portmaster.
|
|
// See TODO on packet.mark() on their relevance
|
|
// and a possibility to remove most IPtables rules.
|
|
const (
|
|
MarkAccept = 1700
|
|
MarkBlock = 1701
|
|
MarkDrop = 1702
|
|
MarkAcceptAlways = 1710
|
|
MarkBlockAlways = 1711
|
|
MarkDropAlways = 1712
|
|
MarkRerouteNS = 1799
|
|
MarkRerouteSPN = 1717
|
|
)
|
|
|
|
func markToString(mark int) string {
|
|
switch mark {
|
|
case MarkAccept:
|
|
return "Accept"
|
|
case MarkBlock:
|
|
return "Block"
|
|
case MarkDrop:
|
|
return "Drop"
|
|
case MarkAcceptAlways:
|
|
return "AcceptAlways"
|
|
case MarkBlockAlways:
|
|
return "BlockAlways"
|
|
case MarkDropAlways:
|
|
return "DropAlways"
|
|
case MarkRerouteNS:
|
|
return "RerouteNS"
|
|
case MarkRerouteSPN:
|
|
return "RerouteSPN"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// packet implements the packet.Packet interface.
|
|
type packet struct {
|
|
pmpacket.Base
|
|
ID uint32
|
|
received time.Time
|
|
queue *Queue
|
|
verdictSet chan struct{}
|
|
}
|
|
|
|
// TODO(ppacher): revisit the following behavior:
|
|
// The legacy implementation of nfqueue (and the interception) module
|
|
// always accept a packet but may mark it so that a subsequent rule in
|
|
// the C17 chain drops, rejects or modifies it.
|
|
//
|
|
// For drop/return we could use the actual nfQueue verdicts Drop and Stop.
|
|
// Re-routing to local NS or SPN can be done by modifying the packet here
|
|
// and using SetVerdictModPacket and reject can be implemented using a simple
|
|
// raw-socket.
|
|
//
|
|
func (pkt *packet) mark(mark int) (err error) {
|
|
defer func() {
|
|
if x := recover(); x != nil {
|
|
err = errors.New("verdict set")
|
|
}
|
|
}()
|
|
for {
|
|
if err := pkt.queue.nf.SetVerdictWithMark(pkt.ID, nfqueue.NfAccept, mark); err != nil {
|
|
log.Warningf("nfqexp: failed to set verdict %s for %d (%s -> %s): %s", markToString(mark), pkt.ID, pkt.Info().Src, pkt.Info().Dst, err)
|
|
if opErr, ok := err.(*netlink.OpError); ok {
|
|
if opErr.Timeout() || opErr.Temporary() {
|
|
continue
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|
|
break
|
|
}
|
|
log.Tracef("nfqexp: marking packet %d (%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))
|
|
close(pkt.verdictSet)
|
|
return nil
|
|
}
|
|
|
|
func (pkt *packet) Accept() error {
|
|
return pkt.mark(MarkAccept)
|
|
}
|
|
|
|
func (pkt *packet) Block() error {
|
|
return pkt.mark(MarkBlock)
|
|
}
|
|
|
|
func (pkt *packet) Drop() error {
|
|
return pkt.mark(MarkDrop)
|
|
}
|
|
|
|
func (pkt *packet) PermanentAccept() error {
|
|
return pkt.mark(MarkAcceptAlways)
|
|
}
|
|
|
|
func (pkt *packet) PermanentBlock() error {
|
|
return pkt.mark(MarkBlockAlways)
|
|
}
|
|
|
|
func (pkt *packet) PermanentDrop() error {
|
|
return pkt.mark(MarkDropAlways)
|
|
}
|
|
|
|
func (pkt *packet) RerouteToNameserver() error {
|
|
return pkt.mark(MarkRerouteNS)
|
|
}
|
|
|
|
func (pkt *packet) RerouteToTunnel() error {
|
|
return pkt.mark(MarkRerouteSPN)
|
|
}
|