Как работают сети: что такое свитч, роутер, DNS, DHCP, NAT, VPN и ещё с десяток необходимых вещей

Illustration of a person opening their shirt to reveal a superhero costume underneath, reminiscent of the iconic Spider-Man suit. Illustration of a person opening their shirt to reveal a superhero costume underneath, reminiscent of the iconic Spider-Man suit.

Тема сетей, к сожалению, весьма скучна для большинства наших коллег. Всем основным задействованным технологиям, протоколам и лучшим практикам уже несколько десятков лет, они давно окружают нас и обеспечивают взаимодействие миллиардов устройств вокруг. Даже программисты чаще всего воспринимают сеть как данность и не задумываются о том, как же она работает.

Часто бывает у наших коллег: вроде бы слова IP и DNS используют каждый день, а понимания как это всё работает нет, и как это всё пощупать вживую тоже непонятно. Такое отношение не только некорректно, но и вредно для карьеры любого уважающего себя инженера из IT. Сколько бы JS-фреймворков ты не выучил, без знания основ сетей тебя никто всерьёз воспринимать не будет. Ни одна часть инфраструктуры не должна оставаться чёрной коробкой ни для разработчиков, ни для администраторов, ни уж тем более для тебя, будущего DevOps инженера.

Целью этой статьи не является дать исчерпывающее руководство по сетям. Внутри самой статьи и в её конце я приведу множество ссылок на ресурсы, которые помогут тебе углубить полученные знания. Не ленись и кликай по всем ссылкам и читай их все.

В этом же тексте мы сфокусируемся на структуре сети, основных её компонентах и рассмотрим как они используются на практике при помощи уже освоенных нами в предущей статье виртуальных машин и libvirt/KVM в частности.

Сетевая модель OSI

В первую очередь нам нужно познакомиться с сетевой моделью OSI. Эта модель стандартизирует взаимодействие сетевых протоколов.

OSI делит коммуникацию на 7 слоёв, на каждом слое есть свои протоколы. Ты часто будешь слышать вещи в духе "это происходит на Layer 3". Вот эти слои:

  1. Физический уровень (physical layer)
  2. Канальный уровень (data link layer)
  3. Сетевой уровень (network layer)
  4. Транспортный уровень (transport layer)
  5. Сеансовый уровень (session layer)
  6. Представительский уровень или уровень представления (presentation layer)
  7. Прикладной уровень (application layer)
Физический уровень (physical layer)

Протоколы этого уровня отвечают за связь между железками на самом низком уровне. Непосредственная передача данных по проводам (и без проводов) описывается как раз на физическом уровне. Примеры протоколов: Wi-Fi, Bluetooth, DSL.

Канальный уровень (data link layer)

Канальный уровень отвечает за передачу данных между устройствами одной сети. Данные передаются в виде кадров (frames), в кадре указан физический адрес получателя и отправителя. Этот адрес называется MAC-адрес.

Кто же выступает в роли отправителя и получателя?

Во-первых, у каждой машины (включая твой ноут) есть NIC — Network Interface Controller. Это железка (или виртуальная железка), которая отвечает за передачу и приём кадров. У NIC есть MAC-адрес — уникальный адрес, который обычно прошит в железке, или же генерируется системой виртуализации.

Само собой, у машины может быть несколько NIC. Посмотрим интерфейсы при помощи команды ip:

[root@localhost ~]$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 52:54:00:05:36:e6 brd ff:ff:ff:ff:ff:ff

В данном случае, интерфейс, использующийся для связи с внешним миром по сети, — это eth0, обладающий MAC-адресом 52:54:00:05:36:e6. Но что такое lo?

lo — это loopback device, специальный виртуальный интерфейс, который система использует, чтобы общаться самой с собой. Благодаря lo даже без подключения к сети локальные приложения могут взаимодействовать друг с другом.

Ты уже заметил, что из твоего компьютера не вылазят миллиарды проводов, напрямую подключённые ко всем другим компьютерам мира. Для организации сети нужны дополнительные устройства.

