squid loops to itself in a split traffic split dns with squid dnsmasq and pritunl

31 Views Asked by At

I have a VM that we'll call vpn server that runs:

  • pritunl
  • dnsmasq
  • squid (6.2 compiled and run on Ubuntu 22.04) - the only part not fully functional Network:
  • public NIC: eth0
  • tunnel NIC: tun+ (every time you restart pritunl it gets a different name like tun5 or tun11. I used the + notation as it used throughout in iptables rules to avoid checkin which number we currently have)
  • eth0 gets a public IP from the infrastructure provider, for this example: 1.2.3.4
  • tun+ gets always 192.168.0.1 - for this example, IRL is a bit more exotic, but KISS

pritunl pushes dns to clients to be 192.168.0.1 that is the vpn server box, and iptables will redirect in PREROUTING 53 to 5353 where dnsmasq listens and for the specific domain example.com that I want to split DNS / split traffic to it returns 192.168.0.1 as IP address of example.com. Otherwise normal IP of the respective host is returned.

Only traffic going to 192.168.0.1/24 network will go through VPN, but this is what we want. All the rest goes directly from the clients via the internet to requested IPs.

Until now all works like a charm.

Now, the client, let's say curl tries to connect to example.com: curl -vvvk https://example.com which get's the proper 192.168.0.1 and there are several rules in iptables to mess the redirect 80 and 443 to 3128 and 3129 respectively where squid listens in intercept mode with a self-signed certificate - I should solve this somehow but in another day.

The request reaches squid all properly formatted, squid responds to the SYN.

Now, squid is not trying to change the IP address of the destination server and tries to connect to... 192.168.0.1 as the final server because this was found in the actual request even thou the host_name in logs is, as expected, example.com. This creates a loop that I had to prevent it to exhaust the file descriptor using iptables and allowing requests from tun+ only on IPs different from 192.168.0.1. This, of course, puts an abrupt end to the request.

Except modifying squid code or using a very complex and time consuming approach, is there a way to either push the host_name to the url_rewrite_program or make squid connect not to the original requested destination address (ip I should say here) but to resolve the hostname from the "Host: " header to the final proper IP address?

I should mention that the IP address of the final destination is very dynamic: unicast addresses from CloudFlare, dynamic addresses from their IP ranges, as well as other infra providers IP addresses as different subdomains of example.com go to different services... So not an option to whitelist all these IP ranges (which will bring a good portion of internet to be forwarded through the VPN server box anyhow - think CloudFlare), and don't want to use other expensive options or services either.

Here is the squid.conf:

acl localnet src 0.0.0.1-0.255.255.255  # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8     # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10      # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16     # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12      # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16     # RFC 1918 local private network (LAN)
acl localnet src fc00::/7           # RFC 4193 local private network range
acl localnet src fe80::/10          # RFC 4291 link-local (directly plugged) machines
acl allowed_subnets src 192.168.0.1/24
acl SSL_ports port 443
acl Safe_ports port 80      # http
acl Safe_ports port 21      # ftp
acl Safe_ports port 443     # https
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280     # http-mgmt
acl Safe_ports port 488     # gss-http
acl Safe_ports port 591     # filemaker
acl Safe_ports port 777     # multiling http
http_access deny !Safe_ports
http_access allow localhost manager
http_access deny manager
http_access allow allowed_subnets
http_access deny all
http_port 192.168.0.1:8080
http_port 192.168.0.1:3128 intercept
https_port 192.168.0:3129 intercept ssl-bump dynamic_cert_mem_cache_size=4MB tls-cert=/etc/squid/squid.pem
always_direct allow all
ssl_bump server-first all
sslproxy_cert_error allow all
client_dst_passthru off
tls_outgoing_options flags=DONT_VERIFY_DOMAIN
sslcrtd_program /lib/squid/security_file_certgen -s /var/cache/squid/ssl_db -M 4MB
debug_options ALL,5
coredump_dir /var/cache/squid
url_rewrite_program /usr/local/bin/resolve-squid-url
refresh_pattern ^ftp:       1440    20% 10080
refresh_pattern -i (/cgi-bin/|\?) 0 0%  0
refresh_pattern .       0   20% 4320
max_filedescriptors 16384

I'm searching the internet since one week, discussed with my new friend Chat 4.0 for hours, I tried to mess with the url_rewrite_program /usr/local/bin/resolve-squid-url config option, but it does not help as I don't get the Host: inside that script.

Tried different iptables redirects, and nothing works so far as squid is rigid about not doing an extra DNS request for me, or I don't know the magic words (- always insert please here -) to change it's tun+ internal IP to the the resolved IP of the Host: header.

My script attempt logs this because I'm trying to change internal IP address with what I thought would be the Host: value and I'm doing even a dns lookup in the script which fails as is the actual IP, but I actually get the ip address in this script:

Original URL: 192.168.0.1:443 192.168.0.4/192.168.0.4 - CONNECT myip=192.168.0.1 myport=3129
Modified URL: 192.168.0.1:443 192.168.0.4/192.168.0.4 - CONNECT myip=192.168.0.1 myport=3129
0

There are 0 best solutions below