NAT(NAPT) и CG-NAT на оборудовании Cisco ASR1000 / CSR1000V

Задача: имея внешний пул IP-адресов (например, два префикса /24), организовать трансляцию приватных адресов на имеющиеся реальные адреса. В этой статье приватными адресами будут 100.64.0.0/16, а реальными 198.51.100.0/24 и 203.0.113.0/24.

Обычный NAPT

Cisco ASR1k / CSR1000V network scheme

При написании этой заметки использовался виртуальный маршрутизатор 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))
Screenshot - wireshark - nat-nfl-v9-create-translation

Screenshot - wireshark - nat-nfl-v9-delete-translation

Таймауты и лимиты

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 же всё как надо:
Screenshot - wireshark - nat-nfl-v9-bpa
Нераспознанные аттрибуты это и есть информация о портах. 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, конфигурация которого легла в основу эту статьи.

Advertisements

4 thoughts on “NAT(NAPT) и CG-NAT на оборудовании Cisco ASR1000 / CSR1000V

  1. dima

    спасибо за статью!
    как раз купили 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

    Reply
    1. Sergey Post author

      Сгенерируйте большее количество соединений, например 100000, будут использоваться и другие внешние адреса

      Reply
  2. aza

    Как происходит доставка сообщений, без destination address cgn nat ? Можете обьяснить подробно, как можно увеличить пул сессии

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s