mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
Merge pull request #130 from safing/fix/listener-checks
Fix and improve network listener system integration and check
This commit is contained in:
commit
8a4865a942
5 changed files with 82 additions and 33 deletions
|
@ -80,7 +80,7 @@ func init() {
|
||||||
"mangle INPUT -j C171",
|
"mangle INPUT -j C171",
|
||||||
"filter OUTPUT -j C17",
|
"filter OUTPUT -j C17",
|
||||||
"filter INPUT -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 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 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",
|
// "nat OUTPUT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to 127.0.0.17",
|
||||||
|
@ -115,7 +115,7 @@ func init() {
|
||||||
"mangle INPUT -j C171",
|
"mangle INPUT -j C171",
|
||||||
"filter OUTPUT -j C17",
|
"filter OUTPUT -j C17",
|
||||||
"filter INPUT -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 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 udp -j DNAT --to [fd17::17]:717",
|
||||||
// "nat OUTPUT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to [fd17::17]",
|
// "nat OUTPUT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to [fd17::17]",
|
||||||
|
|
|
@ -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
|
// we don't apply any checks here and let the request through
|
||||||
// because a malformed domain-name will likely be dropped by
|
// because a malformed domain-name will likely be dropped by
|
||||||
// checks better suited for that.
|
// 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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
domainToCheck := strings.Split(etld1, ".")[0]
|
domainToCheck := strings.Split(etld1, ".")[0]
|
||||||
score := dga.LmsScore(domainToCheck)
|
score := dga.LmsScore(domainToCheck)
|
||||||
if score < 5 {
|
if score < 5 {
|
||||||
log.Tracer(ctx).Warningf(
|
log.Tracer(ctx).Debugf(
|
||||||
"nameserver: possible data tunnel by %s in eTLD+1 %s: %s has an lms score of %.2f, returning nxdomain",
|
"filter: possible data tunnel by %s in eTLD+1 %s: %s has an lms score of %.2f",
|
||||||
conn.Process(),
|
conn.Process(),
|
||||||
etld1,
|
etld1,
|
||||||
domainToCheck,
|
domainToCheck,
|
||||||
|
@ -318,7 +318,7 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
|
||||||
conn.Block("possible DGA domain commonly used by malware")
|
conn.Block("possible DGA domain commonly used by malware")
|
||||||
return true
|
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
|
// 100 is a somewhat arbitrary threshold to ensure we don't mess
|
||||||
// around with CDN domain names to early. They use short second-level
|
// around with CDN domain names to early. They use short second-level
|
||||||
|
@ -328,8 +328,8 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
|
||||||
domainToCheck = trimmedDomain[0:len(etld1)]
|
domainToCheck = trimmedDomain[0:len(etld1)]
|
||||||
score := dga.LmsScoreOfDomain(domainToCheck)
|
score := dga.LmsScoreOfDomain(domainToCheck)
|
||||||
if score < 10 {
|
if score < 10 {
|
||||||
log.Tracer(ctx).Warningf(
|
log.Tracer(ctx).Debugf(
|
||||||
"nameserver: possible data tunnel by %s in subdomain %s: %s has an lms score of %.2f, returning nxdomain",
|
"filter: possible data tunnel by %s in subdomain of %s: %s has an lms score of %.2f",
|
||||||
conn.Process(),
|
conn.Process(),
|
||||||
conn.Entity.Domain,
|
conn.Entity.Domain,
|
||||||
domainToCheck,
|
domainToCheck,
|
||||||
|
@ -338,7 +338,7 @@ func checkDomainHeuristics(ctx context.Context, conn *network.Connection, _ pack
|
||||||
conn.Block("possible data tunnel for covert communication and protection bypassing")
|
conn.Block("possible data tunnel for covert communication and protection bypassing")
|
||||||
return true
|
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
|
return false
|
||||||
|
|
|
@ -138,27 +138,23 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, query *dns.Msg) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get addresses
|
// get remote address
|
||||||
remoteAddr, ok := w.RemoteAddr().(*net.UDPAddr)
|
remoteAddr, ok := w.RemoteAddr().(*net.UDPAddr)
|
||||||
if !ok {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore external request
|
// check if the request is local
|
||||||
if !remoteAddr.IP.Equal(localAddr.IP) {
|
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)
|
log.Warningf("nameserver: external request for %s%s, ignoring", q.FQDN, q.QType)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check if valid domain name
|
// check if valid domain name
|
||||||
if !netutils.IsValidFqdn(q.FQDN) {
|
if !netutils.IsValidFqdn(q.FQDN) {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package netenv
|
package netenv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portmaster/network/netutils"
|
"github.com/safing/portmaster/network/netutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,13 +16,16 @@ func GetAssignedAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
ip := net.ParseIP(strings.Split(addr.String(), "/")[0])
|
netAddr, ok := addr.(*net.IPNet)
|
||||||
if ip != nil {
|
if !ok {
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
log.Warningf("netenv: interface address of unexpected type %T", addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip4 := netAddr.IP.To4(); ip4 != nil {
|
||||||
ipv4 = append(ipv4, ip4)
|
ipv4 = append(ipv4, ip4)
|
||||||
} else {
|
} else {
|
||||||
ipv6 = append(ipv6, ip)
|
ipv6 = append(ipv6, netAddr.IP)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -44,3 +49,50 @@ func GetAssignedGlobalAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
|
||||||
}
|
}
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -155,5 +156,5 @@ func (table *udpTable) cleanStates(now time.Time) {
|
||||||
|
|
||||||
func makeUDPStateKey(address socket.Address) string {
|
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.
|
// 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))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue