Browse Source

Added wip new access list system

Toby Chui 11 months ago
parent
commit
76dc14a16c

+ 3 - 1
main.go

@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"github.com/google/uuid"
+	"imuslab.com/zoraxy/mod/access"
 	"imuslab.com/zoraxy/mod/acme"
 	"imuslab.com/zoraxy/mod/auth"
 	"imuslab.com/zoraxy/mod/database"
@@ -69,7 +70,8 @@ var (
 	tlsCertManager     *tlscert.Manager        //TLS / SSL management
 	redirectTable      *redirection.RuleTable  //Handle special redirection rule sets
 	pathRuleHandler    *pathrule.Handler       //Handle specific path blocking or custom headers
-	geodbStore         *geodb.Store            //GeoIP database, also handle black list and whitelist features
+	geodbStore         *geodb.Store            //GeoIP database, for resolving IP into country code
+	accessController   *access.Controller      //Access controller, handle black list and white list
 	netstatBuffers     *netstat.NetStatBuffers //Realtime graph buffers
 	statisticCollector *statistic.Collector    //Collecting statistic from visitors
 	uptimeMonitor      *uptime.Monitor         //Uptime monitor service worker

+ 153 - 0
mod/access/access.go

@@ -0,0 +1,153 @@
+package access
+
+import (
+	"encoding/json"
+	"errors"
+	"os"
+	"path/filepath"
+	"sync"
+
+	"imuslab.com/zoraxy/mod/database"
+	"imuslab.com/zoraxy/mod/geodb"
+	"imuslab.com/zoraxy/mod/info/logger"
+	"imuslab.com/zoraxy/mod/utils"
+)
+
+/*
+	Access.go
+
+	This module is the new version of access control system
+	where now the blacklist / whitelist are seperated from
+	geodb module
+*/
+
+type Options struct {
+	Logger       logger.Logger
+	ConfigFolder string             //Path for storing config files
+	GeoDB        *geodb.Store       //For resolving country code
+	Database     *database.Database //System key-value database
+}
+
+type AccessRule struct {
+	ID               string
+	Name             string
+	Desc             string
+	BlacklistEnabled bool
+	WhitelistEnabled bool
+
+	/* Whitelist Blacklist Table, value is comment if supported */
+	WhiteListCountryCode *map[string]string
+	WhiteListIP          *map[string]string
+	BlackListContryCode  *map[string]string
+	BlackListIP          *map[string]string
+
+	parent *Controller
+}
+
+type Controller struct {
+	GlobalAccessRule *AccessRule
+	ProxyAccessRule  *sync.Map
+	Options          *Options
+}
+
+// Create a new access controller to handle blacklist / whitelist
+func NewAccessController(options *Options) (*Controller, error) {
+	sysdb := options.Database
+	if sysdb == nil {
+		return nil, errors.New("missing database access")
+	}
+
+	//Create the config folder if not exists
+	confFolder := options.ConfigFolder
+	if !utils.FileExists(confFolder) {
+		err := os.MkdirAll(confFolder, 0775)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Create the global access rule if not exists
+	globalAccessRule := AccessRule{
+		ID:               "default",
+		Name:             "Default",
+		Desc:             "Default access rule for all HTTP proxy hosts",
+		BlacklistEnabled: false,
+		WhitelistEnabled: false,
+	}
+	defaultRuleSettingFile := filepath.Join(confFolder, "default.json")
+	if utils.FileExists(defaultRuleSettingFile) {
+		//Load from file
+		defaultRuleBytes, err := os.ReadFile(defaultRuleSettingFile)
+		if err == nil {
+			err = json.Unmarshal(defaultRuleBytes, &globalAccessRule)
+			if err != nil {
+				options.Logger.PrintAndLog("Access", "Unable to parse default routing rule config file. Using default", err)
+			}
+		}
+	} else {
+		//Create one
+		js, _ := json.MarshalIndent(globalAccessRule, "", " ")
+		os.WriteFile(defaultRuleSettingFile, js, 0775)
+	}
+
+	//Generate a controller object
+	thisController := Controller{
+		GlobalAccessRule: &globalAccessRule,
+		Options:          options,
+	}
+
+	//Load all acccess rules from file
+	configFiles, err := filepath.Glob(options.ConfigFolder + "/*.json")
+	if err != nil {
+		return nil, err
+	}
+	ProxyAccessRules := sync.Map{}
+	for _, configFile := range configFiles {
+		if filepath.Base(configFile) == "default.json" {
+			//Skip this, as this was already loaded as default
+			continue
+		}
+
+		configContent, err := os.ReadFile(configFile)
+		if err != nil {
+			options.Logger.PrintAndLog("Access", "Unable to load config "+filepath.Base(configFile), err)
+			continue
+		}
+
+		//Parse the config file into AccessRule
+		thisAccessRule := AccessRule{}
+		err = json.Unmarshal(configContent, &thisAccessRule)
+		if err != nil {
+			options.Logger.PrintAndLog("Access", "Unable to parse config "+filepath.Base(configFile), err)
+			continue
+		}
+		thisAccessRule.parent = &thisController
+		ProxyAccessRules.Store(thisAccessRule.ID, &thisAccessRule)
+	}
+	thisController.ProxyAccessRule = &ProxyAccessRules
+
+	return &thisController, nil
+}
+
+// Get the global access rule
+func (c *Controller) GetGlobalAccessRule() (*AccessRule, error) {
+	if c.GlobalAccessRule == nil {
+		return nil, errors.New("global access rule is not set")
+	}
+	return c.GlobalAccessRule, nil
+}
+
+// Load access rules to runtime, require rule ID
+func (c *Controller) GetAccessRuleByID(accessRuleID string) (*AccessRule, error) {
+	//Load from sync.Map, should be O(1)
+	targetRule, ok := c.ProxyAccessRule.Load(accessRuleID)
+	if !ok {
+		return nil, errors.New("target access rule not exists")
+	}
+
+	ar, ok := targetRule.(*AccessRule)
+	if !ok {
+		return nil, errors.New("assertion of access rule failed, version too old?")
+	}
+	return ar, nil
+}

+ 124 - 0
mod/access/accessRule.go

@@ -0,0 +1,124 @@
+package access
+
+import (
+	"encoding/json"
+	"net"
+	"os"
+	"path/filepath"
+)
+
+// Check both blacklist and whitelist for access for both geoIP and ip / CIDR ranges
+func (s *AccessRule) AllowIpAccess(ipaddr string) bool {
+	if s.IsBlacklisted(ipaddr) {
+		return false
+	}
+
+	return s.IsWhitelisted(ipaddr)
+}
+
+// Check both blacklist and whitelist for access using net.Conn
+func (s *AccessRule) AllowConnectionAccess(conn net.Conn) bool {
+	if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
+		return s.AllowIpAccess(addr.IP.String())
+	}
+	return true
+}
+
+// Toggle black list
+func (s *AccessRule) ToggleBlacklist(enabled bool) {
+	s.parent.Options.Database.Write("blackwhitelist", "blacklistEnabled", enabled)
+	s.BlacklistEnabled = enabled
+}
+
+// Toggel white list
+func (s *AccessRule) ToggleWhitelist(enabled bool) {
+	s.parent.Options.Database.Write("blackwhitelist", "whitelistEnabled", enabled)
+	s.WhitelistEnabled = enabled
+}
+
+/*
+Check if a IP address is blacklisted, in either country or IP blacklist
+IsBlacklisted default return is false (allow access)
+*/
+func (s *AccessRule) IsBlacklisted(ipAddr string) bool {
+	if !s.BlacklistEnabled {
+		//Blacklist not enabled. Always return false
+		return false
+	}
+
+	if ipAddr == "" {
+		//Unable to get the target IP address
+		return false
+	}
+
+	countryCode, err := s.parent.Options.GeoDB.ResolveCountryCodeFromIP(ipAddr)
+	if err != nil {
+		return false
+	}
+
+	if s.IsCountryCodeBlacklisted(countryCode.CountryIsoCode) {
+		return true
+	}
+
+	if s.IsIPBlacklisted(ipAddr) {
+		return true
+	}
+
+	return false
+}
+
+/*
+IsWhitelisted check if a given IP address is in the current
+server's white list.
+
+Note that the Whitelist default result is true even
+when encountered error
+*/
+func (s *AccessRule) IsWhitelisted(ipAddr string) bool {
+	if !s.WhitelistEnabled {
+		//Whitelist not enabled. Always return true (allow access)
+		return true
+	}
+
+	if ipAddr == "" {
+		//Unable to get the target IP address, assume ok
+		return true
+	}
+
+	countryCode, err := s.parent.Options.GeoDB.ResolveCountryCodeFromIP(ipAddr)
+	if err != nil {
+		return true
+	}
+
+	if s.IsCountryCodeWhitelisted(countryCode.CountryIsoCode) {
+		return true
+	}
+
+	if s.IsIPWhitelisted(ipAddr) {
+		return true
+	}
+
+	return false
+}
+
+/* Utilities function */
+
+// Update the current access rule to json file
+func (s *AccessRule) SaveChanges() error {
+	saveTarget := filepath.Join(s.parent.Options.ConfigFolder, s.ID+".json")
+	js, err := json.MarshalIndent(s, "", " ")
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(saveTarget, js, 0775)
+	return err
+}
+
+// Create a deep copy object of the access rule list
+func deepCopy(valueList map[string]string) map[string]string {
+	result := map[string]string{}
+	js, _ := json.Marshal(valueList)
+	json.Unmarshal(js, &result)
+	return result
+}

+ 75 - 0
mod/access/blacklist.go

@@ -0,0 +1,75 @@
+package access
+
+import (
+	"strings"
+)
+
+/*
+	Blacklist.go
+
+	This script store the blacklist related functions
+*/
+
+// Geo Blacklist
+func (s *AccessRule) AddCountryCodeToBlackList(countryCode string, comment string) {
+	countryCode = strings.ToLower(countryCode)
+	newBlacklistCountryCode := deepCopy(*s.BlackListContryCode)
+	newBlacklistCountryCode[countryCode] = comment
+	s.BlackListContryCode = &newBlacklistCountryCode
+	s.SaveChanges()
+}
+
+func (s *AccessRule) RemoveCountryCodeFromBlackList(countryCode string) {
+	countryCode = strings.ToLower(countryCode)
+	newBlacklistCountryCode := deepCopy(*s.BlackListContryCode)
+	delete(newBlacklistCountryCode, countryCode)
+	s.BlackListContryCode = &newBlacklistCountryCode
+	s.SaveChanges()
+}
+
+func (s *AccessRule) IsCountryCodeBlacklisted(countryCode string) bool {
+	countryCode = strings.ToLower(countryCode)
+	blacklistMap := *s.BlackListContryCode
+	_, ok := blacklistMap[countryCode]
+	return ok
+}
+
+func (s *AccessRule) GetAllBlacklistedCountryCode() []string {
+	bannedCountryCodes := []string{}
+	blacklistMap := *s.BlackListContryCode
+	for cc, _ := range blacklistMap {
+		bannedCountryCodes = append(bannedCountryCodes, cc)
+	}
+	return bannedCountryCodes
+}
+
+// IP Blacklsits
+func (s *AccessRule) AddIPToBlackList(ipAddr string, comment string) {
+	newBlackListIP := deepCopy(*s.BlackListIP)
+	newBlackListIP[ipAddr] = comment
+	s.BlackListIP = &newBlackListIP
+	s.SaveChanges()
+}
+
+func (s *AccessRule) RemoveIPFromBlackList(ipAddr string) {
+	newBlackListIP := deepCopy(*s.BlackListIP)
+	delete(newBlackListIP, ipAddr)
+	s.BlackListIP = &newBlackListIP
+	s.SaveChanges()
+}
+
+func (s *AccessRule) GetAllBlacklistedIp() []string {
+	bannedIps := []string{}
+	blacklistMap := *s.BlackListIP
+	for ip, _ := range blacklistMap {
+		bannedIps = append(bannedIps, ip)
+	}
+
+	return bannedIps
+}
+
+func (s *AccessRule) IsIPBlacklisted(ipAddr string) bool {
+	IPBlacklist := *s.BlackListIP
+	_, ok := IPBlacklist[ipAddr]
+	return ok
+}

+ 22 - 20
mod/geodb/whitelist.go → mod/access/whitelist.go

@@ -1,8 +1,10 @@
-package geodb
+package access
 
 import (
 	"encoding/json"
 	"strings"
+
+	"imuslab.com/zoraxy/mod/netutils"
 )
 
 /*
@@ -25,7 +27,7 @@ type WhitelistEntry struct {
 
 //Geo Whitelist
 
-func (s *Store) AddCountryCodeToWhitelist(countryCode string, comment string) {
+func (s *AccessRule) AddCountryCodeToWhitelist(countryCode string, comment string) {
 	countryCode = strings.ToLower(countryCode)
 	entry := WhitelistEntry{
 		EntryType: EntryType_CountryCode,
@@ -33,22 +35,22 @@ func (s *Store) AddCountryCodeToWhitelist(countryCode string, comment string) {
 		Comment:   comment,
 	}
 
-	s.sysdb.Write("whitelist-cn", countryCode, entry)
+	s.GetDatabase().Write(s.GetFullTableName("whitelist-cn"), countryCode, entry)
 }
 
-func (s *Store) RemoveCountryCodeFromWhitelist(countryCode string) {
+func (s *AccessRule) RemoveCountryCodeFromWhitelist(countryCode string) {
 	countryCode = strings.ToLower(countryCode)
-	s.sysdb.Delete("whitelist-cn", countryCode)
+	s.GetDatabase().Delete(s.GetFullTableName("whitelist-cn"), countryCode)
 }
 
-func (s *Store) IsCountryCodeWhitelisted(countryCode string) bool {
+func (s *AccessRule) IsCountryCodeWhitelisted(countryCode string) bool {
 	countryCode = strings.ToLower(countryCode)
-	return s.sysdb.KeyExists("whitelist-cn", countryCode)
+	return s.GetDatabase().KeyExists(s.GetFullTableName("whitelist-cn"), countryCode)
 }
 
-func (s *Store) GetAllWhitelistedCountryCode() []*WhitelistEntry {
+func (s *AccessRule) GetAllWhitelistedCountryCode() []*WhitelistEntry {
 	whitelistedCountryCode := []*WhitelistEntry{}
-	entries, err := s.sysdb.ListTable("whitelist-cn")
+	entries, err := s.GetDatabase().ListTable(s.GetFullTableName("whitelist-cn"))
 	if err != nil {
 		return whitelistedCountryCode
 	}
@@ -63,22 +65,22 @@ func (s *Store) GetAllWhitelistedCountryCode() []*WhitelistEntry {
 
 //IP Whitelist
 
-func (s *Store) AddIPToWhiteList(ipAddr string, comment string) {
+func (s *AccessRule) AddIPToWhiteList(ipAddr string, comment string) {
 	thisIpEntry := WhitelistEntry{
 		EntryType: EntryType_IP,
 		IP:        ipAddr,
 		Comment:   comment,
 	}
 
-	s.sysdb.Write("whitelist-ip", ipAddr, thisIpEntry)
+	s.GetDatabase().Write(s.GetFullTableName("whitelist-ip"), ipAddr, thisIpEntry)
 }
 
-func (s *Store) RemoveIPFromWhiteList(ipAddr string) {
-	s.sysdb.Delete("whitelist-ip", ipAddr)
+func (s *AccessRule) RemoveIPFromWhiteList(ipAddr string) {
+	s.GetDatabase().Delete(s.GetFullTableName("whitelist-ip"), ipAddr)
 }
 
-func (s *Store) IsIPWhitelisted(ipAddr string) bool {
-	isWhitelisted := s.sysdb.KeyExists("whitelist-ip", ipAddr)
+func (s *AccessRule) IsIPWhitelisted(ipAddr string) bool {
+	isWhitelisted := s.GetDatabase().KeyExists(s.GetFullTableName("whitelist-ip"), ipAddr)
 	if isWhitelisted {
 		//single IP whitelist entry
 		return true
@@ -87,12 +89,12 @@ func (s *Store) IsIPWhitelisted(ipAddr string) bool {
 	//Check for IP wildcard and CIRD rules
 	AllWhitelistedIps := s.GetAllWhitelistedIpAsStringSlice()
 	for _, whitelistRules := range AllWhitelistedIps {
-		wildcardMatch := MatchIpWildcard(ipAddr, whitelistRules)
+		wildcardMatch := netutils.MatchIpWildcard(ipAddr, whitelistRules)
 		if wildcardMatch {
 			return true
 		}
 
-		cidrMatch := MatchIpCIDR(ipAddr, whitelistRules)
+		cidrMatch := netutils.MatchIpCIDR(ipAddr, whitelistRules)
 		if cidrMatch {
 			return true
 		}
@@ -101,9 +103,9 @@ func (s *Store) IsIPWhitelisted(ipAddr string) bool {
 	return false
 }
 
-func (s *Store) GetAllWhitelistedIp() []*WhitelistEntry {
+func (s *AccessRule) GetAllWhitelistedIp() []*WhitelistEntry {
 	whitelistedIp := []*WhitelistEntry{}
-	entries, err := s.sysdb.ListTable("whitelist-ip")
+	entries, err := s.GetDatabase().ListTable(s.GetFullTableName("whitelist-ip"))
 	if err != nil {
 		return whitelistedIp
 	}
@@ -118,7 +120,7 @@ func (s *Store) GetAllWhitelistedIp() []*WhitelistEntry {
 	return whitelistedIp
 }
 
-func (s *Store) GetAllWhitelistedIpAsStringSlice() []string {
+func (s *AccessRule) GetAllWhitelistedIpAsStringSlice() []string {
 	allWhitelistedIPs := []string{}
 	entries := s.GetAllWhitelistedIp()
 	for _, entry := range entries {

+ 0 - 76
mod/aroz/aroz.go

@@ -1,76 +0,0 @@
-package aroz
-
-import (
-	"encoding/json"
-	"flag"
-	"fmt"
-	"net/http"
-	"net/url"
-	"os"
-)
-
-//To be used with arozos system
-type ArozHandler struct {
-	Port            string
-	restfulEndpoint string
-}
-
-//Information required for registering this subservice to arozos
-type ServiceInfo struct {
-	Name         string   //Name of this module. e.g. "Audio"
-	Desc         string   //Description for this module
-	Group        string   //Group of the module, e.g. "system" / "media" etc
-	IconPath     string   //Module icon image path e.g. "Audio/img/function_icon.png"
-	Version      string   //Version of the module. Format: [0-9]*.[0-9][0-9].[0-9]
-	StartDir     string   //Default starting dir, e.g. "Audio/index.html"
-	SupportFW    bool     //Support floatWindow. If yes, floatWindow dir will be loaded
-	LaunchFWDir  string   //This link will be launched instead of 'StartDir' if fw mode
-	SupportEmb   bool     //Support embedded mode
-	LaunchEmb    string   //This link will be launched instead of StartDir / Fw if a file is opened with this module
-	InitFWSize   []int    //Floatwindow init size. [0] => Width, [1] => Height
-	InitEmbSize  []int    //Embedded mode init size. [0] => Width, [1] => Height
-	SupportedExt []string //Supported File Extensions. e.g. ".mp3", ".flac", ".wav"
-}
-
-//This function will request the required flag from the startup paramters and parse it to the need of the arozos.
-func HandleFlagParse(info ServiceInfo) *ArozHandler {
-	var infoRequestMode = flag.Bool("info", false, "Show information about this program in JSON")
-	var port = flag.String("port", ":8000", "Management web interface listening port")
-	var restful = flag.String("rpt", "", "Reserved")
-	//Parse the flags
-	flag.Parse()
-	if *infoRequestMode {
-		//Information request mode
-		jsonString, _ := json.MarshalIndent(info, "", " ")
-		fmt.Println(string(jsonString))
-		os.Exit(0)
-	}
-	return &ArozHandler{
-		Port:            *port,
-		restfulEndpoint: *restful,
-	}
-}
-
-//Get the username and resources access token from the request, return username, token
-func (a *ArozHandler) GetUserInfoFromRequest(w http.ResponseWriter, r *http.Request) (string, string) {
-	username := r.Header.Get("aouser")
-	token := r.Header.Get("aotoken")
-
-	return username, token
-}
-
-func (a *ArozHandler) IsUsingExternalPermissionManager() bool {
-	return !(a.restfulEndpoint == "")
-}
-
-//Request gateway interface for advance permission sandbox control
-func (a *ArozHandler) RequestGatewayInterface(token string, script string) (*http.Response, error) {
-	resp, err := http.PostForm(a.restfulEndpoint,
-		url.Values{"token": {token}, "script": {script}})
-	if err != nil {
-		// handle error
-		return nil, err
-	}
-
-	return resp, nil
-}

BIN
mod/aroz/doc.txt


+ 2 - 2
mod/dynamicproxy/proxyRequestHandler.go

@@ -11,7 +11,7 @@ import (
 	"strings"
 
 	"imuslab.com/zoraxy/mod/dynamicproxy/dpcore"
-	"imuslab.com/zoraxy/mod/geodb"
+	"imuslab.com/zoraxy/mod/netutils"
 	"imuslab.com/zoraxy/mod/statistic"
 	"imuslab.com/zoraxy/mod/websocketproxy"
 )
@@ -224,7 +224,7 @@ func (h *ProxyHandler) logRequest(r *http.Request, succ bool, statusCode int, fo
 	if h.Parent.Option.StatisticCollector != nil {
 		go func() {
 			requestInfo := statistic.RequestInfo{
-				IpAddr:                        geodb.GetRequesterIP(r),
+				IpAddr:                        netutils.GetRequesterIP(r),
 				RequestOriginalCountryISOCode: h.Parent.Option.GeodbStore.GetRequesterCountryISOCode(r),
 				Succ:                          succ,
 				StatusCode:                    statusCode,

+ 7 - 4
mod/dynamicproxy/typedef.go

@@ -111,14 +111,17 @@ type ProxyEndpoint struct {
 	BasicAuthCredentials    []*BasicAuthCredentials   //Basic auth credentials
 	BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
 
-	//Fallback routing logic
-	DefaultSiteOption int    //Fallback routing logic options
-	DefaultSiteValue  string //Fallback routing target, optional
+	//Access Control
+	AccessFilterUUID string //Access filter ID
 
 	Disabled bool //If the rule is disabled
 
+	//Fallback routing logic (Special Rule Sets Only)
+	DefaultSiteOption int    //Fallback routing logic options
+	DefaultSiteValue  string //Fallback routing target, optional
+
 	//Internal Logic Elements
-	parent *Router
+	parent *Router              `json:"-"`
 	proxy  *dpcore.ReverseProxy `json:"-"`
 }
 

+ 0 - 91
mod/geodb/blacklist.go

@@ -1,91 +0,0 @@
-package geodb
-
-import "strings"
-
-/*
-	Blacklist.go
-
-	This script store the blacklist related functions
-*/
-
-//Geo Blacklist
-
-func (s *Store) AddCountryCodeToBlackList(countryCode string) {
-	countryCode = strings.ToLower(countryCode)
-	s.sysdb.Write("blacklist-cn", countryCode, true)
-}
-
-func (s *Store) RemoveCountryCodeFromBlackList(countryCode string) {
-	countryCode = strings.ToLower(countryCode)
-	s.sysdb.Delete("blacklist-cn", countryCode)
-}
-
-func (s *Store) IsCountryCodeBlacklisted(countryCode string) bool {
-	countryCode = strings.ToLower(countryCode)
-	var isBlacklisted bool = false
-	s.sysdb.Read("blacklist-cn", countryCode, &isBlacklisted)
-	return isBlacklisted
-}
-
-func (s *Store) GetAllBlacklistedCountryCode() []string {
-	bannedCountryCodes := []string{}
-	entries, err := s.sysdb.ListTable("blacklist-cn")
-	if err != nil {
-		return bannedCountryCodes
-	}
-	for _, keypairs := range entries {
-		ip := string(keypairs[0])
-		bannedCountryCodes = append(bannedCountryCodes, ip)
-	}
-
-	return bannedCountryCodes
-}
-
-//IP Blacklsits
-
-func (s *Store) AddIPToBlackList(ipAddr string) {
-	s.sysdb.Write("blacklist-ip", ipAddr, true)
-}
-
-func (s *Store) RemoveIPFromBlackList(ipAddr string) {
-	s.sysdb.Delete("blacklist-ip", ipAddr)
-}
-
-func (s *Store) GetAllBlacklistedIp() []string {
-	bannedIps := []string{}
-	entries, err := s.sysdb.ListTable("blacklist-ip")
-	if err != nil {
-		return bannedIps
-	}
-
-	for _, keypairs := range entries {
-		ip := string(keypairs[0])
-		bannedIps = append(bannedIps, ip)
-	}
-
-	return bannedIps
-}
-
-func (s *Store) IsIPBlacklisted(ipAddr string) bool {
-	var isBlacklisted bool = false
-	s.sysdb.Read("blacklist-ip", ipAddr, &isBlacklisted)
-	if isBlacklisted {
-		return true
-	}
-
-	//Check for IP wildcard and CIRD rules
-	AllBlacklistedIps := s.GetAllBlacklistedIp()
-	for _, blacklistRule := range AllBlacklistedIps {
-		wildcardMatch := MatchIpWildcard(ipAddr, blacklistRule)
-		if wildcardMatch {
-			return true
-		}
-
-		cidrMatch := MatchIpCIDR(ipAddr, blacklistRule)
-		if cidrMatch {
-			return true
-		}
-	}
-
-	return false
-}

+ 12 - 143
mod/geodb/geodb.go

@@ -2,11 +2,10 @@ package geodb
 
 import (
 	_ "embed"
-	"log"
-	"net"
 	"net/http"
 
 	"imuslab.com/zoraxy/mod/database"
+	"imuslab.com/zoraxy/mod/netutils"
 )
 
 //go:embed geoipv4.csv
@@ -16,12 +15,10 @@ var geoipv4 []byte //Geodb dataset for ipv4
 var geoipv6 []byte //Geodb dataset for ipv6
 
 type Store struct {
-	BlacklistEnabled bool
-	WhitelistEnabled bool
-	geodb            [][]string //Parsed geodb list
-	geodbIpv6        [][]string //Parsed geodb list for ipv6
-	geotrie          *trie
-	geotrieIpv6      *trie
+	geodb       [][]string //Parsed geodb list
+	geodbIpv6   [][]string //Parsed geodb list for ipv6
+	geotrie     *trie
+	geotrieIpv6 *trie
 	//geoipCache sync.Map
 	sysdb  *database.Database
 	option *StoreOptions
@@ -48,40 +45,6 @@ func NewGeoDb(sysdb *database.Database, option *StoreOptions) (*Store, error) {
 		return nil, err
 	}
 
-	blacklistEnabled := false
-	whitelistEnabled := false
-	if sysdb != nil {
-		err = sysdb.NewTable("blacklist-cn")
-		if err != nil {
-			return nil, err
-		}
-
-		err = sysdb.NewTable("blacklist-ip")
-		if err != nil {
-			return nil, err
-		}
-
-		err = sysdb.NewTable("whitelist-cn")
-		if err != nil {
-			return nil, err
-		}
-
-		err = sysdb.NewTable("whitelist-ip")
-		if err != nil {
-			return nil, err
-		}
-
-		err = sysdb.NewTable("blackwhitelist")
-		if err != nil {
-			return nil, err
-		}
-
-		sysdb.Read("blackwhitelist", "blacklistEnabled", &blacklistEnabled)
-		sysdb.Read("blackwhitelist", "whitelistEnabled", &whitelistEnabled)
-	} else {
-		log.Println("Database pointer set to nil: Entering debug mode")
-	}
-
 	var ipv4Trie *trie
 	if !option.AllowSlowIpv4LookUp {
 		ipv4Trie = constrctTrieTree(parsedGeoData)
@@ -93,27 +56,15 @@ func NewGeoDb(sysdb *database.Database, option *StoreOptions) (*Store, error) {
 	}
 
 	return &Store{
-		BlacklistEnabled: blacklistEnabled,
-		WhitelistEnabled: whitelistEnabled,
-		geodb:            parsedGeoData,
-		geotrie:          ipv4Trie,
-		geodbIpv6:        parsedGeoDataIpv6,
-		geotrieIpv6:      ipv6Trie,
-		sysdb:            sysdb,
-		option:           option,
+		geodb:       parsedGeoData,
+		geotrie:     ipv4Trie,
+		geodbIpv6:   parsedGeoDataIpv6,
+		geotrieIpv6: ipv6Trie,
+		sysdb:       sysdb,
+		option:      option,
 	}, nil
 }
 
-func (s *Store) ToggleBlacklist(enabled bool) {
-	s.sysdb.Write("blackwhitelist", "blacklistEnabled", enabled)
-	s.BlacklistEnabled = enabled
-}
-
-func (s *Store) ToggleWhitelist(enabled bool) {
-	s.sysdb.Write("blackwhitelist", "whitelistEnabled", enabled)
-	s.WhitelistEnabled = enabled
-}
-
 func (s *Store) ResolveCountryCodeFromIP(ipstring string) (*CountryInfo, error) {
 	cc := s.search(ipstring)
 	return &CountryInfo{
@@ -127,90 +78,8 @@ func (s *Store) Close() {
 
 }
 
-/*
-Check if a IP address is blacklisted, in either country or IP blacklist
-IsBlacklisted default return is false (allow access)
-*/
-func (s *Store) IsBlacklisted(ipAddr string) bool {
-	if !s.BlacklistEnabled {
-		//Blacklist not enabled. Always return false
-		return false
-	}
-
-	if ipAddr == "" {
-		//Unable to get the target IP address
-		return false
-	}
-
-	countryCode, err := s.ResolveCountryCodeFromIP(ipAddr)
-	if err != nil {
-		return false
-	}
-
-	if s.IsCountryCodeBlacklisted(countryCode.CountryIsoCode) {
-		return true
-	}
-
-	if s.IsIPBlacklisted(ipAddr) {
-		return true
-	}
-
-	return false
-}
-
-/*
-IsWhitelisted check if a given IP address is in the current
-server's white list.
-
-Note that the Whitelist default result is true even
-when encountered error
-*/
-func (s *Store) IsWhitelisted(ipAddr string) bool {
-	if !s.WhitelistEnabled {
-		//Whitelist not enabled. Always return true (allow access)
-		return true
-	}
-
-	if ipAddr == "" {
-		//Unable to get the target IP address, assume ok
-		return true
-	}
-
-	countryCode, err := s.ResolveCountryCodeFromIP(ipAddr)
-	if err != nil {
-		return true
-	}
-
-	if s.IsCountryCodeWhitelisted(countryCode.CountryIsoCode) {
-		return true
-	}
-
-	if s.IsIPWhitelisted(ipAddr) {
-		return true
-	}
-
-	return false
-}
-
-// A helper function that check both blacklist and whitelist for access
-// for both geoIP and ip / CIDR ranges
-func (s *Store) AllowIpAccess(ipaddr string) bool {
-	if s.IsBlacklisted(ipaddr) {
-		return false
-	}
-
-	return s.IsWhitelisted(ipaddr)
-}
-
-func (s *Store) AllowConnectionAccess(conn net.Conn) bool {
-	if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
-		return s.AllowIpAccess(addr.IP.String())
-	}
-	return true
-}
-
 func (s *Store) GetRequesterCountryISOCode(r *http.Request) string {
-	ipAddr := GetRequesterIP(r)
+	ipAddr := netutils.GetRequesterIP(r)
 	if ipAddr == "" {
 		return ""
 	}

+ 3 - 1
mod/geodb/geoloader.go

@@ -5,6 +5,8 @@ import (
 	"encoding/csv"
 	"io"
 	"strings"
+
+	"imuslab.com/zoraxy/mod/netutils"
 )
 
 func (s *Store) search(ip string) string {
@@ -24,7 +26,7 @@ func (s *Store) search(ip string) string {
 
 	//Search in geotrie tree
 	cc := ""
-	if IsIPv6(ip) {
+	if netutils.IsIPv6(ip) {
 		if s.geotrieIpv6 == nil {
 			cc = s.slowSearchIpv6(ip)
 		} else {

+ 8 - 2
mod/geodb/netutils.go → mod/netutils/ipmatch.go

@@ -1,4 +1,4 @@
-package geodb
+package netutils
 
 import (
 	"net"
@@ -6,7 +6,13 @@ import (
 	"strings"
 )
 
-// Utilities function
+/*
+	MatchIP.go
+
+	This script contains function for matching IP address, comparing
+	CIDR and IPv4 / v6 validations
+*/
+
 func GetRequesterIP(r *http.Request) string {
 	ip := r.Header.Get("X-Real-Ip")
 	if ip == "" {

+ 10 - 0
start.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 	"time"
 
+	"imuslab.com/zoraxy/mod/access"
 	"imuslab.com/zoraxy/mod/acme"
 	"imuslab.com/zoraxy/mod/auth"
 	"imuslab.com/zoraxy/mod/database"
@@ -91,6 +92,15 @@ func startupSequence() {
 		panic(err)
 	}
 
+	//Create the access controller
+	accessController, err = access.NewAccessController(&access.Options{
+		Database: sysdb,
+		GeoDB:    geodbStore,
+	})
+	if err != nil {
+		panic(err)
+	}
+
 	//Create a statistic collector
 	statisticCollector, err = statistic.NewStatisticCollector(statistic.CollectorOption{
 		Database: sysdb,

+ 1 - 1
web/components/cert.html

@@ -237,7 +237,7 @@
                         msgbox("Certificate installed successfully");
                         
                         if (callback != undefined){
-                            callback(false);
+                            callback(true);
                         }
                     }
                 },