Updated SOCKS5 connection lookup code now correctly identifies originating process.

Includes code to read internal proxy state information from (updated) oz-daemon.
shw_dev
shw 8 years ago
parent acf62b63d1
commit 27d0a4809d

@ -7,6 +7,9 @@ import (
"bufio" "bufio"
"strings" "strings"
"strconv" "strconv"
"errors"
"github.com/subgraph/oz/ipc"
) )
const ReceiverSocketPath = "/tmp/fwoz.sock" const ReceiverSocketPath = "/tmp/fwoz.sock"
@ -300,3 +303,66 @@ func OzReceiver(fw *Firewall) {
} }
} }
type ListProxiesMsg struct {
_ string "ListProxies"
}
type ListProxiesResp struct {
Proxies []string "ListProxiesResp"
}
func ListProxies() ([]string, error) {
resp, err := clientSend(&ListProxiesMsg{})
if err != nil {
return nil, err
}
body, ok := resp.Body.(*ListProxiesResp)
if !ok {
return nil, errors.New("ListProxies response was not expected type")
}
return body.Proxies, nil
}
const OzSocketName = "@oz-control"
var bSockName = OzSocketName
var messageFactory = ipc.NewMsgFactory(
new(ListProxiesMsg),
new(ListProxiesResp),
)
func clientConnect() (*ipc.MsgConn, error) {
bSockName = os.Getenv("SOCKET_NAME")
if bSockName != "" {
fmt.Println("Attempting to connect on custom socket provided through environment: ", bSockName)
if bSockName[0:1] != "@" {
fmt.Println("Environment variable specified invalid socket name... prepending @")
bSockName = "@" + bSockName
}
} else {
bSockName = OzSocketName
}
return ipc.Connect(bSockName, messageFactory, nil)
}
func clientSend(msg interface{}) (*ipc.Message, error) {
c, err := clientConnect()
if err != nil {
return nil, err
}
defer c.Close()
rr, err := c.ExchangeMsg(msg)
if err != nil {
return nil, err
}
resp := <-rr.Chan()
rr.Done()
return resp, nil
}

