@Laxarus you could set up a wpad server on a raspberry pi zero I did that. After that I set everything to auto and it works. It is a bit more complex to set up but for me it is easy to use my laptop at the University and go home and it works on my secure network. This is my wpad I use. I am sure you know it's basically just a script that the computer calls to know where the proxy is and what goes into it and what goes direct.
I have ULA ipv6 traffic going direct. I had to use a host name for my proxy so it will resolve ipv6 and ipv4 as my network is a dual stacked network for educational higher level understanding. But again you can make it very basic, Netgate has a doc on how to make one on the system even if you want to have it on the firewall, I was told it is easier to just do it on a raspberry pi and it is more secure that way also.
/*
Highly Optimized Dual-Stack WPAD/PAC Script
Features:
- Fast regex validation prevents slow, blocking DNS lookups inside isInNet().
- Comprehensive loop protection for WPAD and admin endpoints.
- Safe dual-stack handling via FindProxyForURLEx for modern browsers.
*/
function FindProxyForURL(url, host) {
host = host.toLowerCase();
// Normalize IPv6 brackets
var cleanHost = (host.charAt(0) === '[' && host.charAt(host.length - 1) === ']')
? host.substring(1, host.length - 1)
: host;
// WPAD loop protection & local admin endpoints
if (
host === "wpad" || host === "wpad.local" || host === "wpad.localdomain" || host === "wpad.home.arpa" ||
cleanHost === "192.168.1.6" || cleanHost === "2001:db8:8052:a::6" || // Placeholder Admin IP
cleanHost === "192.168.1.1" || cleanHost === "192.168.1.2" || cleanHost === "2001:db8:8052:a::1" ||
host === "localhost" || cleanHost === "127.0.0.1" || cleanHost === "::1"
) {
return "DIRECT";
}
// Plain hostnames (e.g. http://pfsense/)
if (isPlainHostName(host)) {
return "DIRECT";
}
// Local internal domains
if (
dnsDomainIs(host, ".local") ||
dnsDomainIs(host, ".lan") ||
dnsDomainIs(host, ".localdomain") ||
dnsDomainIs(host, ".home.arpa")
) {
return "DIRECT";
}
// IPv4 private ranges (literal addresses only)
if (/^[0-9.]+$/.test(cleanHost)) {
if (
isInNet(cleanHost, "10.0.0.0", "255.0.0.0") ||
isInNet(cleanHost, "127.0.0.0", "255.0.0.0") ||
isInNet(cleanHost, "169.254.0.0", "255.255.0.0") ||
isInNet(cleanHost, "172.16.0.0", "255.240.0.0") ||
isInNet(cleanHost, "192.168.1.0", "255.255.255.224") // Custom limited subnet /27
) {
return "DIRECT";
}
}
// IPv6 ULA and link-local (literal addresses only)
if (cleanHost.indexOf(":") !== -1) {
if (
cleanHost.indexOf("fe80:") === 0 ||
cleanHost.indexOf("fc00:") === 0 ||
cleanHost.indexOf("fd00:") === 0
) {
return "DIRECT";
}
}
// =========================================================
// DEFAULT ROUTING RULE FOR PUBLIC TRAFFIC
// =========================================================
return "PROXY proxy.home.arpa:3128";
}
function FindProxyForURLEx(url, host) {
host = host.toLowerCase();
// Use extended IPv6-aware functions if available (Edge/Windows)
if (typeof isInNetEx === 'function' && typeof dnsResolveEx === 'function') {
var cleanHost = (host.charAt(0) === '[' && host.charAt(host.length - 1) === ']')
? host.substring(1, host.length - 1)
: host;
if (isInNetEx(cleanHost, "fe80::/10") || isInNetEx(cleanHost, "fc00::/7")) {
return "DIRECT";
}
// Change the prefix below to match your local public IPv6 assignment
if (isInNetEx(cleanHost, "2001:db8:8052:a::/64")) {
return "DIRECT";
}
}
return FindProxyForURL(url, host);
}