mirror of
https://github.com/safing/portmaster
synced 2025-09-02 18:49:14 +00:00
Improve handling of unknown links, improve reason messages
This commit is contained in:
parent
12e1eb0917
commit
ca508fd20f
3 changed files with 83 additions and 57 deletions
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/Safing/portmaster/firewall/interception"
|
"github.com/Safing/portmaster/firewall/interception"
|
||||||
"github.com/Safing/portmaster/network"
|
"github.com/Safing/portmaster/network"
|
||||||
"github.com/Safing/portmaster/network/packet"
|
"github.com/Safing/portmaster/network/packet"
|
||||||
"github.com/Safing/portmaster/process"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -92,8 +91,8 @@ func handlePacket(pkt packet.Packet) {
|
||||||
|
|
||||||
// log.Tracef("handling packet: %s", pkt)
|
// log.Tracef("handling packet: %s", pkt)
|
||||||
|
|
||||||
// allow anything local, that is not dns
|
// allow local dns
|
||||||
if pkt.MatchesIP(packet.Remote, localNet4) && !(pkt.GetTCPUDPHeader() != nil && pkt.GetTCPUDPHeader().DstPort == 53) {
|
if pkt.MatchesIP(packet.Remote, localNet4) && pkt.GetTCPUDPHeader() != nil && pkt.GetTCPUDPHeader().DstPort == 53 {
|
||||||
pkt.PermanentAccept()
|
pkt.PermanentAccept()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -150,24 +149,19 @@ func initialHandler(pkt packet.Packet, link *network.Link) {
|
||||||
// get Connection
|
// get Connection
|
||||||
connection, err := network.GetConnectionByFirstPacket(pkt)
|
connection, err := network.GetConnectionByFirstPacket(pkt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != process.ErrConnectionNotFound {
|
// get "unknown" connection
|
||||||
log.Warningf("firewall: could not find process of packet (dropping link %s): %s", pkt.String(), err)
|
link.Deny(fmt.Sprintf("could not get process: %s", err))
|
||||||
link.Deny(fmt.Sprintf("could not find process or it does not exist (unsolicited packet): %s", err))
|
connection, err = network.GetUnknownConnection(pkt)
|
||||||
} else {
|
|
||||||
log.Warningf("firewall: internal error finding process of packet (dropping link %s): %s", pkt.String(), err)
|
if err != nil {
|
||||||
link.Deny(fmt.Sprintf("internal error finding process: %s", err))
|
// all failed
|
||||||
|
log.Errorf("firewall: could not get unknown connection (dropping %s): %s", pkt.String(), err)
|
||||||
|
link.UpdateVerdict(network.DROP)
|
||||||
|
verdict(pkt, network.DROP)
|
||||||
|
link.StopFirewallHandler()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkt.IsInbound() {
|
|
||||||
network.UnknownIncomingConnection.AddLink(link)
|
|
||||||
} else {
|
|
||||||
network.UnknownDirectConnection.AddLink(link)
|
|
||||||
}
|
|
||||||
|
|
||||||
verdict(pkt, link.GetVerdict())
|
|
||||||
link.StopFirewallHandler()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new Link to Connection (and save both)
|
// add new Link to Connection (and save both)
|
||||||
|
@ -195,15 +189,15 @@ func initialHandler(pkt packet.Packet, link *network.Link) {
|
||||||
logInitialVerdict(link)
|
logInitialVerdict(link)
|
||||||
|
|
||||||
// TODO: link this to real status
|
// TODO: link this to real status
|
||||||
// port17Active := mode.Client()
|
// gate17Active := mode.Client()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// case port17Active && link.Inspect:
|
// case gate17Active && link.Inspect:
|
||||||
// // tunnel link, but also inspect (after reroute)
|
// // tunnel link, but also inspect (after reroute)
|
||||||
// link.Tunneled = true
|
// link.Tunneled = true
|
||||||
// link.SetFirewallHandler(inspectThenVerdict)
|
// link.SetFirewallHandler(inspectThenVerdict)
|
||||||
// verdict(pkt, link.GetVerdict())
|
// verdict(pkt, link.GetVerdict())
|
||||||
// case port17Active:
|
// case gate17Active:
|
||||||
// // tunnel link, don't inspect
|
// // tunnel link, don't inspect
|
||||||
// link.Tunneled = true
|
// link.Tunneled = true
|
||||||
// link.StopFirewallHandler()
|
// link.StopFirewallHandler()
|
||||||
|
|
|
@ -44,8 +44,8 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string)
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profileSet := connection.Process().ProfileSet()
|
profileSet := connection.Process().ProfileSet()
|
||||||
if profileSet == nil {
|
if profileSet == nil {
|
||||||
log.Errorf("firewall: denying connection %s, no profile set", connection)
|
log.Errorf("firewall: denying connection %s, no Profile Set", connection)
|
||||||
connection.Deny("no profile set")
|
connection.Deny("no Profile Set")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
profileSet.Update(status.ActiveSecurityLevel())
|
profileSet.Update(status.ActiveSecurityLevel())
|
||||||
|
@ -64,8 +64,8 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string)
|
||||||
log.Infof("firewall: accepting connection %s, endpoint is whitelisted: %s", connection, reason)
|
log.Infof("firewall: accepting connection %s, endpoint is whitelisted: %s", connection, reason)
|
||||||
connection.Accept(fmt.Sprintf("endpoint is whitelisted: %s", reason))
|
connection.Accept(fmt.Sprintf("endpoint is whitelisted: %s", reason))
|
||||||
} else {
|
} else {
|
||||||
log.Infof("firewall: denying connection %s, endpoint is blacklisted", connection)
|
log.Infof("firewall: denying connection %s, endpoint is blacklisted: %s", connection, reason)
|
||||||
connection.Deny("endpoint is blacklisted")
|
connection.Deny(fmt.Sprintf("endpoint is blacklisted: %s", reason))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if matched {
|
if matched {
|
||||||
log.Infof("firewall: accepting connection %s, match to domain was found: %s ~= %s", connection, domainElement, processElement)
|
log.Infof("firewall: accepting connection %s, match to domain was found: %s ~== %s", connection, domainElement, processElement)
|
||||||
connection.Accept("domain is related to process")
|
connection.Accept("domain is related to process")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,8 +148,8 @@ func DecideOnConnectionAfterIntel(connection *network.Connection, fqdn string, r
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profileSet := connection.Process().ProfileSet()
|
profileSet := connection.Process().ProfileSet()
|
||||||
if profileSet == nil {
|
if profileSet == nil {
|
||||||
log.Errorf("firewall: denying connection %s, no profile set", connection)
|
log.Errorf("firewall: denying connection %s, no Profile Set", connection)
|
||||||
connection.Deny("no profile")
|
connection.Deny("no Profile Set")
|
||||||
return rrCache
|
return rrCache
|
||||||
}
|
}
|
||||||
profileSet.Update(status.ActiveSecurityLevel())
|
profileSet.Update(status.ActiveSecurityLevel())
|
||||||
|
@ -184,8 +184,8 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) {
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profileSet := connection.Process().ProfileSet()
|
profileSet := connection.Process().ProfileSet()
|
||||||
if profileSet == nil {
|
if profileSet == nil {
|
||||||
log.Errorf("firewall: denying connection %s, no profile set", connection)
|
log.Errorf("firewall: denying connection %s, no Profile Set", connection)
|
||||||
connection.Deny("no profile")
|
connection.Deny("no Profile Set")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
profileSet.Update(status.ActiveSecurityLevel())
|
profileSet.Update(status.ActiveSecurityLevel())
|
||||||
|
@ -209,7 +209,6 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check network scope
|
// check network scope
|
||||||
|
@ -282,8 +281,8 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profileSet := connection.Process().ProfileSet()
|
profileSet := connection.Process().ProfileSet()
|
||||||
if profileSet == nil {
|
if profileSet == nil {
|
||||||
log.Infof("firewall: no profile, denying %s", link)
|
log.Infof("firewall: no Profile Set, denying %s", link)
|
||||||
link.Block("no profile")
|
link.Block("no Profile Set")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
profileSet.Update(status.ActiveSecurityLevel())
|
profileSet.Update(status.ActiveSecurityLevel())
|
||||||
|
@ -314,7 +313,7 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
log.Infof("firewall: accepting link %s, endpoint is whitelisted: %s", link, reason)
|
log.Infof("firewall: accepting link %s, endpoint is whitelisted: %s", link, reason)
|
||||||
link.Accept(fmt.Sprintf("port whitelisted: %s", reason))
|
link.Accept(fmt.Sprintf("port whitelisted: %s", reason))
|
||||||
} else {
|
} else {
|
||||||
log.Infof("firewall: denying link %s: port %d is blacklisted", link, dstPort)
|
log.Infof("firewall: denying link %s: endpoint is blacklisted: %s", link, reason)
|
||||||
link.Deny("port blacklisted")
|
link.Deny("port blacklisted")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -322,15 +321,15 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
|
|
||||||
switch profileSet.GetProfileMode() {
|
switch profileSet.GetProfileMode() {
|
||||||
case profile.Whitelist:
|
case profile.Whitelist:
|
||||||
log.Infof("firewall: denying link %s: endpoint %d is not whitelisted", link, dstPort)
|
log.Infof("firewall: denying link %s: endpoint is not whitelisted", link)
|
||||||
link.Deny("endpoint is not whitelisted")
|
link.Deny("endpoint is not whitelisted")
|
||||||
return
|
return
|
||||||
case profile.Prompt:
|
case profile.Prompt:
|
||||||
log.Infof("firewall: accepting link %s: endpoint %d is blacklisted", link, dstPort)
|
log.Infof("firewall: accepting link %s: endpoint is not blacklisted (prompting is not yet implemented)", link)
|
||||||
link.Accept("endpoint permitted (prompting is not yet implemented)")
|
link.Accept("endpoint is not blacklisted (prompting is not yet implemented)")
|
||||||
return
|
return
|
||||||
case profile.Blacklist:
|
case profile.Blacklist:
|
||||||
log.Infof("firewall: accepting link %s: endpoint %d is not blacklisted", link, dstPort)
|
log.Infof("firewall: accepting link %s: endpoint is not blacklisted", link)
|
||||||
link.Accept("endpoint is not blacklisted")
|
link.Accept("endpoint is not blacklisted")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,64 @@
|
||||||
package network
|
package network
|
||||||
|
|
||||||
import "github.com/Safing/portmaster/process"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Safing/portmaster/network/netutils"
|
||||||
|
"github.com/Safing/portmaster/network/packet"
|
||||||
|
"github.com/Safing/portmaster/process"
|
||||||
|
)
|
||||||
|
|
||||||
// Static reasons
|
// Static reasons
|
||||||
const (
|
const (
|
||||||
ReasonUnknownProcess = "unknown connection owner: process could not be found"
|
ReasonUnknownProcess = "unknown connection owner: process could not be found"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// GetUnknownConnection returns the connection to a packet of unknown owner.
|
||||||
UnknownDirectConnection = &Connection{
|
func GetUnknownConnection(pkt packet.Packet) (*Connection, error) {
|
||||||
Domain: "PI",
|
if pkt.IsInbound() {
|
||||||
Direction: Outbound,
|
switch netutils.ClassifyIP(pkt.GetIPHeader().Src) {
|
||||||
Verdict: DROP,
|
case netutils.HostLocal:
|
||||||
Reason: ReasonUnknownProcess,
|
return getOrCreateUnknownConnection(pkt, IncomingHost)
|
||||||
process: process.UnknownProcess,
|
case netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast:
|
||||||
|
return getOrCreateUnknownConnection(pkt, IncomingLAN)
|
||||||
|
case netutils.Global, netutils.GlobalMulticast:
|
||||||
|
return getOrCreateUnknownConnection(pkt, IncomingInternet)
|
||||||
|
case netutils.Invalid:
|
||||||
|
return getOrCreateUnknownConnection(pkt, IncomingInvalid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnknownIncomingConnection = &Connection{
|
switch netutils.ClassifyIP(pkt.GetIPHeader().Dst) {
|
||||||
Domain: "II",
|
case netutils.HostLocal:
|
||||||
Direction: Inbound,
|
return getOrCreateUnknownConnection(pkt, PeerHost)
|
||||||
Verdict: DROP,
|
case netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast:
|
||||||
Reason: ReasonUnknownProcess,
|
return getOrCreateUnknownConnection(pkt, PeerLAN)
|
||||||
process: process.UnknownProcess,
|
case netutils.Global, netutils.GlobalMulticast:
|
||||||
|
return getOrCreateUnknownConnection(pkt, PeerInternet)
|
||||||
|
case netutils.Invalid:
|
||||||
|
return getOrCreateUnknownConnection(pkt, PeerInvalid)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
// this should never happen
|
||||||
UnknownDirectConnection.Save()
|
return getOrCreateUnknownConnection(pkt, PeerInvalid)
|
||||||
UnknownIncomingConnection.Save()
|
}
|
||||||
|
|
||||||
|
func getOrCreateUnknownConnection(pkt packet.Packet, connClass string) (*Connection, error) {
|
||||||
|
connection, ok := GetConnection(process.UnknownProcess.Pid, connClass)
|
||||||
|
if !ok {
|
||||||
|
connection = &Connection{
|
||||||
|
Domain: connClass,
|
||||||
|
Direction: pkt.IsInbound(),
|
||||||
|
Verdict: DROP,
|
||||||
|
Reason: ReasonUnknownProcess,
|
||||||
|
process: process.UnknownProcess,
|
||||||
|
Inspect: true,
|
||||||
|
FirstLinkEstablished: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
if pkt.IsOutbound() {
|
||||||
|
connection.Verdict = BLOCK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connection.process.AddConnection()
|
||||||
|
return connection, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue