Setup nat on linux

Быстрый роутинг и NAT в Linux

По мере исчерпания адресов IPv4, многие операторы связи столкнулись с необходимостью организовывать доступ своих клиентов в сеть с помощью трансляции адресов. В этой статье я расскажу, как можно получить производительность уровня Carrier Grade NAT на commodity серверах.

Немного истории

Тема исчерпания адресного пространства IPv4 уже не нова. В какой-то момент в RIPE появились очереди ожидания (waiting list), затем возникли биржи, на которых торговали блоками адресов и заключались сделки по их аренде. Постепенно операторы связи начали предоставлять услуги доступа в Интернет с помощью трансляции адресов и портов. Кто-то не успел получить достаточно адресов, чтобы выдать «белый» адрес каждому абоненту, а кто-то начал экономить средства, отказавшись от покупки адресов на вторичном рынке. Производители сетевого оборудования поддержали эту идею, т.к. этот функционал обычно требует дополнительных модулей расширения или лицензий. Например, у Juniper в линейке маршрутизаторов MX (кроме последних MX104 и MX204) выполнять NAPT можно на отдельной сервисной карте MS-MIC, на Cisco ASR1k требуется лицензия СGN license, на Cisco ASR9k — отдельный модуль A9K-ISM-100 и лицензия A9K-CGN-LIC к нему. В общем, удовольствие стоит немалых денег.

IPTables

Задача выполнения NAT не требует специализированных вычислительных ресурсов, ее в состоянии решать процессоры общего назначения, которые установлены, например, в любом домашнем роутере. В масштабах оператора связи эту задачу можно решить используя commodity серверы под управлением FreeBSD (ipfw/pf) или GNU/Linux (iptables). Рассматривать FreeBSD не будем, т.к. я довольно давно отказался от использования этой ОС, так что остановимся на GNU/Linux.

Включить трансляцию адресов совсем не сложно. Для начала необходимо прописать правило в iptables в таблицу nat:

iptables -t nat -A POSTROUTING -s 100.64.0.0/10 -j SNAT --to - --persistent 

Операционная система загрузит модуль nf_conntrack, который будет следить за всеми активными соединениями и выполнять необходимые преобразования. Тут есть несколько тонкостей. Во-первых, поскольку речь идет о NAT в масштабах оператора связи, то необходимо подкрутить timeout’ы, потому что со значениями по умолчанию размер таблицы трансляций достаточно быстро вырастет до катастрофических значений. Ниже пример настроек, которые я использовал на своих серверах:

net.ipv4.ip_forward = 1 net.ipv4.ip_local_port_range = 8192 65535 net.netfilter.nf_conntrack_generic_timeout = 300 net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 60 net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60 net.netfilter.nf_conntrack_tcp_timeout_established = 600 net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 45 net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 net.netfilter.nf_conntrack_tcp_timeout_close = 10 net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300 net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300 net.netfilter.nf_conntrack_udp_timeout = 30 net.netfilter.nf_conntrack_udp_timeout_stream = 60 net.netfilter.nf_conntrack_icmpv6_timeout = 30 net.netfilter.nf_conntrack_icmp_timeout = 30 net.netfilter.nf_conntrack_events_retry_timeout = 15 net.netfilter.nf_conntrack_checksum=0 

И во-вторых, поскольку по умолчанию размер таблицы трансляций не рассчитан на работу в условиях оператора связи, его необходимо увеличить:

net.netfilter.nf_conntrack_max = 3145728 

Также необходимо увеличить и количество buckets для хэш-таблицы, хранящей все трансляции (это опция модуля nf_conntrack):

options nf_conntrack hashsize=1572864 

После этих нехитрых манипуляций получается вполне работающая конструкция, которая может транслировать большое количество клиентских адресов в пул внешних. Однако, производительность этого решения оставляет желать лучшего. В своих первых попытках использования GNU/Linux для NAT (примерно 2013 год) я смог получить производительность около 7Gbit/s при 0.8Mpps на один сервер (Xeon E5-1650v2). С того времени в сетевом стеке ядра GNU/Linux было сделано много различных оптимизаций, производительность одного сервера на том же железе выросла практически до 18-19 Gbit/s при 1.8-1.9 Mpps (это были предельные значения), но потребность в объеме трафика, обрабатываемого одним сервером, росла намного быстрее. В итоге были выработаны схемы балансировки нагрузки на разные серверы, но всё это увеличило сложность настройки, обслуживания и поддержания качества предоставляемых услуг.

