Experimental changes for use in citadel

shw-merge
dma 6 years ago
parent cfaf7b84ff
commit 6a6f3b75e5

@ -58,7 +58,7 @@
<object class="GtkSearchEntry" id="search_entry"> <object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Rule path or sandbox</property> <property name="tooltip_text" translatable="yes">Rule path or realm</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="margin_top">5</property> <property name="margin_top">5</property>
<property name="margin_bottom">5</property> <property name="margin_bottom">5</property>
@ -68,7 +68,7 @@
<property name="primary_icon_name">edit-find-symbolic</property> <property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property> <property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property> <property name="primary_icon_sensitive">False</property>
<property name="placeholder_text" translatable="yes">Rule path or sandbox</property> <property name="placeholder_text" translatable="yes">Rule path or realm</property>
</object> </object>
</child> </child>
</object> </object>

@ -191,7 +191,7 @@
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="label" translatable="yes">Sandbox:</property> <property name="label" translatable="yes">Realm:</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>

@ -130,7 +130,7 @@
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="label" translatable="yes">Sandbox:</property> <property name="label" translatable="yes">Realm:</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>

@ -201,7 +201,7 @@ func (*defRuleEdit) String() string {
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="label" translatable="yes">Sandbox:</property> <property name="label" translatable="yes">Realm:</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>

@ -140,7 +140,7 @@ func (*defRuleNew) String() string {
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="label" translatable="yes">Sandbox:</property> <property name="label" translatable="yes">Realm:</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>

@ -147,7 +147,7 @@ func (fa *fwApp) init() {
panic(err) panic(err)
} }
fa.initOZProfiles() //fa.initOZProfiles()
fa.initGtk() fa.initGtk()
fa.Settings = settings.Init() 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 { func (fa *fwApp) LookupUsername(uid int32) string {
// TODO: needs to be realm aware
if uid == -1 { if uid == -1 {
return "any" return "any"
} }
@ -938,6 +939,7 @@ func (fa *fwApp) LookupUsername(uid int32) string {
} }
func (fa *fwApp) LookupGroup(gid int32) string { func (fa *fwApp) LookupGroup(gid int32) string {
// TODO: needs to be realm aware
if gid == -1 { if gid == -1 {
return "any" return "any"
} }

@ -1,12 +1,12 @@
package main package main
import ( import (
"fmt" //"fmt"
"os" //"os"
"github.com/subgraph/oz" //"github.com/subgraph/oz"
) )
/*
var ozProfiles oz.Profiles var ozProfiles oz.Profiles
func init() { func init() {
@ -36,3 +36,4 @@ func (fa *fwApp) initOZProfiles() {
} }
} }
} }
*/

@ -102,8 +102,8 @@ func createPromptView(app *fwApp, sw *gtk.ScrolledWindow) (*Prompt, error) {
p.tv.AppendColumn(createColumnText("Path", COL_NO_PATH)) p.tv.AppendColumn(createColumnText("Path", COL_NO_PATH))
sbcol := createColumnText("Sandbox", COL_NO_SANDBOX) sbcol := createColumnText("Realm", COL_NO_SANDBOX)
sbcol.SetVisible(false) //sbcol.SetVisible(true)
p.tv.AppendColumn(sbcol) p.tv.AppendColumn(sbcol)
icol := createColumnText("Icon", COL_NO_ICON) icol := createColumnText("Icon", COL_NO_ICON)

@ -147,6 +147,7 @@ type DbusRule struct {
Mode uint16 Mode uint16
IsSocks bool IsSocks bool
Sandbox string Sandbox string
Realm string
UID int32 UID int32
GID int32 GID int32
Username string Username string

@ -194,6 +194,7 @@ func createDbusRule(r *Rule) DbusRule {
Mode: uint16(r.mode), Mode: uint16(r.mode),
IsSocks: false,//r.is_socks, IsSocks: false,//r.is_socks,
Sandbox: r.policy.sandbox, Sandbox: r.policy.sandbox,
Realm: r.policy.sandbox,
UID: int32(r.uid), UID: int32(r.uid),
GID: int32(r.gid), GID: int32(r.gid),
Username: r.uname, Username: r.uname,

@ -8,6 +8,7 @@ import (
) )
const iptablesRule = "OUTPUT -t mangle -m conntrack --ctstate NEW -j NFQUEUE --queue-num 0 --queue-bypass" 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 dnsRule = "INPUT --protocol udp --sport 53 -j NFQUEUE --queue-num 0 --queue-bypass"
//const logRule = "OUTPUT --protocol tcp -m mark --mark 1 -j LOG" //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() { func setupIPTables() {
// addIPTRules(iptablesRule, dnsRule, logRule, blockRule) // addIPTRules(iptablesRule, dnsRule, logRule, blockRule)
addIPTRules(iptablesRule, dnsRule, blockRule) addIPTRules(iptablesRule, realmsRule, dnsRule, blockRule)
} }
func addIPTRules(rules ...string) { func addIPTRules(rules ...string) {

@ -89,6 +89,10 @@ func (pp *pendingPkt) sandbox() string {
return pp.pinfo.Sandbox return pp.pinfo.Sandbox
} }
func (pp *pendingPkt) realm() string {
return pp.pinfo.Realm
}
func (pp *pendingPkt) getTimestamp() string { func (pp *pendingPkt) getTimestamp() string {
return pp.timestamp.Format("15:04:05.00") return pp.timestamp.Format("15:04:05.00")
} }
@ -602,6 +606,7 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket, timestamp time.Time) {
// return // return
} else { } else {
ppath = pinfo.ExePath ppath = pinfo.ExePath
optstring = fmt.Sprintf("Realm: %s", pinfo.Realm);
cf := strings.Fields(pinfo.CmdLine) cf := strings.Fields(pinfo.CmdLine)
if len(cf) > 1 && strings.HasPrefix(cf[1], "/") { if len(cf) > 1 && strings.HasPrefix(cf[1], "/") {
for _, intp := range _interpreters { for _, intp := range _interpreters {

@ -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("------------ 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) //log.Notice("r.saddr: ", r.saddr, "src: ", src, "sandboxed ", sandboxed, "optstr: ", optstr)
if r.saddr == nil && src != nil && sandboxed { 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 // continue
} else if r.saddr == nil && src == nil && sandboxed { } else if r.saddr == nil && src == nil && sandboxed {
// continue // continue

@ -1,13 +1,8 @@
package sgfw package sgfw
import ( import (
"bufio"
"encoding/json"
"fmt"
"os" "os"
"os/signal" "os/signal"
"regexp"
"strings"
"sync" "sync"
"syscall" "syscall"
"time" "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() { func Main() {
readConfig() readConfig()
logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel) logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel)
@ -235,40 +180,9 @@ func Main() {
fw.loadRules() 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") fw.dbus.emitRefresh("init")
go OzReceiver(fw) //go OzReceiver(fw)
fw.runFilter() fw.runFilter()

@ -11,6 +11,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"unsafe" "unsafe"
// "github.com/godbus/dbus"
) )
var log = logging.MustGetLogger("go-procsockets") var log = logging.MustGetLogger("go-procsockets")
@ -28,6 +29,7 @@ var pcache = &pidCache{}
// Note: this can aid in the construction of unit tests. // Note: this can aid in the construction of unit tests.
type ProcInfo interface { type ProcInfo interface {
LookupTCPSocketProcess(srcPort uint16, dstAddr net.IP, dstPort uint16) *Info 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 LookupUNIXSocketProcess(socketFile string) *Info
LookupUDPSocketProcess(srcPort uint16) *Info LookupUDPSocketProcess(srcPort uint16) *Info
} }
@ -41,6 +43,10 @@ func (r SystemProcInfo) LookupTCPSocketProcess(srcPort uint16, dstAddr net.IP, d
return LookupTCPSocketProcess(srcPort, dstAddr, dstPort) 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. // LookupUNIXSocketProcess returns the process information for a given UNIX socket connection.
func (r SystemProcInfo) LookupUNIXSocketProcess(socketFile string) *Info { func (r SystemProcInfo) LookupUNIXSocketProcess(socketFile string) *Info {
return LookupUNIXSocketProcess(socketFile) return LookupUNIXSocketProcess(socketFile)
@ -58,11 +64,12 @@ func FindProcessForConnection(conn net.Conn, procInfo ProcInfo) *Info {
if conn.LocalAddr().Network() == "tcp" { if conn.LocalAddr().Network() == "tcp" {
fields := strings.Split(conn.RemoteAddr().String(), ":") fields := strings.Split(conn.RemoteAddr().String(), ":")
dstPortStr := fields[1] dstPortStr := fields[1]
srcIP := net.ParseIP(fields[0]);
fields = strings.Split(conn.LocalAddr().String(), ":") fields = strings.Split(conn.LocalAddr().String(), ":")
dstIP := net.ParseIP(fields[0]) dstIP := net.ParseIP(fields[0])
srcP, _ := strconv.ParseUint(dstPortStr, 10, 16) srcP, _ := strconv.ParseUint(dstPortStr, 10, 16)
dstP, _ := strconv.ParseUint(fields[1], 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" { } else if conn.LocalAddr().Network() == "unix" {
info = procInfo.LookupUNIXSocketProcess(conn.LocalAddr().String()) info = procInfo.LookupUNIXSocketProcess(conn.LocalAddr().String())
} }
@ -208,6 +215,43 @@ func getConnections() ([]*connectionInfo, error) {
func resolveProcinfo(conns []*connectionInfo) { func resolveProcinfo(conns []*connectionInfo) {
var sockets []*socketStatus 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") { for _, line := range getSocketLines("tcp") {
if len(strings.TrimSpace(line)) == 0 { if len(strings.TrimSpace(line)) == 0 {
continue continue
@ -225,7 +269,7 @@ func resolveProcinfo(conns []*connectionInfo) {
} }
}*/ }*/
} // }
for _, ci := range conns { for _, ci := range conns {
ss := findContrackSocket(ci, sockets) ss := findContrackSocket(ci, sockets)
if ss == nil { if ss == nil {

@ -9,6 +9,7 @@ import (
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"github.com/godbus/dbus"
) )
// Info is a struct containing the result of a socket proc query // Info is a struct containing the result of a socket proc query
@ -23,6 +24,7 @@ type Info struct {
FirstArg string FirstArg string
ParentCmdLine string ParentCmdLine string
ParentExePath string ParentExePath string
Realm string
Sandbox string Sandbox string
Inode uint64 Inode uint64
FD int 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)) finfo, err := os.Stat(fmt.Sprintf("/proc/%d", pi.Pid))
if err != nil { if err != nil {
log.Warningf("Could not stat /proc/%d: %v", pi.Pid, err) 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.ParentCmdLine = string(pbs)
pi.ParentExePath = string(pexePath) pi.ParentExePath = string(pexePath)
pi.ExePath = exePath pi.ExePath = exePath
pi.Realm = realm
pi.Sandbox = realm
pi.CmdLine = string(bcs) pi.CmdLine = string(bcs)
pi.loaded = true pi.loaded = true
return true return true

@ -3,6 +3,7 @@ package procsnitch
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/godbus/dbus"
"io/ioutil" "io/ioutil"
"net" "net"
"strconv" "strconv"
@ -218,17 +219,35 @@ func findTCPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort ui
if srcAddr.To4() == nil { if srcAddr.To4() == nil {
proto += "6" 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 { if custdata == nil {
return findSocket(proto, func(ss socketStatus) bool { 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) 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)
})
} 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 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 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 { func findUNIXSocket(socketFile string) *socketStatus {
proto := "unix" proto := "unix"
@ -303,6 +322,24 @@ func findSocket(proto string, matcher func(socketStatus) bool) *socketStatus {
return nil 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 { func (ss *socketStatus) parseLine(line string) error {
fs := strings.Fields(line) fs := strings.Fields(line)
if len(fs) < 10 { if len(fs) < 10 {
@ -358,7 +395,21 @@ func (ss *socketStatus) parseUnixProcLine(line string) error {
} }
func getSocketLines(proto string) []string { 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) data, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
log.Warningf("Error reading %s: %v", path, err) log.Warningf("Error reading %s: %v", path, err)

Loading…
Cancel
Save