mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 00:01:40 +01:00 
			
		
		
		
	These erroneously blocked a recent PR, which I fixed by simply re-running CI. But we might as well fix them anyway. These are mostly `printf` to `print` and a couple of `!=` to `!Equal()` Updates #cleanup Signed-off-by: Will Norris <will@tailscale.com>
		
			
				
	
	
		
			142 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| //go:build linux
 | |
| 
 | |
| package tshttpproxy
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"tailscale.com/util/lineiter"
 | |
| )
 | |
| 
 | |
| // These vars are overridden for tests.
 | |
| var (
 | |
| 	synologyProxyConfigPath = "/etc/proxy.conf"
 | |
| 
 | |
| 	openSynologyProxyConf = func() (io.ReadCloser, error) {
 | |
| 		return os.Open(synologyProxyConfigPath)
 | |
| 	}
 | |
| )
 | |
| 
 | |
| var cache struct {
 | |
| 	sync.Mutex
 | |
| 	httpProxy  *url.URL
 | |
| 	httpsProxy *url.URL
 | |
| 	updated    time.Time
 | |
| }
 | |
| 
 | |
| func synologyProxyFromConfigCached(req *http.Request) (*url.URL, error) {
 | |
| 	if req.URL == nil {
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 
 | |
| 	cache.Lock()
 | |
| 	defer cache.Unlock()
 | |
| 
 | |
| 	var err error
 | |
| 	modtime := mtime(synologyProxyConfigPath)
 | |
| 
 | |
| 	if !modtime.Equal(cache.updated) {
 | |
| 		cache.httpProxy, cache.httpsProxy, err = synologyProxiesFromConfig()
 | |
| 		cache.updated = modtime
 | |
| 	}
 | |
| 
 | |
| 	if req.URL.Scheme == "https" {
 | |
| 		return cache.httpsProxy, err
 | |
| 	}
 | |
| 	return cache.httpProxy, err
 | |
| }
 | |
| 
 | |
| func synologyProxiesFromConfig() (*url.URL, *url.URL, error) {
 | |
| 	r, err := openSynologyProxyConf()
 | |
| 	if err != nil {
 | |
| 		if os.IsNotExist(err) {
 | |
| 			return nil, nil, nil
 | |
| 		}
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 	defer r.Close()
 | |
| 
 | |
| 	return parseSynologyConfig(r)
 | |
| }
 | |
| 
 | |
| // parseSynologyConfig parses the Synology proxy configuration, and returns any
 | |
| // http proxy, and any https proxy respectively, or an error if parsing fails.
 | |
| func parseSynologyConfig(r io.Reader) (*url.URL, *url.URL, error) {
 | |
| 	cfg := map[string]string{}
 | |
| 
 | |
| 	for lr := range lineiter.Reader(r) {
 | |
| 		line, err := lr.Value()
 | |
| 		if err != nil {
 | |
| 			return nil, nil, err
 | |
| 		}
 | |
| 		// accept and skip over empty lines
 | |
| 		line = bytes.TrimSpace(line)
 | |
| 		if len(line) == 0 {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		key, value, ok := strings.Cut(string(line), "=")
 | |
| 		if !ok {
 | |
| 			return nil, nil, fmt.Errorf("missing \"=\" in proxy.conf line: %q", line)
 | |
| 		}
 | |
| 		cfg[string(key)] = string(value)
 | |
| 	}
 | |
| 
 | |
| 	if cfg["proxy_enabled"] != "yes" {
 | |
| 		return nil, nil, nil
 | |
| 	}
 | |
| 
 | |
| 	httpProxyURL := new(url.URL)
 | |
| 	httpsProxyURL := new(url.URL)
 | |
| 	if cfg["auth_enabled"] == "yes" {
 | |
| 		httpProxyURL.User = url.UserPassword(cfg["proxy_user"], cfg["proxy_pwd"])
 | |
| 		httpsProxyURL.User = url.UserPassword(cfg["proxy_user"], cfg["proxy_pwd"])
 | |
| 	}
 | |
| 
 | |
| 	// As far as we are aware, synology does not support tls proxies.
 | |
| 	httpProxyURL.Scheme = "http"
 | |
| 	httpsProxyURL.Scheme = "http"
 | |
| 
 | |
| 	httpsProxyURL = addHostPort(httpsProxyURL, cfg["https_host"], cfg["https_port"])
 | |
| 	httpProxyURL = addHostPort(httpProxyURL, cfg["http_host"], cfg["http_port"])
 | |
| 
 | |
| 	return httpProxyURL, httpsProxyURL, nil
 | |
| }
 | |
| 
 | |
| // addHostPort adds to u the given host and port and returns the updated url, or
 | |
| // if host is empty, it returns nil.
 | |
| func addHostPort(u *url.URL, host, port string) *url.URL {
 | |
| 	if host == "" {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if port == "" {
 | |
| 		u.Host = host
 | |
| 	} else {
 | |
| 		u.Host = net.JoinHostPort(host, port)
 | |
| 	}
 | |
| 	return u
 | |
| }
 | |
| 
 | |
| // mtime stat's path and returns its modification time. If path does not exist,
 | |
| // it returns the unix epoch.
 | |
| func mtime(path string) time.Time {
 | |
| 	fi, err := os.Stat(path)
 | |
| 	if err != nil {
 | |
| 		return time.Unix(0, 0)
 | |
| 	}
 | |
| 	return fi.ModTime()
 | |
| }
 |