Route only blocked traffic through VPN while keeping Chinese services direct.
[Client Request]
↓
[iptables/ipset] → Check destination
↓
┌───┴───┐
↓ ↓
[Direct] [VPN]
↓ ↓
[5G] [wireproxy → Mullvad]
# Create set for IPs that should go through VPN
ipset create vpn_ips hash:net
# Add blocked IP ranges (example)
ipset add vpn_ips 8.8.8.0/24 # Google DNS
ipset add vpn_ips 1.1.1.1/32 # Cloudflare DNS
# Add more as needed# Mark packets destined for VPN IPs
iptables -t mangle -A PREROUTING -m set --match-set vpn_ips dst -j MARK --set-mark 1
# Redirect marked packets to redsocks
iptables -t nat -A PREROUTING -p tcp -m mark --mark 1 -j REDIRECT --to-ports 12345Better approach: resolve domains and add IPs to ipset dynamically.
# /etc/dnsmasq.d/gfw.conf
# Add resolved IPs to ipset
# Social media
ipset=/twitter.com/vpn_ips
ipset=/facebook.com/vpn_ips
ipset=/instagram.com/vpn_ips
# Google services
ipset=/google.com/vpn_ips
ipset=/youtube.com/vpn_ips
ipset=/googleapis.com/vpn_ips
# Others
ipset=/telegram.org/vpn_ips
ipset=/wikipedia.org/vpn_ipsPopular GFW lists:
Convert to dnsmasq format:
# Download and convert gfwlist
curl -L https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt | \
base64 -d | \
grep -v '^!' | grep -v '@@' | \
sed 's/||//g; s/|//g; s|https\?://||g' | \
sed 's|/.*||' | \
sort -u | \
while read domain; do
echo "ipset=/$domain/vpn_ips"
done > /etc/dnsmasq.d/gfwlist.confFor HTTP proxy, you can use a PAC file approach:
# /mnt/data/vpn/domains-vpn.txt
google.com
youtube.com
twitter.com
facebook.com
instagram.com
telegram.org#!/bin/sh
# /mnt/data/vpn/smart-proxy.sh
VPN_DOMAINS="/mnt/data/vpn/domains-vpn.txt"
check_domain() {
domain="$1"
while IFS= read -r vpn_domain; do
case "$domain" in
*"$vpn_domain"*) return 0 ;;
esac
done < "$VPN_DOMAINS"
return 1
}For this router, the simplest effective setup:
The router may use connmand's DNS proxy. Check first:
ps | grep -E 'dnsmasq|connman'# Create blocked domains list
cat > /mnt/data/vpn/blocked-domains.conf << 'EOF'
# Social
ipset=/twitter.com/vpn_ips
ipset=/x.com/vpn_ips
ipset=/facebook.com/vpn_ips
ipset=/instagram.com/vpn_ips
ipset=/threads.net/vpn_ips
# Google
ipset=/google.com/vpn_ips
ipset=/youtube.com/vpn_ips
ipset=/googleapis.com/vpn_ips
ipset=/gstatic.com/vpn_ips
ipset=/googlevideo.com/vpn_ips
# Messaging
ipset=/telegram.org/vpn_ips
ipset=/whatsapp.com/vpn_ips
ipset=/signal.org/vpn_ips
# Other
ipset=/wikipedia.org/vpn_ips
ipset=/reddit.com/vpn_ips
ipset=/medium.com/vpn_ips
ipset=/nytimes.com/vpn_ips
EOF#!/bin/sh
# /mnt/data/vpn/setup-split-tunnel.sh
# Create ipset if not exists
ipset create vpn_ips hash:net 2>/dev/null || ipset flush vpn_ips
# Create NAT chain
iptables -t nat -N REDSOCKS 2>/dev/null || iptables -t nat -F REDSOCKS
# Skip local addresses
for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4; do
iptables -t nat -A REDSOCKS -d $net -j RETURN
done
# Redirect VPN-destined traffic
iptables -t nat -A REDSOCKS -p tcp -m set --match-set vpn_ips dst -j REDIRECT --to-ports 12345
# Apply to LAN traffic
iptables -t nat -A PREROUTING -i br0 -p tcp -j REDSOCKS- UDP traffic: redsocks only handles TCP. UDP (like QUIC) goes direct.
- DNS leaks: DNS queries may reveal browsing intent. Use encrypted DNS.
- IP changes: Domain IPs can change. ipset entries may become stale.
# From a client device connected to router WiFi:
# Should go through VPN
curl https://www.google.com
curl https://twitter.com
# Should go direct
curl https://www.baidu.com
curl https://www.taobao.com