pf-kill switch i macOS för OpenVPN: regler som stänger
En pf-regeluppsättning blockerar direkt trafik medan tunneln är nere. Behåll klientens väg till sin server och bevisa sedan blockeringen med tunneln avstängd.
På macOS är en kill switch bara så bra som paketfilterpolicyn bakom den, och pf är delen som upprätthåller den policyn. Policyn måste göra två motsatta saker samtidigt: låta klienten nå sin server så att en tunnel kan finnas, och stoppa allt annat från att gå direkt ut. De flesta publicerade regeluppsättningar klarar det andra och glömmer det första, så maskinen tappar anslutningen i stället för att vinna skydd. Versionen som fungerar namnger ändpunkten, resolvern och tunneln, och inget mer.
Vad ett paketfilter kan avgöra, och vad det inte kan
pf tittar på gränssnitt, adresser, protokollnummer och portar, och stannar där. Det får aldrig veta vilken process som öppnade en socket, så ett tillstånd skrivet för ett program blir ett tillstånd för varje program som kan nå samma port. Det är så ett generöst UDP-undantag gör en kill switch tillbaka till ett vanligt nätverk. Applikationsmedveten blockering hör till klienten eller en systemtilläggning, inte till den här filen.
Filtret skapar inte heller rutter. När klienten faller kan standardrutten fortfarande peka på en död tunnel, och pf gör om det till blockerade paket i stället för en tyst återgång till Wi-Fi. Blockeringen är det avsedda resultatet, inte ett fel att routa runt.
Ordningen avgör utfallet oftare än regeltexten. Utan quick fortsätter pf att utvärdera efter en träff och den sista matchande regeln vinner, så en bred genomgång nederst åsidosätter de noggranna undantagen ovanför. Att markera genomgångarna med quick gör första träffen slutgiltig, vilket en policyskrivare vanligtvis menar.
Läs fakta om gränssnitt och ändpunkt först
Trådlösa gränssnitt numreras inte likadant på varje Mac, och tunnelenheten får ett nummer som kan ändras mellan starter. En regel som namnger en enhet som inte finns misslyckas vid parsning, vilket är högljutt och lätt att fånga, medan en regel som namnger fel befintlig enhet parsas rent och släpper igenom trafik du ville stoppa.
Samla fakta medan klienten är ansluten, eftersom tunnelenheten bara finns då. Du behöver gränssnittet som håller standardrutten, enheten klienten skapade, och adressen och porten till servern den ringer. Just det sista värdet är det som de flesta regeluppsättningar utelämnar, och att utelämna det är varför en kopierad uppsättning blockerar sin egen tunnel.
route -n get default
ifconfig -l
scutil --nc list
Det första kommandot namnger gränssnittet som vinner nu, det andra listar varje enhet kärnan känner till, och det tredje visar de VPN-konfigurationer systemet kan starta. Skriv ner svaren och läs sedan serveradressen och porten från klientens egen konfiguration.
Skriv regeluppsättningen runt tunnelvägen
Filen nedan nekar som standard och släpper in fem saker igen: loopback, tunnelenheten, klientens väg till sin server, resolvern som används innan tunneln finns, och de två utbytena som håller en trådlös länk användbar. Gränssnittsnamn och serveradressen kommer från din maskin, så byt ut värdena du bekräftade. Tunnelnumret kommer inte heller att stämma med ditt.
set skip on lo0
block all
pass out quick on utun0
# maintain this line when the server address changes
pass out quick on en1 inet proto udp to 203.0.113.10 port 1194
# only the resolver the client uses before the tunnel exists
pass out quick on en1 inet proto udp to 192.0.2.53 port 53
pass out quick on en1 inet proto udp from any port 68 to any port 67
pass out quick on en1 inet proto udp to 224.0.0.251 port 5353
DHCP-raden finns eftersom en Mac ber om en adress innan den har en, så begäran lämnar port 68 mot port 67 utan en användbar källadress. Multicast-raden låter systemet bedöma om den trådlösa länken är värd att använda, och att ta bort den ger en maskin som rapporterar ingen anslutning i ett fungerande nätverk. Ändpunktsraden är det som OpenVPN över huvud taget kan nå sin server; utan den släpper block all det yttre handslaget och tunneln reser sig aldrig. Resolverraden är smalare än ett allmänt DNS-tillstånd, eftersom den namnger en adress och en port i stället för varje fråga maskinen gör.
De ändpunkts- och resolverundantagen är de två som måste finnas; allt annat förblir blockerat. Om klienten ringer en bokstavlig adress, ta bort resolverraden och behåll ändpunktsraden. Om serveradressen ändras, uppdatera den raden före nästa anslutning, eller fyll en pf-tabell från klientens egen krok och matcha tabellen i stället.
Ta ner tunneln och starta sedan om
Parsa före laddning, för ett syntaxfel är billigt i en torrkörning och dyrt i en fjärrsession. Ladda sedan filen, aktivera filtret om det var av, och läs tillbaka vad som faktiskt gäller. Tillbakaläsningen är ingen ceremoni: ett annat ankare kan lägga till regler du inte skrev, så jämför den utskrivna uppsättningen med din fil.
sudo pfctl -n -v -f /etc/pf.conf
sudo pfctl -f /etc/pf.conf
sudo pfctl -e
sudo pfctl -s rules
sudo pfctl -s Anchors
sudo pfctl -a <anchor> -s rules
sudo pfctl -s info
Med reglerna laddade, ta ner tunneln och försök ladda en sida. Vanlig trafik ska stanna, och den ska förbli stoppad efter att maskinen sover och vaknar, för det är i den övergången gammalt tillstånd sipprar tillbaka. Anslut igen och bekräfta att trafiken återupptas utan att röra regeluppsättningen. Om en webbläsare fortfarande fungerar med tunneln nere är någon regel bredare än du trodde, och tillbakaläsningen namnger den oftast.
Omstarten är den del folk hoppar över. macOS läser /etc/pf.conf vid start, men att läsa filen är inte samma sak som att aktivera filtret, så en regeluppsättning som fungerar nu kan vara inaktiv efter en omstart. Kör sedan sudo pfctl -s info och bekräfta att statusraden rapporterar filtret som aktiverat.
Håll utgången och omstartsvägen ärliga
En regeluppsättning som blockerar allt kan också låsa dig ute från en maskin du administrerar på distans. Redigera från en lokal session när du kan, ha den förra filen bredvid den nya, och känn till återgången innan du behöver den. Kommandona nedan avaktiverar filtret och laddar om kopian du behöll, och det är sekvensen för en konsol, inte över tunneln du just skar av. En återgång på fem sekunder slår en smart regel varje gång.
sudo pfctl -d
sudo pfctl -f /etc/pf.conf.previous
sudo pfctl -s rules
För beständighet krävs en launch daemon som kör pfctl -e och laddar din fil vid start. Behandla den som vilket annat privilegierat jobb som helst: absoluta sökvägar, en logg du kan läsa efteråt, och ett test på en maskin du fysiskt kan nå. En daemon som misslyckas tyst lämnar maskinen oskyddad och normal utseende.
Dokumentera luckorna, med början i en andra VPN-klient som skapar sin egen tunnelenhet. Dina regler namnger ett tunnelgränssnitt, så ett andra förblir blockerat eller fångas av en bred regel som läggs till senare. Tethering- och hotspotgränssnitt dyker bara upp ibland och förtjänar samma not. Ingen av dessa luckor är skäl att hoppa över policyn; de är villkoren den fortfarande håller under.