瀏覽代碼

Add TrafficRules.AllowASNs/DisallowSubnets/DisallowASNs

Rod Hynes 3 年之前
父節點
當前提交
162f88186d
共有 2 個文件被更改,包括 124 次插入15 次删除
  1. 118 13
      psiphon/server/trafficRules.go
  2. 6 2
      psiphon/server/tunnelServer.go

+ 118 - 13
psiphon/server/trafficRules.go

@@ -22,6 +22,7 @@ package server
 import (
 	"encoding/json"
 	"net"
+	"strconv"
 	"time"
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
@@ -279,16 +280,30 @@ type TrafficRules struct {
 	// AllowSubnets.
 	DisallowUDPPorts *common.PortList
 
-	// AllowSubnets specifies a list of IP address subnets for which all TCP and
-	// UDP ports are allowed. This list is consulted if a port is disallowed by
-	// the AllowTCPPorts or AllowUDPPorts configuration. Each entry is a IP
-	// subnet in CIDR notation.
-	//
-	// Limitation: currently, AllowSubnets only matches port forwards where the
-	// client sends an IP address. Domain names are not resolved before checking
-	// AllowSubnets.
+	// AllowSubnets specifies a list of IP address subnets for which all TCP
+	// and UDP ports are allowed. This list is consulted if a port is not
+	// allowed by the AllowTCPPorts or AllowUDPPorts configuration; but not
+	// if a port is disallowed by DisallowTCPPorts, DisallowUDPPorts,
+	// DisallowSubnets or DisallowASNs. Each entry is a IP subnet in CIDR
+	// notation.
 	AllowSubnets []string
 
+	// AllowASNs specifies a list of ASNs for which all TCP and UDP ports are
+	// allowed. This list is consulted if a port is not allowed by the
+	// AllowTCPPorts or AllowUDPPorts configuration; but not if a port is
+	// disallowed by DisallowTCPPorts, DisallowUDPPorts, DisallowSubnets or
+	// DisallowASNs.
+	AllowASNs []string
+
+	// DisallowSubnets specifies a list of IP address subnets for which all
+	// TCP and UDP ports are disallowed. Each entry is a IP subnet in CIDR
+	// notation.
+	DisallowSubnets []string
+
+	// DisallowASNs specifies a list of ASNs for which all TCP and UDP ports
+	// are disallowed.
+	DisallowASNs []string
+
 	// DisableDiscovery specifies whether to disable server entry discovery,
 	// to manage load on discovery servers.
 	DisableDiscovery *bool
@@ -419,6 +434,27 @@ func (set *TrafficRulesSet) Validate() error {
 			}
 		}
 
+		for _, ASN := range rules.AllowASNs {
+			_, err := strconv.Atoi(ASN)
+			if err != nil {
+				return errors.Tracef("invalid ASN: %s %s", ASN, err)
+			}
+		}
+
+		for _, subnet := range rules.DisallowSubnets {
+			_, _, err := net.ParseCIDR(subnet)
+			if err != nil {
+				return errors.Tracef("invalid subnet: %s %s", subnet, err)
+			}
+		}
+
+		for _, ASN := range rules.DisallowASNs {
+			_, err := strconv.Atoi(ASN)
+			if err != nil {
+				return errors.Tracef("invalid ASN: %s %s", ASN, err)
+			}
+		}
+
 		return nil
 	}
 
@@ -634,6 +670,18 @@ func (set *TrafficRulesSet) GetTrafficRules(
 		trafficRules.AllowSubnets = make([]string, 0)
 	}
 
+	if trafficRules.AllowASNs == nil {
+		trafficRules.AllowASNs = make([]string, 0)
+	}
+
+	if trafficRules.DisallowSubnets == nil {
+		trafficRules.DisallowSubnets = make([]string, 0)
+	}
+
+	if trafficRules.DisallowASNs == nil {
+		trafficRules.DisallowASNs = make([]string, 0)
+	}
+
 	if trafficRules.DisableDiscovery == nil {
 		trafficRules.DisableDiscovery = new(bool)
 	}
@@ -869,6 +917,18 @@ func (set *TrafficRulesSet) GetTrafficRules(
 			trafficRules.AllowSubnets = filteredRules.Rules.AllowSubnets
 		}
 
+		if filteredRules.Rules.AllowASNs != nil {
+			trafficRules.AllowASNs = filteredRules.Rules.AllowASNs
+		}
+
+		if filteredRules.Rules.DisallowSubnets != nil {
+			trafficRules.DisallowSubnets = filteredRules.Rules.DisallowSubnets
+		}
+
+		if filteredRules.Rules.DisallowASNs != nil {
+			trafficRules.DisallowASNs = filteredRules.Rules.DisallowASNs
+		}
+
 		if filteredRules.Rules.DisableDiscovery != nil {
 			trafficRules.DisableDiscovery = filteredRules.Rules.DisableDiscovery
 		}
