Add simple packet metrics

This commit is contained in:
Patrick Pacher 2020-10-01 11:30:18 +02:00
parent c01d61dcd9
commit 7a83e772f4
No known key found for this signature in database
GPG key ID: E8CD2DA160925A6D
7 changed files with 181 additions and 17 deletions

View file

@ -25,7 +25,18 @@ func Start() error {
return nil
}
return start()
var ch = Packets
if packetMetricsDestination != "" {
go metrics.writeMetrics()
ch = make(chan packet.Packet)
go func() {
for p := range ch {
Packets <- tracePacket(p)
}
}()
}
return start(ch)
}
// Stop starts the interception.
@ -34,5 +45,7 @@ func Stop() error {
return nil
}
close(metrics.done)
return stop()
}

View file

@ -7,7 +7,7 @@ import (
)
// 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")
return nil
}

View file

@ -1,8 +1,10 @@
package interception
import "github.com/safing/portmaster/network/packet"
// start starts the interception.
func start() error {
return StartNfqueueInterception()
func start(ch chan packet.Packet) error {
return StartNfqueueInterception(ch)
}
// stop starts the interception.

View file

@ -7,11 +7,12 @@ import (
"github.com/safing/portbase/notifications"
"github.com/safing/portbase/utils/osdetail"
"github.com/safing/portmaster/firewall/interception/windowskext"
"github.com/safing/portmaster/network/packet"
"github.com/safing/portmaster/updates"
)
// start starts the interception.
func start() error {
func start(ch chan packet.Packet) error {
dllFile, err := updates.GetPlatformFile("kext/portmaster-kext.dll")
if err != nil {
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)
}
go windowskext.Handler(Packets)
go windowskext.Handler(ch)
go handleWindowsDNSCache()
return nil

View 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, "packet-metrics", "", "Write packet metrics")
}
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))
}
}
}

View file

@ -223,7 +223,7 @@ func deactivateIPTables(protocol iptables.Protocol, rules, chains []string) erro
}
// StartNfqueueInterception starts the nfqueue interception.
func StartNfqueueInterception() (err error) {
func StartNfqueueInterception(packets chan<- packet.Packet) (err error) {
// @deprecated, remove in v1
if experimentalNfqueueBackend {
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)
}
go handleInterception()
go handleInterception(packets)
return nil
}
@ -286,23 +286,26 @@ func StopNfqueueInterception() error {
return nil
}
func handleInterception() {
func handleInterception(packets chan<- packet.Packet) {
for {
var pkt packet.Packet
select {
case <-shutdownSignal:
return
case pkt := <-out4Queue.PacketChannel():
case pkt = <-out4Queue.PacketChannel():
pkt.SetOutbound()
Packets <- pkt
case pkt := <-in4Queue.PacketChannel():
case pkt = <-in4Queue.PacketChannel():
pkt.SetInbound()
Packets <- pkt
case pkt := <-out6Queue.PacketChannel():
case pkt = <-out6Queue.PacketChannel():
pkt.SetOutbound()
Packets <- pkt
case pkt := <-in6Queue.PacketChannel():
case pkt = <-in6Queue.PacketChannel():
pkt.SetInbound()
Packets <- pkt
}
select {
case packets <- pkt:
case <-shutdownSignal:
return
}
}
}

View 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()
}