Full support for multiple protocol types (UDP, ICMP).

Cleared up awkward fw-settings/fwprompt GUI language caused by introduction of UDP/ICMP ("connection"-less) rules.
fw-daemon automatically passes through all ICMP traffic sent to same address.
Added (temporary) rule for passing through all UDP-based DNS server traffic.
Updated developers' README documentation.
shw_dev
shw 8 years ago
parent ea31a28d3a
commit 51c181a881

@ -8,3 +8,30 @@ root@subgraph:/# cat /etc/fw-daemon-socks.json
"TorSocks": "tcp|127.0.0.1:9050"
}
Remember that fw-settings will need to be compiled separately with go install .../fw-daemon/fw-settings
And the gnome-shell interface must be refreshed with ALT+F2, r
*** All changes require on the interoperation between the latest versions of fw-daemon, fw-settings, and the gnome-shell Javascript frontend.
These rules will need to be sent to ensure that all passed through/sandboxed(clearnet) traffic will be picked up by the firewall:
iptables -t mangle -I PREROUTING 1 -m conntrack --ctstate NEW --proto tcp -j NFQUEUE --queue-num 0 --queue-bypass
iptables -I FORWARD 1 -m mark --mark 0x1 -j REJECT --reject-with icmp-host-prohibited
The following rules are likewise necessary for fw-daemon to catch udp and icmp data:
iptables -t mangle -I PREROUTING 1 --proto udp -j NFQUEUE --queue-num 0 --queue-bypass
iptables -t mangle -I PREROUTING 1 --proto icmp -j NFQUEUE --queue-num 0 --queue-bypass
Here are some examples of the newly formatted rules in /var/lib/sgfw/sgfw_rules:
#[[unknown]] is used to match an unknown process; this is necessary because even though we can sometimes figure out who's sending an ICMP packet, it's functionally impossible for us to tell who the recipient of an ICMP packet is.
[[unknown]]
ALLOW|icmp:4.2.2.4:0|SYSTEM||
#Note the use of wildcards. These rules are of course redundant, but get the same basic job done.
[/usr/sbin/ntpd]
ALLOW|udp:*.ntp.org:123|SYSTEM||
ALLOW|udp:*:123|SYSTEM||

