Support for TLSGuard in prompter

shw_dev
dma 7 years ago
parent 9ff74569f3
commit f3f5414fd4

@ -27,6 +27,7 @@ type promptData struct {
Username string Username string
Groupname string Groupname string
Pid int Pid int
Sandbox string
OptString string OptString string
Expanded bool Expanded bool
Expert bool Expert bool
@ -63,10 +64,10 @@ func newDbusServer() (*dbusServer, error) {
return ds, nil return ds, nil
} }
func (ds *dbusServer) RequestPrompt(application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, func (ds *dbusServer) RequestPrompt(application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string,
optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) { optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) {
log.Printf("request prompt: app = %s, icon = %s, path = %s, address = %s, action = %v\n", application, icon, path, address, action) log.Printf("request prompt: app = %s, icon = %s, path = %s, address = %s, action = %v\n", application, icon, path, address, action)
decision := addRequest(nil, path, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, optstring) decision := addRequest(nil, path, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, optstring, sandbox)
log.Print("Waiting on decision...") log.Print("Waiting on decision...")
decision.Cond.L.Lock() decision.Cond.L.Lock()
for !decision.Ready { for !decision.Ready {

@ -319,7 +319,7 @@ func createListStore(general bool) *gtk.ListStore {
return listStore return listStore
} }
func addRequest(listStore *gtk.ListStore, path, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin, optstring string) *decisionWaiter { func addRequest(listStore *gtk.ListStore, path, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin, optstring string, sandbox string) *decisionWaiter {
if listStore == nil { if listStore == nil {
listStore = globalLS listStore = globalLS
} }

@ -19,7 +19,7 @@ const RuleScope = {
const DetailSection = new Lang.Class({ const DetailSection = new Lang.Class({
Name: 'DetailSection', Name: 'DetailSection',
_init: function() { _init: function(sandboxed) {
this.actor = new St.BoxLayout({ style_class: 'fw-details-section' }); this.actor = new St.BoxLayout({ style_class: 'fw-details-section' });
this._left = new St.BoxLayout({ vertical: true, style_class: 'fw-details-left'}); this._left = new St.BoxLayout({ vertical: true, style_class: 'fw-details-left'});
this._right = new St.BoxLayout({ vertical: true }); this._right = new St.BoxLayout({ vertical: true });
@ -32,6 +32,11 @@ const DetailSection = new Lang.Class({
this.origin = this._addDetails("Origin:"); this.origin = this._addDetails("Origin:");
this.user = this._addDetails("User:"); this.user = this._addDetails("User:");
this.group = this._addDetails("Group:"); this.group = this._addDetails("Group:");
this.sandboxed = sandboxed;
if (sandboxed) {
this.sandbox = this._addDetails("Sandbox:");
}
this.optstring = this._addDetails(""); this.optstring = this._addDetails("");
}, },
@ -43,7 +48,7 @@ const DetailSection = new Lang.Class({
return msg; return msg;
}, },
setDetails: function(ip, path, pid, uid, gid, user, group, origin, proto, optstring) { setDetails: function(ip, path, pid, uid, gid, user, group, origin, proto, optstring, sandbox) {
this.ipAddr.text = ip; this.ipAddr.text = ip;
this.path.text = path; this.path.text = path;
@ -73,6 +78,10 @@ const DetailSection = new Lang.Class({
this.group.text = "gid:" + gid.toString(); this.group.text = "gid:" + gid.toString();
} }
if (sandbox != "") {
this.sandbox.text = sandbox;
}
this.optstring.text = optstring this.optstring.text = optstring
} }
}); });
@ -130,7 +139,7 @@ Signals.addSignalMethods(OptionListItem.prototype);
const OptionList = new Lang.Class({ const OptionList = new Lang.Class({
Name: 'OptionList', Name: 'OptionList',
_init: function(pid_known) { _init: function(pid_known, sandboxed) {
this.actor = new St.BoxLayout({vertical: true, style_class: 'fw-option-list'}); this.actor = new St.BoxLayout({vertical: true, style_class: 'fw-option-list'});
if (pid_known) { if (pid_known) {
this.buttonGroup = new ButtonGroup("Forever", "Session", "Once", "PID"); this.buttonGroup = new ButtonGroup("Forever", "Session", "Once", "PID");
@ -140,6 +149,7 @@ const OptionList = new Lang.Class({
this.actor.add_child(this.buttonGroup.actor); this.actor.add_child(this.buttonGroup.actor);
this.items = []; this.items = [];
this._selected; this._selected;
this.tlsGuard = true;
}, },
setOptionText: function(idx, text) { setOptionText: function(idx, text) {
@ -150,6 +160,29 @@ const OptionList = new Lang.Class({
this.items[idx].setText(text); this.items[idx].setText(text);
}, },
addTLSOption: function(tlsGuardEnabled) {
let tlsg = new OptionListItem("Drop connection if not TLS with valid certificate",0);
tlsg.setSelected(tlsGuardEnabled);
tlsg.connect('selected', Lang.bind(this, function() {
this._toggleTLSGuard(tlsg);
}));
let emptyRow = new OptionListItem("",0);
this.actor.add_child(emptyRow.actor);
this.actor.add_child(tlsg.actor);
},
_toggleTLSGuard: function(item) {
if (this.tlsGuard == true) {
item.actor.remove_style_pseudo_class('selected');
item.setSelected(false);
this.tlsGuard = false;
} else {
this.tlsGuard = true;
item.actor.add_style_pseudo_class('selected');
item.setSelected(true)
}
},
addOptions: function(options) { addOptions: function(options) {
for(let i = 0; i < options.length; i++) { for(let i = 0; i < options.length; i++) {
this._addOption(options[i], i) this._addOption(options[i], i)
@ -422,7 +455,7 @@ const PromptDialog = new Lang.Class({
Name: 'PromptDialog', Name: 'PromptDialog',
Extends: ModalDialog.ModalDialog, Extends: ModalDialog.ModalDialog,
_init: function(invocation, pid_known) { _init: function(invocation, pid_known, sandboxed) {
this.parent({ styleClass: 'fw-prompt-dialog' }); this.parent({ styleClass: 'fw-prompt-dialog' });
this._invocation = invocation; this._invocation = invocation;
this.header = new PromptDialogHeader(); this.header = new PromptDialogHeader();
@ -432,10 +465,10 @@ const PromptDialog = new Lang.Class({
this.contentLayout.add(this.details.actor, {y_fill: false, x_fill: true}); this.contentLayout.add(this.details.actor, {y_fill: false, x_fill: true});
let box = new St.BoxLayout({ vertical: true }); let box = new St.BoxLayout({ vertical: true });
this.details.set_child(box); this.details.set_child(box);
this.info = new DetailSection(); this.info = new DetailSection(sandboxed);
box.add_child(this.info.actor); box.add_child(this.info.actor);
this.optionList = new OptionList(pid_known); this.optionList = new OptionList(pid_known, sandboxed);
box.add_child(this.optionList.actor); box.add_child(this.optionList.actor);
this.optionList.addOptions([ this.optionList.addOptions([
"Only PORT AND ADDRESS", "Only PORT AND ADDRESS",
@ -443,6 +476,13 @@ const PromptDialog = new Lang.Class({
"Only PORT", "Only PORT",
"Any Connection"]); "Any Connection"]);
if (sandboxed) {
this.optionList.addTLSOption(true);
}
// let tlsGuard = new OptionListItem("Drop connection if not TLS with valid certificate.",0);
//box.add_child(optionList.actor);
this._initialKeyFocusDestroyId = 1; this._initialKeyFocusDestroyId = 1;
this.setButtons([ this.setButtons([
{ label: "Allow", action: Lang.bind(this, this.onAllow) }, { label: "Allow", action: Lang.bind(this, this.onAllow) },
@ -467,9 +507,15 @@ const PromptDialog = new Lang.Class({
let verb = "DENY"; let verb = "DENY";
if(allow) { if(allow) {
verb = "ALLOW"; verb = "ALLOW";
if (this.optionList.tlsGuard) {
verb = "ALLOW_TLSONLY";
} else {
verb = "ALLOW";
}
} }
let rule = verb + "|" + this.ruleTarget(); let rule = verb + "|" + this.ruleTarget() + "|" + this.ruleSandbox();
let scope = this.optionList.selectedScope()
let scope = this.optionList.selectedScope();
this._invocation.return_value(GLib.Variant.new('(is)', [scope, rule])); this._invocation.return_value(GLib.Variant.new('(is)', [scope, rule]));
this._invocation = null; this._invocation = null;
}, },
@ -491,10 +537,20 @@ const PromptDialog = new Lang.Class({
} }
}, },
update: function(application, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action) { ruleSandbox: function() {
return this._sandbox;
},
ruleTLSGuard: function() {
return this.optionList.tlsGuard;
},
update: function(application, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, sandbox, expanded, expert, action) {
this._address = address; this._address = address;
this._port = port; this._port = port;
this._proto = proto; this._proto = proto;
this._sandbox = sandbox;
this._tlsGuard;
let port_str = (proto+"").toUpperCase() + " Port "+ port; let port_str = (proto+"").toUpperCase() + " Port "+ port;
@ -502,6 +558,10 @@ const PromptDialog = new Lang.Class({
port_str = (proto+"").toUpperCase() + " Code "+ port; port_str = (proto+"").toUpperCase() + " Code "+ port;
} }
if (sandbox != "") {
application = application + " (sandboxed)"
}
this.header.setTitle(application); this.header.setTitle(application);
if (proto == "tcp") { if (proto == "tcp") {
@ -548,6 +608,6 @@ const PromptDialog = new Lang.Class({
} }
this.optionList.buttonGroup._setChecked(this.optionList.scopeToIdx(action)) this.optionList.buttonGroup._setChecked(this.optionList.scopeToIdx(action))
this.info.setDetails(ip, path, pid, uid, gid, user, group, origin, proto, optstring); this.info.setDetails(ip, path, pid, uid, gid, user, group, origin, proto, optstring, sandbox);
}, },
}); });

@ -57,6 +57,7 @@ const FirewallPromptInterface = '<node> \
<arg type="s" direction="in" name="user" /> \ <arg type="s" direction="in" name="user" /> \
<arg type="s" direction="in" name="group" /> \ <arg type="s" direction="in" name="group" /> \
<arg type="i" direction="in" name="pid" /> \ <arg type="i" direction="in" name="pid" /> \
<arg type="s" direction="in" name="sandbox" /> \
<arg type="s" direction="in" name="optstring" /> \ <arg type="s" direction="in" name="optstring" /> \
<arg type="b" direction="in" name="expanded" /> \ <arg type="b" direction="in" name="expanded" /> \
<arg type="b" direction="in" name="expert" /> \ <arg type="b" direction="in" name="expert" /> \
@ -92,11 +93,11 @@ const FirewallPromptHandler = new Lang.Class({
}, },
RequestPromptAsync: function(params, invocation) { RequestPromptAsync: function(params, invocation) {
let [app, icon, path, address, port, ip, origin, proto, uid, gid, user, group, pid, optstring, expanded, expert, action] = params; let [app, icon, path, address, port, ip, origin, proto, uid, gid, user, group, pid, sandbox, optstring, expanded, expert, action] = params;
// this._closeDialog(); // this._closeDialog();
this._dialog = new Dialog.PromptDialog(invocation, (pid >= 0)); this._dialog = new Dialog.PromptDialog(invocation, (pid >= 0), (sandbox != ""));
this._invocation = invocation; this._invocation = invocation;
this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action); this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, sandbox, expanded, expert, action);
this._dialog.open(); this._dialog.open();
}, },

@ -15,16 +15,19 @@ type RuleAction uint16
const ( const (
RULE_ACTION_DENY RuleAction = iota RULE_ACTION_DENY RuleAction = iota
RULE_ACTION_ALLOW RULE_ACTION_ALLOW
RULE_ACTION_ALLOW_TLSONLY
) )
// RuleActionString is used to get a string from an action id // RuleActionString is used to get a string from an action id
var RuleActionString = map[RuleAction]string{ var RuleActionString = map[RuleAction]string{
RULE_ACTION_DENY: "DENY", RULE_ACTION_DENY: "DENY",
RULE_ACTION_ALLOW: "ALLOW", RULE_ACTION_ALLOW: "ALLOW",
RULE_ACTION_ALLOW_TLSONLY: "ALLOW_TLSONLY",
} }
// RuleActionValue is used to get an action id using the action string // RuleActionValue is used to get an action id using the action string
var RuleActionValue = map[string]RuleAction{ var RuleActionValue = map[string]RuleAction{
RuleActionString[RULE_ACTION_DENY]: RULE_ACTION_DENY, RuleActionString[RULE_ACTION_DENY]: RULE_ACTION_DENY,
RuleActionString[RULE_ACTION_ALLOW]: RULE_ACTION_ALLOW, RuleActionString[RULE_ACTION_ALLOW]: RULE_ACTION_ALLOW,
RuleActionString[RULE_ACTION_ALLOW_TLSONLY]: RULE_ACTION_ALLOW_TLSONLY,
} }
//RuleMode contains the time scope of a rule //RuleMode contains the time scope of a rule
@ -94,18 +97,21 @@ const (
FILTER_DENY FilterResult = iota FILTER_DENY FilterResult = iota
FILTER_ALLOW FILTER_ALLOW
FILTER_PROMPT FILTER_PROMPT
FILTER_ALLOW_TLSONLY
) )
// FilterResultString converts a filter value ID to its string // FilterResultString converts a filter value ID to its string
var FilterResultString = map[FilterResult]string{ var FilterResultString = map[FilterResult]string{
FILTER_DENY: "DENY", FILTER_DENY: "DENY",
FILTER_ALLOW: "ALLOW", FILTER_ALLOW: "ALLOW",
FILTER_PROMPT: "PROMPT", FILTER_PROMPT: "PROMPT",
FILTER_ALLOW_TLSONLY: "ALLOW_TLSONLY",
} }
// FilterResultValue converts a filter value string to its ID // FilterResultValue converts a filter value string to its ID
var FilterResultValue = map[string]FilterResult{ var FilterResultValue = map[string]FilterResult{
FilterResultString[FILTER_DENY]: FILTER_DENY, FilterResultString[FILTER_DENY]: FILTER_DENY,
FilterResultString[FILTER_ALLOW]: FILTER_ALLOW, FilterResultString[FILTER_ALLOW]: FILTER_ALLOW,
FilterResultString[FILTER_PROMPT]: FILTER_PROMPT, FilterResultString[FILTER_PROMPT]: FILTER_PROMPT,
FilterResultString[FILTER_ALLOW_TLSONLY]: FILTER_ALLOW_TLSONLY,
} }
// DbusRule struct of the rule passed to the dbus interface // DbusRule struct of the rule passed to the dbus interface

@ -18,12 +18,13 @@ const ReceiverSocketPath = "/tmp/fwoz.sock"
type OzInitProc struct { type OzInitProc struct {
Name string Name string
Pid int Pid int
SandboxID int
} }
var OzInitPids []OzInitProc = []OzInitProc{} var OzInitPids []OzInitProc = []OzInitProc{}
func addInitPid(pid int, name string) { func addInitPid(pid int, name string, sboxid int) {
fmt.Println("::::::::::: init pid added: ", pid, " -> ", name) fmt.Println("::::::::::: init pid added: ", pid, " -> ", name)
for i := 0; i < len(OzInitPids); i++ { for i := 0; i < len(OzInitPids); i++ {
if OzInitPids[i].Pid == pid { if OzInitPids[i].Pid == pid {
@ -31,7 +32,7 @@ fmt.Println("::::::::::: init pid added: ", pid, " -> ", name)
} }
} }
ozi := OzInitProc{Name: name, Pid: pid} ozi := OzInitProc{Name: name, Pid: pid, SandboxID: sboxid}
OzInitPids = append(OzInitPids, ozi) OzInitPids = append(OzInitPids, ozi)
} }
@ -163,6 +164,7 @@ func ReceiverLoop(fw *Firewall, c net.Conn) {
if tokens[0] == "register-init" && len(tokens) >= 3 { if tokens[0] == "register-init" && len(tokens) >= 3 {
initp := tokens[1] initp := tokens[1]
initpid, err := strconv.Atoi(initp) initpid, err := strconv.Atoi(initp)
if err != nil { if err != nil {
@ -171,8 +173,15 @@ func ReceiverLoop(fw *Firewall, c net.Conn) {
return return
} }
ozname := strings.Join(tokens[2:], " ") sboxid, err := strconv.Atoi(tokens[3])
addInitPid(initpid, ozname) if err != nil {
log.Notice("IPC received invalid oz sbox number: ",tokens[3])
c.Write([]byte("Bad command: sandbox id was invalid"))
return
}
// ozname := strings.Join(tokens[2:], " ")
addInitPid(initpid, tokens[2], sboxid)
c.Write([]byte("OK.\n")) c.Write([]byte("OK.\n"))
return return
} else if tokens[0] == "unregister-init" && len(tokens) == 2 { } else if tokens[0] == "unregister-init" && len(tokens) == 2 {
@ -278,8 +287,8 @@ func OzReceiver(fw *Firewall) {
if len(sboxes) > 0 { if len(sboxes) > 0 {
log.Warning("Adding existing Oz sandbox init pids...") log.Warning("Adding existing Oz sandbox init pids...")
for s := 0; s < len(sboxes); s++ { for s := 0; s < len(sboxes); s++ {
profname := fmt.Sprintf("%s (%d)", sboxes[s].Profile, sboxes[s].Id) //profname := fmt.Sprintf("%s (%d)", sboxes[s].Profile, sboxes[s].Id)
addInitPid(sboxes[s].InitPid, profname) addInitPid(sboxes[s].InitPid, sboxes[s].Profile, sboxes[s].Id)
} }
} else { } else {
log.Warning("It does not appear there were any Oz sandboxed processes already launched.") log.Warning("It does not appear there were any Oz sandboxed processes already launched.")

@ -2,20 +2,20 @@ package sgfw
import ( import (
"fmt" "fmt"
"strings"
"strconv" "strconv"
"strings"
"sync" "sync"
// "encoding/binary" // "encoding/binary"
// nfnetlink "github.com/subgraph/go-nfnetlink" // nfnetlink "github.com/subgraph/go-nfnetlink"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
"github.com/subgraph/go-procsnitch" "github.com/subgraph/go-procsnitch"
"net" "net"
"os"
"syscall" "syscall"
"unsafe" "unsafe"
"os"
) )
var _interpreters = []string{ var _interpreters = []string{
@ -45,7 +45,9 @@ type pendingConnection interface {
srcPort() uint16 srcPort() uint16
dst() net.IP dst() net.IP
dstPort() uint16 dstPort() uint16
sandbox() string
accept() accept()
acceptTLSOnly()
drop() drop()
setPrompting(bool) setPrompting(bool)
getPrompting() bool getPrompting() bool
@ -72,6 +74,10 @@ func getEmptyPInfo() *procsnitch.Info {
return &pinfo return &pinfo
} }
func (pp *pendingPkt) sandbox() string {
return pp.pinfo.Sandbox
}
func (pp *pendingPkt) policy() *Policy { func (pp *pendingPkt) policy() *Policy {
return pp.pol return pp.pol
} }
@ -142,6 +148,13 @@ func (pp *pendingPkt) accept() {
pp.pkt.Accept() pp.pkt.Accept()
} }
func (pp *pendingPkt) acceptTLSOnly() {
// Not implemented
pp.pkt.SetMark(1)
pp.pkt.Accept()
}
func (pp *pendingPkt) drop() { func (pp *pendingPkt) drop() {
pp.pkt.SetMark(1) pp.pkt.SetMark(1)
pp.pkt.Accept() pp.pkt.Accept()
@ -196,7 +209,7 @@ func (fw *Firewall) policyForPath(path string) *Policy {
func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, optstr string) { func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, optstr string) {
/* hbytes, err := pkt.GetHWAddr() /* hbytes, err := pkt.GetHWAddr()
if err != nil { if err != nil {
log.Notice("Failed to get HW address underlying packet: ", err) log.Notice("Failed to get HW address underlying packet: ", err)
} else { log.Notice("got hwaddr: ", hbytes) } */ } else { log.Notice("got hwaddr: ", hbytes) } */
@ -209,7 +222,7 @@ func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, o
if !FirewallConfig.LogRedact { if !FirewallConfig.LogRedact {
log.Infof("Lookup(%s): %s", dstip.String(), name) log.Infof("Lookup(%s): %s", dstip.String(), name)
} }
// fwo := matchAgainstOzRules(srcip, dstip, dstp) // fwo := matchAgainstOzRules(srcip, dstip, dstp)
result := p.rules.filterPacket(pkt, pinfo, srcip, name, optstr) result := p.rules.filterPacket(pkt, pinfo, srcip, name, optstr)
switch result { switch result {
@ -227,7 +240,8 @@ func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, o
func (p *Policy) processPromptResult(pc pendingConnection) { func (p *Policy) processPromptResult(pc pendingConnection) {
p.pendingQueue = append(p.pendingQueue, pc) p.pendingQueue = append(p.pendingQueue, pc)
fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress) fmt.Println("im here now.. processing prompt result..")
fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress)
if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) { if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) {
p.promptInProgress = true p.promptInProgress = true
go p.fw.dbus.prompt(p) go p.fw.dbus.prompt(p)
@ -248,13 +262,13 @@ func (p *Policy) nextPending() (pendingConnection, bool) {
return nil, true return nil, true
} }
// for len(p.pendingQueue) != 0 { // for len(p.pendingQueue) != 0 {
for i := 0; i < len(p.pendingQueue); i++ { for i := 0; i < len(p.pendingQueue); i++ {
if !p.pendingQueue[i].getPrompting() { if !p.pendingQueue[i].getPrompting() {
return p.pendingQueue[i], false return p.pendingQueue[i], false
} }
} }
// } // }
return nil, false return nil, false
} }
@ -281,7 +295,7 @@ func (p *Policy) processNewRule(r *Rule, scope FilterScope) bool {
if scope != APPLY_ONCE { if scope != APPLY_ONCE {
p.rules = append(p.rules, r) p.rules = append(p.rules, r)
} }
log.Noticef("processNewRule: ",r)
p.filterPending(r) p.filterPending(r)
if len(p.pendingQueue) == 0 { if len(p.pendingQueue) == 0 {
p.promptInProgress = false p.promptInProgress = false
@ -291,7 +305,7 @@ func (p *Policy) processNewRule(r *Rule, scope FilterScope) bool {
} }
func (p *Policy) parseRule(s string, add bool) (*Rule, error) { func (p *Policy) parseRule(s string, add bool) (*Rule, error) {
log.Noticef("XXX: attempt to parse rule: |%s|\n", s) log.Noticef("XXX: attempt to parse rule: |%s|\n", s)
r := new(Rule) r := new(Rule)
r.pid = -1 r.pid = -1
r.mode = RULE_MODE_PERMANENT r.mode = RULE_MODE_PERMANENT
@ -324,15 +338,17 @@ func (p *Policy) removeRule(r *Rule) {
func (p *Policy) filterPending(rule *Rule) { func (p *Policy) filterPending(rule *Rule) {
remaining := []pendingConnection{} remaining := []pendingConnection{}
for _, pc := range p.pendingQueue { for _, pc := range p.pendingQueue {
if rule.match(pc.src(), pc.dst(), pc.dstPort(), pc.hostname(), pc.proto(), pc.procInfo().UID, pc.procInfo().GID, uidToUser(pc.procInfo().UID), gidToGroup(pc.procInfo().GID)) { if rule.match(pc.src(), pc.dst(), pc.dstPort(), pc.hostname(), pc.proto(), pc.procInfo().UID, pc.procInfo().GID, uidToUser(pc.procInfo().UID), gidToGroup(pc.procInfo().GID), pc.procInfo().Sandbox) {
log.Infof("Adding rule for: %s", rule.getString(FirewallConfig.LogRedact)) log.Infof("Adding rule for: %s", rule.getString(FirewallConfig.LogRedact))
log.Noticef("%s > %s", rule.getString(FirewallConfig.LogRedact), pc.print()) log.Noticef("%s > %s", rule.getString(FirewallConfig.LogRedact), pc.print())
if rule.rtype == RULE_ACTION_ALLOW { if rule.rtype == RULE_ACTION_ALLOW {
pc.accept() pc.accept()
} else if rule.rtype == RULE_ACTION_ALLOW_TLSONLY {
pc.acceptTLSOnly()
} else { } else {
srcs := pc.src().String() + ":" + strconv.Itoa(int(pc.srcPort())) srcs := pc.src().String() + ":" + strconv.Itoa(int(pc.srcPort()))
log.Warningf("DENIED outgoing connection attempt by %s from %s %s -> %s:%d (user prompt)", log.Warningf("DENIED outgoing connection attempt by %s from %s %s -> %s:%d (user prompt) %v",
pc.procInfo().ExePath, pc.proto(), srcs, pc.dst(), pc.dstPort) pc.procInfo().ExePath, pc.proto(), srcs, pc.dst(), pc.dstPort, rule.rtype)
pc.drop() pc.drop()
} }
} else { } else {
@ -390,7 +406,6 @@ func printPacket(pkt *nfqueue.NFQPacket, hostname string, pinfo *procsnitch.Info
return fmt.Sprintf("(%s %s:%d -> %s:%d)", proto, SrcIp, SrcPort, name, DstPort) return fmt.Sprintf("(%s %s:%d -> %s:%d)", proto, SrcIp, SrcPort, name, DstPort)
} }
return fmt.Sprintf("%s %s %s:%d -> %s:%d", pinfo.ExePath, proto, SrcIp, SrcPort, name, DstPort) return fmt.Sprintf("%s %s %s:%d -> %s:%d", pinfo.ExePath, proto, SrcIp, SrcPort, name, DstPort)
} }
@ -412,8 +427,8 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) {
} }
_, dstip := getPacketIPAddrs(pkt) _, dstip := getPacketIPAddrs(pkt)
/* _, dstp := getPacketPorts(pkt) /* _, dstp := getPacketPorts(pkt)
fwo := matchAgainstOzRules(srcip, dstip, dstp) fwo := eatchAgainstOzRules(srcip, dstip, dstp)
log.Notice("XXX: Attempting [2] to filter packet on rules -> ", fwo) log.Notice("XXX: Attempting [2] to filter packet on rules -> ", fwo)
if fwo == OZ_FWRULE_WHITELIST { if fwo == OZ_FWRULE_WHITELIST {
@ -440,8 +455,8 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) {
ppath = "[unknown]" ppath = "[unknown]"
optstring = "[Connection could not be mapped]" optstring = "[Connection could not be mapped]"
log.Warningf("No proc found for %s", printPacket(pkt, fw.dns.Lookup(dstip, pinfo.Pid), nil)) log.Warningf("No proc found for %s", printPacket(pkt, fw.dns.Lookup(dstip, pinfo.Pid), nil))
// pkt.Accept() // pkt.Accept()
// return // return
} else { } else {
ppath = pinfo.ExePath ppath = pinfo.ExePath
cf := strings.Fields(pinfo.CmdLine) cf := strings.Fields(pinfo.CmdLine)
@ -455,13 +470,13 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) {
} }
} }
log.Debugf("filterPacket [%s] %s", ppath, printPacket(pkt, fw.dns.Lookup(dstip, pinfo.Pid), nil)) log.Debugf("filterPacket [%s] %s", ppath, printPacket(pkt, fw.dns.Lookup(dstip, pinfo.Pid), nil))
/* if basicAllowPacket(pkt) { /* if basicAllowPacket(pkt) {
pkt.Accept() pkt.Accept()
return return
} }
*/ */
policy := fw.PolicyForPath(ppath) policy := fw.PolicyForPath(ppath)
//log.Notice("XXX: flunked basicallowpacket; policy = ", policy) //log.Notice("XXX: flunked basicallowpacket; policy = ", policy)
policy.processPacket(pkt, pinfo, optstring) policy.processPacket(pkt, pinfo, optstring)
} }
@ -502,7 +517,7 @@ func getAllProcNetDataLocal() ([]string, error) {
for i := 0; i < len(OzInitPids); i++ { for i := 0; i < len(OzInitPids); i++ {
fname := fmt.Sprintf("/proc/%d/net/tcp", OzInitPids[i]) fname := fmt.Sprintf("/proc/%d/net/tcp", OzInitPids[i])
//fmt.Println("XXX: opening: ", fname) //fmt.Println("XXX: opening: ", fname)
bdata, err := readFileDirect(fname) bdata, err := readFileDirect(fname)
if err != nil { if err != nil {
@ -558,7 +573,7 @@ func LookupSandboxProc(srcip net.IP, srcp uint16, dstip net.IP, dstp uint16, pro
for i := 0; i < len(OzInitPids); i++ { for i := 0; i < len(OzInitPids); i++ {
data := "" data := ""
fname := fmt.Sprintf("/proc/%d/net/%s", OzInitPids[i].Pid, proto) fname := fmt.Sprintf("/proc/%d/net/%s", OzInitPids[i].Pid, proto)
//fmt.Println("XXX: opening: ", fname) //fmt.Println("XXX: opening: ", fname)
bdata, err := readFileDirect(fname) bdata, err := readFileDirect(fname)
if err != nil { if err != nil {
@ -594,7 +609,8 @@ func LookupSandboxProc(srcip net.IP, srcp uint16, dstip net.IP, dstp uint16, pro
} }
if res != nil { if res != nil {
optstr = "Sandbox: " + OzInitPids[i].Name // optstr = "Sandbox: " + OzInitPids[i].Name
res.Sandbox = OzInitPids[i].Name
res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid) res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid)
break break
} }
@ -657,7 +673,7 @@ func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int)
for i := 0; i < len(OzInitPids); i++ { for i := 0; i < len(OzInitPids); i++ {
data := "" data := ""
fname := fmt.Sprintf("/proc/%d/net/%s", OzInitPids[i].Pid, proto) fname := fmt.Sprintf("/proc/%d/net/%s", OzInitPids[i].Pid, proto)
//fmt.Println("XXX: opening: ", fname) //fmt.Println("XXX: opening: ", fname)
bdata, err := readFileDirect(fname) bdata, err := readFileDirect(fname)
if err != nil { if err != nil {
@ -741,7 +757,7 @@ func getPacketIPAddrs(pkt *nfqueue.NFQPacket) (net.IP, net.IP) {
if ipLayer == nil { if ipLayer == nil {
if ipv4 { if ipv4 {
return net.IP{0,0,0,0}, net.IP{0,0,0,0} return net.IP{0, 0, 0, 0}, net.IP{0, 0, 0, 0}
} }
return net.IP{}, net.IP{} return net.IP{}, net.IP{}
} }

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"os/user" "os/user"
"strconv" "strconv"
//"strings" "strings"
"sync" "sync"
"time" "time"
@ -140,6 +140,8 @@ func (p *prompter) processConnection(pc pendingConnection) {
if pc.dst() != nil { if pc.dst() != nil {
dststr = pc.dst().String() dststr = pc.dst().String()
} else {
dststr = addr + " (proxy to resolve)"
} }
call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPrompt", 0, call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPrompt", 0,
@ -156,6 +158,7 @@ func (p *prompter) processConnection(pc pendingConnection) {
uidToUser(pc.procInfo().UID), uidToUser(pc.procInfo().UID),
gidToGroup(pc.procInfo().GID), gidToGroup(pc.procInfo().GID),
int32(pc.procInfo().Pid), int32(pc.procInfo().Pid),
pc.sandbox(),
pc.getOptString(), pc.getOptString(),
FirewallConfig.PromptExpanded, FirewallConfig.PromptExpanded,
FirewallConfig.PromptExpert, FirewallConfig.PromptExpert,
@ -177,6 +180,16 @@ func (p *prompter) processConnection(pc pendingConnection) {
// sometimes there's a src // sometimes there's a src
// this needs to be re-visited // this needs to be re-visited
toks := strings.Split(rule, "|")
//verb := toks[0]
//target := toks[1]
sandbox := ""
if len(toks) > 2 {
sandbox = toks[2]
}
tempRule := fmt.Sprintf("%s|%s",toks[0],toks[1])
if pc.src() != nil { if pc.src() != nil {
@ -185,12 +198,11 @@ func (p *prompter) processConnection(pc pendingConnection) {
//} //}
//ule += "|||" + pc.src().String() //ule += "|||" + pc.src().String()
rule += "||-1:-1||" + pc.src().String() tempRule += "||-1:-1|"+sandbox+"|" + pc.src().String()
log.Warningf("Creating rule: %v", rule)
} else { } else {
rule += "||-1:-1||" tempRule += "||-1:-1|"+sandbox+"|"
} }
r, err := policy.parseRule(rule, false) r, err := policy.parseRule(tempRule, false)
if err != nil { if err != nil {
log.Warningf("Error parsing rule string returned from dbus RequestPrompt: %v", err) log.Warningf("Error parsing rule string returned from dbus RequestPrompt: %v", err)
policy.removePending(pc) policy.removePending(pc)

@ -7,19 +7,20 @@ import (
"net" "net"
"os" "os"
"path" "path"
"regexp"
"strconv" "strconv"
"strings" "strings"
"regexp"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
// "github.com/subgraph/go-nfnetlink" // "github.com/subgraph/go-nfnetlink"
"github.com/subgraph/go-procsnitch" "github.com/subgraph/go-procsnitch"
) )
const matchAny = 0 const matchAny = 0
//const noAddress = uint32(0xffffffff) //const noAddress = uint32(0xffffffff)
var anyAddress net.IP = net.IP{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,} var anyAddress net.IP = net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
var noAddress net.IP = net.IP{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} var noAddress net.IP = net.IP{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
type Rule struct { type Rule struct {
id uint id uint
@ -48,6 +49,8 @@ func (r *Rule) getString(redact bool) string {
rtype := RuleActionString[RULE_ACTION_DENY] rtype := RuleActionString[RULE_ACTION_DENY]
if r.rtype == RULE_ACTION_ALLOW { if r.rtype == RULE_ACTION_ALLOW {
rtype = RuleActionString[RULE_ACTION_ALLOW] rtype = RuleActionString[RULE_ACTION_ALLOW]
} else if r.rtype == RULE_ACTION_ALLOW_TLSONLY {
rtype = RuleActionString[RULE_ACTION_ALLOW_TLSONLY]
} }
rmode := "" rmode := ""
if r.mode == RULE_MODE_SYSTEM { if r.mode == RULE_MODE_SYSTEM {
@ -67,12 +70,11 @@ func (r *Rule) getString(redact bool) string {
sbox := "|" sbox := "|"
if r.sandbox != "" { if r.sandbox != "" {
sbox = "|SANDBOX:"+sbox sbox = "|" + sbox
} else { } else {
log.Notice("sandbox is ", r.sandbox) log.Notice("sandbox is ", r.sandbox)
} }
return fmt.Sprintf("%s|%s%s%s%s%s", rtype, protostr, r.AddrString(redact), rmode, rpriv, sbox) return fmt.Sprintf("%s|%s%s%s%s%s", rtype, protostr, r.AddrString(redact), rmode, rpriv, sbox)
} }
@ -84,9 +86,9 @@ func (r *Rule) AddrString(redact bool) string {
} else if r.network != nil { } else if r.network != nil {
addr = r.network.String() addr = r.network.String()
} else if !addrMatchesAny(r.addr) && !addrMatchesNone(r.addr) { } else if !addrMatchesAny(r.addr) && !addrMatchesNone(r.addr) {
// bs := make([]byte, 4) // bs := make([]byte, 4)
// binary.BigEndian.PutUint32(bs, r.addr) // binary.BigEndian.PutUint32(bs, r.addr)
// addr = fmt.Sprintf("%d.%d.%d.%d", bs[0], bs[1], bs[2], bs[3]) // addr = fmt.Sprintf("%d.%d.%d.%d", bs[0], bs[1], bs[2], bs[3])
addr = r.addr.String() addr = r.addr.String()
} }
@ -103,7 +105,7 @@ func (r *Rule) AddrString(redact bool) string {
type RuleList []*Rule type RuleList []*Rule
func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, proto string, uid, gid int, uname, gname string) bool { func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, proto string, uid, gid int, uname, gname string, sandbox string) bool {
if r.proto != proto { if r.proto != proto {
return false return false
} }
@ -117,7 +119,7 @@ func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, pr
return false return false
} }
log.Notice("comparison: ", hostname, " / ", dst, " : ", dstPort, " -> ", r.addr, " / ", r.hostname, " : ", r.port) log.Notice("comparison: ", hostname, " / ", dst, " : ", dstPort, " -> ", r.addr, " / ", r.hostname, " : ", r.port)
if r.port != matchAny && r.port != dstPort { if r.port != matchAny && r.port != dstPort {
return false return false
} }
@ -160,26 +162,32 @@ func (rl *RuleList) filter(pkt *nfqueue.NFQPacket, src, dst net.IP, dstPort uint
return FILTER_PROMPT return FILTER_PROMPT
} }
result := FILTER_PROMPT result := FILTER_PROMPT
sandboxed := strings.HasPrefix(optstr, "SOCKS5|Tor / Sandbox") sandboxed := false
if pinfo.Sandbox != "" {
sandboxed = true
}
// sandboxed := strings.HasPrefix(optstr, "SOCKS5|Tor / Sandbox")
for _, r := range *rl { for _, r := range *rl {
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("fuck ",r)
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 { if r.saddr == nil && src != nil && sandboxed {
log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src) 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
} else if r.saddr != nil && !r.saddr.Equal(src) && r.proto != "icmp" { } else if r.saddr != nil && !r.saddr.Equal(src) && r.proto != "icmp" {
log.Notice("! Skipping comparison of mismatching source ips") log.Notice("! Skipping comparison of mismatching source ips")
continue continue
} }
log.Notice("r.saddr = ", r.saddr, "src = ", src, "\n") log.Notice("r.saddr = ", r.saddr, "src = ", src, "\n")
if r.pid >= 0 && r.pid != pinfo.Pid { if r.pid >= 0 && r.pid != pinfo.Pid {
//log.Notice("! Skipping comparison of mismatching PIDs") //log.Notice("! Skipping comparison of mismatching PIDs")
continue continue
} }
if r.match(src, dst, dstPort, hostname, getNFQProto(pkt), pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID)) { if r.match(src, dst, dstPort, hostname, getNFQProto(pkt), pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID), pinfo.Sandbox) {
log.Notice("+ MATCH SUCCEEDED") log.Notice("+ MATCH SUCCEEDED")
dstStr := dst.String() dstStr := dst.String()
if FirewallConfig.LogRedact { if FirewallConfig.LogRedact {
dstStr = STR_REDACTED dstStr = STR_REDACTED
@ -208,9 +216,11 @@ log.Notice("+ MATCH SUCCEEDED")
return result return result
} }
} }
} else { log.Notice("+ MATCH FAILED") } } else {
log.Notice("+ MATCH FAILED")
}
} }
log.Notice("--- RESULT = ", result) log.Notice("--- RESULT = ", result)
return result return result
} }
@ -245,9 +255,7 @@ func (r *Rule) parse(s string) bool {
return false return false
} }
log.Notice("parsed sandbox ", parts[4]) fmt.Printf("uid = %v, gid = %v, user = %v, group = %v, hostname = %v, sandbox = %v\n", r.uid, r.gid, r.uname, r.gname, r.hostname, r.sandbox)
//fmt.Printf("uid = %v, gid = %v, user = %v, group = %v, hostname = %v\n", r.uid, r.gid, r.uname, r.gname, r.hostname)
if len(parts) == 6 && len(strings.TrimSpace(parts[5])) > 0 { if len(parts) == 6 && len(strings.TrimSpace(parts[5])) > 0 {
r.saddr = net.ParseIP(parts[5]) r.saddr = net.ParseIP(parts[5])
@ -262,15 +270,7 @@ func (r *Rule) parse(s string) bool {
} }
func (r *Rule) parseSandbox(p string) bool { func (r *Rule) parseSandbox(p string) bool {
if p == "" { r.sandbox = p
r.sandbox = ""
return true
}
toks := strings.Split(p, ":")
if len(toks) != 2 {
return false
}
r.sandbox = toks[1]
return true return true
} }
@ -312,6 +312,9 @@ func (r *Rule) parseVerb(v string) bool {
case RuleActionString[RULE_ACTION_ALLOW]: case RuleActionString[RULE_ACTION_ALLOW]:
r.rtype = RULE_ACTION_ALLOW r.rtype = RULE_ACTION_ALLOW
return true return true
case RuleActionString[RULE_ACTION_ALLOW_TLSONLY]:
r.rtype = RULE_ACTION_ALLOW_TLSONLY
return true
case RuleActionString[RULE_ACTION_DENY]: case RuleActionString[RULE_ACTION_DENY]:
r.rtype = RULE_ACTION_DENY r.rtype = RULE_ACTION_DENY
return true return true
@ -325,7 +328,7 @@ func (r *Rule) parseTarget(t string) bool {
return false return false
} }
sind := 0 sind := 0
lind := len(addrPort)-1 lind := len(addrPort) - 1
if addrPort[0] == "udp" || addrPort[0] == "icmp" || addrPort[0] == "tcp" { if addrPort[0] == "udp" || addrPort[0] == "icmp" || addrPort[0] == "tcp" {
r.proto = addrPort[0] r.proto = addrPort[0]
sind++ sind++
@ -335,7 +338,7 @@ func (r *Rule) parseTarget(t string) bool {
newAddr := strings.Join(addrPort[sind:lind], ":") newAddr := strings.Join(addrPort[sind:lind], ":")
return r.parseAddr(newAddr) && r.parsePort(addrPort[lind]) return r.parseAddr(newAddr) && r.parsePort(addrPort[lind])
// return r.parseAddr(addrPort[sind]) && r.parsePort(addrPort[sind+1]) // return r.parseAddr(addrPort[sind]) && r.parsePort(addrPort[sind+1])
} }
func (r *Rule) parseAddr(a string) bool { func (r *Rule) parseAddr(a string) bool {
@ -344,12 +347,12 @@ func (r *Rule) parseAddr(a string) bool {
r.addr = anyAddress r.addr = anyAddress
return true return true
} }
// if strings.IndexFunc(a, unicode.IsLetter) != -1 { // if strings.IndexFunc(a, unicode.IsLetter) != -1 {
if net.ParseIP(a) == nil { if net.ParseIP(a) == nil {
r.hostname = a r.hostname = a
return true return true
} }
// ip := net.ParseIP(a) // ip := net.ParseIP(a)
ip, ipnet, err := net.ParseCIDR(a) ip, ipnet, err := net.ParseCIDR(a)
if err != nil || ip == nil { if err != nil || ip == nil {
ip = net.ParseIP(a) ip = net.ParseIP(a)
@ -500,7 +503,7 @@ func addrMatchesAny(addr net.IP) bool {
any := anyAddress any := anyAddress
if addr.To4() != nil { if addr.To4() != nil {
any = net.IP{0,0,0,0} any = net.IP{0, 0, 0, 0}
} }
return any.Equal(addr) return any.Equal(addr)
@ -510,7 +513,7 @@ func addrMatchesNone(addr net.IP) bool {
none := noAddress none := noAddress
if addr.To4() != nil { if addr.To4() != nil {
none = net.IP{0xff,0xff,0xff,0xff} none = net.IP{0xff, 0xff, 0xff, 0xff}
} }
return none.Equal(addr) return none.Equal(addr)

@ -6,19 +6,19 @@ import (
"regexp" "regexp"
"sync" "sync"
"syscall" "syscall"
// "time" // "time"
"bufio" "bufio"
"encoding/json" "encoding/json"
"strings"
"fmt" "fmt"
"strings"
"github.com/op/go-logging" "github.com/op/go-logging"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
// "github.com/subgraph/go-nfnetlink" // "github.com/subgraph/go-nfnetlink"
"github.com/subgraph/go-procsnitch"
"github.com/subgraph/fw-daemon/proc-coroner"
"github.com/google/gopacket" "github.com/google/gopacket"
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
"github.com/subgraph/fw-daemon/proc-coroner"
"github.com/subgraph/go-procsnitch"
) )
var dbusp *dbusObjectP = nil var dbusp *dbusObjectP = nil
@ -96,9 +96,9 @@ func (fw *Firewall) runFilter() {
q := nfqueue.NewNFQueue(0) q := nfqueue.NewNFQueue(0)
// XXX: need to implement this // XXX: need to implement this
// q.DefaultVerdict = nfqueue.DROP // q.DefaultVerdict = nfqueue.DROP
// XXX: need this as well // XXX: need this as well
// q.Timeout = 5 * time.Minute // q.Timeout = 5 * time.Minute
ps, err := q.Open() ps, err := q.Open()
@ -145,6 +145,7 @@ func (fw *Firewall) runFilter() {
} }
type SocksJsonConfig struct { type SocksJsonConfig struct {
Name string
SocksListener string SocksListener string
TorSocks string TorSocks string
} }
@ -174,7 +175,7 @@ func loadSocksConfiguration(configFilePath string) (*SocksJsonConfig, error) {
} }
func getSocksChainConfig(config *SocksJsonConfig) *socksChainConfig { func getSocksChainConfig(config *SocksJsonConfig) *socksChainConfig {
// XXX // TODO: fix this to support multiple named proxy forwarders of different types
fields := strings.Split(config.TorSocks, "|") fields := strings.Split(config.TorSocks, "|")
torSocksNet := fields[0] torSocksNet := fields[0]
torSocksAddr := fields[1] torSocksAddr := fields[1]
@ -182,6 +183,7 @@ func getSocksChainConfig(config *SocksJsonConfig) *socksChainConfig {
socksListenNet := fields[0] socksListenNet := fields[0]
socksListenAddr := fields[1] socksListenAddr := fields[1]
socksConfig := socksChainConfig{ socksConfig := socksChainConfig{
Name: config.Name,
TargetSocksNet: torSocksNet, TargetSocksNet: torSocksNet,
TargetSocksAddr: torSocksAddr, TargetSocksAddr: torSocksAddr,
ListenSocksNet: socksListenNet, ListenSocksNet: socksListenNet,
@ -192,7 +194,6 @@ func getSocksChainConfig(config *SocksJsonConfig) *socksChainConfig {
return &socksConfig return &socksConfig
} }
func Main() { func Main() {
readConfig() readConfig()
logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel) logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel)

@ -17,6 +17,7 @@ type socksChainConfig struct {
TargetSocksAddr string TargetSocksAddr string
ListenSocksNet string ListenSocksNet string
ListenSocksAddr string ListenSocksAddr string
Name string
} }
type socksChain struct { type socksChain struct {
@ -41,6 +42,7 @@ type socksChainSession struct {
const ( const (
socksVerdictDrop = 1 socksVerdictDrop = 1
socksVerdictAccept = 2 socksVerdictAccept = 2
socksVerdictAcceptTLSOnly = 3
) )
type pendingSocksConnection struct { type pendingSocksConnection struct {
@ -56,6 +58,10 @@ type pendingSocksConnection struct {
optstr string optstr string
} }
func (sc *pendingSocksConnection) sandbox() string {
return sc.pinfo.Sandbox
}
func (sc *pendingSocksConnection) policy() *Policy { func (sc *pendingSocksConnection) policy() *Policy {
return sc.pol return sc.pol
} }
@ -96,6 +102,10 @@ func (sc *pendingSocksConnection) deliverVerdict(v int) {
func (sc *pendingSocksConnection) accept() { sc.deliverVerdict(socksVerdictAccept) } func (sc *pendingSocksConnection) accept() { sc.deliverVerdict(socksVerdictAccept) }
// need to generalize special accept
func (sc *pendingSocksConnection) acceptTLSOnly() {sc.deliverVerdict(socksVerdictAcceptTLSOnly) }
func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) } func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) }
func (sc *pendingSocksConnection) getPrompting() bool { return sc.prompting } func (sc *pendingSocksConnection) getPrompting() bool { return sc.prompting }
@ -176,11 +186,13 @@ func (c *socksChainSession) sessionWorker() {
c.req.ReplyAddr(ReplySucceeded, c.bndAddr) c.req.ReplyAddr(ReplySucceeded, c.bndAddr)
} }
case CommandConnect: case CommandConnect:
if !c.filterConnect() { verdict, tls := c.filterConnect()
if !verdict {
c.req.Reply(ReplyConnectionRefused) c.req.Reply(ReplyConnectionRefused)
return return
} }
c.handleConnect() c.handleConnect(tls)
default: default:
// Should *NEVER* happen, validated as part of handshake. // Should *NEVER* happen, validated as part of handshake.
log.Infof("BUG/socks: Unsupported SOCKS command: 0x%02x", c.req.Cmd) log.Infof("BUG/socks: Unsupported SOCKS command: 0x%02x", c.req.Cmd)
@ -255,7 +267,9 @@ func findProxyEndpoint(pdata []string, conn net.Conn) (*procsnitch.Info, string)
return nil, "" return nil, ""
} }
func (c *socksChainSession) filterConnect() bool { func (c *socksChainSession) filterConnect() (bool, bool) {
// return filter verdict, tlsguard
allProxies, err := ListProxies() allProxies, err := ListProxies()
var pinfo *procsnitch.Info = nil var pinfo *procsnitch.Info = nil
var optstr = "" var optstr = ""
@ -270,27 +284,30 @@ func (c *socksChainSession) filterConnect() bool {
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, false
} }
if optstr == "" { if optstr == "" {
optstr = "[via SOCKS5/Tor]" optstr = "Via SOCKS5: " + c.cfg.Name
} else { } else {
optstr = "SOCKS5|Tor / " + optstr optstr = "[Via SOCKS5: " + c.cfg.Name + "] " + 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, false
} }
result := policy.rules.filter(nil, nil, ip, port, hostname, pinfo, optstr) result := policy.rules.filter(nil, nil, ip, port, hostname, pinfo, optstr)
log.Errorf("result %v",result)
switch result { switch result {
case FILTER_DENY: case FILTER_DENY:
return false return false, false
case FILTER_ALLOW: case FILTER_ALLOW:
return true return true, false
case FILTER_ALLOW_TLSONLY:
return true, true
case FILTER_PROMPT: case FILTER_PROMPT:
caddr := c.clientConn.RemoteAddr().String() caddr := c.clientConn.RemoteAddr().String()
caddrt := strings.Split(caddr, ":") caddrt := strings.Split(caddr, ":")
@ -333,15 +350,17 @@ func (c *socksChainSession) filterConnect() bool {
policy.processPromptResult(pending) policy.processPromptResult(pending)
v := <-pending.verdict v := <-pending.verdict
if v == socksVerdictAccept { if v == socksVerdictAccept {
return true return true, false
} else if v == socksVerdictAcceptTLSOnly {
return true, true
} }
} }
return false return false, false
} }
func (c *socksChainSession) handleConnect() { func (c *socksChainSession) handleConnect(tls bool) {
err := c.dispatchTorSOCKS() err := c.dispatchTorSOCKS()
if err != nil { if err != nil {
return return
@ -359,11 +378,12 @@ func (c *socksChainSession) handleConnect() {
// A upstream connection has been established, push data back and forth // A upstream connection has been established, push data back and forth
// till the session is done. // till the session is done.
c.forwardTraffic() c.forwardTraffic(tls)
log.Infof("INFO/socks: Closed SOCKS connection from: %v", c.clientConn.RemoteAddr()) log.Infof("INFO/socks: Closed SOCKS connection from: %v", c.clientConn.RemoteAddr())
} }
func (c *socksChainSession) forwardTraffic() { func (c *socksChainSession) forwardTraffic(tls bool) {
if tls == true {
err := TLSGuard(c.clientConn, c.upstreamConn, c.req.Addr.addrStr) err := TLSGuard(c.clientConn, c.upstreamConn, c.req.Addr.addrStr)
if err != nil { if err != nil {
@ -372,6 +392,7 @@ func (c *socksChainSession) forwardTraffic() {
} else { } else {
log.Notice("TLSGuard approved certificate presented for connection to: ", c.req.Addr.addrStr) log.Notice("TLSGuard approved certificate presented for connection to: ", c.req.Addr.addrStr)
} }
}
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(2) wg.Add(2)

Loading…
Cancel
Save