Dynamic host-name (using SNI) based routing with haproxy on TCP - tcp

TCP router using haproxy.
Use case:
1) Request (TCP/SSL) comes to haproxy
2) haproxy reads the SNI (Server Name Indication) data from the request (subdomain.example.com), extract "subdomain" from the host name
3) Now, this request has to be passed on to a backend server (subdomain.local)
Implementation
frontend tcp_ssl_test
bind 5432 ssl crt /etc/ssl/private/example.com.pem
mode tcp
default_backend tcp_ssl_test_backend
backend tcp_ssl_test_backend
mode tcp
acl app_a req_ssl_sni -i subdomain1.andromeda.io
acl app_b req_ssl_sni -i subdomain2.andromeda.io
use-server bb1 if app_a
use-server bb2 if app_b
server bb1 subdomain1.local
server bb2 subdomain2.local
Problem
If there are many more "subdomains", how can this be done dynamically?
Can the "subdomain" part be extracted from sni host name and be passed on to the server keyword?
For example, something like the below snippet would be great:
acl app_a req_ssl_sni -i (?<subdomain>.+)\.andromeda\.io
use-server bb1 if app_a
server bb1 $subdomain.local

Related

Can an OpenVPN Route over TEST-NET-1 (RFC 5735)

Background
I have a strange use-case where my VPN cannot be on any of the private subnets, but, also cannot use a TAP interface. The machine will be moving through different subnets, and requires access to the entire private address space by design. A single blocked IP would be considered a failure of design.
So, these are all off limits:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
169.254.0.0/16
In searching for a solution, I came across RFC 5735, which defines:
192.0.2.0/24 TEST-NET-1
198.51.100.0/24 TEST-NET-2
203.0.113.0/24 TEST-NET-3
As:
For use in documentation and example code. It is often used in conjunction with domain names
example.com or example.net in vendor and protocol documentation. As described in [RFC5737], addresses within this block do not legitimately appear on the public Internet and can be used without any coordination with IANA or an Internet registry.
Which, was a "Jackpot" moment for me and my use case.
Config
I configured an OpenVPN server as such:
local 0.0.0.0
port 443
proto tcp
dev tun
topology subnet
server 203.0.113.0 255.255.255.0 # TEST-NET-3 RFC 5735
push "route 203.0.113.0 255.255.255.0"
...[Snip]...
With Client:
client
nobind
dev tun
proto tcp
...[Snip]...
And ufw rules:
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 203.0.113.0/24 -o ens160 -j MASQUERADE
COMMIT
However, upon running I get /sbin/ip route add 203.0.113.0/24 via 203.0.113.1 RTNETLINK answers: File exists in the error logs. While the VPN completes the rest of its connection successfully.
No connection
Running the following commands:
Server: sudo python3 -m http.server 80
Client: curl -X GET / 203.0.113.1
Results in:
curl: (28) Failed to connect to 203.0.113.1 port 80: Connection timed out
I have tried:
/sbin/ip route replace 203.0.113.0/24 dev tun 0 on client and server.
/sbin/ip route change 203.0.113.0/24 dev tun 0 on client and server.
Adding route 203.0.113.0 255.255.255.0 to the server.
Adding push "route 203.0.113.0 255.255.255.0 127.0.0.1" to server
And none of it seems to work.
Does anyone have any idea how I can force the client to push this traffic over the VPN to my server, instead of to the public IP?
This does actually work!
Just dont forget to allow connections within your firewall. I fixed my config with:
sudo ufw allow in on tun0
However, 198.18.0.0/15 and 100.64.0.0/10 defined as Benchmarking and Shared address space respectively, may be more appropriate choices, since being able to forward TEST-NET addresses may be considered a bug.

TCP passthroughs is not working for 80 port

Hi I'm trying to implement use TCP passthrough based on SNI. It works for SSL but it's not working for 80.
configuration is below:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
defaults
timeout client 30s
timeout server 30s
timeout connect 5s
frontend https
bind *:443
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl mytonicssl req_ssl_sni -i staging.mytonic.com
use_backend mytonic-ssl if mytonicssl
backend mytonic-ssl
mode tcp
balance roundrobin
stick-table type binary len 32 size 30k expire 30m
acl clienthello req_ssl_hello_type 1
acl serverhello rep_ssl_hello_type 2
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
tcp-response content accept if serverhello
stick on payload_lv(43,1) if clienthello
stick store-response payload_lv(43,1) if serverhello
option ssl-hello-chk
server server1 10.10.17.222:8443 check
frontend http
bind *:80
mode tcp
acl mytonic_http hdr_dom(host) -i staging.mytonic.com
use_backend mytonic_nonssl if mytonic_http
backend mytonic_nonssl
mode tcp
balance roundrobin
server server1 10.10.17.222:8080 check
If i added default backend then it works. But this is not the virtual host solution. My haproxy version is: HA-Proxy version 1.5.18 2016/05/10 any help is appreciated.
SNI is a TLS extension which contains the target hostname. Since it is a TLS extension it can only be used with SSL/TLS traffic. The matching mechanism with plain HTTP (i.e. no SSL/TLS) is the HTTP Host header. But to balance based on this header you need to use mode http (the default) and not mode tcp. See also How to divert traffic based on hostname using HAProxy?

