May 18, 2018

Using SNI Proxy to serve multiple hostnames from a single IP

SNI Proxy

NOTE: THERE'S A HARD CODED DNS SERVER IN THIS CONFIG

Prerequisites

sudo apt update &&\
sudo apt install -y autotools-dev cdbs debhelper \
dh-autoreconf dpkg-dev gettext libev-dev libpcre3-dev \
libudns-dev pkg-config fakeroot devscripts

Clone latest version

git clone https://github.com/dlundquist/sniproxy sniproxy

Build the package

cd sniproxy
./autogen.sh && dpkg-buildpackage

Install

sudo dpkg -i ../sniproxy_<version>_<arch>.deb

Edit the config

sudo nano /etc/sniproxy.conf

CHANGE USER AND GROUP TO BE ROOT FOR TRANSPARENT FORWARDING

# sniproxy example configuration file
# lines that start with # are comments
# lines with only white space are ignored

user nobody
group nogroup

# PID file, needs to be placed in directory writable by user
pidfile /var/tmp/sniproxy.pid

# The DNS resolver is required for tables configured using wildcard or hostname
# targets. If no resolver is specified, the nameserver and search domain are
# loaded from /etc/resolv.conf.
resolver {
    # Specify name server
    #
    # NOTE: it is strongly recommended to use a local caching DNS server, since
    # uDNS and thus SNIProxy only uses single socket to each name server so
    # each DNS query is only protected by the 16 bit query ID and lacks
    # additional source port randomization. Additionally no caching is
    # preformed within SNIProxy, so a local resolver can improve performance.
    nameserver 192.168.1.1

    # DNS search domain
    search YOURDOMAIN

    # Specify which type of address to lookup in DNS:
    # * ipv4_only   query for IPv4 addresses (default)
    # * ipv6_only   query for IPv6 addresses
    # * ipv4_first  query for both IPv4 and IPv6, use IPv4 is present
    # * ipv6_first  query for both IPv4 and IPv6, use IPv6 is present
    mode ipv6_first
}

error_log {
    # Log to the daemon syslog facility
    syslog daemon

    # Alternatively we could log to file
    #filename /var/log/sniproxy.log

    # Control the verbosity of the log
    priority notice
}

# Global access log for all listeners
access_log {
    # Same options as error_log
    filename /tmp/sniproxy-access.log
}

# blocks are delimited with {...}
listen 80 {
    proto http
    table http_hosts

    # Enable SO_REUSEPORT to allow multiple processess to bind to this ip:port pair
    reuseport no

    # Fallback server to use if we can not parse the client request
    fallback localhost:8080

    # Specify the source address for outgoing connections.
    #
    # Use "source client" to enable transparent proxy support. This requires
    # running sniproxy as root ("user root").
    #
    # Do not include a port in this address, otherwise you will be limited
    # to a single connection to each backend server.
    #
    # NOTE: binding to a specific address prevents the operating system from
    # selecting and source address and port optimally and may significantly
    # reduce the maximum number of simultaneous connections possible.
    source IPADDRESSOFSNIPROXY

    # Log the content of bad requests
    #bad_requests log

    # Override global access log for this listener
    access_log {
        # Same options as error_log
        filename /tmp/sniproxy.log
    }
}

listen [::]:443 {
    proto tls
    # controls if this listener will accept IPv4 connections as well on
    # supported operating systems such as Linux or FreeBSD, but not OpenBSD.
    ipv6_v6only on
    table https_hosts
}

listen 0.0.0.0 443 {
    # This listener will only accept IPv4 connections since it is bound to the
    # IPv4 any address.
    proto tls
    table https_hosts
}

listen 0.0.0.0:80 {
    protocol http
    # this will use default table
}

# named tables are defined with the table directive
table http_hosts {

# Each table entry is composed of three parts:
#
# pattern:
# 	valid Perl-compatible Regular Expression that matches the
# 	hostname
#
# target:
#	- a DNS name
#	- an IP address and TCP port
#	- an IP address (will connect to the same port as the listener received the
#	  connection)
#	- '*' to use the hostname that the client requested
#
# pattern	target
#.*\.itunes\.apple\.com$	*:443
#.*	127.0.0.1:4443
}

# named tables are defined with the table directive
table https_hosts {
    # When proxying to local sockets you should use different tables since the
    # local socket server most likely will not detect which protocol is being
    # used
    #example.org unix:/var/run/server.sock
}

# if no table specified the default 'default' table is defined
table {
    # If no port is specified the port of the incoming listener is used
    #example.com 192.0.2.10
    #example.net 192.0.2.20
}

edit daemon config so it will start on boot

sudo nano /etc/default/sniproxy
change daemon 0 to 1
save and reboot