Например, свитч (switch).

Свитч — это такое устройство, которое формирует сеть, и в которое подключаются наши машинки через порты. Задача свитча L2 (есть ещё более продвинутые, относящиеся к L3 и даже к L7) — перенаправлять кадры от MAC отправителя к MAC получателя. Множество машин, подключенных к одному свитчу формируют локальную сеть (LAN).


Конечно, пачка серверов подключенных к одному свитчу — это весьма тривиальный способ создать сеть. А что если мы хотим объединить в одну сеть сервера, находящиеся в разных физических локациях? Или, например, хотим логически разделить сервера подключенные к одному свитчу в одной локации в разные сети?

Для таких случаев создают VLAN (виртуальную локальную сеть), которую можно реализовать, например, при помощи свитча. Работает это достаточно просто: к кадрам добавляется дополнительный заголовок с VLAN-тегом, по которому и определяется к какой сети принадлежит кадр.


Другое устройство — мост (bridge). Мост L2 используют чтобы объединить две сети, сформированные при помощи свитчей, примерно таким образом:


И свитчи и мосты (а ещё хабы (hub), о которых почитай сам) помогают объединить несколько машин в одну сеть. А есть ещё маршрутизаторы (или роутеры, routers), которые соединяют сети между собой и работают уже на L3. Например, твой Wi-Fi роутер соединяет твою локальную сеть (в которой находятся твой ноутбук, телефон и планшет) с Интернетом.

Помимо LAN разделяют ещё несколько типов сетей. Например, WAN. Интернет можно считать за WAN, за тем исключением, что Интернет полностью стирает географические границы сети.


Как я уже упомянул, есть ещё свитчи L3, которые могут не просто перенаправлять кадры от одного устройства к другому, но и обладают более продвинутыми фишками, типа маршрутизации. Чем же отличается роутер от свитча L3, спросишь ты? Тут всё сложно (и скучно), но если тебе интересно, то прочитай статью Layer 3 Switches compared to Routers


Сетевой уровень (network layer)

На третьем, сетевом уровне используются не MAC, а IP адреса. Посмотрим IP адрес нашей машины при помощи той же самой команды ip:

[root@localhost ~]$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:05:36:e6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.212/24 brd 192.168.122.255 scope global dynamic eth0
       valid_lft 2930sec preferred_lft 2930sec
    inet6 fe80::5054:ff:fe05:36e6/64 scope link
       valid_lft forever preferred_lft forever

Интерфейсу eth0 присвоен адрес 192.168.122.212/24.

Но что такое /24? И почему у loopback интерфейса стоит /8? Ты уже, наверное, слышал, что всего существует 4 294 967 296 IPv4 адресов. Интернет — это не одна большая сеть, а много сетей поменьше. При этом для отдельных типов сетей (например, частных, недоступных извне сетей) выделены отдельные блоки IP адресов.

IPv6 адресов гораздо больше. Но полный переход IPv6 ещё не произошёл :-)

CIDR — это метод выделения блоков адресов отдельным сетям. А CIDR-нотация — это способ описать этот блок в виде 192.168.122.212/24, где число /24, называемое маской, как раз и позволяет понять, сколько адресов входит в этот блок.

IPv4 — это простое число длинной 32 бита, которое можно представить в двоичном виде. В двоичной форме IP адреса идут от 00000000000000000000000000000000 до 11111111111111111111111111111111. Для удобства разобьём это число на 4 части по 8 цифр: 11111111.11111111.11111111.11111111. В привычной нам десятеричной системе этот адрес выглядит так: 255.255.255.255.

Маска /24 может быть представлена как 255.255.255.0, или, в двоичной системе, 11111111.11111111.11111111.00000000. Чтобы найти первый и последний адреса сети мы можем использовать один из адресов и маску сети, применив логическое побитовое И на их двоичном представлении:

11000000.10101000.01111010.11010100
&
11111111.11111111.11111111.00000000
=
11000000.10101000.01111010.00000000