Using domain instead of IP in haproxy backend

I have 2 virtual host
app.example.com:80 on ip address xxx.xxx.xxx.xxx
app2.example.com:80 on ip address yyy.yyy.yyy.yyy
my haproxy ipaddress is sss.sss.sss.sss
This is haproxy configuration :
global
log 127.0.0.1 local0 notice
maxconn 2000
user haproxy
group haproxy
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
timeout connect 5000
timeout client 10000
timeout server 10000
frontend www-http
mode http
bind *:80
default_backend appname
stats enable
stats uri /haproxy?stats
stats auth admin:password
stats show-node
backend appname
balance roundrobin
option httpclose
option forwardfor
server lamp1 app.example.com:80 check
server lamp2 app2.example.com:80 check
When trying to access using haproxy ipaddress, web browser returns xampp dashboard instead of backend content.
How can i make haproxy to redirect to backend content?
I do believe that functionality is now available in 1.6,
http://blog.haproxy.com/2015/10/14/whats-new-in-haproxy-1-6/
what you have configured will simply loadbalance the request between those to instances :
server lamp1 app.example.com:80 check
server lamp2 app2.example.com:80 check
if they are 2 seperate apps rather try:
frontend www-http
mode http
bind sss.sss.sss.sss:80
stats enable
stats uri /haproxy?stats
stats auth admin:password
stats show-node
acl app01 hdr(Host) -i app.example.com
acl app02 hdr(Host) -i app02.example.com
use_backend app01 if app01
use_backend app02 if app02
backend app01
balance roundrobin
option httpclose
option forwardfor
server lamp1 xxx.xxx.xxx.xxx:80 check
backend app02
balance roundrobin
option httpclose
option forwardfor
server lamp2 yyy.yyy.yyy.yyy:80 check
If you now hit your haproxy with app.example.com you will be forwarded to lamp1 and app2.example.com will take you to lamp2
if you want to forward everything to the ip to the backend and dont care for extra matching and mapping then id use a straight listen, instead of a frontend :
listen SOMENAME sss.sss.sss.sss:80
balance leastconn
mode http
server lamp1 xxx.xxx.xxx.xxx:80
server lamp2 yyy.yyy.yyy.yyy:80
If i remember correctly, "default_backend" expects to have "backend" value as an attribute, not "listen".
https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4.2-default_backend
So i suggest changing to
backend appname
balance roundrobin
option httpclose
option forwardfor
server lamp1 app.example.com:80 check
server lamp2 app2.example.com:80 check

How to configure haproxy port range to range one by one?

I want to use haproxy to deploy one ftp proxy server. Here's scene:
ftp client <---> ftp-proxy-server(ip:10.0.1.1) <---> ftp-server(ip:172.126.1.1)
ftp server listen on port 21 for control command, data port range [20100-20199]
I had haproxy config on ftp-proxy-server:
listen ftp-proxy-server 10.0.1.1:21
mode tcp
server ftp-server 172.126.1.1:21
listen ftp-proxy-server 10.0.1.1:20100-20199
mode tcp
server ftp-server 172.126.1.1:20100-20199
Here's the question, I can successfully login ftp service from ftp-client, but failed to execute ls command which output "connection refused" message. I guess the reason is port mapping from ftp-proxy-server to ftp-server is random. So when ftp-client get a reserved port(e.g. 20101), but ftp-proxy-server may map it to another port(e.g. 20109), which is not the port ftp-server assigned to ftp-client.
I am think of one solution that configured 100 listens, one listen to one port, but it's complex to write the configure file. Is'there a simply configuration option to map port one by one? Just like 10.0.1.1:20001 -> 172.126.1.1:20001, 10.0.1.1:20002 -> 172.126.1.1:20002.
Welcome any answer:)
You have to remove the port range from the server definition. The haproxy documentation shows that the same port from the source is used for the destination.
listen ftp-proxy-server 10.0.1.1:20100-20199
mode tcp
server ftp-server 172.126.1.1
For haproxy 1.5 on centos,
listen web *:8080-8090
mode tcp
server worker1 10.0.0.1
server worker2 10.0.0.2
For haproxy 1.7 on debian,
listen web
bind *:8080-8090
mode tcp
server worker1 10.0.0.1
server worker2 10.0.0.2

Linux squid proxy configuration

I have 3 virtual machines. I have Squid proxy installed on one of them which functions as a router. I need to configure it to accept HTTP requests from only one of the other 2 machines(IP - 172.16.2.2). The change I made to the squid.conf file is:
http_port 172.16.2.2:3128
I then changed the firewall rule in the route machine so that it redirects traffic from 172.16.2.2 bound for 80 (HTTP port number) to the default squid port 3128. The command is given below:
sudo iptables -A PREROUTING -t nat -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128
Machine 172.16.2.2 is connected to the router on eth1. However, whenn I am making sending a HTTP request from 172.16.2.2, I get a 403 Forbidden error. It says:
X-Squid-Error: ERR_ACCESS_DENIED 0
I can't understand it. Please help.
(edited for style)
http_port is used to configure where squid is listening for request, so if you include an ip address, it should be configured in the same machine that is listening. So, in your case 172.16.2.2 (the "other" machine) is not a correct configuration.

Resources