Читайте также:  Чем смонтировать образ iso linux

NFTables

Сейчас модным направлением в программном «перекладывании пакетиков» является использование DPDK и XDP. На эту тему написана куча статей, сделано много разных выступлений, появляются коммерческие продукты (например, СКАТ от VasExperts). Но в условиях ограниченных ресурсов программистов у операторов связи, пилить самостоятельно какое-нибудь «поделие» на базе этих фреймворков довольно проблематично. Эксплуатировать такое решение в дальнейшем будет намного сложнее, в частности, придется разрабатывать инструменты диагностики. Например, штатный tcpdump с DPDK просто так не заработает, да и пакеты, отправленные назад в провода с помощью XDP, он не «увидит». На фоне всех разговоров про новые технологии вывода форвардинга пакетов в user-space, незамеченными остались доклады и статьи Pablo Neira Ayuso, меинтейнера iptables, про разработку flow offloading в nftables. Давайте рассмотрим этот механизм подробнее.

Основная идея заключается в том, что если роутер пропустил пакеты одной сессии в обе стороны потока (TCP сессия перешла в состояние ESTABLISHED), то нет необходимости пропускать последующие пакеты этой сессии через все правила firewall, т.к. все эти проверки всё равно закончатся передачей пакета далее в роутинг. Да и собственно выбор маршрута выполнять не надо — мы уже знаем в какой интерфейс и какому хосту надо переслать пакеты пределах этой сессии. Остается только сохранить эту информацию и использовать ее для маршрутизации на ранней стадии обработки пакета. При выполнении NAT необходимо дополнительно сохранить информацию об изменениях адресов и портов, преобразованных модулем nf_conntrack. Да, конечно, в этом случае перестают работать различные полисеры и другие информационно-статистические правила в iptables, но в рамках задачи отдельного стоящего NAT или, например, бордера — это не так уж важно, потому что сервисы распределены по устройствам.

Конфигурация

Чтобы воспользоваться этой функцией нам надо:

  • Использовать свежее ядро. Несмотря на то, что сам функционал появился еще в ядре 4.16, довольно долго он было очень «сырой» и регулярно вызывал kernel panic. Стабилизировалось всё примерно в декабре 2019 года, когда вышли LTS ядра 4.19.90 и 5.4.5.
  • Переписать правила iptables в формат nftables, используя достаточно свежую версию nftables. Точно работает в версии 0.9.0

Конфигурация NAT очень проста:

#! /usr/sbin/nft -f table nat < chain postrouting < type nat hook postrouting priority 100; oif snat to - persistent > > 
#! /usr/sbin/nft -f table inet filter < flowtable fastnat < hook ingress priority 0 devices = < , > > chain forward < type filter hook forward priority 0; policy accept; ip protocol < tcp , udp >flow offload @fastnat; > > 

Вот, собственно, и вся настройка. Теперь весь TCP/UDP трафик будет попадать в таблицу fastnat и обрабатываться намного быстрее.

Читайте также:  Linux операционная система обзор на русском

Результаты

Чтобы стало понятно, насколько это «намного быстрее», я приложу скриншот нагрузки на два реальных сервера, с одинаковой начинкой (Xeon E5-1650v2), одинаково настроенных, использующих одно и тоже ядро Linux, но выполняющих NAT в iptables (NAT4) и в nftables (NAT5).

На скриншоте нет графика пакетов в секунду, но в профиле нагрузки этих серверов средний размер пакета в районе 800 байт, поэтому значения доходят до 1.5Mpps. Как видно, запас производительности у сервера с nftables огромный. На текущий момент этот сервер обрабатывает до 30Gbit/s при 3Mpps и явно способен упереться в физическое ограничение сети 40Gbps, имея при этом свободные ресурсы CPU.

Надеюсь, этот материал будет полезен сетевым инженерам, пытающимся улучшить производительность своих серверов.

Источник

How to Configure NAT on Ubuntu