@@ -886,7 +946,12 @@ func (set *TrafficRulesSet) GetTrafficRules(
 	return trafficRules
 }
 
-func (rules *TrafficRules) AllowTCPPort(remoteIP net.IP, port int) bool {
+func (rules *TrafficRules) AllowTCPPort(
+	geoIPService *GeoIPService, remoteIP net.IP, port int) bool {
+
+	if rules.disallowSubnet(remoteIP) || rules.disallowASN(geoIPService, remoteIP) {
+		return false
+	}
 
 	if rules.DisallowTCPPorts.Lookup(port) {
 		return false
@@ -900,10 +965,15 @@ func (rules *TrafficRules) AllowTCPPort(remoteIP net.IP, port int) bool {
 		return true
 	}
 
-	return rules.allowSubnet(remoteIP)
+	return rules.allowSubnet(remoteIP) || rules.allowASN(geoIPService, remoteIP)
 }
 
-func (rules *TrafficRules) AllowUDPPort(remoteIP net.IP, port int) bool {
+func (rules *TrafficRules) AllowUDPPort(
+	geoIPService *GeoIPService, remoteIP net.IP, port int) bool {
+
+	if rules.disallowSubnet(remoteIP) || rules.disallowASN(geoIPService, remoteIP) {
+		return false
+	}
 
 	if rules.DisallowUDPPorts.Lookup(port) {
 		return false
@@ -917,12 +987,35 @@ func (rules *TrafficRules) AllowUDPPort(remoteIP net.IP, port int) bool {
 		return true
 	}
 
-	return rules.allowSubnet(remoteIP)
+	return rules.allowSubnet(remoteIP) || rules.allowASN(geoIPService, remoteIP)
 }
 
 func (rules *TrafficRules) allowSubnet(remoteIP net.IP) bool {
+	return ipInSubnets(remoteIP, rules.AllowSubnets)
+}
+
+func (rules *TrafficRules) allowASN(
+	geoIPService *GeoIPService, remoteIP net.IP) bool {
+
+	if len(rules.AllowASNs) == 0 || geoIPService == nil {
+		return false
+	}
+
+	return common.Contains(
+		rules.AllowASNs,
+		geoIPService.LookupISPForIP(remoteIP).ASN)
+}
+
+func (rules *TrafficRules) disallowSubnet(remoteIP net.IP) bool {
+	return ipInSubnets(remoteIP, rules.DisallowSubnets)
+}
+
+func ipInSubnets(remoteIP net.IP, subnets []string) bool {
+
+	for _, subnet := range subnets {
+
+		// TODO: cache parsed results
 
-	for _, subnet := range rules.AllowSubnets {
 		// Note: ignoring error as config has been validated
 		_, network, _ := net.ParseCIDR(subnet)
 		if network.Contains(remoteIP) {
@@ -933,6 +1026,18 @@ func (rules *TrafficRules) allowSubnet(remoteIP net.IP) bool {
 	return false
 }
 
+func (rules *TrafficRules) disallowASN(
+	geoIPService *GeoIPService, remoteIP net.IP) bool {
+
+	if len(rules.DisallowASNs) == 0 || geoIPService == nil {
+		return false
+	}
+
+	return common.Contains(
+		rules.DisallowASNs,
+		geoIPService.LookupISPForIP(remoteIP).ASN)
+}
+
 // GetMeekRateLimiterConfig gets a snapshot of the meek rate limiter
 // configuration values.
 func (set *TrafficRulesSet) GetMeekRateLimiterConfig() (

+ 6 - 2
psiphon/server/tunnelServer.go

@@ -3729,11 +3729,15 @@ func (sshClient *sshClient) isPortForwardPermitted(
 		// Traffic rules checks.
 		switch portForwardType {
 		case portForwardTypeTCP:
-			if !sshClient.trafficRules.AllowTCPPort(remoteIP, port) {
+			if !sshClient.trafficRules.AllowTCPPort(
+				sshClient.sshServer.support.GeoIPService, remoteIP, port) {
+
 				allowed = false
 			}
 		case portForwardTypeUDP:
-			if !sshClient.trafficRules.AllowUDPPort(remoteIP, port) {
+			if !sshClient.trafficRules.AllowUDPPort(
+				sshClient.sshServer.support.GeoIPService, remoteIP, port) {
+
 				allowed = false
 			}
 		}