diff --git a/sgfw/dns.go b/sgfw/dns.go index 823ecc7..4fe5351 100644 --- a/sgfw/dns.go +++ b/sgfw/dns.go @@ -65,7 +65,7 @@ func (dc *dnsCache) processDNS(pkt *nfqueue.NFQPacket) { } q := dns.question[0] if q.Qtype == dnsTypeA { - srcip, _ := getPacketIP4Addrs(pkt) + srcip, _ := getPacketIPAddrs(pkt) pinfo := getEmptyPInfo() if !isNSTrusted(srcip) { pinfo, _ = findProcessForPacket(pkt, true, procsnitch.MATCH_LOOSEST) @@ -145,6 +145,8 @@ func (dc *dnsCache) processRecordA(name string, answers []dnsRR, pid int) { if !FirewallConfig.LogRedact { log.Infof("Adding %s: %s", name, ip) } + case *dnsRR_AAAA: + log.Warning("AAAA record read from DNS; not supported.") case *dnsRR_CNAME: // Not that exotic; just ignore it default: diff --git a/sgfw/icons.go b/sgfw/icons.go index 0366e7a..4beed49 100644 --- a/sgfw/icons.go +++ b/sgfw/icons.go @@ -68,7 +68,10 @@ func loadDesktopFile(path string) { inDE = false } if inDE && strings.HasPrefix(line, "Exec=") { - exec = strings.Fields(line[5:])[0] + fields := strings.Fields(line[5:]) + if len(fields) > 0 { + exec = fields[0] + } } if inDE && strings.HasPrefix(line, "Icon=") { icon = line[5:] diff --git a/sgfw/ipc.go b/sgfw/ipc.go index 4823b38..34d2d0c 100644 --- a/sgfw/ipc.go +++ b/sgfw/ipc.go @@ -7,7 +7,6 @@ import ( "bufio" "strings" "strconv" - "encoding/binary" ) const ReceiverSocketPath = "/tmp/fwoz.sock" @@ -120,8 +119,6 @@ func ReceiverLoop(fw *Firewall, c net.Conn) { c.Write([]byte(banner)) for r := 0; r < len(rl); r++ { - ip := make([]byte, 4) - binary.BigEndian.PutUint32(ip, rl[r].addr) hostname := "" if rl[r].hostname != "" { @@ -134,7 +131,7 @@ func ReceiverLoop(fw *Firewall, c net.Conn) { portstr = "*" } - ruledesc := fmt.Sprintf("id %v, %v | %v, src:%v -> %v%v: %v\n", rl[r].id, RuleModeString[rl[r].mode], RuleActionString[rl[r].rtype], rl[r].saddr, net.IP(ip), hostname, portstr) + ruledesc := fmt.Sprintf("id %v, %v | %v, src:%v -> %v%v: %v\n", rl[r].id, RuleModeString[rl[r].mode], RuleActionString[rl[r].rtype], rl[r].saddr, rl[r].addr, hostname, portstr) c.Write([]byte(ruledesc)) } diff --git a/sgfw/policy.go b/sgfw/policy.go index ea1f0cb..dfeacbb 100644 --- a/sgfw/policy.go +++ b/sgfw/policy.go @@ -93,21 +93,13 @@ func (pp *pendingPkt) hostname() string { } func (pp *pendingPkt) src() net.IP { - src, _ := getPacketIP4Addrs(pp.pkt) + src, _ := getPacketIPAddrs(pp.pkt) return src } func (pp *pendingPkt) dst() net.IP { - _, dst := getPacketIP4Addrs(pp.pkt) + _, dst := getPacketIPAddrs(pp.pkt) return dst -/* dst := pp.pkt.Packet.NetworkLayer().NetworkFlow().Dst() - - if dst.EndpointType() != layers.EndpointIPv4 { - return nil - } - - return dst.Raw() */ -// pp.pkt.NetworkLayer().Layer } func getNFQProto(pkt *nfqueue.NFQPacket) string { @@ -368,7 +360,7 @@ func (p *Policy) hasPersistentRules() bool { func printPacket(pkt *nfqueue.NFQPacket, hostname string, pinfo *procsnitch.Info) string { proto := "???" SrcPort, DstPort := uint16(0), uint16(0) - SrcIp, DstIp := getPacketIP4Addrs(pkt) + SrcIp, DstIp := getPacketIPAddrs(pkt) code := 0 codestr := "" @@ -418,7 +410,7 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) { } } - _, dstip := getPacketIP4Addrs(pkt) + _, dstip := getPacketIPAddrs(pkt) /* _, dstp := getPacketPorts(pkt) fwo := matchAgainstOzRules(srcip, dstip, dstp) log.Notice("XXX: Attempting [2] to filter packet on rules -> ", fwo) @@ -558,14 +550,14 @@ func getRealRoot(pathname string, pid int) string { } func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int) (*procsnitch.Info, string) { - srcip, dstip := getPacketIP4Addrs(pkt) + srcip, dstip := getPacketIPAddrs(pkt) srcp, dstp := getPacketPorts(pkt) proto := "" optstr := "" icode := -1 if reverse { - dstip, srcip = getPacketIP4Addrs(pkt) + dstip, srcip = getPacketIPAddrs(pkt) dstp, srcp = getPacketPorts(pkt) } @@ -576,6 +568,9 @@ func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int) } else if pkt.Packet.Layer(layers.LayerTypeICMPv4) != nil { proto = "icmp" icode, _ = getpacketICMPCode(pkt) + } else if pkt.Packet.Layer(layers.LayerTypeICMPv6) != nil { + proto = "icmp" + icode, _ = getpacketICMPCode(pkt) } if proto == "" { @@ -656,7 +651,7 @@ func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int) } func basicAllowPacket(pkt *nfqueue.NFQPacket) bool { - srcip, dstip := getPacketIP4Addrs(pkt) + srcip, dstip := getPacketIPAddrs(pkt) if pkt.Packet.Layer(layers.LayerTypeUDP) != nil { _, dport := getPacketUDPPorts(pkt) if dport == 53 { @@ -674,15 +669,29 @@ func basicAllowPacket(pkt *nfqueue.NFQPacket) bool { pkt.Packet.Layer(layers.LayerTypeICMPv4) == nil) } -func getPacketIP4Addrs(pkt *nfqueue.NFQPacket) (net.IP, net.IP) { +func getPacketIPAddrs(pkt *nfqueue.NFQPacket) (net.IP, net.IP) { + ipv4 := true ipLayer := pkt.Packet.Layer(layers.LayerTypeIPv4) if ipLayer == nil { - return net.IP{0,0,0,0}, net.IP{0,0,0,0} + ipv4 = false + ipLayer = pkt.Packet.Layer(layers.LayerTypeIPv6) + } + + if ipLayer == nil { + if ipv4 { + return net.IP{0,0,0,0}, net.IP{0,0,0,0} + } + return net.IP{}, net.IP{} + } + + if !ipv4 { + ip6, _ := ipLayer.(*layers.IPv6) + return ip6.SrcIP, ip6.DstIP } - ip, _ := ipLayer.(*layers.IPv4) - return ip.SrcIP, ip.DstIP + ip4, _ := ipLayer.(*layers.IPv4) + return ip4.SrcIP, ip4.DstIP } func getpacketICMPCode(pkt *nfqueue.NFQPacket) (int, string) { diff --git a/sgfw/rules.go b/sgfw/rules.go index c636c55..8d15f41 100644 --- a/sgfw/rules.go +++ b/sgfw/rules.go @@ -9,7 +9,6 @@ import ( "path" "strconv" "strings" - "unicode" "regexp" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" @@ -18,7 +17,9 @@ import ( ) 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 noAddress net.IP = net.IP{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} type Rule struct { id uint @@ -28,7 +29,7 @@ type Rule struct { proto string hostname string network *net.IPNet - addr uint32 + addr net.IP saddr net.IP port uint16 uid int @@ -66,10 +67,11 @@ func (r *Rule) AddrString(redact bool) string { addr = r.hostname } else if r.network != nil { addr = r.network.String() - } else if r.addr != matchAny && r.addr != noAddress { - bs := make([]byte, 4) - binary.BigEndian.PutUint32(bs, r.addr) - addr = fmt.Sprintf("%d.%d.%d.%d", bs[0], bs[1], bs[2], bs[3]) + } else if !addrMatchesAny(r.addr) && !addrMatchesNone(r.addr) { +// bs := make([]byte, 4) +// binary.BigEndian.PutUint32(bs, r.addr) +// addr = fmt.Sprintf("%d.%d.%d.%d", bs[0], bs[1], bs[2], bs[3]) + addr = r.addr.String() } if r.port != matchAny || r.proto == "icmp" { @@ -99,13 +101,11 @@ func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, pr return false } -xip := make(net.IP, 4) -binary.BigEndian.PutUint32(xip, r.addr) -log.Notice("comparison: ", hostname, " / ", dst, " : ", dstPort, " -> ", xip, " / ", r.hostname, " : ", r.port) +log.Notice("comparison: ", hostname, " / ", dst, " : ", dstPort, " -> ", r.addr, " / ", r.hostname, " : ", r.port) if r.port != matchAny && r.port != dstPort { return false } - if r.addr == matchAny { + if addrMatchesAny(r.addr) { return true } if r.hostname != "" { @@ -126,15 +126,15 @@ log.Notice("comparison: ", hostname, " / ", dst, " : ", dstPort, " -> ", xip, " } 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())) { + if (r.network != nil && r.network.Contains(src)) || (r.addr.Equal(src)) { return true } } - return r.addr == binary.BigEndian.Uint32(dst.To4()) + return r.addr.Equal(dst) } func (rl *RuleList) filterPacket(p *nfqueue.NFQPacket, pinfo *procsnitch.Info, srcip net.IP, hostname, optstr string) FilterResult { - _, dstip := getPacketIP4Addrs(p) + _, dstip := getPacketIPAddrs(p) _, dstp := getPacketPorts(p) return rl.filter(p, srcip, dstip, dstp, hostname, pinfo, optstr) } @@ -162,7 +162,7 @@ log.Notice("+ MATCH SUCCEEDED") } srcStr := STR_UNKNOWN if pkt != nil { - srcip, _ := getPacketIP4Addrs(pkt) + srcip, _ := getPacketIPAddrs(pkt) srcp, _ := getPacketPorts(pkt) srcStr = fmt.Sprintf("%s:%d", srcip, srcp) } @@ -272,30 +272,31 @@ func (r *Rule) parseVerb(v string) bool { func (r *Rule) parseTarget(t string) bool { addrPort := strings.Split(t, ":") - if len(addrPort) != 2 && len(addrPort) != 3 { + if len(addrPort) < 2 { return false } sind := 0 - if len(addrPort) == 3 { - if addrPort[0] != "udp" && addrPort[0] != "icmp" && addrPort[0] != "tcp" { - return false - } + lind := len(addrPort)-1 + if addrPort[0] == "udp" || addrPort[0] == "icmp" || addrPort[0] == "tcp" { r.proto = addrPort[0] sind++ } else { r.proto = "tcp" } - return r.parseAddr(addrPort[sind]) && r.parsePort(addrPort[sind+1]) + newAddr := strings.Join(addrPort[sind:lind], ":") + return r.parseAddr(newAddr) && r.parsePort(addrPort[lind]) +// return r.parseAddr(addrPort[sind]) && r.parsePort(addrPort[sind+1]) } func (r *Rule) parseAddr(a string) bool { if a == "*" { r.hostname = "" - r.addr = matchAny + r.addr = anyAddress return true } - if strings.IndexFunc(a, unicode.IsLetter) != -1 { +// if strings.IndexFunc(a, unicode.IsLetter) != -1 { + if net.ParseIP(a) == nil { r.hostname = a return true } @@ -310,7 +311,7 @@ func (r *Rule) parseAddr(a string) bool { } else { r.network = ipnet } - r.addr = binary.BigEndian.Uint32(ip.To4()) + r.addr = ip return true } @@ -445,3 +446,23 @@ func processRuleLine(policy *Policy, line string) { return } } + +func addrMatchesAny(addr net.IP) bool { + any := anyAddress + + if addr.To4() != nil { + any = net.IP{0,0,0,0} + } + + return any.Equal(addr) +} + +func addrMatchesNone(addr net.IP) bool { + none := noAddress + + if addr.To4() != nil { + none = net.IP{0xff,0xff,0xff,0xff} + } + + return none.Equal(addr) +} diff --git a/sgfw/sgfw.go b/sgfw/sgfw.go index 86261a1..97ad4ba 100644 --- a/sgfw/sgfw.go +++ b/sgfw/sgfw.go @@ -16,6 +16,8 @@ import ( nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" // "github.com/subgraph/go-nfnetlink" "github.com/subgraph/go-procsnitch" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" ) var dbusp *dbusObjectP = nil @@ -108,6 +110,22 @@ func (fw *Firewall) runFilter() { go func() { for p := range ps { if fw.isEnabled() { + ipLayer := p.Packet.Layer(layers.LayerTypeIPv4) + if ipLayer == nil { + continue + } + + ip, _ := ipLayer.(*layers.IPv4) + if ip == nil { + continue + } + + if ip.Version == 6 { + ip6p := gopacket.NewPacket(ip.LayerContents(), layers.LayerTypeIPv6, gopacket.Default) + p.Packet = ip6p + + } + fw.filterPacket(p) } else { p.Accept() diff --git a/vendor/github.com/subgraph/go-procsnitch/proc.go b/vendor/github.com/subgraph/go-procsnitch/proc.go index e867e86..823850e 100644 --- a/vendor/github.com/subgraph/go-procsnitch/proc.go +++ b/vendor/github.com/subgraph/go-procsnitch/proc.go @@ -2,6 +2,7 @@ package procsnitch import ( "encoding/hex" + "encoding/binary" "errors" "fmt" "github.com/op/go-logging" @@ -9,9 +10,11 @@ import ( "net" "strconv" "strings" + "unsafe" ) var log = logging.MustGetLogger("go-procsockets") +var isLittleEndian = -1 // SetLogger allows setting a custom go-logging instance func SetLogger(logger *logging.Logger) { @@ -157,11 +160,32 @@ func ParseIP(ip string) (net.IP, error) { } // Reverse byte order -- /proc/net/tcp etc. is little-endian // TODO: Does this vary by architecture? - for i, j := 0, len(dst)-1; i < j; i, j = i+1, j-1 { - dst[i], dst[j] = dst[j], dst[i] + if isLittleEndian == -1 { + setEndian() } - result = net.IP(dst) - return result, nil + + if len(dst) != 4 && len(dst) != 16 { + return result, errors.New("Unsupported address type (not IPv4 or IPv16)") + } + + if isLittleEndian > 0 { + for i := 0; i < len(dst) / 4; i++ { + start, end := i*4, (i+1)*4 + word := dst[start:end] + lval := binary.LittleEndian.Uint32(word) + binary.BigEndian.PutUint32(dst[start:], lval) + } + } + +/* if len(dst) == 16 { + dst2 := []byte{dst[3], dst[2], dst[1], dst[0], dst[7], dst[6], dst[5], dst[4], dst[11], dst[10], dst[9], dst[8], dst[15], dst[14], dst[13], dst[12]} + return net.IP(dst2), nil + } + for i, j := 0, len(dst)-1; i < j; i, j = i+1, j-1 { + dst[i], dst[j] = dst[j], dst[i] + } */ + + return net.IP(dst), nil } // ParsePort parses a base16 port represented as a string to a uint16 @@ -285,3 +309,15 @@ func stripLabel(s string) string { } return s[idx+1:] } + +// stolen from github.com/virtao/GoEndian +const INT_SIZE int = int(unsafe.Sizeof(0)) +func setEndian() { + var i int = 0x1 + bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i)) + if bs[0] == 0 { + isLittleEndian = 0 + } else { + isLittleEndian = 1 + } +} diff --git a/vendor/github.com/subgraph/go-procsnitch/socket.go b/vendor/github.com/subgraph/go-procsnitch/socket.go index 9c18ce3..448eba2 100644 --- a/vendor/github.com/subgraph/go-procsnitch/socket.go +++ b/vendor/github.com/subgraph/go-procsnitch/socket.go @@ -85,52 +85,61 @@ func (ss *socketStatus) String() string { } func findICMPSocketAll(srcAddr net.IP, dstAddr net.IP, code int, custdata []string) *socketStatus { + proto := "icmp" + if srcAddr.To4() == nil { + proto += "6" + } + if custdata == nil { - return findSocket("icmp", func(ss socketStatus) bool { + return findSocket(proto, func(ss socketStatus) bool { return ss.remote.ip.Equal(dstAddr) && ss.local.ip.Equal(srcAddr) }) } - return findSocketCustom("icmp", custdata, func(ss socketStatus) bool { + return findSocketCustom(proto, 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, strictness int) *socketStatus { - wildcard := net.IP{0,0,0,0} + proto := "udp" + + if srcAddr.To4() == nil { + proto += "6" + } if custdata == nil { if strictness == MATCH_STRICT { - return findSocket("udp", func(ss socketStatus) bool { + return findSocket(proto, func(ss socketStatus) bool { return ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) }) } else if strictness == MATCH_LOOSE { - 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) || - (ss.local.ip.Equal(dstAddr) || ss.local.ip.Equal(wildcard)) && ss.remote.port == srcPort && ss.remote.ip.Equal(srcAddr) + return findSocket(proto, func(ss socketStatus) bool { + return (ss.remote.ip.Equal(dstAddr) || addrMatchesAny(ss.remote.ip)) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) || + (ss.local.ip.Equal(dstAddr) || addrMatchesAny(ss.local.ip)) && ss.remote.port == srcPort && ss.remote.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) || ss.local.ip.Equal(wildcard)) || - (ss.local.ip.Equal(dstAddr) || ss.local.ip.Equal(wildcard)) && ss.remote.port == srcPort && (ss.remote.ip.Equal(srcAddr) || ss.remote.ip.Equal(srcAddr)) + return findSocket(proto, func(ss socketStatus) bool { + return (ss.remote.ip.Equal(dstAddr) || addrMatchesAny(ss.remote.ip)) && ss.local.port == srcPort && (ss.local.ip.Equal(srcAddr) || addrMatchesAny(ss.local.ip)) || + (ss.local.ip.Equal(dstAddr) || addrMatchesAny(ss.local.ip)) && ss.remote.port == srcPort && (ss.remote.ip.Equal(srcAddr) || ss.remote.ip.Equal(srcAddr)) }) } if strictness == MATCH_STRICT { - return findSocketCustom("udp", custdata, func(ss socketStatus) bool { + return findSocketCustom(proto, custdata, func(ss socketStatus) bool { return ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) }) } else if strictness == MATCH_LOOSE { - 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) || - (ss.local.ip.Equal(dstAddr) || ss.local.ip.Equal(wildcard)) && ss.remote.port == srcPort && ss.remote.ip.Equal(srcAddr) + return findSocketCustom(proto, custdata, func(ss socketStatus) bool { + return (ss.remote.ip.Equal(dstAddr) || addrMatchesAny(ss.remote.ip)) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) || + (ss.local.ip.Equal(dstAddr) || addrMatchesAny(ss.local.ip)) && ss.remote.port == srcPort && ss.remote.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) || ss.local.ip.Equal(wildcard)) || - (ss.local.ip.Equal(dstAddr) || ss.local.ip.Equal(wildcard)) && ss.remote.port == srcPort && (ss.remote.ip.Equal(srcAddr) || ss.remote.ip.Equal(srcAddr)) + return findSocketCustom(proto, custdata, func(ss socketStatus) bool { + return (ss.remote.ip.Equal(dstAddr) || addrMatchesAny(ss.remote.ip)) && ss.local.port == srcPort && (ss.local.ip.Equal(srcAddr) || addrMatchesAny(ss.local.ip)) || + (ss.local.ip.Equal(dstAddr) || addrMatchesAny(ss.local.ip)) && ss.remote.port == srcPort && (ss.remote.ip.Equal(srcAddr) || ss.remote.ip.Equal(srcAddr)) }) } @@ -141,19 +150,29 @@ func findUDPSocket(srcPort uint16) *socketStatus { } func findTCPSocket(srcPort uint16, dstAddr net.IP, dstPort uint16) *socketStatus { - return findSocket("tcp", func(ss socketStatus) bool { + proto := "tcp" + if dstAddr.To4() == nil { + proto += "6" + } + + return findSocket(proto, func(ss socketStatus) bool { return ss.remote.port == dstPort && ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort }) } func findTCPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort uint16, custdata []string) *socketStatus { + proto := "tcp" + if srcAddr.To4() == nil { + proto += "6" + } + if custdata == nil { - return findSocket("tcp", func(ss socketStatus) bool { + 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("tcp", 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) }) } @@ -298,3 +317,13 @@ func getSocketLines(proto string) []string { } return lines } + +func addrMatchesAny(addr net.IP) bool { + wildcard := net.IP{0,0,0,0} + + if addr.To4() == nil { + wildcard = net.IP{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + } + + return wildcard.Equal(addr) +}