NAT or Network Address Translation allows multiple computers on a private network to share a common IP to access the Internet. One set of IP addresses is used inside the organization and the other set is used by it to present itself to the internet. This helps in conserving limited public IP space. At the same time, it also provides security by hiding the internal network from direct access from the outside world.

How Does the NAT Work?

NAT simply converts the source address of the outgoing packet to a public IP address to make it routable on the internet. In the same way, the source address of the response packets coming from outside (internet) is converted back to local or private IP address.

What will we cover?

In this guide we will learn to set up Ubuntu 20.04 as a NAT router. For this we will use an Ubuntu VM as NAT router and another Ubuntu VM as client VM for the purpose of testing. To test the setup, we are using Virtualbox for creating and managing virtual machines(VMs).

Pre-flight Check

  1. Two Ubuntu VMs with one having two network interfaces(NICs).
  2. Ubuntu 20.04 installed on both the VMs.
  3. Administrative(sudo) access on both the VMs.

Experimental Setup

We have used the following setup for the two VMs mentioned above:

1. VM1 (NAT Router): Our Router machine has two network interfaces: enp0s3 and enp0s8 (these names may vary depending on the system). The enp0s3 interface acts as a WAN(internet) interface and is accessible from the outside world(Internet). Its IP address is assigned via DHCP and in our case it is 192.168.11.201.

The enp0s8 interface is a local or LAN interface and is accessible only on the local network where our client will be deployed. We have manually set the IP address for this interface as 10.10.10.1/24 and the “gateway address is left blank”.

2. VM2 (Client Machine): The client machine has only one local or LAN interface i.e. enp0s3. It is attached to the local network of the above machine(VM2) with the IP address set to 10.10.10.3/24. The only thing to care of is that the gateway in this case is the local interface (enp0s8) IP address of the above machine(VM2) i.e., 10.10.10.1

Читайте также:  Linux install without driver

The summary of the configuration of the two virtual machines is given in the below table:

Interface Name → enp0s3 enp0s8
VM Name ↓ IP address Gateway IP IP address Gateway IP
VM1(NAT Router ) 192.168.11.201/24 Via DHCP 10.10.10.1/24
VM2(Client) 10.10.10.3/24 10.10.10.1

Let’s Begin…

Now that we have set up the required IP addresses on our machine, we are set to configure them. Let us first check the connectivity between these machines. Both the machines should be able to ping each other. VM1, which is our NAT router machine, should be able to reach the global internet as it is connected to WAN via enp0s3. VM2, which is our local client machine, should not be able to reach the internet until we configure the NAT router on VM1. Now, follow the steps below:

Step 1. First check the IP addresses on both the machines with the command:

Step 2. Also check the connectivity of the machines before configuring the NAT router as mentioned above. You can use the ping command like:

Result for the VM1 (NAT Router VM) are shown below:

Result for the VM2 (ClientVM) are shown below:

Both the VMs are working as we have expected them to be. Now we will start configuring VM2(NAT Router).

Step 3. On VM2 open the sysctl.conf file and set the “net.ipv4.ip_forward” parameter to one by uncommenting it:

Step 4. Now enable the changes to above file using the command:

Step 5. Now, install the iptables-persistent package (boot-time loader for netfilter rules, iptables plugin) using:

Step 6. List the already configured iptable policies by issuing the command:

Step 7. Now mask the requests from inside the LAN with the external IP of NAT router VM.

$ sudo iptables -t nat -A POSTROUTING -j MASQUERADE

Step 8. Save the iptable rules using:

Testing The Setup

Now, to check if everything is working fine, ping any public IP from the VM2(client):

Note: If you want, you can add a DNS server manually in the client network configuration for domain name resolution. This will suppress the ‘Temporary failure in name resolution’. We have used the Google DNS IP i.e. 8.8.8.8 in our VM1.

We can see that ping is now working as expected on VM1(client machine).

Conclusion

NAT is a very essential tool for preserving limited public IPv4 address space. Although IPv6 is emerging next generation IP protocol which is supposed to finish the IPv4 limitations, but that’s a long way process; so until then NAT is very important for organizations.

About the author

Ali Imran Nagori

Ali imran is a technical writer and Linux enthusiast who loves to write about Linux system administration and related technologies. You can connect with him on LinkedIn
.

Источник

Оцените статью
Adblock
detector