Improve handling of unknown links, improve reason messages

This commit is contained in:
Daniel 2019-02-12 16:33:34 +01:00
parent 12e1eb0917
commit ca508fd20f
3 changed files with 83 additions and 57 deletions

View file

@ -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()

View file

@ -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
} }

View file

@ -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
} }