Add ICMP listener

This commit is contained in:
Daniel 2021-03-29 13:41:17 +02:00
parent 5d61b7b682
commit 259a0a8b22
2 changed files with 98 additions and 2 deletions

View file

@ -139,15 +139,29 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) {
switch meta.Protocol {
case packet.ICMP:
// Submit to ICMP listener.
submitted := netenv.SubmitPacketToICMPListener(pkt)
// Always permit ICMP.
log.Debugf("filter: fast-track accepting ICMP: %s", pkt)
_ = pkt.PermanentAccept()
if submitted {
_ = pkt.Accept()
} else {
_ = pkt.PermanentAccept()
}
return true
case packet.ICMPv6:
// Submit to ICMP listener.
submitted := netenv.SubmitPacketToICMPListener(pkt)
// Always permit ICMPv6.
log.Debugf("filter: fast-track accepting ICMPv6: %s", pkt)
_ = pkt.PermanentAccept()
if submitted {
_ = pkt.Accept()
} else {
_ = pkt.PermanentAccept()
}
return true
case packet.UDP, packet.TCP:

82
netenv/icmp_listener.go Normal file
View file

@ -0,0 +1,82 @@
package netenv
import (
"sync"
"github.com/tevino/abool"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/network/packet"
)
var (
// listenICMPLock locks the ICMP listening system for one user at a time.
listenICMPLock sync.Mutex
// listenICMPEnabled defines whether or not the firewall should send ICMP
// packets through this interface.
listenICMPEnabled = abool.New()
// listenICMPInput is created for every use of the ICMP listenting system.
listenICMPInput chan packet.Packet
listenICMPInputLock sync.Mutex
)
func ListenToICMP() (packets chan packet.Packet, done func()) {
// Lock for single use.
listenICMPLock.Lock()
// Create new input channel.
listenICMPInputLock.Lock()
listenICMPInput = make(chan packet.Packet, 10)
listenICMPEnabled.Set()
listenICMPInputLock.Unlock()
return listenICMPInput, func() {
// Close input channel.
listenICMPInputLock.Lock()
listenICMPEnabled.UnSet()
close(listenICMPInput)
listenICMPInputLock.Unlock()
// Release for someone else to use.
listenICMPLock.Unlock()
}
}
func SubmitPacketToICMPListener(pkt packet.Packet) (submitted bool) {
// Hot path.
if !listenICMPEnabled.IsSet() {
return false
}
// Slow path.
submitPacketToICMPListenerSlow(pkt)
return true
}
func submitPacketToICMPListenerSlow(pkt packet.Packet) {
// Make sure the payload is available.
if err := pkt.LoadPacketData(); err != nil {
log.Warningf("netenv: failed to get payload for ICMP listener: %s", err)
return
}
// Send to input channel.
listenICMPInputLock.Lock()
defer listenICMPInputLock.Unlock()
// Check if still enabled.
if !listenICMPEnabled.IsSet() {
return
}
log.Criticalf("netenv: recvd ICMP packet: %s", pkt)
// Send to channel, if possible.
select {
case listenICMPInput <- pkt:
default:
log.Warning("netenv: failed to send packet payload to ICMP listener: channel full")
}
}