mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 01:36:37 +08:00
[功能] 添加OpenRestyResolvers支持,优化DNS解析器配置和验证逻辑
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"openflare/common"
|
||||
"openflare/model"
|
||||
@@ -89,6 +90,7 @@ type openRestyConfigSnapshot struct {
|
||||
GzipEnabled bool `json:"gzip_enabled"`
|
||||
GzipMinLength int `json:"gzip_min_length"`
|
||||
GzipCompLevel int `json:"gzip_comp_level"`
|
||||
Resolvers string `json:"resolvers,omitempty"`
|
||||
CacheEnabled bool `json:"cache_enabled"`
|
||||
CachePath string `json:"cache_path,omitempty"`
|
||||
CacheLevels string `json:"cache_levels"`
|
||||
@@ -124,7 +126,6 @@ const (
|
||||
nginxLuaDirPlaceholder = "__OPENFLARE_LUA_DIR__"
|
||||
nginxObservabilityListenPlaceholder = "__OPENFLARE_OBSERVABILITY_LISTEN__"
|
||||
nginxObservabilityPortPlaceholder = "__OPENFLARE_OBSERVABILITY_PORT__"
|
||||
nginxResolverDirectivePlaceholder = "__OPENFLARE_RESOLVER_DIRECTIVE__"
|
||||
)
|
||||
|
||||
var requiredMainConfigTemplatePlaceholders = []string{
|
||||
@@ -355,7 +356,7 @@ func buildCurrentConfigBundle(requireRoutes bool) (*configBundle, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routeConfig, supportFiles, err := renderRouteConfig(routes)
|
||||
routeConfig, supportFiles, err := renderRouteConfig(routes, openRestyConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -469,6 +470,7 @@ func buildOpenRestyConfigSnapshot() openRestyConfigSnapshot {
|
||||
GzipEnabled: common.OpenRestyGzipEnabled,
|
||||
GzipMinLength: common.OpenRestyGzipMinLength,
|
||||
GzipCompLevel: common.OpenRestyGzipCompLevel,
|
||||
Resolvers: common.OpenRestyResolvers,
|
||||
CacheEnabled: common.OpenRestyCacheEnabled,
|
||||
CachePath: common.OpenRestyCachePath,
|
||||
CacheLevels: common.OpenRestyCacheLevels,
|
||||
@@ -530,6 +532,7 @@ func diffOpenRestyOptionDetails(left openRestyConfigSnapshot, right openRestyCon
|
||||
appendIfChanged("OpenRestyGzipEnabled", fmt.Sprintf("%t", left.GzipEnabled), fmt.Sprintf("%t", right.GzipEnabled))
|
||||
appendIfChanged("OpenRestyGzipMinLength", fmt.Sprintf("%d", left.GzipMinLength), fmt.Sprintf("%d", right.GzipMinLength))
|
||||
appendIfChanged("OpenRestyGzipCompLevel", fmt.Sprintf("%d", left.GzipCompLevel), fmt.Sprintf("%d", right.GzipCompLevel))
|
||||
appendIfChanged("OpenRestyResolvers", left.Resolvers, right.Resolvers)
|
||||
appendIfChanged("OpenRestyCacheEnabled", fmt.Sprintf("%t", left.CacheEnabled), fmt.Sprintf("%t", right.CacheEnabled))
|
||||
appendIfChanged("OpenRestyCachePath", left.CachePath, right.CachePath)
|
||||
appendIfChanged("OpenRestyCacheLevels", left.CacheLevels, right.CacheLevels)
|
||||
@@ -576,6 +579,7 @@ func openRestyOptionKeys() []string {
|
||||
"OpenRestyGzipEnabled",
|
||||
"OpenRestyGzipMinLength",
|
||||
"OpenRestyGzipCompLevel",
|
||||
"OpenRestyResolvers",
|
||||
"OpenRestyCacheEnabled",
|
||||
"OpenRestyCachePath",
|
||||
"OpenRestyCacheLevels",
|
||||
@@ -588,7 +592,7 @@ func openRestyOptionKeys() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func renderRouteConfig(routes []*model.ProxyRoute) (string, []SupportFile, error) {
|
||||
func renderRouteConfig(routes []*model.ProxyRoute, cfg openRestyConfigSnapshot) (string, []SupportFile, error) {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("# This file is generated by OpenFlare. Do not edit manually.\n")
|
||||
supportFiles := make([]SupportFile, 0)
|
||||
@@ -598,7 +602,7 @@ func renderRouteConfig(routes []*model.ProxyRoute) (string, []SupportFile, error
|
||||
return "", nil, fmt.Errorf("路由 %s 自定义请求头无效", route.Domain)
|
||||
}
|
||||
if !route.EnableHTTPS {
|
||||
builder.WriteString(renderHTTPProxyServer(route.Domain, route.OriginURL, route.OriginHost, customHeaders))
|
||||
builder.WriteString(renderHTTPProxyServer(route.Domain, route.OriginURL, route.OriginHost, customHeaders, cfg))
|
||||
continue
|
||||
}
|
||||
if route.CertID == nil || *route.CertID == 0 {
|
||||
@@ -615,9 +619,9 @@ func renderRouteConfig(routes []*model.ProxyRoute) (string, []SupportFile, error
|
||||
if route.RedirectHTTP {
|
||||
builder.WriteString(renderHTTPRedirectServer(route.Domain))
|
||||
} else {
|
||||
builder.WriteString(renderHTTPProxyServer(route.Domain, route.OriginURL, route.OriginHost, customHeaders))
|
||||
builder.WriteString(renderHTTPProxyServer(route.Domain, route.OriginURL, route.OriginHost, customHeaders, cfg))
|
||||
}
|
||||
builder.WriteString(renderHTTPSServer(route.Domain, route.OriginURL, route.OriginHost, certificate.ID, customHeaders))
|
||||
builder.WriteString(renderHTTPSServer(route.Domain, route.OriginURL, route.OriginHost, certificate.ID, customHeaders, cfg))
|
||||
}
|
||||
return builder.String(), dedupeSupportFiles(supportFiles), nil
|
||||
}
|
||||
@@ -673,7 +677,7 @@ func renderMainConfigTemplate(templateText string, cfg openRestyConfigSnapshot)
|
||||
"{{OpenRestyGzip}}", onOff(cfg.GzipEnabled),
|
||||
"{{OpenRestyGzipMinLength}}", fmt.Sprintf("%d", cfg.GzipMinLength),
|
||||
"{{OpenRestyGzipCompLevel}}", fmt.Sprintf("%d", cfg.GzipCompLevel),
|
||||
"{{OpenRestyResolverDirective}}", nginxResolverDirectivePlaceholder,
|
||||
"{{OpenRestyResolverDirective}}", renderResolverDirective(cfg.Resolvers),
|
||||
"{{OpenRestyCacheBlock}}", renderOpenRestyCacheTemplateBlock(cfg),
|
||||
"{{OpenRestyRouteConfigInclude}}", nginxRouteConfigPlaceholder,
|
||||
)
|
||||
@@ -752,18 +756,18 @@ func nextVersionNumber(now time.Time) (string, error) {
|
||||
return fmt.Sprintf("%s-%03d", prefix, count+1), nil
|
||||
}
|
||||
|
||||
func renderHTTPProxyServer(domain string, originURL string, originHost string, customHeaders []ProxyRouteCustomHeaderInput) string {
|
||||
return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s\n location / {\n%s%s }\n}\n\n", domain, renderExactHostGuard(domain), renderProxyHeaderBlock(originURL, originHost, customHeaders), renderProxyPassBlock(originURL))
|
||||
func renderHTTPProxyServer(domain string, originURL string, originHost string, customHeaders []ProxyRouteCustomHeaderInput, cfg openRestyConfigSnapshot) string {
|
||||
return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s\n location / {\n%s%s }\n}\n\n", domain, renderExactHostGuard(domain), renderProxyHeaderBlock(originURL, originHost, customHeaders), renderProxyPassBlock(originURL, cfg))
|
||||
}
|
||||
|
||||
func renderHTTPRedirectServer(domain string) string {
|
||||
return fmt.Sprintf("server {\n listen 80;\n server_name %s;\n%s\n return 301 https://$host$request_uri;\n}\n\n", domain, renderExactHostGuard(domain))
|
||||
}
|
||||
|
||||
func renderHTTPSServer(domain string, originURL string, originHost string, certificateID uint, customHeaders []ProxyRouteCustomHeaderInput) string {
|
||||
func renderHTTPSServer(domain string, originURL string, originHost string, certificateID uint, customHeaders []ProxyRouteCustomHeaderInput, cfg openRestyConfigSnapshot) string {
|
||||
certPath := fmt.Sprintf("%s/%s", nginxCertDirPlaceholder, certificateCertFileName(certificateID))
|
||||
keyPath := fmt.Sprintf("%s/%s", nginxCertDirPlaceholder, certificateKeyFileName(certificateID))
|
||||
return fmt.Sprintf("server {\n listen 443 ssl;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n%s\n location / {\n%s%s }\n}\n\n", domain, certPath, keyPath, renderExactHostGuard(domain), renderProxyHeaderBlock(originURL, originHost, customHeaders), renderProxyPassBlock(originURL))
|
||||
return fmt.Sprintf("server {\n listen 443 ssl;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n%s\n location / {\n%s%s }\n}\n\n", domain, certPath, keyPath, renderExactHostGuard(domain), renderProxyHeaderBlock(originURL, originHost, customHeaders), renderProxyPassBlock(originURL, cfg))
|
||||
}
|
||||
|
||||
func renderExactHostGuard(domain string) string {
|
||||
@@ -798,11 +802,14 @@ func renderProxyHeaderBlock(originURL string, originHost string, customHeaders [
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func renderProxyPassBlock(originURL string) string {
|
||||
func renderProxyPassBlock(originURL string, cfg openRestyConfigSnapshot) string {
|
||||
parsed, err := url.Parse(originURL)
|
||||
if err != nil || parsed.Host == "" || parsed.Scheme == "" {
|
||||
return fmt.Sprintf(" proxy_pass %s;\n", originURL)
|
||||
}
|
||||
if !shouldUseRuntimeResolver(originURL, cfg.Resolvers) {
|
||||
return fmt.Sprintf(" proxy_pass %s;\n", originURL)
|
||||
}
|
||||
upstreamURL := fmt.Sprintf("%s://%s", parsed.Scheme, parsed.Host)
|
||||
basePath := strings.TrimRight(parsed.EscapedPath(), "/")
|
||||
if basePath == "" || basePath == "." {
|
||||
@@ -825,6 +832,35 @@ func renderProxyPassBlock(originURL string) string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func shouldUseRuntimeResolver(originURL string, resolvers string) bool {
|
||||
if strings.TrimSpace(resolvers) == "" {
|
||||
return false
|
||||
}
|
||||
return requiresRuntimeResolver(originURL)
|
||||
}
|
||||
|
||||
func requiresRuntimeResolver(originURL string) bool {
|
||||
parsed, err := url.Parse(strings.TrimSpace(originURL))
|
||||
if err != nil || parsed.Hostname() == "" {
|
||||
return false
|
||||
}
|
||||
return net.ParseIP(parsed.Hostname()) == nil
|
||||
}
|
||||
|
||||
func renderResolverDirective(value string) string {
|
||||
resolvers := splitResolverList(value)
|
||||
if len(resolvers) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf(" resolver %s valid=30s ipv6=off;\n resolver_timeout 5s;\n", strings.Join(resolvers, " "))
|
||||
}
|
||||
|
||||
func splitResolverList(value string) []string {
|
||||
return strings.FieldsFunc(strings.TrimSpace(value), func(r rune) bool {
|
||||
return r == ',' || r == '\n' || r == '\r' || r == '\t' || r == ' '
|
||||
})
|
||||
}
|
||||
|
||||
func resolveUpstreamServerName(originURL string, originHost string) string {
|
||||
parsed, err := url.Parse(originURL)
|
||||
if err != nil || !strings.EqualFold(parsed.Scheme, "https") {
|
||||
|
||||
Reference in New Issue
Block a user