From 49f39b5cdb1442632948b40055a5aba02ff432ff Mon Sep 17 00:00:00 2001 From: Jordi Subira Nieto Date: Mon, 17 Mar 2025 14:05:35 +0100 Subject: [PATCH 1/2] initial commit --- forward/forwardproxy.go | 67 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/forward/forwardproxy.go b/forward/forwardproxy.go index 36f543b..7101c27 100644 --- a/forward/forwardproxy.go +++ b/forward/forwardproxy.go @@ -24,6 +24,7 @@ import ( "net" "net/http" "net/textproto" + "os" "strconv" "strings" "sync" @@ -39,6 +40,13 @@ import ( "github.com/scionproto-contrib/http-proxy/forward/utils" ) +const ( + hostsFile = "/etc/hosts" + hostsComment = " # Line added by the SCION HTTP Forward Proxy" + // TODO: make the address injectable via configuration + hostsEntry = "127.0.0.1\tforward-proxy.scion" +) + // ResolveHandler defines an interface for handling HTTP requests related to // host resolution and redirection. Implementations of this interface should // provide mechanisms to handle redirection back or errors, as well as host @@ -89,11 +97,18 @@ func (cp *CoreProxy) Initialize() error { } cp.metricsHandler = panpolicy.NewMetricsHandler(cp.policyManager, cp.logger.With(zap.String("component", "metrics-handler"))) cp.resolver = resolver.NewPANResolver(cp.logger.With(zap.String("component", "resolver")), cp.resolveTimeout) + + if err := cp.addHostsEntry(); err != nil { + cp.logger.Warn("Failed to add entry to /etc/hosts file", zap.Error(err)) + } return nil } // Cleanup cleans up the core proxy logic. func (cp *CoreProxy) Cleanup() error { + if err := cp.removeHostsEntry(); err != nil { + cp.logger.Warn("Failed to remove entry from /etc/hosts file", zap.Error(err)) + } return cp.policyManager.Stop() } @@ -158,6 +173,58 @@ func (cp *CoreProxy) HandleTunnelRequest(w http.ResponseWriter, r *http.Request) return cp.forwardRequest(w, r, dialer) } +func (cp *CoreProxy) addHostsEntry() error { + content, err := os.ReadFile(hostsFile) + if err != nil { + return fmt.Errorf("failed to read hosts file: %w", err) + } + + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if strings.Contains(line, hostsEntry) { + cp.logger.Debug("Hosts entry already exists", zap.String("entry", hostsEntry)) + return nil + } + } + + file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return fmt.Errorf("failed to open hosts file for writing: %w", err) + } + defer file.Close() + + entry := hostsComment + "\n" + hostsEntry + "\n" + if _, err := file.WriteString(entry); err != nil { + return fmt.Errorf("failed to write to hosts file: %w", err) + } + + cp.logger.Info("Added entry to hosts file", zap.String("entry", hostsEntry)) + return nil +} + +func (cp *CoreProxy) removeHostsEntry() error { + content, err := os.ReadFile(hostsFile) + if err != nil { + return fmt.Errorf("failed to read hosts file: %w", err) + } + + var newLines []string + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if !strings.Contains(line, hostsEntry) && !strings.Contains(line, hostsComment) { + newLines = append(newLines, line) + } + } + + err = os.WriteFile(hostsFile, []byte(strings.Join(newLines, "\n")), 0644) + if err != nil { + return fmt.Errorf("failed to write to hosts file: %w", err) + } + + cp.logger.Info("Removed entry from hosts file", zap.String("entry", hostsEntry)) + return nil +} + func (cp *CoreProxy) parseCookieFromProxyAuth(w http.ResponseWriter, r *http.Request) error { // the path policy cookie is passed in the proxy-authorization header as the cookie username, cookie, err := proxyBasicAuth(r) From 89a22b9080b2a45e8247746c3a5c9cd1a027bd2e Mon Sep 17 00:00:00 2001 From: Jordi Subira Nieto Date: Wed, 9 Apr 2025 15:06:04 +0200 Subject: [PATCH 2/2] add check to avoid overwriting --- forward/forwardproxy.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/forward/forwardproxy.go b/forward/forwardproxy.go index 7101c27..4de14dd 100644 --- a/forward/forwardproxy.go +++ b/forward/forwardproxy.go @@ -43,8 +43,9 @@ import ( const ( hostsFile = "/etc/hosts" hostsComment = " # Line added by the SCION HTTP Forward Proxy" + hostName = "forward-proxy.scion" // TODO: make the address injectable via configuration - hostsEntry = "127.0.0.1\tforward-proxy.scion" + hostsEntry = "127.0.0.1\t" + hostName ) // ResolveHandler defines an interface for handling HTTP requests related to @@ -181,8 +182,8 @@ func (cp *CoreProxy) addHostsEntry() error { lines := strings.Split(string(content), "\n") for _, line := range lines { - if strings.Contains(line, hostsEntry) { - cp.logger.Debug("Hosts entry already exists", zap.String("entry", hostsEntry)) + if !strings.HasPrefix(strings.TrimSpace(line), "#") && strings.Contains(line, hostName) { + cp.logger.Debug("Entry for host name already exists", zap.String("entry", line)) return nil } }