Files
GoLangProxy/config.go
2025-03-01 19:13:22 +00:00

161 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"fmt"
"os"
"time"
"gopkg.in/yaml.v2"
)
// Config defines the structure of the proxy configuration loaded from config.yaml
type Config struct {
ListenHTTP string `yaml:"listen_http"` // Port for HTTP server (e.g., ":80")
ListenHTTPS string `yaml:"listen_https"` // Port for HTTPS server (e.g., ":443")
CertDir string `yaml:"cert_dir"` // Directory for certificate files
CertFile string `yaml:"cert_file"` // Certificate filename
KeyFile string `yaml:"key_file"` // Private key filename
Routes map[string]string `yaml:"routes"` // Mapping of hostnames to target URLs
TrustTarget map[string]bool `yaml:"trust_target"` // Whether to skip TLS verification for targets
NoHTTPSRedirect map[string]bool `yaml:"no_https_redirect"` // Whether to skip HTTP->HTTPS redirect
}
// loadConfig reads and parses the config.yaml file
func loadConfig() (Config, error) {
data, err := os.ReadFile(configPath)
if err != nil {
return Config{}, fmt.Errorf("failed to read config %s: %v", configPath, err)
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return Config{}, fmt.Errorf("failed to unmarshal config: %v", err)
}
return cfg, nil
}
// generateDefaultConfig creates a default configuration if config.yaml doesnt exist
func generateDefaultConfig() Config {
return Config{
ListenHTTP: ":80",
ListenHTTPS: ":443",
CertDir: "./certificate",
CertFile: "certificate.pem",
KeyFile: "key.pem",
Routes: map[string]string{
"*": "https://127.0.0.1:3000", // Wildcard route
"main.example.com": "https://10.100.111.254:4444", // Specific route
},
TrustTarget: map[string]bool{
"*": true, // Skip TLS verification by default
"main.example.com": true,
},
NoHTTPSRedirect: map[string]bool{
"*": false, // Redirect HTTP to HTTPS by default
"main.example.com": false,
},
}
}
// saveConfig writes the configuration to config.yaml
func saveConfig(cfg Config) error {
if err := os.MkdirAll(baseDir, 0755); err != nil {
return fmt.Errorf("failed to create base directory %s: %v", baseDir, err)
}
data, err := yaml.Marshal(cfg)
if err != nil {
return fmt.Errorf("failed to marshal config: %v", err)
}
if err := os.WriteFile(configPath, data, 0644); err != nil {
return fmt.Errorf("failed to write config to %s: %v", configPath, err)
}
return nil
}
// monitorConfig watches config.yaml for changes and updates the in-memory config
func monitorConfig() {
var lastModTime time.Time
for {
configInfo, err := os.Stat(configPath)
if err != nil {
errorLogger.Printf("Error checking config file: %v", err)
time.Sleep(5 * time.Second)
continue
}
if configInfo.ModTime() != lastModTime {
newConfig, err := loadConfig()
if err != nil {
errorLogger.Printf("Error reloading config: %v", err)
} else {
configMux.Lock()
// Update individual fields only if theyve changed
if newConfig.ListenHTTP != config.ListenHTTP {
config.ListenHTTP = newConfig.ListenHTTP
refreshLogger.Printf("Updated listen_http to %s", config.ListenHTTP)
}
if newConfig.ListenHTTPS != config.ListenHTTPS {
config.ListenHTTPS = newConfig.ListenHTTPS
refreshLogger.Printf("Updated listen_https to %s", config.ListenHTTPS)
}
if newConfig.CertDir != config.CertDir || newConfig.CertFile != config.CertFile || newConfig.KeyFile != config.KeyFile {
config.CertDir = newConfig.CertDir
config.CertFile = newConfig.CertFile
config.KeyFile = newConfig.KeyFile
updatePaths()
if err := loadCertificate(); err != nil {
errorLogger.Printf("Error reloading certificate after path change: %v", err)
} else {
refreshLogger.Println("Updated certificate paths and reloaded certificate")
}
}
// Update routes
for k, v := range newConfig.Routes {
if oldV, exists := config.Routes[k]; !exists || oldV != v {
config.Routes[k] = v
refreshLogger.Printf("Updated route %s to %s", k, v)
}
}
for k := range config.Routes {
if _, exists := newConfig.Routes[k]; !exists {
delete(config.Routes, k)
refreshLogger.Printf("Removed route %s", k)
}
}
// Update trust_target
for k, v := range newConfig.TrustTarget {
if oldV, exists := config.TrustTarget[k]; !exists || oldV != v {
config.TrustTarget[k] = v
refreshLogger.Printf("Updated trust_target %s to %v", k, v)
}
}
for k := range config.TrustTarget {
if _, exists := newConfig.TrustTarget[k]; !exists {
delete(config.TrustTarget, k)
refreshLogger.Printf("Removed trust_target %s", k)
}
}
// Update no_https_redirect
for k, v := range newConfig.NoHTTPSRedirect {
if oldV, exists := config.NoHTTPSRedirect[k]; !exists || oldV != v {
config.NoHTTPSRedirect[k] = v
refreshLogger.Printf("Updated no_https_redirect %s to %v", k, v)
}
}
for k := range config.NoHTTPSRedirect {
if _, exists := newConfig.NoHTTPSRedirect[k]; !exists {
delete(config.NoHTTPSRedirect, k)
refreshLogger.Printf("Removed no_https_redirect %s", k)
}
}
configMux.Unlock()
refreshLogger.Println("Config reloaded successfully")
lastModTime = configInfo.ModTime()
}
}
time.Sleep(5 * time.Second) // Poll every 5 seconds
}
}