mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
Merge pull request #167 from safing/feature/packet-metrics
Add simple packet metrics
This commit is contained in:
commit
a385423634
7 changed files with 181 additions and 17 deletions
|
@ -25,7 +25,18 @@ func Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return start()
|
var inputPackets = Packets
|
||||||
|
if packetMetricsDestination != "" {
|
||||||
|
go metrics.writeMetrics()
|
||||||
|
inputPackets = make(chan packet.Packet)
|
||||||
|
go func() {
|
||||||
|
for p := range inputPackets {
|
||||||
|
Packets <- tracePacket(p)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
return start(inputPackets)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop starts the interception.
|
// Stop starts the interception.
|
||||||
|
@ -34,5 +45,7 @@ func Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(metrics.done)
|
||||||
|
|
||||||
return stop()
|
return stop()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// start starts the interception.
|
// start starts the interception.
|
||||||
func start() error {
|
func start(ch chan packet.Packet) error {
|
||||||
log.Info("interception: this platform has no support for packet interception - a lot of functionality will be broken")
|
log.Info("interception: this platform has no support for packet interception - a lot of functionality will be broken")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package interception
|
package interception
|
||||||
|
|
||||||
|
import "github.com/safing/portmaster/network/packet"
|
||||||
|
|
||||||
// start starts the interception.
|
// start starts the interception.
|
||||||
func start() error {
|
func start(ch chan packet.Packet) error {
|
||||||
return StartNfqueueInterception()
|
return StartNfqueueInterception(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop starts the interception.
|
// stop starts the interception.
|
||||||
|
|
|
@ -7,11 +7,12 @@ import (
|
||||||
"github.com/safing/portbase/notifications"
|
"github.com/safing/portbase/notifications"
|
||||||
"github.com/safing/portbase/utils/osdetail"
|
"github.com/safing/portbase/utils/osdetail"
|
||||||
"github.com/safing/portmaster/firewall/interception/windowskext"
|
"github.com/safing/portmaster/firewall/interception/windowskext"
|
||||||
|
"github.com/safing/portmaster/network/packet"
|
||||||
"github.com/safing/portmaster/updates"
|
"github.com/safing/portmaster/updates"
|
||||||
)
|
)
|
||||||
|
|
||||||
// start starts the interception.
|
// start starts the interception.
|
||||||
func start() error {
|
func start(ch chan packet.Packet) error {
|
||||||
dllFile, err := updates.GetPlatformFile("kext/portmaster-kext.dll")
|
dllFile, err := updates.GetPlatformFile("kext/portmaster-kext.dll")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("interception: could not get kext dll: %s", err)
|
return fmt.Errorf("interception: could not get kext dll: %s", err)
|
||||||
|
@ -31,7 +32,7 @@ func start() error {
|
||||||
return fmt.Errorf("interception: could not start windows kext: %s", err)
|
return fmt.Errorf("interception: could not start windows kext: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go windowskext.Handler(Packets)
|
go windowskext.Handler(ch)
|
||||||
go handleWindowsDNSCache()
|
go handleWindowsDNSCache()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
78
firewall/interception/introspection.go
Normal file
78
firewall/interception/introspection.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package interception
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
packetMetricsDestination string
|
||||||
|
metrics = &packetMetrics{
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&packetMetricsDestination, "write-packet-metrics", "", "Write packet metrics to the specified file")
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
performanceRecord struct {
|
||||||
|
start int64
|
||||||
|
duration time.Duration
|
||||||
|
verdict string
|
||||||
|
}
|
||||||
|
|
||||||
|
packetMetrics struct {
|
||||||
|
done chan struct{}
|
||||||
|
l sync.Mutex
|
||||||
|
records []*performanceRecord
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (pm *packetMetrics) record(tp *tracedPacket, verdict string) {
|
||||||
|
go func(start int64, duration time.Duration) {
|
||||||
|
pm.l.Lock()
|
||||||
|
defer pm.l.Unlock()
|
||||||
|
|
||||||
|
pm.records = append(pm.records, &performanceRecord{
|
||||||
|
start: start,
|
||||||
|
duration: duration,
|
||||||
|
verdict: verdict,
|
||||||
|
})
|
||||||
|
}(tp.start.UnixNano(), time.Since(tp.start))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *packetMetrics) writeMetrics() {
|
||||||
|
if packetMetricsDestination == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(packetMetricsDestination)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to create packet metrics file: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-pm.done:
|
||||||
|
return
|
||||||
|
case <-time.After(time.Second * 5):
|
||||||
|
}
|
||||||
|
pm.l.Lock()
|
||||||
|
records := pm.records
|
||||||
|
pm.records = nil
|
||||||
|
pm.l.Unlock()
|
||||||
|
|
||||||
|
for _, r := range records {
|
||||||
|
fmt.Fprintf(f, "%d;%s;%s;%.2f\n", r.start, r.verdict, r.duration, float64(r.duration)/float64(time.Microsecond))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -223,7 +223,7 @@ func deactivateIPTables(protocol iptables.Protocol, rules, chains []string) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartNfqueueInterception starts the nfqueue interception.
|
// StartNfqueueInterception starts the nfqueue interception.
|
||||||
func StartNfqueueInterception() (err error) {
|
func StartNfqueueInterception(packets chan<- packet.Packet) (err error) {
|
||||||
// @deprecated, remove in v1
|
// @deprecated, remove in v1
|
||||||
if experimentalNfqueueBackend {
|
if experimentalNfqueueBackend {
|
||||||
log.Warningf("[DEPRECATED] --experimental-nfqueue has been deprecated as the backend is now used by default")
|
log.Warningf("[DEPRECATED] --experimental-nfqueue has been deprecated as the backend is now used by default")
|
||||||
|
@ -257,7 +257,7 @@ func StartNfqueueInterception() (err error) {
|
||||||
return fmt.Errorf("nfqueue(IPv6, in): %w", err)
|
return fmt.Errorf("nfqueue(IPv6, in): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go handleInterception()
|
go handleInterception(packets)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,23 +286,26 @@ func StopNfqueueInterception() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleInterception() {
|
func handleInterception(packets chan<- packet.Packet) {
|
||||||
for {
|
for {
|
||||||
|
var pkt packet.Packet
|
||||||
select {
|
select {
|
||||||
case <-shutdownSignal:
|
case <-shutdownSignal:
|
||||||
return
|
return
|
||||||
case pkt := <-out4Queue.PacketChannel():
|
case pkt = <-out4Queue.PacketChannel():
|
||||||
pkt.SetOutbound()
|
pkt.SetOutbound()
|
||||||
Packets <- pkt
|
case pkt = <-in4Queue.PacketChannel():
|
||||||
case pkt := <-in4Queue.PacketChannel():
|
|
||||||
pkt.SetInbound()
|
pkt.SetInbound()
|
||||||
Packets <- pkt
|
case pkt = <-out6Queue.PacketChannel():
|
||||||
case pkt := <-out6Queue.PacketChannel():
|
|
||||||
pkt.SetOutbound()
|
pkt.SetOutbound()
|
||||||
Packets <- pkt
|
case pkt = <-in6Queue.PacketChannel():
|
||||||
case pkt := <-in6Queue.PacketChannel():
|
|
||||||
pkt.SetInbound()
|
pkt.SetInbound()
|
||||||
Packets <- pkt
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case packets <- pkt:
|
||||||
|
case <-shutdownSignal:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
67
firewall/interception/packet_tracer.go
Normal file
67
firewall/interception/packet_tracer.go
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package interception
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/safing/portmaster/network/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tracedPacket struct {
|
||||||
|
start time.Time
|
||||||
|
packet.Packet
|
||||||
|
}
|
||||||
|
|
||||||
|
func tracePacket(p packet.Packet) packet.Packet {
|
||||||
|
return &tracedPacket{
|
||||||
|
start: time.Now(),
|
||||||
|
Packet: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) markServed(v string) {
|
||||||
|
if packetMetricsDestination == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics.record(p, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) Accept() error {
|
||||||
|
defer p.markServed("accept")
|
||||||
|
return p.Packet.Accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) Block() error {
|
||||||
|
defer p.markServed("block")
|
||||||
|
return p.Packet.Block()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) Drop() error {
|
||||||
|
defer p.markServed("drop")
|
||||||
|
return p.Packet.Drop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) PermanentAccept() error {
|
||||||
|
defer p.markServed("perm-accept")
|
||||||
|
return p.Packet.PermanentAccept()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) PermanentBlock() error {
|
||||||
|
defer p.markServed("perm-block")
|
||||||
|
return p.Packet.PermanentBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) PermanentDrop() error {
|
||||||
|
defer p.markServed("perm-drop")
|
||||||
|
return p.Packet.PermanentDrop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) RerouteToNameserver() error {
|
||||||
|
defer p.markServed("reroute-ns")
|
||||||
|
return p.Packet.RerouteToNameserver()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tracedPacket) RerouteToTunnel() error {
|
||||||
|
defer p.markServed("reroute-tunnel")
|
||||||
|
return p.Packet.RerouteToTunnel()
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue