Задача: имея внешний пул IP-адресов (например, два префикса /24), организовать трансляцию приватных адресов на имеющиеся реальные адреса. В этой статье приватными адресами будут 100.64.0.0/16, а реальными 198.51.100.0/24 и 203.0.113.0/24.
Обычный NAPT
При написании этой заметки использовался виртуальный маршрутизатор CSR1000V (IOS-XE 3.13.01.S), программный эквивалент оборудования Cisco ASR 1000 Series. Минимальная конфигурация для реализации этой схемы:
interface GigabitEthernet1 ip address 192.0.2.1 255.255.255.252 ip nat outside ! interface GigabitEthernet2 ip address 100.64.0.1 255.255.255.252 ip nat inside ! ip route 0.0.0.0 0.0.0.0 192.0.2.2 ip route 100.64.0.0 255.255.0.0 100.64.0.2 ip route 198.51.100.0 255.255.255.0 Null0 ip route 203.0.113.0 255.255.255.0 Null0 ! ip access-list extended nat-cust permit ip 100.64.0.0 0.0.255.255 any ! ip nat translation syn-timeout 10000 //исключительно для удобства тестирования ip nat translation max-entries 512000 //лимит по умолчанию всего 128к ip nat pool nat-pool prefix-length 24 address 198.51.100.0 198.51.100.255 address 203.0.113.0 203.0.113.255 ip nat inside source list nat-cust pool nat-pool overload //задаёт какие серые адреса в какие белые NAT-ить
Далее возникает вопрос, каким образом будут распределяться реальные адреса, будет ли постоянна связки customer source ip и external source ip, каким образом логировать трансляции и сопутствующие вопросы.
Если внешний IP для одного и того же серого адреса будет “плавающим”, то это может привести к проблемам с некоторыми сервисами/приложениями, которые привязывают IP к “сессии”. Проверим работу такой конфигурации NAT с помощью 4101 tcp syn-пакета, имеющих 4 различных(случайных) ip.source и случайный ip.destination, отправив этот трафик в интерфейс Gi2(от абонента).
for x in range(0, 4100): ip = IP() ip.src = "100.64.%i.%i" % (random.randint(1,4),0) ip.dst = "200.%i.%i.%i" % (random.randint(0,255),random.randint(0,255),random.randint(0,255)) tcp = TCP() tcp.sport = random.randint(1,65535) tcp.dport = random.randint(1,65535) tcp.flags = 'S' send(ip/tcp, verbose=0) sys.stdout.write(".") sys.stdout.flush()
Запуск: “cat synflood.py | scapy”. Смотрим результат:
nat#show ip nat translations Pro Inside global Inside local Outside local Outside global ... tcp 203.0.113.5:835 100.64.4.0:6571 200.41.6.219:40643 200.41.6.219:40643 tcp 203.0.113.6:995 100.64.4.0:26565 200.161.156.237:25669 200.161.156.237:25669 tcp 203.0.113.0:652 100.64.2.0:4714 200.79.143.230:28084 200.79.143.230:28084 ...
Отсюда видно, что в одной tcp-сессии ip.src 100.64.4.0 транслировался в 203.0.113.5, а в другой в 203.0.113.6. Это уже не очень хорошо. Теперь попробуем понять как внешний IP будет зависеть от IP адреса назначения(ip.dst). Сгенерируем 10001 tcp syn-пакет, у которых будут 4 различных(случайных) ip.src и примерно 2К различных(случайных) ip.dst. Для этого нужно исправить скрипт следующим образом:
for x in range(0, 10000): ... ip.dst = "200.%i.%i.%i" % (0,random.randint(0,7),random.randint(0,255)) ...
Проверив всего несколько ip.dst, находится пример, подтверждающий, что внешний адрес не является детерминированной функцией от внутреннего ip.src и ip.dst:
nat#show ip nat trans | i 200.0.0.142 tcp 203.0.113.1:961 100.64.4.0:27343 200.0.0.142:59773 200.0.0.142:59773 tcp 203.0.113.2:722 100.64.3.0:39613 200.0.0.142:36955 200.0.0.142:36955 tcp 203.0.113.13:830 100.64.4.0:39848 200.0.0.142:58626 200.0.0.142:58626 tcp 203.0.113.12:1026 100.64.3.0:32046 200.0.0.142:51226 200.0.0.142:51226 tcp 203.0.113.9:552 100.64.2.0:20313 200.0.0.142:15225 200.0.0.142:15225
(см. на пары строк (2,4) и (3,5)).
И наконец, проверим сценарий, когда tcp.dport фиксированный, например равен 80. Проверив несколько ip.dst опять же находится подтверждение тому, что внешний ip для одного и того же абонента, обращающегося к одному и тому же ip.dst:tcp.dport, является “плавающим”:
nat#show ip nat trans | i 200.0.6.214 tcp 203.0.113.4:793 100.64.2.0:21889 200.0.6.214:80 200.0.6.214:80 tcp 203.0.113.2:645 100.64.3.0:7375 200.0.6.214:80 200.0.6.214:80 tcp 203.0.113.13:698 100.64.4.0:8859 200.0.6.214:80 200.0.6.214:80 tcp 203.0.113.2:778 100.64.4.0:46802 200.0.6.214:80 200.0.6.214:80 tcp 203.0.113.1:731 100.64.2.0:39387 200.0.6.214:80 200.0.6.214:80
Здесь видно, что 100.64.2.0 транслировался в 203.0.113.4 и 203.0.113.1 (строки 2 и 6), а 100.64.4.0 в 203.0.113.13 и 203.0.113.2 (строки 4 и 5). Многие онлайн банки такому посетителю точно рады не будут и тут можно расчитывать лишь на http(s) keep-alive.
Таким образом, many-to-many NAT с настройками как в этом примере можно смело забраковать. В качестве workaround-а можно явно задавать маппинги серая сеть->белый ip, например 100.64.0.0/24->203.0.113.0, 100.65.0.0/24->203.0.113.1, но такой подход не очень удобен для оператора, т.к. требуется оценка распределения(заполнения) серых ip-адресов и коррекция маппингов при её изменении(если требуется более-менее равномерное распределение абонентов по IP-адресам). Для предприятий же такая явная схема распределения внешних IP-адресов, чаще всего, подходит.
Почему же нельзя всех абонентов занатить в 1 внешний IP? В самом деле, есть одно фундаментальное ограничение, на один и тот же ip.dst:tcp.dport может быть не более 65К tcp-сессий, т.е. если у вас 65К абонентов онлайн и все они одновременно полезли на какой-нибудь сайт (у которого всего 1 IP-адрес у DNS-имени), то этот ресурс исчерпается. Но куда быстрее вы столкнётесь с другой неприятностью – капчей (картинкой из букв) у поисковых систем и некоторых других ресурсов. Тут даже не нужно иметь 65К абонентов онлайн, даже 500 абонентов за одним IP могут добиться капчи, а могут и не добиться, зависит от их активности и наличия вирусов на компьютерах, делающих поисковые запросы. Именно по этой причине задача NAT many-to-many является актуальной в ISP.
PAP (Paired-Address-Pooling)
Начиная с IOS-XE 3.9S появилась возможность связывания inside local и inside global адресов (т.е. серого и реального адресов), как бы решающая проблему “плавающего” внешнего адреса абонента. Механизм работает следующим образом: при создании первой трансляции от абонента, происходит привязка внутреннего адреса к внешнему и эта привязка действует до тех пор, пока есть хотя бы одна запись в таблице трансляций, относящася к этому абоненту. Перефразировать это можно следующим образом, “пока есть активность от абонента, его внешний ip-адрес остаётся постоянным”, а дальше всё упирается в сконфигурированные таймауты, позволяющие делать абоненту паузы между потреблением трафика и при этом не меняя внешней IP абоненту. Команда для включения этого функционала:
ip nat settings pap
После того как не останется ни одной трансляции, относящейся к рассматриваемому абоненту, внешний IP может изменится. Кроме очевидных таймаутов (tcp, tcp-syn, dns и т.п.) есть один интересный таймаут за счёт которого поддерживается связывание внутреннего и внешнего адреса, а именно finrst-timeout(“ip nat translation finrst-timeout”), который сохраняет трансляцию в течение заданного времени, хотя tcp-соединение уже завершено или сброшено (по умолчанию равен 60 секундам). Такие трансляции выглядят следующим образом:
#show ip nat translations verbose Pro Inside global Inside local Outside local Outside global tcp 203.0.113.11:1024 100.64.0.2:56767 192.0.2.2:5001 192.0.2.2:5001 create: 11/04/14 15:00:06, use: 11/04/14 15:00:48, timeout: 00:00:59 Map-Id(In): 1 Flags: timing-out Appl type: none Mac-Address: 0000.0000.0000 Input-IDB: GigabitEthernet2 entry-id: 0xe89bef50, use_count:1
Кроме связывания адресов, PAP даёт возможность (от которой нельзя отказаться) ограничения количества внутренних адресов на один внешний (по умолчанию этот лимит равен 120). Конфигурируется с помощью команды “ip nat settings pap limit LIMIT”.
Логирование трансляций с помощью syslog
Это наиболее простой способ, но далеко не самый эффективный с точки зрения потребления ресурсов самого NAT-устройства и syslog-сервера, который собирает эти логи. В первом приближении настраивается так:
no logging console ip nat log translations syslog logging host 192.0.2.2
При этом логи будут попадать на сервер 192.0.2.2 и локальный log-buffer. loghost-сообщения выглядят следующим образом:
192.0.2.1.50425 > 192.0.2.2.514: [udp sum ok] SYSLOG, length: 210 Facility local7 (23), Severity info (6) Msg: 253: *Nov 4 15:26:06.187: %IOSXE-6-PLATFORM: F0: cpp_cp: QFP:0.0 Thread:000 TS:00000077488544760730 %NAT-6-LOG_TRANSLATION: Deleted Translation ICMP 100.64.0.2:4761 203.0.113.11:1 1.1.1.1:4761 1.1.1.1:1 0 192.0.2.1.50425 > 192.0.2.2.514: [udp sum ok] SYSLOG, length: 210 Facility local7 (23), Severity info (6) Msg: 254: *Nov 4 15:26:06.414: %IOSXE-6-PLATFORM: F0: cpp_cp: QFP:0.0 Thread:000 TS:00000077488775891403 %NAT-6-LOG_TRANSLATION: Created Translation ICMP 100.64.0.2:4761 203.0.113.11:1 1.1.1.1:4761 1.1.1.1:1 0
Логирование трансляций с помощью netflow v9
Это значительно более эффективный способ логирования по сравнению с классическим syslog за счёт того, что используется бинарный формат сообщения, а также в одном udp-пакете помещается сразу несколько записей о трансляциях. Настройка:
ip nat log translations flow-export v9 udp destination 192.0.2.2 10000
После чего на 192.0.2.2:10000 будет отправляться информация о трансляциях. Шаблон netflow v9 отправляется периодически. Если будете работать с wireshark, то нужно дождаться пока будет отправлен шаблон, чтобы wireshark понял как именно интерпретировать информацию о flow. Ниже представлены два скриншоты flow-потоков из wireshark (1ый с созданием трансляций(nat event: 1), 2ой с удалением(nat event: 2))
Таймауты и лимиты
Cisco ASR1k/CSR1000V позволяют конфигуририровать таймауты трансляций и различные ограничения по утилизации таблицы трансляций. Особых разъяснений здесь не требуется, достаточно вызвать подсказку “ip nat translation ?” и “ip nat translation max-entries ?”. Посмотреть текущие таймауты можно командой “show platform hardware qfp active feature nat datapath time”.
CGN NAT44
Зачем нужен режим CGN? В случае с ASR1k, это даёт в 2 раза больше трансляций, например для ESP40 в обычном режиме (описанном выше) имеем 2М трансляций, а в CGN mode 4М трансляций(архив). На первый взгляд не ясно много это или мало и как это соотнести с производительностью ESP-карты. Из практики – на 10G-in+10G-out трафика приходится порядка 800К трансляций, т.е. если загрузить ESP40 на 30G-in+30G-out(с чем эта карта справится), то получим примерно 2.5М трансляций при ограничении в 2М. Поэтому придётся включать режим CGN.
Включается режим CGN так:
ip nat settings mode cgn no ip nat settings support mapping outside
(вторая команда должна появиться сама, после ввода первой)
А трансляции при этом выглядят несколько иначе, в отличии от обычного NAT:
nat#show ip nat translations Pro Inside global Inside local Outside local Outside global tcp 203.0.113.5:1033 100.64.36.5:11538 --- --- tcp 203.0.113.5:1029 100.64.35.5:28479 --- ---
За счёт отсутствия destination ip-адреса в трансляции достигается бо’льшее количество трансляций. Исходя из этого становится очевидно, что в режиме CGN на один внешний IP-адрес может приходится не более 65К трансляций.
В режиме CGN внешний IP-адрес является плавающим (чтобы не наскучивать скриптами для scapy не буду это демонстрировать). Для предотвращения такого поведения, по аналогии с default mode, нужно использовать функционал PAP. При включении функционала PAP, например с limit=60, 60 абонентов делят ресурс 65К трансляций, т.е. жётского лимит в ~1К трансляций на абонента при этом нет. Каким-то абонентам нужно всего 100 трансляций, а другим 3000. Однако рекомендуется установить верхний лимит трансляций на абонента, например 5000, чтобы один абонент не смог израсходовать все 65К трансляций и тем самым мешать работать другим своим “соседям” по внешнему IP.
Именно из-за лимита в 65К трансляций на 1 внешний IP, функционал CGN может быть не применим для enterprise’а имеющего всего 1 внешний адрес, можно упереться в это ограничение.
BPA (Bulk Port Allocation), логирование в syslog и netflow
Второе, что нам даёт CGN это выделение портов блоками, что в свою очередь позволяет реализовать очень эффективное логирование трансляций (начиная с версии IOS-XE 3.10S). Например, выделяя по 512 портов за раз, не нужно логировать каждую отдельную трансляцию, достаточно залогировать сам факт выделения этого блока портов абоненту. Пример настройки:
ip nat settings pap limit 60 bpa set-size 512
(О значении параметров bpa можно прочитать здесь(архив))
К сожаленью, логирование bpa не реализовано с помощью syslog. При включении bpa логи трансляций выглядят точно также как и в default mode:
Nov 4 17:20:08.937: %IOSXE-6-PLATFORM: F0: cpp_cp: QFP:0.0 Thread:000 TS:00000084331300685347 %NAT-6-LOG_TRANSLATION: Created Translation TCP 100.64.34.10:50328 203.0.113.5:23553 200.0.1.65:80 200.0.1.65:80 0
Т.е. логируется каждая создаваемая трансляция (также стоит заметить, что в логе трансляции присутствует destination ip, хотя в таблице трансляций в cgn mode его нет).
В netflow же всё как надо:
Нераспознанные аттрибуты это и есть информация о портах. type 361 = Port block start, type 363 = Port block step size, type 364 = Number of ports in the block (По этому поводу отправлен bug report разработчикам wireshark). На пример из скриншота, для flow 1: port-block-start=0x3000=12288, step-size=1, block-size=0x200=512.
С учётом того, что на абонента приходится порядка 200 трансляций (в среднем), то получаем снижение объёма данных логирования примерно в 200 раз. Остаётся лишь научить коллектор понимать такие flow-потоки.
P.S. Выражаю благодарность Егору Сюндюкову за проделанную работу по настройке NAT на ASR1k, конфигурация которого легла в основу эту статьи.
Отличная статья!
спасибо за статью!
как раз купили asr1001 с ios 03.13.01.S, стоит задача настроить обычный napt как в первом пункте. и сразу вопрос: все соединения транслируются в один внешний адрес, хотя указан пул. конфиг:
interface GigabitEthernet0/0/0.10
ip address 10.0.0.254 255.255.255.252
ip nat outside
!
interface GigabitEthernet0/0/1.11
ip address 10.50.0.1 255.255.255.0
ip nat inside
!
ip access-list extended NAT
permit ip 10.50.0.0 0.0.255.255 any
ip nat pool NAT 185.0.0.0 185.0.0.7 prefix-length 29
ip nat inside source list NAT pool NAT overload
!
ip route 185.0.0.0 255.255.255.248 Null0
!
трансляции:
tcp 185.0.0.0:1133 10.50.0.2:49206 94.100.180.200:443 94.100.180.200:443
tcp 185.0.0.0:1165 10.50.0.2:49874 193.0.170.53:443 193.0.170.53:443
tcp 185.0.0.0:1156 10.50.0.2:4705 185.50.24.116:80 185.50.24.116:80
tcp 185.0.0.0:1157 10.50.0.2:49860 217.69.139.59:443 217.69.139.59:443
tcp 185.0.0.0:1030 10.50.0.2:50333 94.100.191.58:2042 94.100.191.58:2042
Сгенерируйте большее количество соединений, например 100000, будут использоваться и другие внешние адреса
Как происходит доставка сообщений, без destination address cgn nat ? Можете обьяснить подробно, как можно увеличить пул сессии
Buy game accounts cheap