Како OpenVPN клијент иза NAT постаје интернет излаз
Излаз сам позива ка споља, па његов рутер не треба ниједан улазни порт. Пратите шта чвориште рутира, шта излаз прослеђује и одакле долази повратни пут.
Три Linux домаћина, један дизајн: јавно доступно чвориште OpenVPN, кориснички лаптоп и излазна машина иза обичног кућног рутера који ништа не прослеђује унутра. Излаз сам позива чвориште. Затим интернет саобраћај корисника улази у тунел на лаптопу и излази преко сопственог узлазног канала излаза. Све изненађујуће у овом распореду произлази из једног детаља: излаз је започео везу, па пут ка унутра већ постоји и није потребно прослеђивање порта да би се створио.
Оно што следи прати пут пакета, а не редослед конфигурације, јер конфигурација има смисла тек када се зна која компонента носи коју одлуку. Сваки слој носи тачно једну одлуку, а грешке се гомилају тамо где се два слоја узимају као један.
Две транспортне сесије, један унутрашњи пут
Сваки домаћин држи своју спољну везу ка чворишту и ниједна од тих веза не зна за ону другу. Саобраћај корисника ка интернету је одвојен унутрашњи ток који се случајно преноси унутар корисничког тунела, а затим поново емитује из тунела излаза. Чвориште мора да рутира управо тај унутрашњи ток, а излаз га мора проследити.
outer: consumer --TLS--> hub
outer: exit --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink
Пошто обе спољне везе излазе са клијентске стране, рутер излаза никада не види долазни SYN и никада му не треба правило за одредишни NAT. Треба само да одржава успостављени транспорт живим, што већ чини за сваку дуготрајну везу. Ништа на јавном интернету не мора прво да стигне до излаза, зато динамичка адреса на том узлазном каналу није проблем. Рутер ипак мора да дозволи одлазну сесију, али то је исто дозвола коју прегледач већ користи.
Шта iroute заправо инсталира унутар сервера
Чвориште је једини уређај који одлучује који партнер поседује које одредиште, и ту одлуку доноси у сопственој таблици рутирања корисничког простора, а не у таблици језгра. Запис client-config-dir за излаз под именом exit-node може тамо да затражи подразумевани префикс:
# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0
Та линија говори серверском процесу "унутрашњи пакети са било којим одредиштем припадају овом клијенту". Не додаје подразумевану руту у оперативни систем чворишта и не чини чвориште интернет пролазом. OpenVPN 2.6 приручник држи унутрашње рутирање специфично за клијента и рутирање језгра као одвојене механизме, и управо то раздвајање је разлог зашто дизајн ради без дирања подразумеване руте чворишта.
Кориснику је потребна огледалска инструкција, достављена као push, да његов саобраћај уђе у тунел уместо да изађе кроз локални пролаз. У топологији подмреже базен је повезана рута на tun уређају излаза, зато повратни смер не тражи додатни push; оно што излаз не сме да добије је преусмеравање испод, које би вратило његов сопствени узлазни саобраћај у тунел који покушава да користи. Шаљите га само кориснику и читајте примењене руте на клијенту уместо да верујете да је CCD датотека изабрана.
# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"
Прослеђивање обавља језгро излаза
Унутар излаза пакет од корисника стиже на tun интерфејс, адресиран на неки интернет домаћин. Језгро прегледа своју таблицу рутирања, налази стварни узлазни канал као најбоље поклапање и затим примењује две независне политике: сме ли овај пакет уопште да се проследи и сме ли да изађе кроз тај интерфејс са том изворном адресом. Прослеђивање је sysctl и у многим дистрибуцијама је подразумевано искључено.
Зато је излазу потребно трајно укључено прослеђивање IPv4, правило које прима изворе корисничког тунела ка узлазном каналу и пут одговора назад кроз tun. Укључивање прослеђивања за цео домаћин мења и понашање свега другог што се рутира кроз њега, зато правило треба да именује изворе и интерфејсе уместо да прихвати све.
Повратни пут купује превод извора
Интернет домаћин нема руту до адресе 10.90.0.x, па би одговори били одбачени пре него што стигну до излаза. Преписивање извора док пакет напушта узлазни канал решава то, а праћење веза окреће преписивање на повратном путу.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9 # run on the exit: must point at the tun
Правило горе је почетна тачка за један узлазни интерфејс, а не firewall политика. Сузите извор на доделе које сте заиста овластили и држите сопствену улазну политику излаза одвојеном, да маскирање тунелског саобраћаја не изложи тихо локалне услуге. На домаћину са динамичком узлазном адресом маскирање вас штеди и ручног праћења адресе.
Где чвориште може да спроведе, а где не
Са client-to-client и традиционалним корисничким путем података, чвориште предаје унутрашње пакете између партнера унутар серверског процеса. Они никада не пролазе кроз FORWARD ланац језгра чворишта, зато правило у језгру тамо не може да ограничи прелаз између партнера, колико год пажљиво било написано. Спровођење мора да живи у сопственој политици сервера: ко сме да се повеже, коју CCD датотеку добија и да ли се уопште даје подразумевано власништво излаза.
Зато је подразумевани iroute широка одлука о поверењу. Излаз мора законито да прима повратни саобраћај са произвољних интернет адреса и мора да буде машина коју контролишете, ажурирате и надгледате. Дати исто власништво партнеру коме не бисте дали рутер је грешка на коју овај дизајн позива.
Чланство је прави контрол. Сваки клијент који може да конфигурише сопствене руте може да покуша да користи излаз, зато је ограничавање ко сме да се повеже или којим партнерима ће излаз служити део дизајна, а не накнадна мисао.
Безбедно отказивање када излаз нестане
Искључите излаз и унутрашње подразумевано власништво нестаје са његовом сесијом. Оно што не сме да се догоди је да чвориште тихо постане заменски излаз: никаква подразумевана рута из VPN базена ка узлазном каналу чворишта и никакво широко правило маскирања на чворишту које би радо проследило исти саобраћај. Тестирајте то отказивање намерно, а затим тестирајте опоравак свежим током, а не страницом која је већ била отворена.
# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
Ако саобраћај корисника и после нестанка излаза стиже до интернета, носи га нешто друго и предвиђена граница не постоји. Третирајте DNS и IPv6 такође као одвојене одлуке: рута IPv4 са маскирањем не говори ништа о AAAA саобраћају, а резолвер који чвориште гурне одговараће одакле захтев заиста излази.