Skip to content

Commit

Permalink
Fix and improve network listener system integration and check
Browse files Browse the repository at this point in the history
Also, improve logging.
  • Loading branch information
dhaavi committed Aug 12, 2020
1 parent edf46d3 commit 9d35ff3
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 33 deletions.
4 changes: 2 additions & 2 deletions firewall/interception/nfqueue_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func init() {
"mangle INPUT -j C171",
"filter OUTPUT -j C17",
"filter INPUT -j C17",
"nat OUTPUT -m mark --mark 1799 -p udp -j DNAT --to 127.0.0.1:53",
"nat OUTPUT -m mark --mark 1799 -p udp -j DNAT --to 127.0.0.17:53",
"nat OUTPUT -m mark --mark 1717 -p tcp -j DNAT --to 127.0.0.17:717",
"nat OUTPUT -m mark --mark 1717 -p udp -j DNAT --to 127.0.0.17:717",
// "nat OUTPUT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to 127.0.0.17",
Expand Down Expand Up @@ -115,7 +115,7 @@ func init() {
"mangle INPUT -j C171",
"filter OUTPUT -j C17",
"filter INPUT -j C17",
"nat OUTPUT -m mark --mark 1799 -p udp -j DNAT --to [::1]:53",
"nat OUTPUT -m mark --mark 1799 -p udp -j DNAT --to [fd17::17]:53",
"nat OUTPUT -m mark --mark 1717 -p tcp -j DNAT --to [fd17::17]:717",
"nat OUTPUT -m mark --mark 1717 -p udp -j DNAT --to [fd17::17]:717",
// "nat OUTPUT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to [fd17::17]",
Expand Down
14 changes: 7 additions & 7 deletions firewall/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,15 +301,15 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
// we don't apply any checks here and let the request through
// because a malformed domain-name will likely be dropped by
// checks better suited for that.
log.Tracer(ctx).Warningf("nameserver: failed to get eTLD+1: %s", err)
log.Tracer(ctx).Warningf("filter: failed to get eTLD+1: %s", err)
return false
}

domainToCheck := strings.Split(etld1, ".")[0]
score := dga.LmsScore(domainToCheck)
if score < 5 {
log.Tracer(ctx).Warningf(
"nameserver: possible data tunnel by %s in eTLD+1 %s: %s has an lms score of %.2f, returning nxdomain",
log.Tracer(ctx).Debugf(
"filter: possible data tunnel by %s in eTLD+1 %s: %s has an lms score of %.2f",
conn.Process(),
etld1,
domainToCheck,
Expand All @@ -318,7 +318,7 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
conn.Block("possible DGA domain commonly used by malware")
return true
}
log.Tracer(ctx).Infof("LMS score of eTLD+1 %s is %.2f", etld1, score)
log.Tracer(ctx).Tracef("filter: LMS score of eTLD+1 %s is %.2f", etld1, score)

// 100 is a somewhat arbitrary threshold to ensure we don't mess
// around with CDN domain names to early. They use short second-level
Expand All @@ -328,8 +328,8 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
domainToCheck = trimmedDomain[0:len(etld1)]
score := dga.LmsScoreOfDomain(domainToCheck)
if score < 10 {
log.Tracer(ctx).Warningf(
"nameserver: possible data tunnel by %s in subdomain %s: %s has an lms score of %.2f, returning nxdomain",
log.Tracer(ctx).Debugf(
"filter: possible data tunnel by %s in subdomain of %s: %s has an lms score of %.2f",
conn.Process(),
conn.Entity.Domain,
domainToCheck,
Expand All @@ -338,7 +338,7 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
conn.Block("possible data tunnel for covert communication and protection bypassing")
return true
}
log.Tracer(ctx).Infof("LMS score of entire domain is %.2f", score)
log.Tracer(ctx).Tracef("filter: LMS score of entire domain is %.2f", score)
}

return false
Expand Down
26 changes: 11 additions & 15 deletions nameserver/nameserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,26 +138,22 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) er
return nil
}

// get addresses
// get remote address
remoteAddr, ok := w.RemoteAddr().(*net.UDPAddr)
if !ok {
log.Warningf("nameserver: could not get remote address of request for %s%s, ignoring", q.FQDN, q.QType)
log.Warningf("nameserver: failed to get remote address of request for %s%s, ignoring", q.FQDN, q.QType)
return nil
}
if !netutils.IPIsLocalhost(remoteAddr.IP) {
// If request is not from a localhost address, check it it's really local.

localAddr, ok := w.RemoteAddr().(*net.UDPAddr)
if !ok {
log.Warningf("nameserver: could not get local address of request for %s%s, ignoring", q.FQDN, q.QType)
return nil
}

// ignore external request
if !remoteAddr.IP.Equal(localAddr.IP) {
log.Warningf("nameserver: external request for %s%s, ignoring", q.FQDN, q.QType)
return nil
}
// check if the request is local
local, err := netenv.IsMyIP(remoteAddr.IP)
if err != nil {
log.Warningf("nameserver: failed to check if request for %s%s is local: %s", q.FQDN, q.QType, err)
return nil
}
if !local {
log.Warningf("nameserver: external request for %s%s, ignoring", q.FQDN, q.QType)
return nil
}

// check if valid domain name
Expand Down
68 changes: 60 additions & 8 deletions netenv/addresses.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package netenv

import (
"fmt"
"net"
"strings"
"sync"

"github.com/safing/portbase/log"
"github.com/safing/portmaster/network/netutils"
)

Expand All @@ -14,13 +16,16 @@ func GetAssignedAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
return nil, nil, err
}
for _, addr := range addrs {
ip := net.ParseIP(strings.Split(addr.String(), "/")[0])
if ip != nil {
if ip4 := ip.To4(); ip4 != nil {
ipv4 = append(ipv4, ip4)
} else {
ipv6 = append(ipv6, ip)
}
netAddr, ok := addr.(*net.IPNet)
if !ok {
log.Warningf("netenv: interface address of unexpected type %T", addr)
continue
}

if ip4 := netAddr.IP.To4(); ip4 != nil {
ipv4 = append(ipv4, ip4)
} else {
ipv6 = append(ipv6, netAddr.IP)
}
}
return
Expand All @@ -44,3 +49,50 @@ func GetAssignedGlobalAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
}
return
}

var (
myIPs []net.IP
myIPsLock sync.Mutex
)

// IsMyIP returns whether the given IP is currently configured on the local host.
func IsMyIP(ip net.IP) (yes bool, err error) {
if netutils.IPIsLocalhost(ip) {
return true, nil
}

myIPsLock.Lock()
defer myIPsLock.Unlock()

// check
for _, myIP := range myIPs {
if ip.Equal(myIP) {
return true, nil
}
}

// refresh IPs
myAddrs, err := net.InterfaceAddrs()
if err != nil {
return false, fmt.Errorf("failed to refresh interface addresses: %s", err)
}
myIPs = make([]net.IP, 0, len(myAddrs))
for _, addr := range myAddrs {
netAddr, ok := addr.(*net.IPNet)
if !ok {
log.Warningf("netenv: interface address of unexpected type %T", addr)
continue
}

myIPs = append(myIPs, netAddr.IP)
}

// check again
for _, myIP := range myIPs {
if ip.Equal(myIP) {
return true, nil
}
}

return false, nil
}
3 changes: 2 additions & 1 deletion network/state/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package state

import (
"context"
"strconv"
"sync"
"time"

Expand Down Expand Up @@ -155,5 +156,5 @@ func (table *udpTable) cleanStates(now time.Time) {

func makeUDPStateKey(address socket.Address) string {
// This could potentially go wrong, but as all IPs are created by the same source, everything should be fine.
return string(address.IP) + string(address.Port)
return string(address.IP) + strconv.Itoa(int(address.Port))
}

0 comments on commit 9d35ff3

Please sign in to comment.