Как известно, адресное пространство IPv4 практически исчерпано, а переход на IPv6 затянулся на долгие годы и особого прогресса в нём до сих пор нет. В то же время, Интернет развивается, провайдеры строят сети и всё более острой становится проблема дефицита IP. Частично «уплотнить» IP пулы позволяет использование BRAS и динамическая адресация, но, в конечном счёте, дело идёт к массовому NAT.
Вступление
NAT (Network Address Translation) — в общем случае технология изменения source или destination IP адреса в пакете на какой-то другой. Чаще всего (в том числе в этой статье) речь идёт о частном случае — napt44, он же inside source NAT with overload, он же PAT (Port Address Translation). Суть этой технологии в том, что меняется не только source IP, но и source port в L4 заголовке, и в специальную таблицу заносится соответствие inside IP/inside port — outside IP/outside port, и эта же таблица используется для трансляции обратного трафика. Всё это позволяет нескольким хостам выходить в Интернет, используя один и тот же реальный IP адрес. Хостам же назначаются т.н. «серые» адреса, которые маршрутизируются только в пределах локальной сети и не являются уникальными в Интернете. У технологии множество минусов, и, по мнению многих, она является костылём, но пока что это практически единственный способ давать пользователям доступ в Интернет в условиях нехватки IP адресов (nat64 с dns-alg ещё намного ужаснее и костыльнее).
RFC 6598 определяет специальный диапазон серых IP для CGN — 100.64.0.0/10. Несмотря на это, многие используют привычные всем серые IP из RFC1918. Когда речь идёт о небольшой сети и трафике до нескольких гигабит, со всем вышенаписанным справится обычный сервер с Linux/FreeBSD или софтовый роутер. Но при более высоких нагрузках появляется необходимость использовать специальное железо. Последние несколько лет вендоры активно работают над этим, мне известно о решениях у Cisco, Juniper, Huawei с заявленной производительностью от 20 до 80 Gbps на слот. Общие принципы у всех одинаковы, но в примерах я буду приводить Juniper, так как имею опыт внедрения CGN решения на оборудовании этого вендора. Кроме того, мне известно о решении на оборудовании Huawei у одного из операторов. О внедрённых решениях CGN от Cisco (на базе ASR 9000) я не слышал (что неудивительно при их ценах), но наверняка где-то в мире есть.
Расчёт пулов и аллокация портов
Первая и очевидно возникающая задача — расчёт количества L4 портов и белых IP для нат пула. Примем 64к портов на IP адрес (well-known ports для NAT не используются). У NAT карты, в свою очередь, есть своё ограничение по количеству сессий. К примеру, у MS-DPC это 4 миллиона сессий (в каждую сторону) на каждый из двух PIC'ов (Physical Interface Card). Поделив 4000000 на 64000, получим 62.5, что соответствует /26 сети (64 адреса). Однако, аллокация портов по одному приведёт к деградации производительности сервисной карты, поэтому мы будем использовать PBA (Port Block Allocation). Эта фича позволяет выделять для абонента блок портов при установке первого соединения, и дальше использовать порты из этого блока. Обратной стороной такой конфигурации будет неполный расход L4 портов, так что придётся использовать больший пул белых IP для достижения полной утилизации карты.
> show configuration services nat pool sp101
address 1.1.1.0/24;
port {
automatic {
random-allocation;
}
secured-port-block-allocation block-size 1024 max-blocks-per-address 4 active-block-timeout 300;
}
address-allocation round-robin;
Подсеть /24 позволит использовать почти 16к портов на каждый белый IP, пользователю выделяются блоки по 1к портов (максимум 4 блока) с таймаутом в 5 минут. Juniper рекомендует создавать блоки из расчёта в 2 или 4 раза больше, чем реально использует абонент.
Кроме того, стоит упомянуть две важные опции:
- Address Pooling — все соединения с одного серего IP транслируются в один и тот же белый. Рекомендуется включать, иначе могут возникнуть проблемы с приложениями, устанавливающими несколько сессий (в случае, если произойдёт трансляция в разные белые IP).
- EIM (Endpoint Independent Mapping) — соединениям с одним и тем же сочетанием серый IP/source port назначается то же сочетание белый IP/external source port. По сути — костыль для некоторых приложений, обычным домохозяйкам, которых и сажаем за NAT, это не надо.
Так выглядит правило трансляций:
> show configuration services nat rule sp101
match-direction input;
term t10 {
from {
source-address {
100.64.0.0/10;
}
}
then {
translated {
source-pool sp101;
translation-type {
napt-44;
}
address-pooling paired;
}
}
}
Кроме метода аллокации портов, в целях безопасности стоит ещё установить ограничение по количеству одновременных соединений для пользователя. Обычный пользователь очень редко будет использовать больше, чем 200-300 одновременных сессий, но некоторые приложения (в основном торрент) могут быстро забить этот лимит. К счастью, MS-DPC умеет быть IDS'ом (вообще, lookup block в любой линейной карте построенной на Trio архитектуре, умеет аппаратно разбирать до 256 байт в пакете, но сейчас нам это не надо). Так что можно поставить отдельный лимит на количество UDP сессий по портам выше, чем well known, и отдельный лимит для всего остального трафика.
Шаблон приложения:
> show configuration applications
application all_udp {
protocol udp;
destination-port 1024-65535;
}
Правило IDS:
> show configuration services ids
rule nat_max_flows {
match-direction input;
term t10 {
from {
applications all_udp;
}
then {
session-limit {
by-source {
maximum 400;
}
}
}
}
term t20 {
then {
session-limit {
by-source {
maximum 600;
}
}
}
}
}
Как показывает практика, такого лимита хватает с запасом. UDP с номерами портов выше 1024, как правило, использует или торрент или онлайн игры, вряд-ли пользователь будет включать и то и другое одновременно; важно же то, что включенный торрент не помешает другим приложениям большим количеством одновременно открытых соединений. Конечно, решение может показаться слегка «костыльным», но это соответствует парадигме NAT. У меня был единственный инцидент, когда по ошибке или незнанию выдали серый IP какой-то фирме, судя по всему, с немалым количеством пользователей (которые сидят за их внутренним натом), им не хватило и 4к сессий. Разумеется, таким надо давать белый IP.
К вопросу безопасности стоит упомянуть ещё важную вещь: кровавый режим некоторых стран требует от провайдера раскрытия личности абонента по IP. NAT тут добавляет проблем, т.к. за белым IP сидит несколько абонентов. Решается это логированием каждого установленного соединения (нагружает сервисную карту) или использованием deterministic PBA. Конфигурируется почти так же, как и secured PBA, но отличается алгоритм аллокации портов, таким образом по сочетанию [белый IP]:[source port] можно однозначно определить серый IP, который был транслирован. Подробнее по ссылке.
> show configuration services nat pool sp101
address 1.1.1.0/24;
port {
automatic {
random-allocation;
}
deterministic-port-block-allocation block-size 1024;
}
address-allocation round-robin;
Изменение способа аллокации портов на MS-DPC требует перезагрузки платы или PIC, но у нас же Carrier Grade, так что должен сразу срабатывать резерв, о чём ниже.
Настройка трансляции
Указанные выше правила теперь нужно прицепить к service-set. Их в Junos есть 2 типа: interface style и next-hop style. Первый проще:
> show configuration services service-set sp101
nat-rules sp101;
ids-rules nat_max_flows;
interface-service {
service-interface sp-10/1/0;
}
И указанной конфигурации достаточно, чтоб NAT наконец заработал. Но возникнут проблемы с резервированием и балансировкой трафика, так что лучше использовать next-hop style service-set.
> show configuration services service-set sp101
nat-rules sp101;
ids-rules nat_max_flows;
next-hop-service {
inside-service-interface sp-10/1/0.10;
outside-service-interface sp-10/1/0.20;
}
> show configuration interfaces sp-10/1/0
unit 10 {
family inet;
service-domain inside;
}
unit 20 {
family inet;
service-domain outside;
}
Схема прохождения трафика через роутер при использовании next-hop style service-set. Здесь используется пример inline NAT на обычной линейной карте с Trio чипсетом, но в PAT на MS-DPC принцип тот же.
Теперь нам осталось направить трафик, подлежащий NAT, на сервисный интерфейс sp-10/1/0 unit 10, а обратный трафик будет приходить на unit 20. Делается это при помощи FBF (Firewall Based Forwarding), аналог PBR в Cisco.
> show configuration firewall family inet filter Nat
term t10 {
from {
source-address {
100.64.0.0/10;
}
}
then {
routing-instance Nat;
}
}
term t20 {
then accept;
}
> show configuration interfaces irb unit 50
family inet {
mtu 1500;
filter {
input Nat;
}
address 2.2.2.2/30;
}
Соответственно, создаётся routing instance. В Junos их есть несколько типов, включая VRF, для данной задачи проще всего использовать тип инстанса forwarding. Это просто дополнительная таблица маршрутизации, в которую можно импортить маршруты при помощи rib-groups. Rib-groups — очень мощный инструмент в Junos с довольно широким применением, на хабре была про него статья.
> show configuration routing-instances Nat
instance-type forwarding;
routing-options {
static {
route 0.0.0.0/0 next-hop [ sp-8/0/0.10 sp-8/1/0.10 sp-10/0/0.10 sp-10/1/0.10 ];
}
}
В данном примере используются 2 MS-DPC в 8-м и 10-м слотах маршрутизатора, каждая из карт имеет 2 PIC, каждому из которых соответствует сервисный интерфейс. При этом создаётся таблица маршрутизации Nat.inet.0, в которую надо импортировать directly connected маршруты:
> show configuration routing-options interface-routes
rib-group inet iface_rib;
> show configuration routing-options rib-groups iface_rib
import-rib [ inet.0 Nat.inet.0 ];
Подробнее про rib-groups можно почитать в приведённой выше статье.
Трафик балансируется между сервисными интерфейсами и в случае падения одной из карт переходит на исправную. Для балансировки применяются общие в Junos настройки L2 и L3 лоад балансинга.
> show configuration policy-options policy-statement load_balance
then {
load-balance per-packet;
}
> show configuration routing-options forwarding-table
export load_balance;
> show configuration forwarding-options hash-key
family inet {
layer-3;
layer-4;
}
Опция hash-key работает только для DPC карт. Для новой NAT карты MS-MPC, а также обычных линейных карт (которые на Trio чипсете) используется опция enhanced-hash-key. Есть ещё нюанс, который не описан в мануалах, но я обнаружил при тестировании: при использовании в хэш-кее L3 и L4 заголовков, производительность MS-DPC для NAT вырастает примерно на 20-25%, по сравнению с использованием только L3, что довольно существенно. Инженер Juniper подтвердил это и порекомендовал использовать L3+L4, но я не знаю, проводил ли он какие-то дополнительные тесты. Впрочем, всё это уже не очень актуально, т.к. для новых инсталляций используется более производительная MS-MPC.
На этом конфигурацию CGN можно считать законченной. Можно жёстко привязывать серые подсети к определённому белому IP, чтоб не ругались системы безопасности некоторых интернет ресурсов, но, как показала практика, большой необходимости в этом нет. Делать обратный (destination) NAT, как и статический NAT 1 в 1 для некоторых абонентов — тоже плохая идея, т.к. это создаёт лишнюю нагрузку на NAT карту, а белые IP не экономит. Проще выдавать таким клиентам белые IP. Задачу по разделению трафика по входящему интерфейсу (актуально для многих украинских провайдеров по историческим причинам) я решил методом домосетей с линуксовыми роутерами: маркировка dscp на входе и фильтр на сервисном интерфейсе. Если кто-то заинтересуется, расскажу подробнее, но всё довольно очевидно. Интересно, что архитектура MX позволяет на одном и том же роутере промаркировать пакет и на основе этой же маркировки принимать решение.
Всем коллегам желаю успешного внедрения CGN, но не стоит забывать, что это только временное решение перед переходом на IPv6. Не превращайте его в решение постоянное. Не надо так.
Литература
- Carrier Grade NAT Implementation Guide
- Junos Address Aware Carrier Grade NAT and IPv6 Feature Guide
- CGN Implementation: Best Practices
- Juniper MX Series: A Comprehensive Guide to Trio Technologies on the MX
- Wikipedia: NAT
- RFC 6888
- RFC 6598
Автор: Levor