sniproxy

repository·master·Indexed 42 days ago

https://github.com/mosajjal/sniproxy

A high-performance SNI proxy with an integrated DNS server that selectively proxies TLS/HTTP traffic for specific domains by intercepting DNS queries and redirecting traffic based on SNI or Host headers. It features Access Control Lists (ACL) with GeoIP and CIDR filtering, FQDN overrides, and a DNS-over-HTTPS (DoH) server.

Tokens
4.2K
Snippets
13
Records
21
Agent score
55%

What's inside sniproxy

  1. What is sniproxy and how does it work?

    master

    sniproxy is an SNI proxy with a built-in DNS server. It allows you to selectively proxy traffic for specific domains through a server without a full VPN.

    Workflow:

    1. DNS Interception: A client sends a DNS query for a domain (e.g., example.com).
    2. ACL Check: sniproxy checks the domain against its Access Control List (ACL) rules.
    3. DNS Response: If the domain is in the ACL, sniproxy responds with its own public IP. If not, it forwards the query upstream to return the real IP.
    4. Connection Proxying: When the client connects to sniproxy on port 443 (TLS) or 80 (HTTP), sniproxy reads the SNI (Server Name Indication) or the Host header, connects to the real destination server, and pipes the traffic bi-directionally.
  2. Profile goroutine leaks in sniproxy

    master

    sniproxy includes advanced profiling for detecting goroutine leaks. There are three ways to use this feature:

    1. Live via HTTP (pprof): Set bind_pprof in your configuration. You can then fetch profiles via HTTP. It is recommended to bind this to loopback to prevent external access.

    # View readable stacks
    curl 'http://127.0.0.1:6060/debug/pprof/goroutineleak?debug=1'
    
    # Use go tool pprof for binary profiles
    go tool pprof http://127.0.0.1:6060/debug/pprof/goroutineleak

    2. As a Prometheus metric: Set goroutine_leak_interval (e.g., 15m) in the config. sniproxy will periodically check for leaks and publish the count as the goroutines.leaked gauge. This check forces a full GC.

    3. On process exit: Run sniproxy with the --prof flag to write the profile to a temporary directory when the process shuts down.

    sniproxy --prof goroutineleak
    curl 'http://127.0.0.1:6060/debug/pprof/goroutineleak?debug=1'
  3. Install sniproxy

    master

    You can install sniproxy via Go, Docker, or an automated installer script.

    Using Go:

    go install github.com/mosajjal/sniproxy/v2/cmd/sniproxy@latest

    Using Docker: Note: If using source-IP based ACLs (cidr, geoip), use --network host instead of port mappings (-p) to avoid Docker's bridge NAT rewriting the client source IP.

    docker run -d --pull always \
      -p 80:80 -p 443:443 -p 53:53/udp \
      -v "$(pwd)/config.yaml:/tmp/config.yaml" \
      ghcr.io/mosajjal/sniproxy:latest --config /tmp/config.yaml

    Using the Installer Script: This script sets up systemd and other necessary components.

    bash <(curl -L https://raw.githubusercontent.com/mosajjal/sniproxy/master/install.sh)
    go install github.com/mosajjal/sniproxy/v2/cmd/sniproxy@latest
  4. Configure sniproxy using YAML

    master

    sniproxy is configured via a YAML file. You can generate a template containing all default settings using the --defaultconfig flag.

    Generate default config:

    sniproxy --defaultconfig > config.yaml

    The configuration file controls upstream DNS, bind addresses, ACL rules, TLS certificates, and SOCKS5 proxy settings.

    sniproxy --defaultconfig > config.yaml
  5. Override configuration with environment variables

    master

    You can override any YAML configuration setting using environment variables with the SNIPROXY_ prefix. Use double underscores (__) to represent nested keys in the YAML structure.

    Example: To override general.bind_dns_over_udp, use SNIPROXY_GENERAL__BIND_DNS_OVER_UDP.

    SNIPROXY_GENERAL__BIND_DNS_OVER_UDP=0.0.0.0:5555
  6. How FQDN overrides work

    master

    The override ACL allows you to redirect a destination IP to a custom IP and port, bypassing the result of upstream DNS or the proxy's own resolution.

    Key constraints:

    • Currently, only HTTPS is supported.
    • If the destination is HTTP, the proxy uses the provided tls_cert and tls_key to terminate the original connection.
    • Rules are matched using simple string matching (not regex), so they are not suitable for very large rule sets.
    • For large rule sets, it is recommended to use a dedicated reverse proxy in front of sniproxy.
  7. How GeoIP filtering works

    master

    GeoIP filtering follows a specific logic flow:

    1. If the MMDB file is not loaded or available, the filter fails open (allows by default).
    2. If the IP cannot be resolved to a country, the connection is rejected.
    3. If the country is in the blocked list, it is rejected.
    4. If the country is in the allowed list, it is allowed.

    Priority Note: The blocked list is checked before the allowed list. If the blocked list is empty and the allowed list contains [US], a connection from CA will be rejected. If the blocked list contains [US] and the allowed list is empty, a connection from CA will be allowed.

  8. Enable profiling in sniproxy

    master

    You can enable various profiling modes using the --prof flag. This is useful for debugging performance or resource usage. Supported profile types include:

    • cpu: CPU profiling
    • mem: Memory profiling
    • block: Block profiling
    • mutex: Mutex profiling
    • trace: Execution trace
    • threadcreate: Thread creation profiling
    • goroutine: Goroutine profiling
    • goroutineleak: Detects goroutines that can never become runnable again and writes a profile to a temporary file upon exit.
    • clock: Clock profiling

    Note: To use goroutineleak profiling, the binary must be built with the appropriate Go experiment enabled (GOEXPERIMENT).

    sniproxy --prof goroutineleak
  9. Override configuration using environment variables

    master

    You can override settings from the default configuration or a configuration file using environment variables.

    To do this, use the SNIPROXY_ prefix, followed by the full tree of the parameter, with each level separated by two underscores (__).

    Example: To change the DNS server binding from the default 0.0.0.0:53 to 0.0.0.0:5555, set the following environment variable: SNIPROPROXY_GENERAL__BIND_DNS_OVER_UDP=0.0.0.0:5555

    export SNIPROXY_GENERAL__BIND_DNS_OVER_UDP=0.0.0.0:5555
  10. Resolve port 53 conflicts on Ubuntu

    master

    On Ubuntu, systemd-resolved often occupies port 53, which prevents sniproxy from binding its DNS server. You can disable the stub listener to free the port:

    sed -i 's/#DNS=/DNS=9.9.9.9/; s/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
    systemctl restart systemd-resolved
    sed -i 's/#DNS=/DNS=9.9.9.9/; s/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
    systemctl restart systemd-resolved
  11. Configure sniproxy via environment variables

    master

    sniproxy supports configuration via environment variables. All environment variables must be prefixed with SNIPROXY_. To represent nested configuration keys (e.g., in a YAML file), use double underscores __ in the environment variable name, which are converted to dots . at runtime.

    Example Mapping:

    • YAML key general.upstream_dns $\rightarrow$ Environment variable SNIPROXY_GENERAL__UPSTREAM_DNS
  12. Configure the DoH Server

    master

    The config struct (accessed via NewDefaultConfig) controls the behavior of the DoH server. Key configuration fields include:

    FieldDefaultDescription
    Listen[]string{"127.0.0.1:8053", "[::1]:8053"}List of network addresses to listen on.
    Path"/dns-query"The HTTP endpoint path for DNS queries.
    Upstream[]string{"udp:8.8.8.8:53", "udp:8.8.4.4:53"}List of upstream DNS servers (supports udp:, tcp:, or tcp-tls: prefixes).
    Timeout10Timeout in seconds for upstream queries.
    Tries1Number of attempts to reach an upstream server before failing.
    LocalAddr""Specific local address to bind for outgoing client connections.
    Cert / Key""Paths to TLS certificate and private key for HTTPS.
    TLSClientAuthfalseEnables mTLS client authentication.
    TLSClientAuthCA""Path to the CA certificate used to verify client certificates.
    VerbosefalseIf true, enables combined logging for HTTP requests.