@ -116,7 +116,11 @@ func (rr *ruleRow) update() {
rr.gtkLabelApp.SetText(rr.rule.App)
rr.gtkLabelApp.SetTooltipText(rr.rule.Path)
rr.gtkLabelVerb.SetText(getVerbText(rr.rule))
rr.gtkLabelOrigin.SetText(rr.rule.Origin)
if (rr.rule.Proto == "tcp") {
rr.gtkLabelOrigin.SetText(rr.rule.Origin)
} else {
rr.gtkLabelOrigin.SetText(rr.rule.Origin + " (" + rr.rule.Proto + ")")
}
rr.gtkLabelPrivs.SetText(rr.rule.Privs)
rr.gtkLabelTarget.SetText(getTargetText(rr.rule))
}
@ -139,13 +143,26 @@ func getTargetText(rule *sgfw.DbusRule) string {
}
if items[0] == "*" {
return fmt.Sprintf("Connections to All hosts on port %s", items[1])
if rule.Proto == "tcp" {
return fmt.Sprintf("Connections to ALL hosts on port %s", items[1])
} else if rule.Proto == "icmp" {
return fmt.Sprintf("Data to ALL hosts with ICMP code %s", items[1])
}
return fmt.Sprintf("Data to ALL hosts on port %s", items[1])
}
if items[1] == "*" {
return fmt.Sprintf("All connections to host %s", items[0])
if rule.Proto == "tcp" {
return fmt.Sprintf("All connections to host %s", items[0])
}
return fmt.Sprintf("All data to host %s", items[0])
}
return fmt.Sprintf("Connections to %s on port %s", items[0], items[1])
if rule.Proto == "tcp" {
return fmt.Sprintf("Connections to %s on port %s", items[0], items[1])
} else if rule.Proto == "icmp" {
return fmt.Sprintf("Data to %s with ICMP code %s", items[0], items[1])
}
return fmt.Sprintf("Data to %s on port %s", items[0], items[1])
}
func (rr *ruleRow) onSaveAsNew() {

@ -42,7 +42,7 @@ const DetailSection = new Lang.Class({
return msg;
},
setDetails: function(ip, path, pid, uid, gid, user, group, origin, optstring) {
setDetails: function(ip, path, pid, uid, gid, user, group, origin, proto, optstring) {
this.ipAddr.text = ip;
this.path.text = path;
@ -55,13 +55,19 @@ const DetailSection = new Lang.Class({
this.origin.text = origin;
if (user != "") {
this.user.text = user + " (" + uid.toString() + ")";
this.user.text = user;
if (uid != -1) {
this.user.text += " (" + uid.toString() + ")";
}
} else {
this.user.text = "uid:" + uid.toString();
}
if (group != "") {
this.group.text = group + " (" + gid.toString() + ")";
this.group.text = group;
if (gid != -1) {
this.group.text += " (" + gid.toString() + ")";
}
} else {
this.group.text = "gid:" + gid.toString();
}
@ -460,26 +466,42 @@ const PromptDialog = new Lang.Class({
},
ruleTarget: function() {
let base = "";
if(this._proto != "tcp") {
base = this._proto + ":";
}
switch(this.optionList.selectedIdx()) {
case 0:
return this._address + ":" + this._port;
return base + this._address + ":" + this._port;
case 1:
return this._address + ":*";
return base + this._address + ":*";
case 2:
return "*:" + this._port;
return base + "*:" + this._port;
case 3:
return "*:*";
return base + "*:*";
}
},
update: function(application, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action) {
this._address = address;
this._port = port;
this._proto = proto;
let port_str = (proto+"").toUpperCase() + " Port "+ port;
if (proto == "icmp") {
port_str = (proto+"").toUpperCase() + " Code "+ port;
}
this.header.setTitle(application);
this.header.setMessage("Wants to connect to "+ address + " on " + port_str);
if (proto == "tcp") {
this.header.setMessage("Wants to connect to "+ address + " on " + port_str);
} else if (proto == "udp") {
this.header.setMessage("Wants to send data to "+ address + " on " + port_str);
} else if (proto == "icmp") {
this.header.setMessage("Wants to send data to "+ address + " with " + port_str);
}
if (expanded) {
this.details.isOpen = false;
@ -491,16 +513,32 @@ const PromptDialog = new Lang.Class({
this.header.setIconDefault();
}
this.optionList.setOptionText(0, "Only "+ address + " on "+ port_str);
if (proto == "icmp") {
this.optionList.setOptionText(0, "Only "+ address + " with "+ port_str);
} else {
this.optionList.setOptionText(0, "Only "+ address + " on "+ port_str);
}
if (expert) {
this.optionList.setOptionText(1, "Only "+ address + " on any port");
if (proto == "icmp") {
this.optionList.setOptionText(1, "Only "+ address + " with any ICMP code");
} else if (proto == "udp") {
this.optionList.setOptionText(1, "Only "+ address + " on any UDP port");
} else {
this.optionList.setOptionText(1, "Only "+ address + " on any port");
}
this.optionList.setOptionText(2, "Only "+ port_str);
} else {
this.optionList.setOptionText(1, false);
this.optionList.setOptionText(2, false);
}
if (proto != "tcp") {
this.optionList.setOptionText(3, "Any " + proto.toUpperCase() + " data");
}
this.optionList.buttonGroup._setChecked(this.optionList.scopeToIdx(action))
this.info.setDetails(ip, path, pid, uid, gid, user, group, origin, optstring);
this.info.setDetails(ip, path, pid, uid, gid, user, group, origin, proto, optstring);
},
});

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

@ -107,6 +107,7 @@ type DbusRule struct {
ID uint32
Net string
Origin string
Proto string
Privs string
App string
Path string

@ -131,6 +131,7 @@ func createDbusRule(r *Rule) DbusRule {
ID: uint32(r.id),
Net: netstr,
Origin: ostr,
Proto: r.proto,
Privs: pstr,
App: path.Base(r.policy.path),
Path: r.policy.path,

@ -41,6 +41,7 @@ type pendingConnection interface {
procInfo() *procsnitch.Info
hostname() string
getOptString() string
proto() string
src() net.IP
srcPort() uint16
dst() net.IP
@ -107,22 +108,40 @@ func (pp *pendingPkt) dst() net.IP {
// pp.pkt.NetworkLayer().Layer
}
func getNFQProto(pkt *nfqueue.NFQPacket) string {
if pkt.Packet.Layer(layers.LayerTypeTCP) != nil {
return "tcp"
} else if pkt.Packet.Layer(layers.LayerTypeUDP) != nil {
return "udp"
} else if pkt.Packet.Layer(layers.LayerTypeICMPv4) != nil {
return "icmp"
}
return "[unknown]"
}
func (pp *pendingPkt) proto() string {
return getNFQProto(pp.pkt)
}
func (pp *pendingPkt) srcPort() uint16 {
srcp, _ := getPacketTCPPorts(pp.pkt)
return srcp
}
func (pp *pendingPkt) dstPort() uint16 {
/* dst := pp.pkt.Packet.TransportLayer().TransportFlow().Dst()
if dst.EndpointType() != layers.EndpointTCPPort {
return 0
if pp.proto() == "tcp" {
_, dstp := getPacketTCPPorts(pp.pkt)
return dstp
} else if pp.proto() == "udp" {
_, dstp := getPacketUDPPorts(pp.pkt)
return dstp
} else if pp.proto() == "icmp" {
code, _ := getpacketICMPCode(pp.pkt)
return uint16(code)
}
return binary.BigEndian.Uint16(dst.Raw()) */
_, dstp := getPacketTCPPorts(pp.pkt)
return dstp
// return pp.pkt.DstPort
return 0
}
func (pp *pendingPkt) accept() {
@ -294,7 +313,7 @@ func (p *Policy) removeRule(r *Rule) {
func (p *Policy) filterPending(rule *Rule) {
remaining := []pendingConnection{}
for _, pc := range p.pendingQueue {
if rule.match(pc.src(), pc.dst(), pc.dstPort(), pc.hostname(), 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)) {
log.Infof("Adding rule for: %s", rule.getString(FirewallConfig.LogRedact))
log.Noticef("%s > %s", rule.getString(FirewallConfig.LogRedact), pc.print())
if rule.rtype == RULE_ACTION_ALLOW {
@ -302,7 +321,7 @@ func (p *Policy) filterPending(rule *Rule) {
} else {
srcs := pc.src().String() + ":" + strconv.Itoa(int(pc.srcPort()))
log.Warningf("DENIED outgoing connection attempt by %s from %s %s -> %s:%d (user prompt)",
pc.procInfo().ExePath, "TCP", srcs, pc.dst(), pc.dstPort)
pc.procInfo().ExePath, pc.proto(), srcs, pc.dst(), pc.dstPort)
pc.drop()
}
} else {
@ -327,20 +346,23 @@ func printPacket(pkt *nfqueue.NFQPacket, hostname string, pinfo *procsnitch.Info
proto := "???"
SrcPort, DstPort := uint16(0), uint16(0)
SrcIp, DstIp := getPacketIP4Addrs(pkt)
code := 0
codestr := ""
// switch pkt.Packet.TransportLayer().TransportFlow().EndpointType() {
if pkt.Packet.Layer(layers.LayerTypeTCP) != nil {
// case 4:
proto = "TCP"
} else if pkt.Packet.Layer(layers.LayerTypeUDP) != nil {
// case 5:
proto = "UDP"
} else if pkt.Packet.Layer(layers.LayerTypeICMPv4) != nil {
proto = "ICMP"
}
if proto == "TCP" {
SrcPort, DstPort = getPacketTCPPorts(pkt)
} else if proto == "UDP" {
SrcPort, DstPort = getPacketUDPPorts(pkt)
} else if proto == "ICMP" {
code, codestr = getpacketICMPCode(pkt)
}
if FirewallConfig.LogRedact {
@ -351,9 +373,13 @@ func printPacket(pkt *nfqueue.NFQPacket, hostname string, pinfo *procsnitch.Info
name = DstIp.String()
}
if pinfo == nil {
if proto == "ICMP" {
return fmt.Sprintf("(%s %s -> %s: %s [%d])", proto, SrcIp, name, codestr, code)
}
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)
}
@ -505,78 +531,111 @@ func getRealRoot(pathname string, pid int) string {
func findProcessForPacket(pkt *nfqueue.NFQPacket) (*procsnitch.Info, string) {
srcip, dstip := getPacketIP4Addrs(pkt)
srcp, dstp := getPacketPorts(pkt)
proto := ""
optstr := ""
icode := -1
if pkt.Packet.Layer(layers.LayerTypeTCP) != nil {
// Try normal way first, before the more resource intensive/invasive way.
res := procsnitch.LookupTCPSocketProcessAll(srcip, srcp, dstip, dstp, nil)
proto = "tcp"
} else if pkt.Packet.Layer(layers.LayerTypeUDP) != nil {
proto = "udp"
} else if pkt.Packet.Layer(layers.LayerTypeICMPv4) != nil {
proto = "icmp"
icode, _ = getpacketICMPCode(pkt)
}
if res == nil {
removePids := make([]int, 0)
if proto == "" {
log.Warningf("Packet has unknown protocol: %d", pkt.Packet.NetworkLayer().LayerType())
return nil, optstr
}
for i := 0; i < len(OzInitPids); i++ {
data := ""
fname := fmt.Sprintf("/proc/%d/net/tcp", OzInitPids[i].Pid)
fmt.Println("XXX: opening: ", fname)
bdata, err := readFileDirect(fname)
var res *procsnitch.Info = nil
if err != nil {
fmt.Println("Error reading proc data from ", fname, ": ", err)
// Try normal way first, before the more resource intensive/invasive way.
if proto == "tcp" {
res = procsnitch.LookupTCPSocketProcessAll(srcip, srcp, dstip, dstp, nil)
} else if proto == "udp" {
res = procsnitch.LookupUDPSocketProcessAll(srcip, srcp, dstip, dstp, nil, true)
} else if proto == "icmp" {
res = procsnitch.LookupICMPSocketProcessAll(srcip, dstip, icode, nil)
}
if err == syscall.ENOENT {
removePids = append(removePids, OzInitPids[i].Pid)
}
if res == nil {
removePids := make([]int, 0)
continue
} else {
data = string(bdata)
lines := strings.Split(data, "\n")
rlines := make([]string, 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)
for l := 0; l < len(lines); l++ {
lines[l] = strings.TrimSpace(lines[l])
ssplit := strings.Split(lines[l], ":")
if err != nil {
fmt.Println("Error reading proc data from ", fname, ": ", err)
if len(ssplit) != 6 {
continue
}
if err == syscall.ENOENT {
removePids = append(removePids, OzInitPids[i].Pid)
}
rlines = append(rlines, strings.Join(ssplit, ":"))
}
continue
} else {
data = string(bdata)
lines := strings.Split(data, "\n")
rlines := make([]string, 0)
res = procsnitch.LookupTCPSocketProcessAll(srcip, srcp, dstip, dstp, rlines)
for l := 0; l < len(lines); l++ {
lines[l] = strings.TrimSpace(lines[l])
ssplit := strings.Split(lines[l], ":")
if res != nil {
optstr = "Sandbox: " + OzInitPids[i].Name
res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid)
break
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, true)
} else if proto == "icmp" {
res = procsnitch.LookupICMPSocketProcessAll(srcip, dstip, icode, rlines)
}
for _, p := range removePids {
removeInitPid(p)
if res != nil {
optstr = "Sandbox: " + OzInitPids[i].Name
res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid)
break
}
}
}
return res, optstr
} else if pkt.Packet.Layer(layers.LayerTypeUDP) != nil {
return procsnitch.LookupUDPSocketProcess(srcp), optstr
for _, p := range removePids {
removeInitPid(p)
}
}
log.Warningf("Packet has unknown protocol: %d", pkt.Packet.NetworkLayer().LayerType())
//log.Warningf("Packet has unknown protocol: %d", pkt.Protocol)
return nil, optstr
return res, optstr
}
func basicAllowPacket(pkt *nfqueue.NFQPacket) bool {
_, dstip := getPacketIP4Addrs(pkt)
srcip, dstip := getPacketIP4Addrs(pkt)
if pkt.Packet.Layer(layers.LayerTypeUDP) != nil {
_, dport := getPacketUDPPorts(pkt)
if dport == 53 {
return true
}
}
if pkt.Packet.Layer(layers.LayerTypeICMPv4) != nil && srcip.Equal(dstip) {
// An ICMP dest unreach packet sent to ourselves probably isn't a big security risk.
return true
}
return dstip.IsLoopback() ||
dstip.IsLinkLocalMulticast() ||
pkt.Packet.Layer(layers.LayerTypeTCP) == nil
// pkt.Protocol != nfqueue.TCP
(pkt.Packet.Layer(layers.LayerTypeTCP) == nil &&
pkt.Packet.Layer(layers.LayerTypeUDP) == nil &&
pkt.Packet.Layer(layers.LayerTypeICMPv4) == nil)
}
func getPacketIP4Addrs(pkt *nfqueue.NFQPacket) (net.IP, net.IP) {
@ -590,6 +649,17 @@ func getPacketIP4Addrs(pkt *nfqueue.NFQPacket) (net.IP, net.IP) {
return ip.SrcIP, ip.DstIP
}
func getpacketICMPCode(pkt *nfqueue.NFQPacket) (int, string) {
icmpLayer := pkt.Packet.Layer(layers.LayerTypeICMPv4)
if icmpLayer == nil {
return -1, ""
}
icmp, _ := icmpLayer.(*layers.ICMPv4)
return int(icmp.TypeCode.Code()), icmp.TypeCode.String()
}
func getPacketTCPPorts(pkt *nfqueue.NFQPacket) (uint16, uint16) {
tcpLayer := pkt.Packet.Layer(layers.LayerTypeTCP)

@ -77,6 +77,7 @@ func (p *prompter) processConnection(pc pendingConnection) {
int32(pc.dstPort()),
pc.dst().String(),
pc.src().String(),
pc.proto(),
int32(pc.procInfo().UID),
int32(pc.procInfo().GID),
uidToUser(pc.procInfo().UID),

@ -25,6 +25,7 @@ type Rule struct {
policy *Policy
mode RuleMode
rtype RuleAction
proto string
hostname string
network *net.IPNet
addr uint32
@ -50,7 +51,12 @@ func (r *Rule) getString(redact bool) string {
rmode = "|" + RuleModeString[RULE_MODE_SYSTEM]
}
return fmt.Sprintf("%s|%s%s", rtype, r.AddrString(redact), rmode)
protostr := ""
if r.proto != "tcp" {
protostr = r.proto + ":"
}
return fmt.Sprintf("%s|%s%s%s", rtype, protostr, r.AddrString(redact), rmode)
}
func (r *Rule) AddrString(redact bool) string {
@ -66,7 +72,7 @@ func (r *Rule) AddrString(redact bool) string {
addr = fmt.Sprintf("%d.%d.%d.%d", bs[0], bs[1], bs[2], bs[3])
}
if r.port != matchAny {
if r.port != matchAny || r.proto == "icmp" {
port = fmt.Sprintf("%d", r.port)
}
@ -79,7 +85,10 @@ func (r *Rule) AddrString(redact bool) string {
type RuleList []*Rule
func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname 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) bool {
if r.proto != proto {
return false
}
if r.uid != -1 && r.uid != uid {
return false
} else if r.gid != -1 && r.gid != gid {
@ -115,6 +124,12 @@ log.Notice("comparison: ", hostname, " / ", dst, " : ", dstPort, " -> ", xip, "
if r.network != nil && r.network.Contains(dst) {
return true
}
if proto == "icmp" {
fmt.Printf("network = %v, src = %v, r.addr = %x, src to4 = %x\n", r.network, src, r.addr, binary.BigEndian.Uint32(src.To4()))
if (r.network != nil && r.network.Contains(src)) || (r.addr == binary.BigEndian.Uint32(src.To4())) {
return true
}
}
return r.addr == binary.BigEndian.Uint32(dst.To4())
}
@ -135,11 +150,11 @@ log.Notice("------------ trying match of src ", src, " against: ", r, " | ", r.s
if r.saddr == nil && src != nil && sandboxed {
log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src)
continue
} else if r.saddr != nil && !r.saddr.Equal(src) {
} else if r.saddr != nil && !r.saddr.Equal(src) && r.proto != "icmp" {
log.Notice("! Skipping comparison of mismatching source ips")
continue
}
if r.match(src, dst, dstPort, hostname, 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)) {
log.Notice("+ MATCH SUCCEEDED")
dstStr := dst.String()
if FirewallConfig.LogRedact {
@ -153,12 +168,12 @@ log.Notice("+ MATCH SUCCEEDED")
}
log.Noticef("%s > %s %s %s -> %s:%d",
r.getString(FirewallConfig.LogRedact),
pinfo.ExePath, "TCP",
pinfo.ExePath, r.proto,
srcStr,
dstStr, dstPort)
if r.rtype == RULE_ACTION_DENY {
log.Warningf("DENIED outgoing connection attempt by %s from %s %s -> %s:%d",
pinfo.ExePath, "TCP",
pinfo.ExePath, r.proto,
srcStr,
dstStr, dstPort)
return FILTER_DENY
@ -257,11 +272,21 @@ func (r *Rule) parseVerb(v string) bool {
func (r *Rule) parseTarget(t string) bool {
addrPort := strings.Split(t, ":")
if len(addrPort) != 2 {
if len(addrPort) != 2 && len(addrPort) != 3 {
return false
}
sind := 0
if len(addrPort) == 3 {
if addrPort[0] != "udp" && addrPort[0] != "icmp" && addrPort[0] != "tcp" {
return false
}
r.proto = addrPort[0]
sind++
} else {
r.proto = "tcp"
}
return r.parseAddr(addrPort[0]) && r.parsePort(addrPort[1])
return r.parseAddr(addrPort[sind]) && r.parsePort(addrPort[sind+1])
}
func (r *Rule) parseAddr(a string) bool {
@ -296,7 +321,7 @@ func (r *Rule) parsePort(p string) bool {
}
var err error
port, err := strconv.ParseUint(p, 10, 16)
if err != nil || port == 0 || port > 0xFFFF {
if err != nil || (port == 0 && r.proto != "icmp") || port > 0xFFFF {
return false
}
r.port = uint16(port)

@ -72,6 +72,9 @@ func (sc *pendingSocksConnection) hostname() string {
func (sc *pendingSocksConnection) dst() net.IP {
return sc.destIP
}
func (sc *pendingSocksConnection) proto() string {
return "tcp"
}
func (sc *pendingSocksConnection) srcPort() uint16 {
return sc.sourcePort
}

@ -66,6 +66,24 @@ func FindProcessForConnection(conn net.Conn, procInfo ProcInfo) *Info {
return info
}
// LookupICMPSocketProcessAll searches for a ICMP socket a given source host, destination IP, and type
func LookupICMPSocketProcessAll(srcAddr net.IP, dstAddr net.IP, code int, custdata []string) *Info {
ss := findICMPSocketAll(srcAddr, dstAddr, code, custdata)
if ss == nil {
return nil
}
return pcache.lookup(ss.inode)
}
// LookupUDPSocketProcessAll searches for a UDP socket a given source port, destination IP, and destination port - AND source destination
func LookupUDPSocketProcessAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort uint16, custdata []string, loose bool) *Info {
ss := findUDPSocketAll(srcAddr, srcPort, dstAddr, dstPort, custdata, loose)
if ss == nil {
return nil
}
return pcache.lookup(ss.inode)
}
// LookupUDPSocketProcess searches for a UDP socket with a source port
func LookupUDPSocketProcess(srcPort uint16) *Info {
ss := findUDPSocket(srcPort)

@ -78,6 +78,45 @@ func (ss *socketStatus) String() string {
return fmt.Sprintf("%s -> %s uid=%d inode=%d", ss.local, ss.remote, ss.uid, ss.inode)
}
func findICMPSocketAll(srcAddr net.IP, dstAddr net.IP, code int, custdata []string) *socketStatus {
if custdata == nil {
return findSocket("icmp", func(ss socketStatus) bool {
return ss.remote.ip.Equal(dstAddr) && ss.local.ip.Equal(srcAddr)
})
}
return findSocketCustom("icmp", custdata, func(ss socketStatus) bool {
return ss.remote.ip.Equal(dstAddr) && ss.local.ip.Equal(srcAddr)
})
}
func findUDPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort uint16, custdata []string, loose bool) *socketStatus {
wildcard := net.IP{0,0,0,0}
if custdata == nil {
if !loose {
return findSocket("udp", 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.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr)
})
}
return findSocket("udp", func(ss socketStatus) bool {
return (ss.remote.ip.Equal(dstAddr) || ss.remote.ip.Equal(wildcard)) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr)
})
}
if !loose {
return findSocketCustom("udp", custdata, func(ss socketStatus) bool {
return ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr)
})
}
return findSocketCustom("udp", custdata, func(ss socketStatus) bool {
return (ss.remote.ip.Equal(dstAddr) || ss.remote.ip.Equal(wildcard)) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr)
})
}
func findUDPSocket(srcPort uint16) *socketStatus {
return findSocket("udp", func(ss socketStatus) bool {
return ss.local.port == srcPort
@ -91,12 +130,10 @@ func findTCPSocket(srcPort uint16, dstAddr net.IP, dstPort uint16) *socketStatus
}
func findTCPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort uint16, custdata []string) *socketStatus {
found := findSocket("tcp", func(ss socketStatus) bool {
return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr)
})
if found != nil || custdata == nil {
return found
if custdata == nil {
return findSocket("tcp", 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("tcp", custdata, func(ss socketStatus) bool {

Loading…
Cancel
Save