Working (but not intensively tested) IPv6 support!

shw_dev
shw 8 years ago
parent 5f5042fed4
commit 8546f6c416

@ -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:

@ -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:]

@ -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))
}

@ -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 {
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) {

@ -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)
}

@ -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()

@ -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?
if isLittleEndian == -1 {
setEndian()
}
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]
}
result = net.IP(dst)
return result, nil
} */
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
}
}

@ -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)
}

Loading…
Cancel
Save