En enhet via en router-VPN kräver tre regler, inte en strömbrytare
En enhet via en router-VPN är policyrouting, inte en kryssruta: en markerad tabell, en avgränsad NAT-regel, plus DNS-, IPv6- och LAN-vägarna som guider hoppar över.
Det finns ingen strömbrytare per enhet på en router-VPN; strömbrytaren du letar efter är en genväg som skriver policyrutningsregler åt dig. I samma stund som en laptop, ett portintervall, en adresslista eller ett LAN-segment måste använda tunneln medan allt annat stannar på WAN, bygger du en policyrutt i stället för att slå på en funktion. Jobbet har tre rörliga delar, och varje del fallerar olika: en markerad tabell utan rutt ser ut som tystnad, ett märke satt i fel kedja ser ut som om ingenting hände, och en saknad NAT-regel ser ut som en tunnel som ansluter och inte transporterar något. Ytterligare två delar saknas eftersom de aldrig dyker upp i mangle-regeln, och det är DNS och IPv6.
Myten: tunneln är en klientinställning
En VPN-klient på routersidan gör en grov sak bra: den lägger 0.0.0.0/0 i huvudrutttabellen och pekar den mot tunneln. WireGuard härleder det från AllowedIPs, OpenVPN och från en redirect-gateway som skickas från servern, och båda ändrar vägen för varje värd bakom routern. Att snäva in AllowedIPs eller lägga till route-nopull ändrar vad klienten installerar. Det ändrar inte vem installationen gäller, eftersom klienten aldrig ser enheter. Den ser bara paket.
Val utifrån källa eller destination är ett routingbeslut, så det hör till routerns policylager: en mangle-regel plus en andra tabell på RouterOS, ett MARK plus en ip rule på OpenWrt eller DD-WRT, eller en brandväggsregel vars gateway är tunneln på pfSense. Netgates recept för WireGuard-klienten är den du bör läsa innan du gissar, eftersom regelns gateway, gränssnittstilldelningen och NAT-posten för utgående trafik måste stämma på den plattformen innan en enda klient använder tunneln.
Den andra halvan av myten är den andra routern. Att köpa en extra burk, eller flytta enheten till ett gäst-SSID, fungerar ofta, och orsaken är inte hårdvaran: det sätter enheten i sitt eget subnät, vilket ger dig källväljaren som firmware redan förstår. Om du kan definiera det segmentet på din egen router löser den extra burken ett problem du inte hade.
Del ett: en tunnel som inte är standardrutten
På RouterOS lägger du till klienten utan standardrutt och ger tunneln sin egen tabell. Den första rutten är den markerade standarden; den andra är felhalvan.
/ip route add dst-address=0.0.0.0/0 gateway=VPN_GATEWAY_IP routing-mark=vpn distance=1
/ip route add dst-address=0.0.0.0/0 type=unreachable routing-mark=vpn distance=2
Den oåtkomliga rutten är anledningen till att en markerad tabell slår en undantagslista i huvudtabellen. När tunneln faller får markerade paket omedelbart oåtkomligt i stället för att tyst falla tillbaka till WAN, så felet dyker upp i programmets felmeddelande och inte på en geolokaliseringssida du kontrollerar en timme senare.
RouterOS 7 delar upp det som 6.x höll ihop: du deklarerar tabellen med /routing table add name=vpn fib och refererar sedan till den vid namn på rutten och i mangle-regeln. En 6.x-snutt som skriver routing-mark utan att definiera tabellen läses in rent och matchar ingenting. Den andra klassikern är två 0.0.0.0/1-halvor, eller två standardrutter på samma avstånd i en tabell: kärnan väljer en, och beteendet kan ändras efter en omstart.
Del två: märk före rutsökningen
Väljaren avgör vilka paket som kommer in i den tabellen. RouterOS börjar oftast med en adresslista för destinationspolicy, eller en källadress för enhetspolicy:
/ip firewall mangle add chain=prerouting src-address=192.168.88.50 action=mark-routing new-routing-mark=vpn
/ip firewall mangle add chain=prerouting dst-address-list=via-vpn action=mark-routing new-routing-mark=vpn
/ip firewall address-list add list=via-vpn address=203.0.113.10
Linux-firmware gör samma sak med ett netfilter-märke och en regel som styr märkta paket in i en tabell du fyllt:
iptables -t mangle -A PREROUTING -p tcp --dport 27000:27050 -j MARK --set-mark 0x200
ip route add default dev tun0 table 100
ip rule add fwmark 0x200 table 100
Kedjan är inte ett stilval. När ett paket når FORWARD har rutsökningen redan skett, så ett MARK eller DROP där kan bara skriva om eller kasta. Märket måste landa i PREROUTING för vidarebefordrad trafik och i OUTPUT för trafik som routern själv skapar, där routerns DNS, NTP och uppdateringskontroller bor. Den utvägen är det vanliga skälet till att en helt tunnelansluten installation fortfarande svarar från ISP:ns resolver i ett läckagetest.
Enhetspolicy behöver en matchning som inte glider. Reservera adressen i DHCP, eller matcha ett gränssnitt för ett dedikerat segment; en adress som senare flyttar till en annan enhet tillämpar tyst tunneln på fel klient. En brygga per SSID med eget subnät är den mer hållbara versionen av samma idé, och den ger IPv6-reglerna en plats att bo på också.
Del tre: NAT, DNS och LAN-undantaget
Trafik som lämnar via tunneln behöver en källadress som andra sidan svarar på. Avgränsa översättningen till tunnelns gränssnitt: out-interface=VPN_NAME på RouterOS, -o tun0 på Linux, en matchande NAT-post för utgående trafik på pfSense. En masquerade-regel utan den avgränsningen skriver om trafik du menade att lämna ifred, och symtomet är att enheten utan tunnel tappar sin publika adress.
LAN-undantaget skapar fler supporttrådar än själva tunneln. Om den markerade tabellen bara har en standardrutt matchar en skrivar- eller NAS-destination från den valda enheten den standarden och försvinner in i tunneln. Lägg till LAN-rutten i samma tabell, eller uteslut det lokala subnätet i väljaren; båda fungerar, och uteslutningen är lättare att hålla korrekt när du lägger till VLAN senare.
DNS tar en egen väg. Frågor som routern vidarebefordrar är routerns egna och följer OUTPUT, inte det vidarebefordrade märket, så en helt tunnelansluten laptop kan fortfarande lösa namn via ISP:n. Peka klienterna mot en resolver som nås över tunneln, eller märk routerns egen port 53-trafik, och kontrollera sedan den lösta adressen i stället för att anta att svaret reste med webbförfrågan.
När regeln matchar men appen fortfarande använder WAN
Destinationslistor åldras dåligt. Ett namn löses upp till en adress som inte finns i listan, så förfrågan tar WAN medan varje test du gjorde mot den listade adressen fungerade. Uppdatera listan från samma resolver som klienten använder, och föredra en källbaserad väljare när du verkligen vill ha all trafik från en enhet.
IPv6 är den tysta omvägen. Enheten har en andra adressfamilj med sin egen standardrutt och sin egen regeluppsättning, och att bara matcha IPv4-adressen är halva policyn. Använd samma väljare på ip6tables eller nftables-motsvarigheten, eller stäng av IPv6 på det segmentet med avsikt i stället för av misstag.
Etablerade anslutningar spelar också roll. En conntrack-post som skapades före ändringen fortsätter följa den gamla vägen tills den löper ut, så en webbläsare som stod öppen under redigeringen ser exakt ut som en regel som aldrig tillämpades. Öppna en ny anslutning, eller rensa tillståndet, innan du bedömer policyn.
Verifiera med två enheter och en omstart
Testa enheten som ska vara i tunneln och enheten som inte ska vara det, och jämför andra hoppet i stället för en hastighetssiffra. En traceroute från var och en visar antingen tunnelns gateway eller ISP:ns gateway på hopp två; om båda ser likadana ut gör inte märket eller tabellen det regeln säger. Använd nya anslutningar för testet.
Starta sedan om. Startordningen är där en fungerande policy blir trasig, eftersom klienten måste vara uppe innan den oåtkomliga rutten installeras, och en sparad ögonblicksbild som återställer det gamla regelverket skriver över din tabell. Kontrollera att varje regel finns i den sparade konfigurationen och att den markerade standarden finns efter start, inte bara efter att du skrev in den.
Om något fallerar, ta bort märket först och se om normal trafik kommer tillbaka, ta sedan bort tabellen. Den ordningen säger om du jagar ett routing- eller ett brandväggsproblem, och den lämnar hushållet med en fungerande skrivare medan du gör klart jobbet.