From 6a6f3b75e5156577ac3252cef3f8350c68ca36b2 Mon Sep 17 00:00:00 2001 From: dma Date: Thu, 8 Nov 2018 20:11:21 -0500 Subject: [PATCH] Experimental changes for use in citadel --- fw-settings/definitions/Dialog.ui | 4 +- fw-settings/definitions/RuleEdit.ui | 2 +- fw-settings/definitions/RuleNew.ui | 2 +- fw-settings/definitions/rule_edit.go | 2 +- fw-settings/definitions/rule_new.go | 2 +- fw-settings/main.go | 4 +- fw-settings/oz-sandboxes.go | 9 +- fw-settings/prompt.go | 6 +- sgfw/const.go | 1 + sgfw/dbus.go | 1 + sgfw/iptables.go | 3 +- sgfw/policy.go | 5 ++ sgfw/rules.go | 5 +- sgfw/sgfw.go | 88 +------------------ .../github.com/subgraph/go-procsnitch/proc.go | 48 +++++++++- .../subgraph/go-procsnitch/proc_pid.go | 11 ++- .../subgraph/go-procsnitch/socket.go | 63 +++++++++++-- 17 files changed, 144 insertions(+), 112 deletions(-) diff --git a/fw-settings/definitions/Dialog.ui b/fw-settings/definitions/Dialog.ui index 87f9477..2d33084 100644 --- a/fw-settings/definitions/Dialog.ui +++ b/fw-settings/definitions/Dialog.ui @@ -58,7 +58,7 @@ True True - Rule path or sandbox + Rule path or realm center 5 5 @@ -68,7 +68,7 @@ edit-find-symbolic False False - Rule path or sandbox + Rule path or realm diff --git a/fw-settings/definitions/RuleEdit.ui b/fw-settings/definitions/RuleEdit.ui index 4b11b9d..4ece6b9 100644 --- a/fw-settings/definitions/RuleEdit.ui +++ b/fw-settings/definitions/RuleEdit.ui @@ -191,7 +191,7 @@ False start False - Sandbox: + Realm: diff --git a/fw-settings/definitions/RuleNew.ui b/fw-settings/definitions/RuleNew.ui index 43dad84..5b45e90 100644 --- a/fw-settings/definitions/RuleNew.ui +++ b/fw-settings/definitions/RuleNew.ui @@ -130,7 +130,7 @@ False start False - Sandbox: + Realm: diff --git a/fw-settings/definitions/rule_edit.go b/fw-settings/definitions/rule_edit.go index 325c071..3e7d4a1 100644 --- a/fw-settings/definitions/rule_edit.go +++ b/fw-settings/definitions/rule_edit.go @@ -201,7 +201,7 @@ func (*defRuleEdit) String() string { False start False - Sandbox: + Realm: diff --git a/fw-settings/definitions/rule_new.go b/fw-settings/definitions/rule_new.go index 7b33a5b..c997535 100644 --- a/fw-settings/definitions/rule_new.go +++ b/fw-settings/definitions/rule_new.go @@ -140,7 +140,7 @@ func (*defRuleNew) String() string { False start False - Sandbox: + Realm: diff --git a/fw-settings/main.go b/fw-settings/main.go index 81938d9..95f0b45 100644 --- a/fw-settings/main.go +++ b/fw-settings/main.go @@ -147,7 +147,7 @@ func (fa *fwApp) init() { panic(err) } - fa.initOZProfiles() + //fa.initOZProfiles() fa.initGtk() fa.Settings = settings.Init() @@ -925,6 +925,7 @@ func (fa *fwApp) ConnectShortcut(accel, group, title string, w gtk.Window, actio } func (fa *fwApp) LookupUsername(uid int32) string { + // TODO: needs to be realm aware if uid == -1 { return "any" } @@ -938,6 +939,7 @@ func (fa *fwApp) LookupUsername(uid int32) string { } func (fa *fwApp) LookupGroup(gid int32) string { + // TODO: needs to be realm aware if gid == -1 { return "any" } diff --git a/fw-settings/oz-sandboxes.go b/fw-settings/oz-sandboxes.go index 0e7df29..02bac46 100644 --- a/fw-settings/oz-sandboxes.go +++ b/fw-settings/oz-sandboxes.go @@ -1,12 +1,12 @@ package main import ( - "fmt" - "os" + //"fmt" + //"os" - "github.com/subgraph/oz" + //"github.com/subgraph/oz" ) - +/* var ozProfiles oz.Profiles func init() { @@ -36,3 +36,4 @@ func (fa *fwApp) initOZProfiles() { } } } +*/ diff --git a/fw-settings/prompt.go b/fw-settings/prompt.go index 23f44b5..eeef6a0 100644 --- a/fw-settings/prompt.go +++ b/fw-settings/prompt.go @@ -57,7 +57,7 @@ const ( type ruleColumns struct { nrefs int Path string - Sandbox string + Sandbox string GUID string Icon string Proto string @@ -102,8 +102,8 @@ func createPromptView(app *fwApp, sw *gtk.ScrolledWindow) (*Prompt, error) { p.tv.AppendColumn(createColumnText("Path", COL_NO_PATH)) - sbcol := createColumnText("Sandbox", COL_NO_SANDBOX) - sbcol.SetVisible(false) + sbcol := createColumnText("Realm", COL_NO_SANDBOX) + //sbcol.SetVisible(true) p.tv.AppendColumn(sbcol) icol := createColumnText("Icon", COL_NO_ICON) diff --git a/sgfw/const.go b/sgfw/const.go index db1a723..15ee97b 100644 --- a/sgfw/const.go +++ b/sgfw/const.go @@ -147,6 +147,7 @@ type DbusRule struct { Mode uint16 IsSocks bool Sandbox string + Realm string UID int32 GID int32 Username string diff --git a/sgfw/dbus.go b/sgfw/dbus.go index 47fdf1a..41f3fc3 100644 --- a/sgfw/dbus.go +++ b/sgfw/dbus.go @@ -194,6 +194,7 @@ func createDbusRule(r *Rule) DbusRule { Mode: uint16(r.mode), IsSocks: false,//r.is_socks, Sandbox: r.policy.sandbox, + Realm: r.policy.sandbox, UID: int32(r.uid), GID: int32(r.gid), Username: r.uname, diff --git a/sgfw/iptables.go b/sgfw/iptables.go index f61542d..d9cede2 100644 --- a/sgfw/iptables.go +++ b/sgfw/iptables.go @@ -8,6 +8,7 @@ import ( ) const iptablesRule = "OUTPUT -t mangle -m conntrack --ctstate NEW -j NFQUEUE --queue-num 0 --queue-bypass" +const realmsRule = "FORWARD -t mangle -m conntrack --ctstate NEW -j NFQUEUE --queue-num 0 --queue-bypass" const dnsRule = "INPUT --protocol udp --sport 53 -j NFQUEUE --queue-num 0 --queue-bypass" //const logRule = "OUTPUT --protocol tcp -m mark --mark 1 -j LOG" @@ -15,7 +16,7 @@ const blockRule = "OUTPUT --protocol tcp -m mark --mark 1 -j REJECT" func setupIPTables() { // addIPTRules(iptablesRule, dnsRule, logRule, blockRule) - addIPTRules(iptablesRule, dnsRule, blockRule) + addIPTRules(iptablesRule, realmsRule, dnsRule, blockRule) } func addIPTRules(rules ...string) { diff --git a/sgfw/policy.go b/sgfw/policy.go index 33974fa..ccd2ab7 100644 --- a/sgfw/policy.go +++ b/sgfw/policy.go @@ -89,6 +89,10 @@ func (pp *pendingPkt) sandbox() string { return pp.pinfo.Sandbox } +func (pp *pendingPkt) realm() string { + return pp.pinfo.Realm +} + func (pp *pendingPkt) getTimestamp() string { return pp.timestamp.Format("15:04:05.00") } @@ -602,6 +606,7 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket, timestamp time.Time) { // return } else { ppath = pinfo.ExePath + optstring = fmt.Sprintf("Realm: %s", pinfo.Realm); cf := strings.Fields(pinfo.CmdLine) if len(cf) > 1 && strings.HasPrefix(cf[1], "/") { for _, intp := range _interpreters { diff --git a/sgfw/rules.go b/sgfw/rules.go index 1508134..1b51b8c 100644 --- a/sgfw/rules.go +++ b/sgfw/rules.go @@ -165,7 +165,10 @@ func (rl *RuleList) filter(pkt *nfqueue.NFQPacket, src, dst net.IP, dstPort uint //log.Notice("------------ trying match of src ", src, " against: ", r, " | ", r.saddr, " / optstr = ", optstr, "; pid ", pinfo.Pid, " vs rule pid ", r.pid) //log.Notice("r.saddr: ", r.saddr, "src: ", src, "sandboxed ", sandboxed, "optstr: ", optstr) if r.saddr == nil && src != nil && sandboxed { - log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src) + if pkt != nil { + nfqproto = getNFQProto(pkt) + } + //log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src) // continue } else if r.saddr == nil && src == nil && sandboxed { // continue diff --git a/sgfw/sgfw.go b/sgfw/sgfw.go index 805e58a..a8022aa 100644 --- a/sgfw/sgfw.go +++ b/sgfw/sgfw.go @@ -1,13 +1,8 @@ package sgfw import ( - "bufio" - "encoding/json" - "fmt" "os" "os/signal" - "regexp" - "strings" "sync" "syscall" "time" @@ -146,56 +141,6 @@ func (fw *Firewall) runFilter() { } } -type SocksJsonConfig struct { - Name string - SocksListener string - TorSocks string -} - -var commentRegexp = regexp.MustCompile("^[ \t]*#") - -const defaultSocksCfgPath = "/etc/sgfw/fw-daemon-socks.json" - -func loadSocksConfiguration(configFilePath string) (*SocksJsonConfig, error) { - config := SocksJsonConfig{} - file, err := os.Open(configFilePath) - if err != nil { - return nil, err - } - scanner := bufio.NewScanner(file) - bs := "" - for scanner.Scan() { - line := scanner.Text() - if !commentRegexp.MatchString(line) { - bs += line + "\n" - } - } - if err := json.Unmarshal([]byte(bs), &config); err != nil { - return nil, err - } - return &config, nil -} - -func getSocksChainConfig(config *SocksJsonConfig) *socksChainConfig { - // TODO: fix this to support multiple named proxy forwarders of different types - fields := strings.Split(config.TorSocks, "|") - torSocksNet := fields[0] - torSocksAddr := fields[1] - fields = strings.Split(config.SocksListener, "|") - socksListenNet := fields[0] - socksListenAddr := fields[1] - socksConfig := socksChainConfig{ - Name: config.Name, - TargetSocksNet: torSocksNet, - TargetSocksAddr: torSocksAddr, - ListenSocksNet: socksListenNet, - ListenSocksAddr: socksListenAddr, - } - log.Notice("Loaded Socks chain config:") - log.Notice(socksConfig) - return &socksConfig -} - func Main() { readConfig() logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel) @@ -235,40 +180,9 @@ func Main() { fw.loadRules() - /* - go func() { - http.ListenAndServe("localhost:6060", nil) - }() - */ - - wg := sync.WaitGroup{} - - scfile := os.Getenv("SGFW_SOCKS_CONFIG") - - if scfile == "" { - scfile = defaultSocksCfgPath - } - - config, err := loadSocksConfiguration(scfile) - if err != nil && !os.IsNotExist(err) { - panic(err) - } - if config != nil { - socksConfig := getSocksChainConfig(config) - chain := NewSocksChain(socksConfig, &wg, fw) - chain.start() - } else { - log.Notice("Did not find SOCKS5 configuration file at", scfile, "; ignoring subsystem...") - } - - dbLogger, err = newDbusRedactedLogger() - if err != nil { - panic(fmt.Sprintf("Failed to connect to DBus system bus for redacted logger: %v", err)) - } - fw.dbus.emitRefresh("init") - go OzReceiver(fw) + //go OzReceiver(fw) fw.runFilter() diff --git a/vendor/github.com/subgraph/go-procsnitch/proc.go b/vendor/github.com/subgraph/go-procsnitch/proc.go index fe23232..0c7e73f 100644 --- a/vendor/github.com/subgraph/go-procsnitch/proc.go +++ b/vendor/github.com/subgraph/go-procsnitch/proc.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" "unsafe" + // "github.com/godbus/dbus" ) var log = logging.MustGetLogger("go-procsockets") @@ -28,6 +29,7 @@ var pcache = &pidCache{} // Note: this can aid in the construction of unit tests. type ProcInfo interface { LookupTCPSocketProcess(srcPort uint16, dstAddr net.IP, dstPort uint16) *Info + LookupTCPSocketProcessAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort uint16, custdata []string) *Info LookupUNIXSocketProcess(socketFile string) *Info LookupUDPSocketProcess(srcPort uint16) *Info } @@ -41,6 +43,10 @@ func (r SystemProcInfo) LookupTCPSocketProcess(srcPort uint16, dstAddr net.IP, d return LookupTCPSocketProcess(srcPort, dstAddr, dstPort) } +func (r SystemProcInfo) LookupTCPSocketProcessAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort uint16, custdata []string) *Info { + return LookupTCPSocketProcessAll(srcAddr, srcPort, dstAddr, dstPort, custdata) +} + // LookupUNIXSocketProcess returns the process information for a given UNIX socket connection. func (r SystemProcInfo) LookupUNIXSocketProcess(socketFile string) *Info { return LookupUNIXSocketProcess(socketFile) @@ -58,11 +64,12 @@ func FindProcessForConnection(conn net.Conn, procInfo ProcInfo) *Info { if conn.LocalAddr().Network() == "tcp" { fields := strings.Split(conn.RemoteAddr().String(), ":") dstPortStr := fields[1] + srcIP := net.ParseIP(fields[0]); fields = strings.Split(conn.LocalAddr().String(), ":") dstIP := net.ParseIP(fields[0]) srcP, _ := strconv.ParseUint(dstPortStr, 10, 16) dstP, _ := strconv.ParseUint(fields[1], 10, 16) - info = procInfo.LookupTCPSocketProcess(uint16(srcP), dstIP, uint16(dstP)) + info = procInfo.LookupTCPSocketProcessAll(srcIP, uint16(srcP), dstIP, uint16(dstP), nil) } else if conn.LocalAddr().Network() == "unix" { info = procInfo.LookupUNIXSocketProcess(conn.LocalAddr().String()) } @@ -208,6 +215,43 @@ func getConnections() ([]*connectionInfo, error) { func resolveProcinfo(conns []*connectionInfo) { var sockets []*socketStatus + //conn, _ := dbus.SystemBus() + +/* m := make(map[string]string) + + for _, ci := range conns { + if _, ok := m[ci.local.ip.String()]; !ok { + var leaderpid string + obj := conn.Object("com.subgraph.realms", "/") + call := obj.Call("com.subgraph.realms.Manager.LeaderPidFromIP", 0, ci.local.ip.String()).Store(&leaderpid); + m[ci.local.ip.String()] = leaderpid; + } + } + + for ip, pid := range m { + if pid != "" { + for _, line := range getSocketLinesPid("tcp", pid) { + if len(strings.TrimSpace(line)) == 0 { + continue + } + ss := new(socketStatus) + if err := ss.parseLine(line); err != nil { + log.Warningf("Unable to parse line [%s]: %v", line, err) + } + } + } else { + for _, line := range getSocketLines("tcp") { + if len(strings.TrimSpace(line)) == 0 { + continue + } + ss := new (socketStatus) + if err := ss.parseLine(line); err != nil { + log.Warningf("Unable to parse line [%s]: %v", line, err) + } + } + } + } +/* for _, line := range getSocketLines("tcp") { if len(strings.TrimSpace(line)) == 0 { continue @@ -225,7 +269,7 @@ func resolveProcinfo(conns []*connectionInfo) { } }*/ - } + // } for _, ci := range conns { ss := findContrackSocket(ci, sockets) if ss == nil { diff --git a/vendor/github.com/subgraph/go-procsnitch/proc_pid.go b/vendor/github.com/subgraph/go-procsnitch/proc_pid.go index 549ea37..e0c4b03 100644 --- a/vendor/github.com/subgraph/go-procsnitch/proc_pid.go +++ b/vendor/github.com/subgraph/go-procsnitch/proc_pid.go @@ -9,6 +9,7 @@ import ( "strings" "sync" "syscall" + "github.com/godbus/dbus" ) // Info is a struct containing the result of a socket proc query @@ -23,7 +24,8 @@ type Info struct { FirstArg string ParentCmdLine string ParentExePath string - Sandbox string + Realm string + Sandbox string Inode uint64 FD int } @@ -182,6 +184,11 @@ func (pi *Info) loadProcessInfo() bool { } } + conn, _ := dbus.SystemBus() + obj := conn.Object("com.subgraph.realms", "/") + realm := "Realm: unknown" + obj.Call("com.subgraph.realms.Manager.RealmFromContainerPid", 0, fmt.Sprintf("%d",pi.Pid)).Store(&realm) + finfo, err := os.Stat(fmt.Sprintf("/proc/%d", pi.Pid)) if err != nil { log.Warningf("Could not stat /proc/%d: %v", pi.Pid, err) @@ -194,6 +201,8 @@ func (pi *Info) loadProcessInfo() bool { pi.ParentCmdLine = string(pbs) pi.ParentExePath = string(pexePath) pi.ExePath = exePath + pi.Realm = realm + pi.Sandbox = realm pi.CmdLine = string(bcs) pi.loaded = true return true diff --git a/vendor/github.com/subgraph/go-procsnitch/socket.go b/vendor/github.com/subgraph/go-procsnitch/socket.go index 102b5b7..36055a3 100644 --- a/vendor/github.com/subgraph/go-procsnitch/socket.go +++ b/vendor/github.com/subgraph/go-procsnitch/socket.go @@ -3,6 +3,7 @@ package procsnitch import ( "errors" "fmt" + "github.com/godbus/dbus" "io/ioutil" "net" "strconv" @@ -218,16 +219,34 @@ func findTCPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort ui if srcAddr.To4() == nil { proto += "6" } + // HACK +// var sockets []*socketStatus + conn, _ := dbus.SystemBus() + var leaderpid string + obj := conn.Object("com.subgraph.realms", "/") + obj.Call("com.subgraph.realms.Manager.LeaderPidFromIP", 0, srcAddr.String()).Store(&leaderpid) + if leaderpid != "" { + if custdata == nil { + return findSocketPid(proto, leaderpid, func(ss socketStatus) bool { + return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) + }) + } - if custdata == nil { - return findSocket(proto, func(ss socketStatus) bool { + return findSocketCustom(proto, custdata, func(ss socketStatus) bool { return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) }) + } else { + if custdata == nil { + return findSocket(proto, func(ss socketStatus) bool { + return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) + }) + return findSocketCustom(proto, custdata, func(ss socketStatus) bool { + return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) + }) + } } - return findSocketCustom(proto, custdata, func(ss socketStatus) bool { - return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) - }) + return nil } func findUNIXSocket(socketFile string) *socketStatus { @@ -303,6 +322,24 @@ func findSocket(proto string, matcher func(socketStatus) bool) *socketStatus { return nil } +func findSocketPid(proto string, pid string, matcher func(socketStatus) bool) *socketStatus { + var ss socketStatus + for _, line := range getSocketLinesPid(proto,pid) { + if len(line) == 0 { + continue + } + if err := ss.parseLine(line); err != nil { + log.Warningf("Unable to parse line from /proc/net/%s [%s]: %v", proto, line, err) + continue + } + if matcher(ss) { + ss.line = line + return &ss + } + } + return nil +} + func (ss *socketStatus) parseLine(line string) error { fs := strings.Fields(line) if len(fs) < 10 { @@ -358,7 +395,21 @@ func (ss *socketStatus) parseUnixProcLine(line string) error { } func getSocketLines(proto string) []string { - path := fmt.Sprintf("/proc/net/%s", proto) + path := fmt.Sprintf("/proc/2047/root/proc/1/net/%s", proto) + data, err := ioutil.ReadFile(path) + if err != nil { + log.Warningf("Error reading %s: %v", path, err) + return nil + } + lines := strings.Split(string(data), "\n") + if len(lines) > 0 { + lines = lines[1:] + } + return lines +} + +func getSocketLinesPid(proto string, leaderpid string) []string { + path := fmt.Sprintf("/proc/%s/root/proc/1/net/%s", leaderpid, proto) data, err := ioutil.ReadFile(path) if err != nil { log.Warningf("Error reading %s: %v", path, err)