From ca508fd20ff2d805127457103f11aeebf17e2322 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 12 Feb 2019 16:33:34 +0100 Subject: [PATCH] Improve handling of unknown links, improve reason messages --- firewall/firewall.go | 38 ++++++++++-------------- firewall/master.go | 33 ++++++++++----------- network/unknown.go | 69 ++++++++++++++++++++++++++++++++------------ 3 files changed, 83 insertions(+), 57 deletions(-) diff --git a/firewall/firewall.go b/firewall/firewall.go index 49890737..63d46c63 100644 --- a/firewall/firewall.go +++ b/firewall/firewall.go @@ -13,7 +13,6 @@ import ( "github.com/Safing/portmaster/firewall/interception" "github.com/Safing/portmaster/network" "github.com/Safing/portmaster/network/packet" - "github.com/Safing/portmaster/process" ) var ( @@ -92,8 +91,8 @@ func handlePacket(pkt packet.Packet) { // log.Tracef("handling packet: %s", pkt) - // allow anything local, that is not dns - if pkt.MatchesIP(packet.Remote, localNet4) && !(pkt.GetTCPUDPHeader() != nil && pkt.GetTCPUDPHeader().DstPort == 53) { + // allow local dns + if pkt.MatchesIP(packet.Remote, localNet4) && pkt.GetTCPUDPHeader() != nil && pkt.GetTCPUDPHeader().DstPort == 53 { pkt.PermanentAccept() return } @@ -150,24 +149,19 @@ func initialHandler(pkt packet.Packet, link *network.Link) { // get Connection connection, err := network.GetConnectionByFirstPacket(pkt) if err != nil { - if err != process.ErrConnectionNotFound { - log.Warningf("firewall: could not find process of packet (dropping link %s): %s", pkt.String(), err) - link.Deny(fmt.Sprintf("could not find process or it does not exist (unsolicited packet): %s", err)) - } else { - log.Warningf("firewall: internal error finding process of packet (dropping link %s): %s", pkt.String(), err) - link.Deny(fmt.Sprintf("internal error finding process: %s", err)) + // get "unknown" connection + link.Deny(fmt.Sprintf("could not get process: %s", err)) + connection, err = network.GetUnknownConnection(pkt) + + if err != nil { + // 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) @@ -195,15 +189,15 @@ func initialHandler(pkt packet.Packet, link *network.Link) { logInitialVerdict(link) // TODO: link this to real status - // port17Active := mode.Client() + // gate17Active := mode.Client() switch { - // case port17Active && link.Inspect: + // case gate17Active && link.Inspect: // // tunnel link, but also inspect (after reroute) // link.Tunneled = true // link.SetFirewallHandler(inspectThenVerdict) // verdict(pkt, link.GetVerdict()) - // case port17Active: + // case gate17Active: // // tunnel link, don't inspect // link.Tunneled = true // link.StopFirewallHandler() diff --git a/firewall/master.go b/firewall/master.go index b8dadb01..f4490725 100644 --- a/firewall/master.go +++ b/firewall/master.go @@ -44,8 +44,8 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string) // check if there is a profile profileSet := connection.Process().ProfileSet() if profileSet == nil { - log.Errorf("firewall: denying connection %s, no profile set", connection) - connection.Deny("no profile set") + log.Errorf("firewall: denying connection %s, no Profile Set", connection) + connection.Deny("no Profile Set") return } 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) connection.Accept(fmt.Sprintf("endpoint is whitelisted: %s", reason)) } else { - log.Infof("firewall: denying connection %s, endpoint is blacklisted", connection) - connection.Deny("endpoint is blacklisted") + log.Infof("firewall: denying connection %s, endpoint is blacklisted: %s", connection, reason) + connection.Deny(fmt.Sprintf("endpoint is blacklisted: %s", reason)) } return } @@ -117,7 +117,7 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string) } 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") } } @@ -148,8 +148,8 @@ func DecideOnConnectionAfterIntel(connection *network.Connection, fqdn string, r // check if there is a profile profileSet := connection.Process().ProfileSet() if profileSet == nil { - log.Errorf("firewall: denying connection %s, no profile set", connection) - connection.Deny("no profile") + log.Errorf("firewall: denying connection %s, no Profile Set", connection) + connection.Deny("no Profile Set") return rrCache } profileSet.Update(status.ActiveSecurityLevel()) @@ -184,8 +184,8 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) { // check if there is a profile profileSet := connection.Process().ProfileSet() if profileSet == nil { - log.Errorf("firewall: denying connection %s, no profile set", connection) - connection.Deny("no profile") + log.Errorf("firewall: denying connection %s, no Profile Set", connection) + connection.Deny("no Profile Set") return } profileSet.Update(status.ActiveSecurityLevel()) @@ -209,7 +209,6 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) { return } default: - } // check network scope @@ -282,8 +281,8 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet // check if there is a profile profileSet := connection.Process().ProfileSet() if profileSet == nil { - log.Infof("firewall: no profile, denying %s", link) - link.Block("no profile") + log.Infof("firewall: no Profile Set, denying %s", link) + link.Block("no Profile Set") return } 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) link.Accept(fmt.Sprintf("port whitelisted: %s", reason)) } 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") } return @@ -322,15 +321,15 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet switch profileSet.GetProfileMode() { 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") return case profile.Prompt: - log.Infof("firewall: accepting link %s: endpoint %d is blacklisted", link, dstPort) - link.Accept("endpoint permitted (prompting is not yet implemented)") + log.Infof("firewall: accepting link %s: endpoint is not blacklisted (prompting is not yet implemented)", link) + link.Accept("endpoint is not blacklisted (prompting is not yet implemented)") return 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") return } diff --git a/network/unknown.go b/network/unknown.go index fc31aca8..6e8131be 100644 --- a/network/unknown.go +++ b/network/unknown.go @@ -1,31 +1,64 @@ 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 const ( ReasonUnknownProcess = "unknown connection owner: process could not be found" ) -var ( - UnknownDirectConnection = &Connection{ - Domain: "PI", - Direction: Outbound, - Verdict: DROP, - Reason: ReasonUnknownProcess, - process: process.UnknownProcess, +// GetUnknownConnection returns the connection to a packet of unknown owner. +func GetUnknownConnection(pkt packet.Packet) (*Connection, error) { + if pkt.IsInbound() { + switch netutils.ClassifyIP(pkt.GetIPHeader().Src) { + case netutils.HostLocal: + return getOrCreateUnknownConnection(pkt, IncomingHost) + 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{ - Domain: "II", - Direction: Inbound, - Verdict: DROP, - Reason: ReasonUnknownProcess, - process: process.UnknownProcess, + switch netutils.ClassifyIP(pkt.GetIPHeader().Dst) { + case netutils.HostLocal: + return getOrCreateUnknownConnection(pkt, PeerHost) + case netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast: + return getOrCreateUnknownConnection(pkt, PeerLAN) + case netutils.Global, netutils.GlobalMulticast: + return getOrCreateUnknownConnection(pkt, PeerInternet) + case netutils.Invalid: + return getOrCreateUnknownConnection(pkt, PeerInvalid) } -) -func init() { - UnknownDirectConnection.Save() - UnknownIncomingConnection.Save() + // this should never happen + return getOrCreateUnknownConnection(pkt, PeerInvalid) +} + +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 }