И переведём результат в человеко-читаемую форму: 192.168.122.0 — начальный адрес нашей сети. Чтобы подсчитать число доступных адресов, нужно посчитать число нулей в маске. В нашем случае нулей, или разрядов, 8. Каждый может принимать значение 1 или 0, поэтому в сумме получаем 2^8 степени, или 256 адресов. Значит, последний адрес сети будет равен 192.168.122.255.

Вручную всё считать необязательно, можно воспользоваться калькулятором.

ARP

Мы уже знаем, что на L2 используются MAC-адреса, а на L3 — IP адреса. Должен существовать какой-то механизм, который ассоциирует MAC-адрес сервера с его IP адресом. Этот механим называется ARP (Address Resolution Protocol).

В Линуксе есть одноимённая команда arp, которая позволит посмотреть табличку известных машине MAC-адресов и соответствующих им IP адресов:

[root@localhost]# arp -n
Address HWtype HWaddress Flags Mask Iface
192.168.178.1 ether 5c:49:79:99:f3:23 C wlp3s0

В данном случае, 192.168.178.1 — это IP адрес моего Wi-Fi роутера, к которому ноутбук подключен через интерфейс wlp3s0.

Команда arp считается deprecated и вместо неё рекомендуется использовать ip neigh.

Один из видов кибер-атак связан с ARP и называется ARP spoofing. Цель такой атаки — подменить MAC-адрес, ассоциированный с определённым IP, на адрес машины хакера. Как страшно жить, да?

DHCP

Но как именно у сетевого интерфейса появляется IP адрес? Один из вариантов — задать его вручную. Недостаток: ручная работа. Если руки кривые, то можно настроить дублирующиеся адреса и получить конфликт :)

Другой вариант: Dynamic Host Configuration Protocol (DHCP), протокол, использующийся для автоматического выставления различной конфигурации, в том числе IP-адресов.

За детальным изучением DHCP обратись к документации в RFC: https://www.ietf.org/rfc/rfc2131.txt

Для работы DHCP нужен DHCP-сервер, раздающий IP-адреса и DHCP-клиент на твоей машине, который будет запрашивать адрес для этой машины. В домашних условиях чаще всего DHCP-сервер находится на роутере.

Чтобы понять как именно работает DHCP, нам нужно отвлечься на понятие "broadcasting". Это процесс, в котором наш сервер отправляет сообщение на все сервера в сети, так как он не знает где именно находится та информация, которая ему нужна. Ближе всего такое broadcast общение к радио вещанию.

Как это происходит в случае с DHCP:

  1. DHCP-клиент отправляет broadcast сообщение с вопросом "Хочу IP адрес"
  2. DHCP-сервер его ловит и в ответ отправляет так же broadcast сообщение "У меня есть адрес x.x.x.x, хочешь его?"
  3. DHCP-клиент получает это сообщение и отправляет ещё одно: "Да, я хочу адрес x.x.x.x"
  4. DHCP-сервер отвечает "Хорошо, тогда x.x.x.x принадлежит тебе"

Вот в этом видео чуть более наглядно показан весь процесс: https://www.youtube.com/watch?v=RUZohsAxPxQ

А где хранятся настройки соединений?

Настройки сетевых подключений хранятся в /etc/sysconfig/network-scripts. Там ты можешь отредактировать такие вещи, как способ получения IP адреса (автоматический или статичный), стартовать ли соединение автоматически при загрузке системы и т.п. Например, вот так выглядит мой конфиг для Wi-Fi-соединения:

[root@localhost network-scripts]# cat ifcfg-FRITZ-Box_7490
HWADDR=4C:34:88:54:C1:2B
ESSID="FRITZ!Box 7490"
MODE=Managed
KEY_MGMT=WPA-PSK
TYPE=Wireless
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME="FRITZ!Box 7490"
UUID=55ba9218-1d2f-407d-af13-51502d542edb
ONBOOT=yes
SECURITYMODE=open
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes

Обрати внимание на BOOTPROTO=dhcp — эта опция означает, что будет использован DHCP-сервер, в том числе для получения IP адреса. Для сравнения, конфиг соединения для loopback устройства:

[root@localhost network-scripts]# cat ifcfg-lo
DEVICE=lo
IPADDR=127.0.0.1
NETMASK=255.0.0.0
NETWORK=127.0.0.0
# If you're having problems with gated making 127.0.0.0/8 a martian,
# you can change this to something else (255.255.255.255, for example)
BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback

Здесь прописан статичный адрес: IPADDR=127.0.0.1. В домашнаних условиях вместо редактирования конфигов вручную можно использовать утилиту nmcli, либо установить пакетик NetworkManager-tui, который предоставит удобный текстовый интерфейс прямо в консоли. В боевых условиях на серверах лучше так не делать, а использовать систему конфигурации (Puppet, Chef, Salt).

Ещё одна важная часть конфигурации: роутинг. Как понять, куда именно побежит трафик? Всё просто: достаточно посмотреть локальную таблицу роутинга при помощи команды ip r. На момент написания этих строк я сижу в кофейне с ноутбука, который использует телефон как роутер. Вот что мне выдаёт ip r:

default via 172.20.10.1 dev wlp3s0 proto static metric 600
172.20.10.0/28 dev wlp3s0 proto kernel scope link src 172.20.10.3 metric 600
192.168.100.0/24 dev virbr2 proto kernel scope link src 192.168.100.1
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1

Как видишь, весь трафик идёт по-умолчанию на машинку с адресом 172.20.10.1. А если выполнить ip addr show, то можно увидеть, что у сетевого интерфейса в ноутбуке так же есть IP адрес из этой сети:

4: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 4c:34:88:54:c1:2b brd ff:ff:ff:ff:ff:ff
    inet 172.20.10.3/28 brd 172.20.10.15 scope global dynamic wlp3s0
       valid_lft 83892sec preferred_lft 83892sec
    inet6 fe80::4e34:88ff:fe54:c12b/64 scope link
       valid_lft forever preferred_lft forever

Командой ip r add можно добавлять новые пути, а командой ip r del — удалять.

DNS

Про DNS ты наверняка слышишь не в первый раз. Простая идея: обращаться к серверу не по IP адресу (тяжело запомнить для людей), а по нормальному имени.

Самый старый и популярный DNS-сервер (тот, что хранит информацию об адресах и отвечает на запросы) — это BIND. Альтернатив тоже много, но тебе в первую очередь рекомендуется развернуть локально именно BIND.

Обязателен к прочтению материал от Cisco DNS Best Practices, Network Protections, and Attack Identification — там узнаешь не только все основы DNS, но и кучу важных рекомендаций по созданию безопасного и устойчивого DNS-сервера.

Есть возможность обновлять записи в DNS-сервере динамически. Для этого почитай про nsupdate. Ниже найдёшь ссылку на отличное руководство по настройке, включая безопасное обновление записей. Одно из интересных применений — service discovery. Поищи в Интернете, о чём это, или дождись соответствующей статьи на mkdev ;-)

До появления DNS всё, что у нас было — это файлик /etc/hosts. Он и сейчас часто используется.

Рубрика "Вирусы для чайников"! Открываем /etc/hosts на компьютера друга и добавляем туда строчку 52.28.20.212 vk.com. Хватит другу сидеть вконтакте, пусть учится разработке!

Ещё очень интересен файлик /etc/nsswitch.conf. В нём определяется в каком порядке и где искать разную информацию, в том числе где искать хосты. По-умолчанию, сначала они ищутся в /etc/hosts, а уже потом отправляется запрос в DNS-сервер.

Используемый для разрешения DNS-имён сервер, кстати, указан в /etc/resolv.conf.

Дебажить DNS проблемы удобнее всего командой dig и nslookup. Например, чтобы запросить информацию о mkdev.me у nameserver 8.8.8.8 можно сделать так:

