package access import ( "encoding/json" "errors" "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.BlacklistEnabled = enabled s.SaveChanges() } // Toggel white list func (s *AccessRule) ToggleWhitelist(enabled bool) { s.WhitelistEnabled = enabled s.SaveChanges() } /* 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 { if s.parent == nil { return errors.New("save failed: access rule detached from controller") } 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 } // Delete this access rule, this will only delete the config file. // for runtime delete, use DeleteAccessRuleByID from parent Controller func (s *AccessRule) DeleteConfigFile() error { saveTarget := filepath.Join(s.parent.Options.ConfigFolder, s.ID+".json") return os.Remove(saveTarget) } // Delete the access rule by given ID func (c *Controller) DeleteAccessRuleByID(accessRuleID string) error { targetAccessRule, err := c.GetAccessRuleByID(accessRuleID) if err != nil { return err } //Delete config file associated with this access rule err = targetAccessRule.DeleteConfigFile() if err != nil { return err } //Delete the access rule in runtime c.ProxyAccessRule.Delete(accessRuleID) return nil } // 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 }