среда, 22 февраля 2017 г.

Использование if_ipsec во FreeBSD

Как многие уже знают, во FreeBSD 12.0-CURRENT был добавлен новый сетевой псевдоинтерфейс if_ipsec(4). На первый взгляд кажется, что он выполняет те же самые задачи что и уже существующий десятилетия if_gif(4). Но это не совсем так.
Оба интерфейса предоставляют виртуальный туннель, в который может маршрутизироваться трафик. Оба интерфейса настраиваются подобным образом: при помощи ifconfig(8) создаётся интерфейс, ему назначаются адреса конечных точек туннеля, настраиваются адреса внутри туннеля, при необходимости добавляются дополнительные маршруты. В случае с if_gif(4) этих действий уже достаточно для работы интерфейса. Он может принимать и передавать инкапсулированные в IPv4 или IPv6 пакеты.
Чтобы зашифровать передаваемый внутри туннеля трафик необходимо настроить политики и ассоциации безопасности, которые будут применять IPsec преобразования к трафику туннеля, т.е. в качестве селектора адресов для политики должны выступать адреса конечных точек туннеля, а селектором протокола - в зависимости от настроек могут быть различные вариации инкапсуляции IP в IP. Можно конечно "матчить" весь трафик между конечными точками туннеля, но это чаще всего неудобно.   Когда таких туннелей нужно создать много, то встаёт задача синхронизации настроек каждого if_gif(4) туннеля и настроек политик безопасности IPsec. К тому же, наличие большого числа политик безопасности не ускоряет работу по поиску подходящей политики для каждого пакета.
В решении части этих проблем и должен помочь if_ipsec(4). Его особенность в том, что он не выполняет инкапсуляцию сам, как это делает if_gif(4), а использует применяемую для туннельного режима "встроенную" в IPsec инкапсуляцию. При настройке туннеля if_ipsec(4) автоматически создаёт нужные политики безопасности, в которых уже указаны адреса конечных точек туннеля. Стоит заметить, что и принцип применения этих политик отличается от используемого для if_gif(4). Создаваемые интерфейсом if_ipsec(4) политики безопасности "матчат" вообще весь IPv4 и IPv6 трафик. Но так как они привязаны к конкретному интерфейсу, то и "матчат" они только трафик, проходящий через интерфейс.
В итоге можно иметь сотни таких политик безопасности в системе, но при прохождении пакетов поиск подходящей политики вообще не выполняется, т.к. каждый if_ipsec(4) интерфейс выбирает свою единственную политику, которой владеет он. 
На маршрутизаторе, где используется только if_ipsec(4), даже fastforwarding будет работать для всего остального трафика, чего нельзя получить с классическим if_gif(4) и глобальными политиками безопасности, т.к. fastforwarding автоматически отключается при наличии таких политик.
Теперь про особенности настройки. Как я уже сказал, с точки зрения конфигурации интерфейса, всё настраивается точно так же как и для if_gif(4). Но есть один дополнительный параметр reqid. Который может назначаться автоматически, но если не предполагается использовать IKE, то лучше назначить его руками. Этот параметр помагает системе различать политики нескольких интерфейсов и выполнять поиск подходящей ассоциации безопасности.
Ещё одна особенность, отличающая if_ipsec(4) от if_gif(4) - при использовании if_ipsec(4) нет возможности "выключить" IPsec и проверить, что всё работает без шифрования.
Ну и конечно же, настройку ассоциаций безопасности никто не отменял. Пароли и ключи шифрования автоматически никто придумывать за вас не будет. Чтобы ассоциация безопасности начала использоваться интерфейсом if_ipsec(4), нужно при её добавлении использовать специальный параметр у утилиты setkey(8) "-u id", где id - это упомянутый ранее reqid интерфейса. 
Пример создания туннеля между двумя тестовыми машинами test15 и test25:
test15# ifconfig ipsec0 create reqid 145
test15# ifconfig ipsec0 inet tunnel 87.250.242.145 87.250.242.144
test15# ifconfig ipsec0 inet 10.0.0.145/24 10.0.0.144
test15# ifconfig ipsec0
ipsec0: flags=8051 metric 0 mtu 1400
 tunnel inet 87.250.242.145 --> 87.250.242.144
 inet 10.0.0.145 --> 10.0.0.144 netmask 0xffffff00 
 inet6 fe80::225:90ff:fef9:3c92%ipsec0 prefixlen 64 scopeid 0x4 
 nd6 options=23
 reqid: 145
 groups: ipsec 