@ -549,6 +549,66 @@ func getRealRoot(pathname string, pid int) string {
return pathname return pathname
} }
// XXX: This is redundant code.... it should be called by findProcessForPacket()
func LookupSandboxProc(srcip net.IP, srcp uint16, dstip net.IP, dstp uint16, proto string, strictness, icode int) (*procsnitch.Info, string) {
var res *procsnitch.Info = nil
var optstr string
removePids := make([]int, 0)
for i := 0; i < len(OzInitPids); i++ {
data := ""
fname := fmt.Sprintf("/proc/%d/net/%s", OzInitPids[i].Pid, proto)
//fmt.Println("XXX: opening: ", fname)
bdata, err := readFileDirect(fname)
if err != nil {
fmt.Println("Error reading proc data from ", fname, ": ", err)
if err == syscall.ENOENT {
removePids = append(removePids, OzInitPids[i].Pid)
}
continue
} else {
data = string(bdata)
lines := strings.Split(data, "\n")
rlines := make([]string, 0)
for l := 0; l < len(lines); l++ {
lines[l] = strings.TrimSpace(lines[l])
ssplit := strings.Split(lines[l], ":")
if len(ssplit) != 6 {
continue
}
rlines = append(rlines, strings.Join(ssplit, ":"))
}
if proto == "tcp" {
res = procsnitch.LookupTCPSocketProcessAll(srcip, srcp, dstip, dstp, rlines)
} else if proto == "udp" {
res = procsnitch.LookupUDPSocketProcessAll(srcip, srcp, dstip, dstp, rlines, strictness)
} else if proto == "icmp" {
res = procsnitch.LookupICMPSocketProcessAll(srcip, dstip, icode, rlines)
}
if res != nil {
optstr = "Sandbox: " + OzInitPids[i].Name
res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid)
break
}
}
}
for _, p := range removePids {
removeInitPid(p)
}
return res, optstr
}
func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int) (*procsnitch.Info, string) { func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int) (*procsnitch.Info, string) {
srcip, dstip := getPacketIPAddrs(pkt) srcip, dstip := getPacketIPAddrs(pkt)
srcp, dstp := getPacketPorts(pkt) srcp, dstp := getPacketPorts(pkt)

@ -53,6 +53,7 @@ type pendingSocksConnection struct {
pinfo *procsnitch.Info pinfo *procsnitch.Info
verdict chan int verdict chan int
prompting bool prompting bool
optstr string
} }
func (sc *pendingSocksConnection) policy() *Policy { func (sc *pendingSocksConnection) policy() *Policy {
@ -64,7 +65,7 @@ func (sc *pendingSocksConnection) procInfo() *procsnitch.Info {
} }
func (sc *pendingSocksConnection) getOptString() string { func (sc *pendingSocksConnection) getOptString() string {
return "" return sc.optstr
} }
func (sc *pendingSocksConnection) hostname() string { func (sc *pendingSocksConnection) hostname() string {
@ -205,20 +206,86 @@ func (c *socksChainSession) addressDetails() (string, net.IP, uint16) {
return "", ip, uint16(port) return "", ip, uint16(port)
} }
func findProxyEndpoint(pdata []string, conn net.Conn) (*procsnitch.Info, string) {
for _, pstr := range pdata {
toks := strings.Split(pstr, " ")
if len(toks) != 6 {
continue
}
s1, d1, s2, d2 := toks[0], toks[2], toks[3], toks[5]
if strings.HasSuffix(d1, ",") {
d1 = d1[0:len(d1)-1]
}
if conn.LocalAddr().String() == d2 && conn.RemoteAddr().String() == s2 {
srcips, srcps, err := net.SplitHostPort(s1)
dstips, dstps, err2 := net.SplitHostPort(d1)
if err != nil && err2 != nil {
continue
}
srcip := net.ParseIP(srcips)
dstip := net.ParseIP(dstips)
if srcip == nil || dstip == nil {
continue
}
srcport, err := strconv.Atoi(srcps)
dstport, err2 := strconv.Atoi(dstps)
if err != nil || err2 != nil {
continue
}
res := procsnitch.LookupTCPSocketProcessAll(srcip, uint16(srcport), dstip, uint16(dstport), nil)
res, optstr := LookupSandboxProc(srcip, uint16(srcport), dstip, uint16(dstport), "tcp", procsnitch.MATCH_STRICT, 0)
if res != nil {
return res, optstr
}
}
}
return nil, ""
}
func (c *socksChainSession) filterConnect() bool { func (c *socksChainSession) filterConnect() bool {
pinfo := procsnitch.FindProcessForConnection(c.clientConn, c.procInfo) allProxies, err := ListProxies()
var pinfo *procsnitch.Info = nil
var optstr = ""
if err == nil {
pinfo, optstr = findProxyEndpoint(allProxies, c.clientConn)
}
if pinfo == nil {
pinfo = procsnitch.FindProcessForConnection(c.clientConn, c.procInfo)
}
if pinfo == nil { if pinfo == nil {
log.Warningf("No proc found for [socks5] connection from: %s", c.clientConn.RemoteAddr()) log.Warningf("No proc found for [socks5] connection from: %s", c.clientConn.RemoteAddr())
return false return false
} }
if optstr == "" {
optstr = "[via SOCKS5/Tor]"
} else {
optstr = "SOCKS5|Tor / " + optstr
}
policy := c.server.fw.PolicyForPath(pinfo.ExePath) policy := c.server.fw.PolicyForPath(pinfo.ExePath)
hostname, ip, port := c.addressDetails() hostname, ip, port := c.addressDetails()
if ip == nil && hostname == "" { if ip == nil && hostname == "" {
return false return false
} }
result := policy.rules.filter(nil, nil, ip, port, hostname, pinfo, "SOCKS") result := policy.rules.filter(nil, nil, ip, port, hostname, pinfo, optstr)
switch result { switch result {
case FILTER_DENY: case FILTER_DENY:
return false return false
@ -261,6 +328,7 @@ func (c *socksChainSession) filterConnect() bool {
pinfo: pinfo, pinfo: pinfo,
verdict: make(chan int), verdict: make(chan int),
prompting: false, prompting: false,
optstr: optstr,
} }
policy.processPromptResult(pending) policy.processPromptResult(pending)
v := <-pending.verdict v := <-pending.verdict

Loading…
Cancel
Save