mirror of
https://github.com/safing/portmaster
synced 2025-09-01 10:09:11 +00:00
Implement review suggestions
This commit is contained in:
parent
9f72660e8e
commit
bbb1c828e8
6 changed files with 87 additions and 38 deletions
|
@ -144,6 +144,10 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) {
|
||||||
|
|
||||||
// Always permit ICMP.
|
// Always permit ICMP.
|
||||||
log.Debugf("filter: fast-track accepting ICMP: %s", pkt)
|
log.Debugf("filter: fast-track accepting ICMP: %s", pkt)
|
||||||
|
|
||||||
|
// If the packet was submitted to the listener, we must not do a
|
||||||
|
// permanent accept, because then we won't see any future packets of that
|
||||||
|
// connection and thus cannot continue to submit them.
|
||||||
if submitted {
|
if submitted {
|
||||||
_ = pkt.Accept()
|
_ = pkt.Accept()
|
||||||
} else {
|
} else {
|
||||||
|
@ -157,6 +161,10 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) {
|
||||||
|
|
||||||
// Always permit ICMPv6.
|
// Always permit ICMPv6.
|
||||||
log.Debugf("filter: fast-track accepting ICMPv6: %s", pkt)
|
log.Debugf("filter: fast-track accepting ICMPv6: %s", pkt)
|
||||||
|
|
||||||
|
// If the packet was submitted to the listener, we must not do a
|
||||||
|
// permanent accept, because then we won't see any future packets of that
|
||||||
|
// connection and thus cannot continue to submit them.
|
||||||
if submitted {
|
if submitted {
|
||||||
_ = pkt.Accept()
|
_ = pkt.Accept()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,12 +9,25 @@ import (
|
||||||
"github.com/safing/portmaster/network/packet"
|
"github.com/safing/portmaster/network/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This ICMP listening system is a simple system for components to listen to ICMP
|
||||||
|
packets via the firewall.
|
||||||
|
|
||||||
|
The main use case for this is to receive ICMP packets that are not always
|
||||||
|
delivered correctly, or need special permissions and or sockets to receive
|
||||||
|
them. This is the case when doing a traceroute.
|
||||||
|
|
||||||
|
In order to keep it simple, the system is only designed to be used by one
|
||||||
|
"user" at at time. Further calls to ListenToICMP will wait for the previous
|
||||||
|
operation to complete.
|
||||||
|
*/
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// listenICMPLock locks the ICMP listening system for one user at a time.
|
// listenICMPLock locks the ICMP listening system for one user at a time.
|
||||||
listenICMPLock sync.Mutex
|
listenICMPLock sync.Mutex
|
||||||
|
|
||||||
// listenICMPEnabled defines whether or not the firewall should send ICMP
|
// listenICMPEnabled defines whether or not the firewall should submit ICMP
|
||||||
// packets through this interface.
|
// packets to this interface.
|
||||||
listenICMPEnabled = abool.New()
|
listenICMPEnabled = abool.New()
|
||||||
|
|
||||||
// listenICMPInput is created for every use of the ICMP listenting system.
|
// listenICMPInput is created for every use of the ICMP listenting system.
|
||||||
|
@ -22,28 +35,35 @@ var (
|
||||||
listenICMPInputLock sync.Mutex
|
listenICMPInputLock sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ListenToICMP returns a new channel for listenting to icmp packets. Please
|
||||||
|
// note that any icmp packet will be passed and filtering must be done on
|
||||||
|
// the side of the caller. The caller must call the returned done function when
|
||||||
|
// done with the listener.
|
||||||
func ListenToICMP() (packets chan packet.Packet, done func()) {
|
func ListenToICMP() (packets chan packet.Packet, done func()) {
|
||||||
// Lock for single use.
|
// Lock for single use.
|
||||||
listenICMPLock.Lock()
|
listenICMPLock.Lock()
|
||||||
|
|
||||||
// Create new input channel.
|
// Create new input channel.
|
||||||
listenICMPInputLock.Lock()
|
listenICMPInputLock.Lock()
|
||||||
listenICMPInput = make(chan packet.Packet, 10)
|
listenICMPInput = make(chan packet.Packet, 100)
|
||||||
listenICMPEnabled.Set()
|
listenICMPEnabled.Set()
|
||||||
listenICMPInputLock.Unlock()
|
listenICMPInputLock.Unlock()
|
||||||
|
|
||||||
return listenICMPInput, func() {
|
return listenICMPInput, func() {
|
||||||
|
// Release for someone else to use.
|
||||||
|
defer listenICMPLock.Unlock()
|
||||||
|
|
||||||
// Close input channel.
|
// Close input channel.
|
||||||
listenICMPInputLock.Lock()
|
listenICMPInputLock.Lock()
|
||||||
listenICMPEnabled.UnSet()
|
listenICMPEnabled.UnSet()
|
||||||
close(listenICMPInput)
|
close(listenICMPInput)
|
||||||
listenICMPInputLock.Unlock()
|
listenICMPInputLock.Unlock()
|
||||||
|
|
||||||
// Release for someone else to use.
|
|
||||||
listenICMPLock.Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubmitPacketToICMPListener checks if an ICMP packet should be submitted to
|
||||||
|
// the listener. If so, it is submitted right away. The function returns
|
||||||
|
// whether or not the packet should be submitted, not if it was successful.
|
||||||
func SubmitPacketToICMPListener(pkt packet.Packet) (submitted bool) {
|
func SubmitPacketToICMPListener(pkt packet.Packet) (submitted bool) {
|
||||||
// Hot path.
|
// Hot path.
|
||||||
if !listenICMPEnabled.IsSet() {
|
if !listenICMPEnabled.IsSet() {
|
||||||
|
@ -71,8 +91,6 @@ func submitPacketToICMPListenerSlow(pkt packet.Packet) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Criticalf("netenv: recvd ICMP packet: %s", pkt)
|
|
||||||
|
|
||||||
// Send to channel, if possible.
|
// Send to channel, if possible.
|
||||||
select {
|
select {
|
||||||
case listenICMPInput <- pkt:
|
case listenICMPInput <- pkt:
|
||||||
|
|
|
@ -66,6 +66,24 @@ type DeviceLocation struct {
|
||||||
SourceAccuracy int
|
SourceAccuracy int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsMoreAccurateThan checks if the device location is more accurate than the
|
||||||
|
// given one.
|
||||||
|
func (dl *DeviceLocation) IsMoreAccurateThan(other *DeviceLocation) bool {
|
||||||
|
switch {
|
||||||
|
case dl.SourceAccuracy > other.SourceAccuracy:
|
||||||
|
// Higher accuracy is better.
|
||||||
|
return true
|
||||||
|
case dl.ASN != 0 && other.ASN == 0:
|
||||||
|
// Having an ASN is better than having none.
|
||||||
|
return true
|
||||||
|
case dl.Country == "" && other.Country != "":
|
||||||
|
// Having a Country is better than having none.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type DeviceLocationSource string
|
type DeviceLocationSource string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -106,28 +124,6 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) {
|
||||||
SourceAccuracy: source.Accuracy(),
|
SourceAccuracy: source.Accuracy(),
|
||||||
}
|
}
|
||||||
|
|
||||||
locationsLock.Lock()
|
|
||||||
defer locationsLock.Unlock()
|
|
||||||
|
|
||||||
// Add to locations, if better.
|
|
||||||
key := loc.IP.String()
|
|
||||||
existing, ok := locations.All[key]
|
|
||||||
if ok && existing.SourceAccuracy > loc.SourceAccuracy {
|
|
||||||
// Existing entry is better.
|
|
||||||
// Return true, because the IP address is part of the locations.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
locations.All[key] = loc
|
|
||||||
|
|
||||||
// Find best location.
|
|
||||||
var best *DeviceLocation
|
|
||||||
for _, dl := range locations.All {
|
|
||||||
if best == nil || dl.SourceAccuracy > best.SourceAccuracy {
|
|
||||||
best = dl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
locations.Best = best
|
|
||||||
|
|
||||||
// Get geoip information, but continue if it fails.
|
// Get geoip information, but continue if it fails.
|
||||||
geoLoc, err := geoip.GetLocation(ip)
|
geoLoc, err := geoip.GetLocation(ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -139,6 +135,28 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) {
|
||||||
loc.ASOrg = geoLoc.AutonomousSystemOrganization
|
loc.ASOrg = geoLoc.AutonomousSystemOrganization
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locationsLock.Lock()
|
||||||
|
defer locationsLock.Unlock()
|
||||||
|
|
||||||
|
// Add to locations, if better.
|
||||||
|
key := loc.IP.String()
|
||||||
|
existing, ok := locations.All[key]
|
||||||
|
if ok && existing.IsMoreAccurateThan(loc) {
|
||||||
|
// Existing entry is more accurate, abort adding.
|
||||||
|
// Return true, because the IP address is already part of the locations.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
locations.All[key] = loc
|
||||||
|
|
||||||
|
// Find best location.
|
||||||
|
best := loc
|
||||||
|
for _, dl := range locations.All {
|
||||||
|
if dl.IsMoreAccurateThan(best) {
|
||||||
|
best = dl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locations.Best = best
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,15 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
networkChangeCheckTrigger = make(chan struct{}, 1)
|
networkChangeCheckTrigger = make(chan struct{}, 1)
|
||||||
networkChangedFlagController = utils.NewFlagController()
|
networkChangedBroadcastFlag = utils.NewBroadcastFlag()
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetNetworkChangedFlag() *utils.Flag {
|
func GetNetworkChangedFlag() *utils.Flag {
|
||||||
return networkChangedFlagController.NewFlag()
|
return networkChangedBroadcastFlag.NewFlag()
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifyOfNetworkChange() {
|
func notifyOfNetworkChange() {
|
||||||
networkChangedFlagController.NotifyAndReset()
|
networkChangedBroadcastFlag.NotifyAndReset()
|
||||||
module.TriggerEvent(NetworkChangedEvent, nil)
|
module.TriggerEvent(NetworkChangedEvent, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,8 +144,8 @@ func Parse(packetData []byte, pktBase *Base) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pktBase.layers = packet
|
pktBase.layers = packet
|
||||||
if packet.TransportLayer() != nil {
|
if transport := packet.TransportLayer(); transport != nil {
|
||||||
pktBase.layer5Data = packet.TransportLayer().LayerPayload()
|
pktBase.layer5Data = transport.LayerPayload()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,13 @@ func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {
|
||||||
// Check if this is the system resolver.
|
// Check if this is the system resolver.
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
if (p.Path == `C:\Windows\System32\svchost.exe` || p.Path == `C:\Windows\system32\svchost.exe`) &&
|
// Depending on the OS version System32 may be capitalized or not.
|
||||||
(strings.Contains(p.SpecialDetail, "Dnscache") || strings.Contains(p.CmdLine, "-s Dnscache")) {
|
if (p.Path == `C:\Windows\System32\svchost.exe` ||
|
||||||
|
p.Path == `C:\Windows\system32\svchost.exe`) &&
|
||||||
|
// This comes from the windows tasklist command and should be pretty consistent.
|
||||||
|
(strings.Contains(p.SpecialDetail, "Dnscache") ||
|
||||||
|
// As an alternative in case of failure, we try to match the svchost.exe service parameter.
|
||||||
|
strings.Contains(p.CmdLine, "-s Dnscache")) {
|
||||||
profileID = profile.SystemResolverProfileID
|
profileID = profile.SystemResolverProfileID
|
||||||
}
|
}
|
||||||
case "linux":
|
case "linux":
|
||||||
|
|
Loading…
Add table
Reference in a new issue