test15# setkey -c
add 87.250.242.145 87.250.242.144 esp 0xbadcafe -u 145 -E rijndael-cbc "1234567890987654" -A hmac-sha2-256 "12345678901234561234567890123456";
add 87.250.242.144 87.250.242.145 esp 0xcafebad -u 145 -E rijndael-cbc "0987654321123456" -A hmac-sha2-256 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa12";
^D

После настройки адресов туннеля на интерфейсе создаются вот такие политики безопасности.
test15# setkey -DP
0.0.0.0/0[any] 0.0.0.0/0[any] any
 in ipsec
 esp/tunnel/87.250.242.144-87.250.242.145/unique:145
 spid=1 seq=3 pid=9427
 refcnt=1
::/0[any] ::/0[any] any
 in ipsec
 esp/tunnel/87.250.242.144-87.250.242.145/unique:145
 spid=3 seq=2 pid=9427
 refcnt=1
0.0.0.0/0[any] 0.0.0.0/0[any] any
 out ipsec
 esp/tunnel/87.250.242.145-87.250.242.144/unique:145
 spid=2 seq=1 pid=9427
 refcnt=1
::/0[any] ::/0[any] any
 out ipsec
 esp/tunnel/87.250.242.145-87.250.242.144/unique:145
 spid=4 seq=0 pid=9427
 refcnt=1
Изменить политики можно только уничтожив интерфейс или изменив его настройки (адреса или reqid). Удалить их при помощи setkey -DPF так же не выйдет.
test25# ifconfig ipsec0 create reqid 144
test25# ifconfig ipsec0 inet tunnel 87.250.242.144 87.250.242.145
test25# ifconfig ipsec0 inet 10.0.0.144/24 10.0.0.145
test15# setkey -c
add 87.250.242.145 87.250.242.144 esp 0xbadcafe -u 144 -E rijndael-cbc "1234567890987654" -A hmac-sha2-256 "12345678901234561234567890123456";
add 87.250.242.144 87.250.242.145 esp 0xcafebad -u 144 -E rijndael-cbc "0987654321123456" -A hmac-sha2-256 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa12";
^D
test15# tcpdump -qnvi ix0 host 87.250.242.144
tcpdump: listening on ix0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:28:25.170705 IP (tos 0x0, ttl 64, id 33289, offset 0, flags [none], proto ESP (50), length 156)
    87.250.242.144 > 87.250.242.145: ESP(spi=0x0cafebad,seq=0x3), length 136
14:28:25.170928 IP (tos 0x0, ttl 64, id 4871, offset 0, flags [none], proto ESP (50), length 156, bad cksum 0 (->d212)!)
    87.250.242.145 > 87.250.242.144: ESP(spi=0x0badcafe,seq=0x1), length 136
14:28:45.288935 IP (tos 0x0, ttl 64, id 21702, offset 0, flags [none], proto ICMP (1), length 84)
    87.250.242.144 > 87.250.242.145: ICMP echo request, id 37388, seq 0, length 64
14:28:45.288955 IP (tos 0x0, ttl 64, id 32712, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->65ca)!)
    87.250.242.145 > 87.250.242.144: ICMP echo reply, id 37388, seq 0, length 64
