Add bandwidth stats support

This commit is contained in:
Vladimir Stoilov 2024-01-29 22:23:54 +02:00
parent e308543f4f
commit 7babfb13ab
6 changed files with 185 additions and 75 deletions

View file

@ -30,14 +30,30 @@ func startInterception(packets chan packet.Packet) error {
// Start packet handler. // Start packet handler.
module.StartServiceWorker("kext packet handler", 0, func(ctx context.Context) error { module.StartServiceWorker("kext packet handler", 0, func(ctx context.Context) error {
windowskext.Handler(ctx, packets) windowskext.Handler(ctx, packets, BandwidthUpdates)
return nil return nil
}) })
// Start bandwidth stats monitor. // Start bandwidth stats monitor.
// module.StartServiceWorker("kext bandwidth stats monitor", 0, func(ctx context.Context) error { module.StartServiceWorker("kext bandwidth request worker", 0, func(ctx context.Context) error {
// return windowskext.BandwidthStatsWorker(ctx, 1*time.Second, BandwidthUpdates) timer := time.NewTicker(1 * time.Second)
// }) for {
select {
case <-timer.C:
{
err := windowskext.SendBandwidthStatsRequest()
if err != nil {
return err
}
}
case <-ctx.Done():
{
return nil
}
}
}
})
// Start kext logging. The worker will periodically send request to the kext to send logs. // Start kext logging. The worker will periodically send request to the kext to send logs.
module.StartServiceWorker("kext log request worker", 0, func(ctx context.Context) error { module.StartServiceWorker("kext log request worker", 0, func(ctx context.Context) error {

View file

@ -81,7 +81,7 @@ func reportBandwidth(ctx context.Context, bandwidthUpdates chan *packet.Bandwidt
return nil return nil
} }
func StartBandwithConsoleLogger() { func StartBandwidthConsoleLogger() {
go func() { go func() {
ticker := time.NewTicker(2 * time.Second) ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop() defer ticker.Stop()

View file

@ -6,6 +6,7 @@ package windowskext
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"time" "time"
"github.com/safing/portmaster/process" "github.com/safing/portmaster/process"
@ -28,7 +29,7 @@ func (v *VersionInfo) String() string {
} }
// Handler transforms received packets to the Packet interface. // Handler transforms received packets to the Packet interface.
func Handler(ctx context.Context, packets chan packet.Packet) { func Handler(ctx context.Context, packets chan packet.Packet, bandwidthUpdate chan *packet.BandwidthUpdate) {
for { for {
packetInfo, err := RecvVerdictRequest() packetInfo, err := RecvVerdictRequest()
if err != nil { if err != nil {
@ -36,9 +37,11 @@ func Handler(ctx context.Context, packets chan packet.Packet) {
return return
} }
if packetInfo.Connection != nil { switch {
log.Tracef("packet: %+v", packetInfo.Connection) case packetInfo.ConnectionV4 != nil:
conn := packetInfo.Connection {
log.Tracef("packet: %+v", packetInfo.ConnectionV4)
conn := packetInfo.ConnectionV4
// New Packet // New Packet
new := &Packet{ new := &Packet{
verdictRequest: conn.Id, verdictRequest: conn.Id,
@ -85,22 +88,106 @@ func Handler(ctx context.Context, packets chan packet.Packet) {
packets <- new packets <- new
} }
case packetInfo.ConnectionV6 != nil:
{
log.Tracef("packet: %+v", packetInfo.ConnectionV6)
conn := packetInfo.ConnectionV6
// New Packet
new := &Packet{
verdictRequest: conn.Id,
verdictSet: abool.NewBool(false),
}
info := new.Info()
info.Inbound = conn.Direction > 0
info.InTunnel = false
info.Protocol = packet.IPProtocol(conn.Protocol)
info.PID = int(conn.ProcessId)
info.SeenAt = time.Now()
// if packetInfo.LogLines != nil { // Check PID
// for _, line := range *packetInfo.LogLines { if info.PID == 0 {
// switch line.Severity { // Windows does not have zero PIDs.
// case int(log.DebugLevel): // Set to UndefinedProcessID.
// log.Debugf("kext: %s", line.Line) info.PID = process.UndefinedProcessID
// case int(log.InfoLevel): }
// log.Infof("kext: %s", line.Line)
// case int(log.WarningLevel): // Set IP version
// log.Warningf("kext: %s", line.Line) info.Version = packet.IPv6
// case int(log.ErrorLevel):
// log.Errorf("kext: %s", line.Line) // Set IPs
// case int(log.CriticalLevel): if info.Inbound {
// log.Criticalf("kext: %s", line.Line) // Inbound
// } info.Src = conn.RemoteIp[:]
// } info.Dst = conn.LocalIp[:]
// } } else {
// Outbound
info.Src = conn.LocalIp[:]
info.Dst = conn.RemoteIp[:]
}
// Set Ports
if info.Inbound {
// Inbound
info.SrcPort = conn.RemotePort
info.DstPort = conn.LocalPort
} else {
// Outbound
info.SrcPort = conn.LocalPort
info.DstPort = conn.RemotePort
}
packets <- new
}
case packetInfo.LogLine != nil:
{
line := packetInfo.LogLine
switch line.Severity {
case byte(log.DebugLevel):
log.Debugf("kext: %s", line.Line)
case byte(log.InfoLevel):
log.Infof("kext: %s", line.Line)
case byte(log.WarningLevel):
log.Warningf("kext: %s", line.Line)
case byte(log.ErrorLevel):
log.Errorf("kext: %s", line.Line)
case byte(log.CriticalLevel):
log.Criticalf("kext: %s", line.Line)
}
}
case packetInfo.BandwidthStats != nil:
{
bandwidthStats := packetInfo.BandwidthStats
for _, stat := range bandwidthStats.ValuesV4 {
connID := packet.CreateConnectionID(
packet.IPProtocol(bandwidthStats.Protocol),
net.IP(stat.LocalIP[:]), stat.LocalPort,
net.IP(stat.RemoteIP[:]), stat.RemotePort,
false,
)
update := &packet.BandwidthUpdate{
ConnID: connID,
BytesReceived: stat.ReceivedBytes,
BytesSent: stat.TransmittedBytes,
Method: packet.Additive,
}
bandwidthUpdate <- update
}
for _, stat := range bandwidthStats.ValuesV6 {
connID := packet.CreateConnectionID(
packet.IPProtocol(bandwidthStats.Protocol),
net.IP(stat.LocalIP[:]), stat.LocalPort,
net.IP(stat.RemoteIP[:]), stat.RemotePort,
false,
)
update := &packet.BandwidthUpdate{
ConnID: connID,
BytesReceived: stat.ReceivedBytes,
BytesSent: stat.TransmittedBytes,
Method: packet.Additive,
}
bandwidthUpdate <- update
}
}
}
} }
} }

View file

@ -77,37 +77,41 @@ func Stop() error {
// Sends a shutdown request. // Sends a shutdown request.
func shutdownRequest() error { func shutdownRequest() error {
return kext_interface.WriteShutdownCommand(kextFile) return kext_interface.SendShutdownCommand(kextFile)
} }
// Send request for logs of the kext. // Send request for logs of the kext.
func SendLogRequest() error { func SendLogRequest() error {
return kext_interface.WriteGetLogsCommand(kextFile) return kext_interface.SendGetLogsCommand(kextFile)
}
func SendBandwidthStatsRequest() error {
return kext_interface.SendGetBandwidthStatsCommand(kextFile)
} }
// RecvVerdictRequest waits for the next verdict request from the kext. If a timeout is reached, both *VerdictRequest and error will be nil. // RecvVerdictRequest waits for the next verdict request from the kext. If a timeout is reached, both *VerdictRequest and error will be nil.
func RecvVerdictRequest() (*kext_interface.Info, error) { func RecvVerdictRequest() (*kext_interface.Info, error) {
return kext_interface.ReadInfo(kextFile) return kext_interface.RecvInfo(kextFile)
} }
// SetVerdict sets the verdict for a packet and/or connection. // SetVerdict sets the verdict for a packet and/or connection.
func SetVerdict(pkt *Packet, verdict network.Verdict) error { func SetVerdict(pkt *Packet, verdict network.Verdict) error {
if verdict == network.VerdictRerouteToNameserver { if verdict == network.VerdictRerouteToNameserver {
redirect := kext_interface.RedirectV4{Id: pkt.verdictRequest, RemoteAddress: [4]uint8{127, 0, 0, 1}, RemotePort: 53} redirect := kext_interface.RedirectV4{Id: pkt.verdictRequest, RemoteAddress: [4]uint8{127, 0, 0, 1}, RemotePort: 53}
kext_interface.WriteRedirectCommand(kextFile, redirect) kext_interface.SendRedirectV4Command(kextFile, redirect)
} else if verdict == network.VerdictRerouteToTunnel { } else if verdict == network.VerdictRerouteToTunnel {
redirect := kext_interface.RedirectV4{Id: pkt.verdictRequest, RemoteAddress: [4]uint8{192, 168, 122, 196}, RemotePort: 717} redirect := kext_interface.RedirectV4{Id: pkt.verdictRequest, RemoteAddress: [4]uint8{192, 168, 122, 196}, RemotePort: 717}
kext_interface.WriteRedirectCommand(kextFile, redirect) kext_interface.SendRedirectV4Command(kextFile, redirect)
} else { } else {
verdict := kext_interface.Verdict{Id: pkt.verdictRequest, Verdict: uint8(verdict)} verdict := kext_interface.Verdict{Id: pkt.verdictRequest, Verdict: uint8(verdict)}
kext_interface.WriteVerdictCommand(kextFile, verdict) kext_interface.SendVerdictCommand(kextFile, verdict)
} }
return nil return nil
} }
// Clears the internal connection cache. // Clears the internal connection cache.
func ClearCache() error { func ClearCache() error {
return kext_interface.WriteClearCacheCommand(kextFile) return kext_interface.SendClearCacheCommand(kextFile)
} }
// Updates a specific connection verdict. // Updates a specific connection verdict.
@ -134,7 +138,7 @@ func UpdateVerdict(conn *network.Connection) error {
RedirectPort: uint16(redirectPort), RedirectPort: uint16(redirectPort),
} }
kext_interface.WriteUpdateCommand(kextFile, update) kext_interface.SendUpdateV4Command(kextFile, update)
return nil return nil
} }

View file

@ -4,6 +4,7 @@
package windowskext package windowskext
import ( import (
"fmt"
"sync" "sync"
"github.com/tevino/abool" "github.com/tevino/abool"
@ -42,7 +43,7 @@ func (pkt *Packet) ExpectInfo() bool {
// GetPayload returns the full raw packet. // GetPayload returns the full raw packet.
func (pkt *Packet) LoadPacketData() error { func (pkt *Packet) LoadPacketData() error {
return nil return fmt.Errorf("Not implemented")
} }
// Accept accepts the packet. // Accept accepts the packet.

2
go.mod
View file

@ -7,6 +7,8 @@ toolchain go1.21.2
// TODO: Remove when https://github.com/tc-hib/winres/pull/4 is merged or changes are otherwise integrated. // TODO: Remove when https://github.com/tc-hib/winres/pull/4 is merged or changes are otherwise integrated.
replace github.com/tc-hib/winres => github.com/dhaavi/winres v0.2.2 replace github.com/tc-hib/winres => github.com/dhaavi/winres v0.2.2
replace github.com/vlabo/portmaster_windows_rust_kext/kext_interface => /home/vladimir/Dev/Safing/portmaster_windows_rust_kext/kext_interface
require ( require (
github.com/Xuanwo/go-locale v1.1.0 github.com/Xuanwo/go-locale v1.1.0
github.com/agext/levenshtein v1.2.3 github.com/agext/levenshtein v1.2.3