# dig mkdev.me @8.8.8.8

; <<>> DiG 9.10.3-P4-RedHat-9.10.3-12.P4.fc23 <<>> mkdev.me @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3320
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;mkdev.me. IN A

;; ANSWER SECTION:
mkdev.me. 299 IN A 52.28.20.212

;; Query time: 355 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri May 27 12:51:04 CEST 2016
;; MSG SIZE rcvd: 53

Виртуалки

До этого момента все примеры выполнялись на локальной машине. Это, конечно, полезно для восприятия, но не так интересно. Поэтому дальше мы укрепим только что прочитанное при помощи виртуальных машин и libvirt, а заодно познакомимся с ещё парой терминов.

В первую очередь, создадим виртуалку при помощи virt-install:

sudo virt-install --name mkdev-networking-basics-1 \
--location ~/Downloads/CentOS-7-x86_64-Minimal-1511.iso \
--initrd-inject /path/to/ks.cfg \
--extra-args ks=file:/ks.cfg \
--memory=1024 --vcpus=1 --disk size=8

По-умолчанию libvirt создаёт одну сеть:

[root@localhost]# virsh net-list
 Name State Autostart Persistent
----------------------------------------------------------
 default active yes yes

Блок 192.168.0.0/16 выделен для частных сетей. libvirt выделил для своей сети блок 192.168.122.212/24, то есть все адреса от 192.168.122.0 до 192.168.122.255.

Чтобы посмотреть подробную информацию о конкретной сети можно использовать либо virsh net-info, либо virsh net-dumpxml. Вторая команда вернёт гораздо больше деталей, поэтому используем её:

[root@CentOS-72-64-minimal ~]# virsh net-dumpxml default
<network connections='1'>
  <name>default</name>
  <uuid>f2ee9249-6bed-451f-a248-9cd223a80702</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:83:b4:74'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

connections показывает количество машинок, подключённых к этой сети. Подробное описание всех возможных опций этого XML-файла можно прочитать в документации libvirt. Нас же сейчас интересуют два слова: bridge и dhcp.

bridge, или устройство virbr0, или virtual network switch — это специальное устройство, в которое подсоединяются все виртуалки этой сети. Все запросы от одной виртуалки к другой в пределах одной сети идут через этот виртуальный свитч. Для каждой сети libvirt создаёт по одному виртуальному свитчу и каждый свитч распознаётся как отдельное устройство на хост машине:

[root@localhost]# ip link show
8: virbr1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT
    link/ether 52:54:00:a8:02:f2 brd ff:ff:ff:ff:ff:ff

Создание сети в libvirt по умолчанию приравнивается к созданию виртуального свитча, к которому цепляются все виртуалки, тем самым образую локальную сеть, LAN.

Реализован свитч virbr0 при помощи Linux Bridge — технологии, изначально предназначенной как раз для создания виртуальных локальных сетей. Выполнив команду brctl show на хост-машине можно увидеть список всех свитчей.

Linux Bridge "слегка" отличается от типичного железного свитча L2. За годы его существования к нему прилепили множество дополнительных фич, например, фильтрацию трафика и файрвол. Корректнее всего назвать его свитчем L3, но здесь ваш покорный слуга не уверен до конца.

Теперь обратим внимание на следующую секцию:

  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>

Здесь указан блок адресов, использующихся для виртуальных машин в этой сети. 192.168.122.1 — IP-адрес хост-машины в пределах этой виртуальной сети.

Выполнив ip r в виртуалке увидим:

[vagrant@localhost ~]$ ip r
default via 192.168.122.1 dev eth0 proto static metric 100
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.209 metric 100

По умолчанию трафик из виртуалки во внешний мир идёт через хост-машину. В качестве забавы можешь настроить, чтобы трафик к одной виртуалке шёл через другую.

Как мы уже знаем, за назначение IP адресов отвечает служба DHCP. Libvirt использует dnsmaq для DHCP и DNS и запускает по экземпляру dnsmasq для каждой сети.