test25# ping -c1 10.0.0.145
PING 10.0.0.145 (10.0.0.145): 56 data bytes
64 bytes from 10.0.0.145: icmp_seq=0 ttl=64 time=0.508 ms

--- 10.0.0.145 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.508/0.508/0.508/0.000 ms
test25# ping -c1 87.250.242.145
PING 87.250.242.145 (87.250.242.145): 56 data bytes
64 bytes from 87.250.242.145: icmp_seq=0 ttl=64 time=0.090 ms

--- 87.250.242.145 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.090/0.090/0.090/0.000 ms 

Этот пример показывает как использовать if_ipsec(4) в режиме ручной настройки. Но if_ipsec(4) вполне может использоваться совместно с различными IKE демонами. В этом случае создание политик безопасности от IKE демона не требуется. Ядро запросит у IKEd создание ассоциации безопасности при первой же попытке прохождения пакета через интерфейс, что может инициировать согласование параметров ассоциаций безопасности между IKE.

пятница, 10 февраля 2017 г.

Отключение проверки на "поддерживаемость" модулей для сетевых карт Intel XL710

Новое поколение сетевых карт Intel 710 серии обслуживается во FreeBSD драйвером if_ixl(4). И как это обычно любит делать Intel, если используемый с картой модуль не находится в "белом" списке производителя, то карта отказывается с ним работать. Во FreeBSD это сопровождается такими сообщениями:
ixl0: Link failed because an unqualified module was detected!
ixl1: Link failed because an unqualified module was detected!
ixl2: Link failed because an unqualified module was detected!
ixl3: Link failed because an unqualified module was detected!
В драйвере if_ixgbe(4) для отключения такого поведения была специальная настройка в loader.conf: hw.ix.unsupported_sfp="1".
В этом драйвере такой настройки нет и судя по всему, эта особенность контролируется firmware карты. Т.е. если карта обнаруживает неподдерживаемый модуль, она отказывается с ним работать и никакие проверки в драйвере этому помешать не могут.
Никаких утилит от производителя для настройки этого поведения найти не удалось. В линуксах, судя по архивам рассылок, эта проблема тоже присутствует. И для линукса был найден вот этот репозиторий, в котором содержится две утилиты. Одна для поиска нужной структуры в NVM карты, а вторая для модификации нужных данных. Автору не удалось найти закономерность в расположении данных в NVM, поэтому, видимо, он не оформил утилиты в виде законченного решения.

Проведя несколько часов за чтением спецификации и драйвера, я написал аналог его утилиты поиска нужной структуры для работы во FreeBSD. И разглядывая полученные данные я нашёл закономерность для получения адреса нужной структуры данных. В результате чего появилась на свет  утилита ixl_unlock. Утилита была проверена на работоспособность с версией драйвера ixl 1.6.6 и версией firmware:
dev.ixl.0.fw_version: fw 5.0.40043 api 1.5 nvm 5.05 etid 800028a2 oem 1.262.0
Чтобы проверить, находит ли она нужные данные, надо использовать её с ключиком -g:
# ./ixl_unlock -g ixl0
EMP SR: 0x66ac
PHY CAP DATA OFFSET: 0x67fa
PHY Capability data structure 0:
000067fa  00  0x000b (Section Length) should be 0x000b
000067fa  01  0x0003
000067fa  02  0x0880
000067fa  03  0x00f0
000067fa  04  0x0000
000067fa  05  0x0000
000067fa  06  0x0e0d
000067fa  07  0x0000
000067fa  08  0x0f08 (PHY Capabilities Misc0) <== will be modified
000067fa  09  0x0000
000067fa  0a  0x0a1e (40 LESM Timer Values) should be 0x0a1e
000067fa  0b  0x0001

Если подписанные данные соответствуют действительности, значит утилита будет работать с вашей картой и можно запускать её с ключом -u. Если нет - вероятно что-то изменилось в расположении структур данных в прошивке и утилиту использовать нельзя.