add option to block domains, add option to resolve specific domains through specific proxies, option to set the check interval

This commit is contained in:
Cyberes 2024-05-06 21:00:35 -06:00
parent 2ce41d0637
commit a886056d7f
5 changed files with 50 additions and 9 deletions

View File

@ -4,6 +4,9 @@ http_port: 9000
# How many proxies will be checked at once?
proxy_checkers: 50
# The interval between proxy checks in seconds.
proxy_check_interval: 60
# URL to get a proxy's IP.
ip_checker_url: https://api.ipify.org
@ -32,3 +35,12 @@ thirdparty_bypass_domains:
# Shuffle the proxy lists whenever the background thread refreshes them.
# If false, round-robin on default order.
shuffle_proxies: false
# Don't allow requests to these domains through the proxy.
blocked_domains:
- example.com
# Resolve specific domains through specific proxies.
# Proxies here are not validated.
resolve_through:
github.com: http://1.2.3.4:3128

View File

@ -19,6 +19,9 @@ type Config struct {
ThirdpartyTestUrls []string
ThirdpartyBypassDomains []string
ShuffleProxies bool
BlockedDomains []string
ResolveThrough map[string]string
ProxyCheckInterval int
}
func SetConfig(configFile string) (*Config, error) {
@ -36,6 +39,9 @@ func SetConfig(configFile string) (*Config, error) {
viper.SetDefault("thirdparty_test_urls", make([]string, 0))
viper.SetDefault("thirdparty_bypass_domains", make([]string, 0))
viper.SetDefault("shuffle_proxies", false)
viper.SetDefault("blocked_domains", make([]string, 0))
viper.SetDefault("resolve_through", make(map[string]string))
viper.SetDefault("proxy_check_interval", 60)
err := viper.ReadInConfig()
if err != nil {
@ -51,6 +57,9 @@ func SetConfig(configFile string) (*Config, error) {
ThirdpartyTestUrls: viper.GetStringSlice("thirdparty_test_urls"),
ThirdpartyBypassDomains: viper.GetStringSlice("thirdparty_bypass_domains"),
ShuffleProxies: viper.GetBool("shuffle_proxies"),
BlockedDomains: viper.GetStringSlice("blocked_domains"),
ResolveThrough: viper.GetStringMapString("resolve_through"),
ProxyCheckInterval: viper.GetInt("proxy_check_interval"),
}
if len(config.ProxyPoolOurs) == 0 && len(config.ProxyPoolThirdparty) == 0 {

View File

@ -82,6 +82,8 @@ func main() {
log.Fatalf(`Failed to load config: %s`, err)
}
log.Debugf(`Proxy check interval: %d sec`, config.GetConfig().ProxyCheckInterval)
proxyCluster := proxy.NewForwardProxyCluster()
go func() {
log.Fatal(http.ListenAndServe(":"+configData.HTTPPort, proxyCluster))

View File

@ -24,6 +24,7 @@ func logProxyRequest(remoteAddr string, proxyHost string, targetHost string, ret
}
func (p *ForwardProxyCluster) validateRequestAndGetProxy(w http.ResponseWriter, req *http.Request) (string, string, string, string, *url.URL, error) {
urlHostname := req.URL.Hostname()
if p.BalancerReady.GetCount() != 0 {
errStr := "proxy is not ready"
http.Error(w, errStr, http.StatusServiceUnavailable)
@ -39,6 +40,12 @@ func (p *ForwardProxyCluster) validateRequestAndGetProxy(w http.ResponseWriter,
return "", "", "", "", nil, errors.New(errStr)
}
if slices.Contains(config.GetConfig().BlockedDomains, urlHostname) {
errStr := "this domain has been blocked"
http.Error(w, errStr, http.StatusUnavailableForLegalReasons)
return "", "", "", "", nil, errors.New(errStr)
}
headerIncludeBrokenThirdparty := req.Header.Get(HeaderThirdpartyIncludeBroken)
req.Header.Del(HeaderThirdpartyIncludeBroken)
headerBypassThirdparty := req.Header.Get(HeaderThirdpartyBypass)
@ -50,15 +57,20 @@ func (p *ForwardProxyCluster) validateRequestAndGetProxy(w http.ResponseWriter,
}
var selectedProxy string
if slices.Contains(config.GetConfig().ThirdpartyBypassDomains, req.URL.Hostname()) {
selectedProxy = p.getProxyFromOurs()
if val, ok := config.GetConfig().ResolveThrough[urlHostname]; ok {
selectedProxy = val
} else {
if headerIncludeBrokenThirdparty != "" {
selectedProxy = p.getProxyFromAllWithBroken()
} else if headerBypassThirdparty != "" {
if slices.Contains(config.GetConfig().ThirdpartyBypassDomains, urlHostname) {
selectedProxy = p.getProxyFromOurs()
} else {
selectedProxy = p.getProxyFromAll()
if headerIncludeBrokenThirdparty != "" {
selectedProxy = p.getProxyFromAllWithBroken()
} else if headerBypassThirdparty != "" {
selectedProxy = p.getProxyFromOurs()
} else {
selectedProxy = p.getProxyFromAll()
}
}
}
if selectedProxy == "" {
@ -82,7 +94,10 @@ func (p *ForwardProxyCluster) proxyHttpConnect(w http.ResponseWriter, req *http.
_, proxyUser, proxyPass, proxyHost, parsedProxyUrl, err := p.validateRequestAndGetProxy(w, req)
if err != nil {
// Error has already been handled, just log and return.
log.Debugf(`%s -> %s -- HTTP -- Rejecting request: %s`, remoteAddr, proxyHost, err)
if proxyHost == "" {
proxyHost = "none"
}
log.Debugf(`%s -> %s -> %s -- HTTP -- Rejecting request: %s`, remoteAddr, proxyHost, req.Host, err)
return
}
var returnCode *int
@ -132,7 +147,10 @@ func (p *ForwardProxyCluster) proxyHttpsConnect(w http.ResponseWriter, req *http
_, proxyUser, proxyPass, proxyHost, _, err := p.validateRequestAndGetProxy(w, req)
if err != nil {
// Error has already been handled, just log and return.
log.Debugf(`%s -> %s -- CONNECT -- Rejecting request: %s`, remoteAddr, proxyHost, err)
if proxyHost == "" {
proxyHost = "none"
}
log.Debugf(`%s -> %s -> %s -- CONNECT -- Rejecting request: %s`, remoteAddr, proxyHost, targetHost, err)
return
}
var returnCode *int

View File

@ -127,7 +127,7 @@ func (p *ForwardProxyCluster) ValidateProxiesThread() {
p.mu.RUnlock()
p.refreshInProgress = false
time.Sleep(60 * time.Second)
time.Sleep(time.Duration(config.GetConfig().ProxyCheckInterval) * time.Second)
}
}