`[root@CentOS-72-64-minimal ~]# ps aux | grep dns
nobody 10600 0.0 0.0 15548 856 ? S Apr01 0:02 /sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
root 10601 0.0 0.0 15520 312 ? S Apr01 0:00 /sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper

Мы можем посмотреть табличку DHCP, которая покажет нам выданные адреса:

[root@loclahost]# virsh net-dhcp-leases default
 Expiry Time MAC address Protocol IP address Hostname Client ID or DUID
-------------------------------------------------------------------------------------------------------------------
 2016-04-29 16:31:19 52:54:00:05:36:e6 ipv4 192.168.122.212/24 - -

Обрати внимание, что 52:54:00:05:36:e6 это MAC-адрес интерфейса eth0 нашей виртуалки.

NAT

Читая ранее про CIDR тебя могло кое-что насторожить: даже если мы разделим сеть на много блоков, то общее количество IP адресов не увеличится. На самом деле, всегда используется комбинация из частных и публичных адресов. Обычно за одним публичным адресом прячется множество машин, у каждой из которых есть свой частный адрес.

Это так же и верно для наших виртуалок. У каждой есть частный IP-адрес из блока 192.168.122.0/24, и все они скрываются за публичным адресом хост-машины.

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

На первый взгляд, то, что виртуалки имеют доступ к Интернету, кажется само собой разумеющимся. Но ведь у виртуалки есть только частный адрес, недоступный вне хост машины. Публичному серверу, к которому виртуалка обращается, нужно куда-то отправлять ответ и частный IP адрес виртуалки он просто-напросто не сможет найти (на то он и частный).

Эту проблему решает NAT (Network Address Translation) — механизм преобразования IP адресов в сетевых пакетах. Обычно в пакете указан IP, откуда пакет отправлен и IP, куда пакет идёт. NAT позволяет динамически менять эти адреса и сохранять таблицу подменённых адресов.

Существует SNAT (source NAT), который и используется для наших виртуалок для доступа в Интернет. Когда пакет отправляется, то его исходящий адрес заменяется на адрес хост машины. Когда ответ от сервера назначения идёт назад, то адрес меняется с адреса хост машины на адрес виртуалки. Меняет адрес роутер.

DNAT (destination NAT) занимается примерно тем же самым, но наоборот: это когда ты обращаешься к некоему публичному адресу, за которым скрываются частные, локальные адреса.

NAT — способ по умолчанию для общения виртуалок с внешним миром. Но libvirt штука гибкая. Можно, например, цеплять виртуалки напрямую к физическому интерфейсу хоста, вместо виртуального свитча. Вариантов создания сети, на самом деле, много.

Для NAT libvirt использует iptables. Если кратко, то это инструмент, отвечающий за фильтрацию сетевых пакетов. iptables настраиваются через специальные правила (rules), которые комбинируются в цепочки (chains). Вот путём добавления таких правил libvirt и добавляет нашим виртуалкам доступ в Интернет, используя NAT. Мы вернёмся к iptables когда будем говорить о безопасности в целом.

Ещё для того чтобы на хосте работало перенаправление пакетов в настройках ядра должна быть включена опция ipforward. Включается она просто: `echo 1 > /proc/sys/net/ipv4/ipforward`

tcpdump

Пожалуй, самый незаменимый инструмент для дебаггинга сетевых проблем, а, конкретнее, трафика, который проходит через нашу машину — это tcpdump. Уметь им пользоваться обязательно. Посмотрим, например, что происходит на нашем virbr0 при перезапуске виртуалки.

Открываем консоль на хост-машине и делаем tcpdump -i virbr0.

Открываем отдельное окошко и делаем virsh reboot #{номер_виртуалки}.

Смотрим результат в первом окошке и видимо откуда какие запросы пришли:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on virbr0, link-type EN10MB (Ethernet), capture size 262144 bytes
12:57:31.339135 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
12:57:31.397937 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 52:54:00:e0:06:54 (oui Unknown), length 300
12:57:31.398182 IP linux.fritz.box.bootps > 192.168.122.209.bootpc: BOOTP/DHCP, Reply, length 301
12:57:31.590332 ARP, Request who-has linux.fritz.box tell 192.168.122.209, length 28
12:57:31.590373 ARP, Reply linux.fritz.box is-at 52:54:00:7e:33:23 (oui Unknown), length 28
12:57:31.590409 IP 192.168.122.209.38438 > linux.fritz.box.domain: 61342+ A? 0.centos.pool.ntp.org. (39)
12:57:31.590458 IP 192.168.122.209.38438 > linux.fritz.box.domain: 25671+ AAAA? 0.centos.pool.ntp.org. (39)
12:57:31.590618 IP linux.fritz.box.domain > 192.168.122.209.38438: 25671 0/0/0 (39)
### И так далее

Вот, например, broadcast от виртуалки: 12:57:31.397937 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 52:54:00:e0:06:54 (oui Unknown), length 300.

Ну и заодно глянем ARP табличку:

Address HWtype HWaddress Flags Mask Iface
# ...
192.168.122.209 ether 52:54:00:e0:06:54 C virbr0
# ...

VPN

Иногда (на самом деле, очень часто) необходимо сделать так, как будто и клиент и сервер находятся в одной частной сети. Например, когда все сервисы компании находятся в закрытой сети, доступной только в офисе, и нужно дать сотрудникам удалённый доступ. Или когда у компании несколько офисов или дата центров, которые нужно соединить друг с другом так, чтобы по-прежнему не открывать всю сеть всему интернету.

По сути VPN — это вложение одного tcp/ip пакета в другой и шифрование содержимого. Получается виртуальная сеть работающая внутри реальной сети. Для виртуальных сетей создаются виртуальные сетевые устройства (tun/tap) с виртуальными же IP адресами, видимыми только внутри нашей виртуальной зашифрованной сети.

Я оставлю настройку VPN за пределами этой статьи. На совести читателя останется попробовать это сделать самостоятельно при помощи OpenVPN или strongSwan.

Мы ещё вернёмся к тебе безопасности, но ты уже можешь почитать про IPsec — этот протокол использует strongSwan.

Для самостоятельного изучения

Мы только что пробежались по самым основам сетей, но, конечно же, есть ещё с десяток технологий, которые стоит посмотреть. Погугли самостоятельно VXLAN, изучи TCP и UDP (и разберись когда какой использовать), глянь что такое ICMP. Ты постоянно будешь сталкиваться с новыми терминами, но, как и всегда, главное — усвоить основы.

Мы не поднялись до более высоких уровней модели OSI, не посмотрели различные протоколы, с которыми работают веб-приложения: HTTP(S), FTP, SSH, NTP и многие другие.

Не забывай заглядывать в RFC. Это первая остановка в поиске нужной тебе информации по сетям.

Мы, скорее всего, вернёмся к этим темам в последующих статьях. Для меня лично сложнее всего было раньше понять именно то, как всё работает на уровнях ниже уровня приложения: все эти сети, подсети, непонятные проблемы с доступом от одного сервера к другому и т.п.

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

Что дальше?

Я знаю, что дорогой читатель ждёт-недождётся, когда я начну рассказывать про Chef, Puppet, Ansible и прочие модные штуки. Но рано, пока ещё рано. Нас ждёт ещё как минимум одна статья подобного рода, в которой мы рассмотрим все возможные способы аутенфицировать и авторизовывать пользователей и сервера, тем самым сильно копнув в сторону темы безопасности в целом.

Дополнительное чтение

Как я уже говорил, тема сетей сложная, глубокая и задействует множество различных частей. Ты наверняка чувствуешь лёгкую кашу в голове. Ничего страшного! Ссылки ниже помогут тебе ещё глубже усвоить всё, что тебе нужно знать о сетях.