From 0708f9127c20a8ea00cbed6861460da801ba1ffc Mon Sep 17 00:00:00 2001 From: shw Date: Wed, 10 May 2017 22:14:14 +0000 Subject: [PATCH] Proper logging of all connections denied by firewall. fw-daemon now also forces logging to syslog if launched from a terminal. --- sgfw/log.go | 16 +++++++++++-- sgfw/policy.go | 10 +++++++++ sgfw/rules.go | 4 ++++ sgfw/sgfw.go | 10 +++++++-- sgfw/socks_server_chain.go | 46 ++++++++++++++++++++++++++++++++------ 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/sgfw/log.go b/sgfw/log.go index e634d73..54b1111 100644 --- a/sgfw/log.go +++ b/sgfw/log.go @@ -4,6 +4,7 @@ import ( "os" "syscall" "unsafe" + "fmt" "github.com/op/go-logging" ) @@ -43,14 +44,25 @@ func isTerminal(fd int) bool { return err == 0 } -func setupLoggerBackend(lvl logging.Level) logging.LeveledBackend { +func setupLoggerBackend(lvl logging.Level) (logging.LeveledBackend, logging.LeveledBackend) { format := logFormat + sleveler := logging.LeveledBackend(nil) if isTerminal(int(os.Stderr.Fd())) { format = ttyFormat + fmt.Fprintf(os.Stderr, "Program was launched from a terminal; forcing output to syslog.\n") + sbackend, err := logging.NewSyslogBackend("sgfw") + + if err != nil { + log.Error("Could not open syslog backend for logging: %v", err) + } else { + sformatter := logging.NewBackendFormatter(sbackend, logFormat) + sleveler = logging.AddModuleLevel(sformatter) + sleveler.SetLevel(lvl, "sgfw") + } } backend := logging.NewLogBackend(os.Stderr, "", 0) formatter := logging.NewBackendFormatter(backend, format) leveler := logging.AddModuleLevel(formatter) leveler.SetLevel(lvl, "sgfw") - return leveler + return leveler, sleveler } diff --git a/sgfw/policy.go b/sgfw/policy.go index 7288705..7fa3f5a 100644 --- a/sgfw/policy.go +++ b/sgfw/policy.go @@ -3,6 +3,7 @@ package sgfw import ( "fmt" "strings" + "strconv" "sync" // "encoding/binary" @@ -41,6 +42,7 @@ type pendingConnection interface { hostname() string getOptString() string src() net.IP + srcPort() uint16 dst() net.IP dstPort() uint16 accept() @@ -105,6 +107,11 @@ func (pp *pendingPkt) dst() net.IP { // pp.pkt.NetworkLayer().Layer } +func (pp *pendingPkt) srcPort() uint16 { + srcp, _ := getPacketTCPPorts(pp.pkt) + return srcp +} + func (pp *pendingPkt) dstPort() uint16 { /* dst := pp.pkt.Packet.TransportLayer().TransportFlow().Dst() @@ -293,6 +300,9 @@ func (p *Policy) filterPending(rule *Rule) { if rule.rtype == RULE_ACTION_ALLOW { pc.accept() } else { + srcs := pc.src().String() + ":" + strconv.Itoa(int(pc.srcPort())) + log.Warningf("DENIED outgoing connection attempt by %s from %s %s -> %s:%d (user prompt)", + pc.procInfo().ExePath, "TCP", srcs, pc.dst(), pc.dstPort) pc.drop() } } else { diff --git a/sgfw/rules.go b/sgfw/rules.go index 4ec45c1..b4d8ec8 100644 --- a/sgfw/rules.go +++ b/sgfw/rules.go @@ -127,6 +127,10 @@ log.Notice("+ MATCH SUCCEEDED") srcStr, dstStr, dstPort) if r.rtype == RULE_ACTION_DENY { + log.Warningf("DENIED outgoing connection attempt by %s from %s %s -> %s:%d", + pinfo.ExePath, "TCP", + srcStr, + dstStr, dstPort) return FILTER_DENY } else if r.rtype == RULE_ACTION_ALLOW { result = FILTER_ALLOW diff --git a/sgfw/sgfw.go b/sgfw/sgfw.go index 508f082..e38fb84 100644 --- a/sgfw/sgfw.go +++ b/sgfw/sgfw.go @@ -173,8 +173,14 @@ func getSocksChainConfig(config *SocksJsonConfig) *socksChainConfig { func Main() { readConfig() - logBackend := setupLoggerBackend(FirewallConfig.LoggingLevel) - log.SetBackend(logBackend) + logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel) + + if logBackend2 == nil { + logging.SetBackend(logBackend) + } else { + logging.SetBackend(logBackend, logBackend2) + } + procsnitch.SetLogger(log) if os.Geteuid() != 0 { diff --git a/sgfw/socks_server_chain.go b/sgfw/socks_server_chain.go index f9e8daf..f10257c 100644 --- a/sgfw/socks_server_chain.go +++ b/sgfw/socks_server_chain.go @@ -7,6 +7,7 @@ import ( "sync" "github.com/subgraph/go-procsnitch" + "strings" "strconv" ) @@ -46,6 +47,7 @@ type pendingSocksConnection struct { hname string srcIP net.IP destIP net.IP + sourcePort uint16 destPort uint16 pinfo *procsnitch.Info verdict chan int @@ -70,6 +72,9 @@ func (sc *pendingSocksConnection) hostname() string { func (sc *pendingSocksConnection) dst() net.IP { return sc.destIP } +func (sc *pendingSocksConnection) srcPort() uint16 { + return sc.sourcePort +} func (sc *pendingSocksConnection) dstPort() uint16 { return sc.destPort } @@ -204,14 +209,41 @@ func (c *socksChainSession) filterConnect() bool { case FILTER_ALLOW: return true case FILTER_PROMPT: + caddr := c.clientConn.RemoteAddr().String() + caddrt := strings.Split(caddr, ":") + caddrIP := net.IP{0,0,0,0} + caddrPort := uint16(0) + + if len(caddrt) != 2 { + log.Errorf("Error reading peer information from SOCKS client connection") + } else { + srcp, err := strconv.Atoi(caddrt[1]) + + if err != nil || srcp <= 0 || srcp > 65535 { + log.Errorf("Error getting port of SOCKS client connection") + } else { + caddrPort = uint16(srcp) + ip := net.ParseIP(caddrt[0]) + + if ip == nil { + log.Errorf("Error getting host IP of SOCKS5 client connection: %v", err) + } else { + caddrIP = ip + } + + } + + } + pending := &pendingSocksConnection{ - pol: policy, - hname: hostname, - destIP: ip, - srcIP: net.IP{0,0,0,0}, - destPort: port, - pinfo: pinfo, - verdict: make(chan int), + pol: policy, + hname: hostname, + destIP: ip, + srcIP: caddrIP, + sourcePort: caddrPort, + destPort: port, + pinfo: pinfo, + verdict: make(chan int), } policy.processPromptResult(pending) v := <-pending.verdict