Сетевые протоколы. Семейство протоколов TCP/IP

Так случилось, что Мефодий мало что знал о компьютерных сетях до знакомства с Linux. Если пользоваться только www-броузером и почтовой программой, сведений, вроде "у каждого компьютера Internet есть имя, на компьютерах бывает почта и WWW", бывает вполне достаточно. Строго говоря, если сеть настроена, почтовые клиенты или броузеры Linux не требуют большего объёма знаний. Однако Linux хорош именно тем, что позволяет проследить работу сети от процедур самого низкого уровня, вроде поведения сетевых карт, до приложений высокого уровня и их протоколов.

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

Итак, если бы Мефодий получил задание "придумать Internet" на пару с Гуревичем, какие бы вопросы перед ними встали?

  1. Среда передачи данных. Посредством чего передавать данные? Как именно представляется передаваемая информация?
  2. Устройство передачи данных. (Раз уж известно, как передаются данные). Как подключаться к среде? Как отличить данные от не-данных (т. е. определить идёт ли передача)? Как определить очерёдность работы нескольких устройств, подключённых к одной среде передачи данных? Как определить, кому предназначаются данные, передаваемые в общей среде?

  3. Топология неоднородной сети. (Раз уж известно, как подключить компьютер к одной или нескольким средам передачи данных). Если в сеть объединены несколько сред передачи данных, как определить адресата (и отправителя тоже)? Как обеспечить пересылку данных из одной среды в другую? Как выстроить непрерывный маршрут пересылок от отправителя к адресату.

  4. Доставка данных. (Раз уж есть механизм передачи данных от любого абонента сети к любому). Как обеспечить целостность и надёжность передачи данных (и нужно ли)? Как управлять самим каналом передачи данных (например, чтобы не отправлять данных больше, чем принимающая сторона в состоянии принять)? Как разделять несколько каналов передачи данных (например, когда от одного компьютера к другому одновременно передаются два файла)?

  5. Интерпретация данных. (Раз уж возможна надёжная и без искажений доставка). Что делать с полученными данными? Какие части операционной системы отвечают за их обработку, и откуда про это знает абонент с другой стороны соединения?

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

В приведённом делении на этапы (уровни) примечательна их относительная независимость: если группа задач, связанная с некоторым уровнем, решена, на следующем уровне можно забыть, как именно решались эти задачи. Так, устройство передачи данных типа "Ethernet" с точки зрения компьютера всегда одно и то же, какой бы носитель при этом не использовался: коаксиальный кабель или кабель типа "витая пара", хотя с физической и даже топологической точки зрения эти среды сильно различаются(1). Точно так же обстоят дела при переходе со второго уровня на третий: во время получения данных уже совершенно неважно, какие среды передачи были при этом задействованы (ethernet, три провода, голубиная почта(2)...). Переход с третьего уровня на четвёртый и с четвёртого на пятый тоже обладает этим свойством.

По всей видимости, именно с этими задачами сталкивались и разработчики из института ARPA (Advanced Research Projects Agency, "Агентство Перспективных Исследовательских Проектов"; в процессе работы оно было переименовано в DARPA, где "D" означало Defence). По крайней мере, предложенное ими в середине семидесятых семейство протоколов TCP/IP также подразделялось на пять уровней: аппаратный, интерфейсный, сетевой, транспортный и прикладной. Впоследствии аппаратный уровень стали смешивать с интерфейсным, так как с точки зрения операционной системы они неразличимы(3). Именно разделение на независимые друг от друга уровни позволило со временем объединить большинство разнородных локальных сетей в единое сетевое пространство -- глобальную сеть Internet.

В TCP/IP вопрос о том, как обеспечить нескольким абонентам сети возможность передавать данные, не мешая друг другу, решён с помощью разделения пакетов данных. Разделение пакетов предполагает, что данные передаются не единым блоком, а по частям, пакетами. Алгоритмы, определяющие, когда абоненту разрешено посылать следующий пакет, могут быть разными, но результат всегда один: в сети передаются попеременно фрагменты всех сеансов передачи данных. В сильно загруженном состоянии такая сеть может просто не принять очередной пакет от абонента-отправителя, и тому придётся ждать удобного случая, чтобы всё-таки "пропихнуть" его в переполненную другими пакетами среду. Таким образом, обеспечить гарантированное время передачи одного пакета в сетях с разделением пакетов бывает довольно сложно, хотя есть алгоритмы, позволяющие это сделать.

Противоположность метода разделения пакетов -- метод разделения каналов, который предполагает, что в сети имеется определённое число каналов передачи данных, которые абоненты сети арендуют на всё время передачи. По такому принципу построены, например, телефонные линии: дозвонившись, мы арендуем канал связи между двумя телефонными аппаратами, и до тех пор, пока этот канал занят, невозможно ни воспользоваться им кому-то другому, ни организовать параллельно передачу данных откуда-нибудь ещё. Главное достоинство сетей с разделением каналов -- постоянная (за вычетом помех на линии) скорость передачи данных. Главный недостаток -- ограниченное количество каналов передачи. Проектировать среду передачи так, чтобы каждый абонент был связан с каждым отдельным каналом, имеет смысл только когда абонентов очень мало: количество каналов будет пропорционально квадрату количества абонентов. Количество каналов в большой сети будет существенно меньшим, и ровно столько сеансов передачи данных можно будет в этой сети установить. Попытка соединиться с абонентом, когда все каналы уже заняты, окончится неудачей. Мефодий припомнил своего знакомого, дозвониться которому тяжело, хотя телефон тот занимает нечасто и не подолгу. По всей видимости, каналов между какими-то двумя АТС, через которые Мефодий связывается с приятелем, хронически недостаёт (так бывает, когда отдалённый район быстро застраивается и наполняется телефонами).

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

Таким образом, процесс передачи данных выглядит так: порция данных прикладного уровня нарезается на части, соответствующие размеру пакета транспортного уровня (фрагментируется), к каждому фрагменту приписывается транспортная служебная информация, получаются пакеты транспортного уровня. Каждый пакет транспортного уровня может быть опять-таки фрагментирован для передачи по сети, к каждому получившемуся фрагменту добавляется служебная информация сетевого уровня, что даёт последовательность сетевых пакетов. Каждый сетевой пакет тоже может быть фрагментирован до размера, "пролезающего" через конкретное сетевое устройство, из него формируются пакеты интерфейсного уровня (фреймы). Наконец, к каждому фрейму само устройство (по крайне мере, так это сделано в ethernet) приписывает некоторый ключ, по которому принимающее устройство распознаёт начало фрейма. В таком виде данные передадутся по проводам. Процесс "заворачивания" пакетов более высокого уровня в пакеты более низкого уровня называется инкапсуляцией.

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

сетевой пакет

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

Аппаратный и интерфейсный уровни

Итак, на аппаратном уровне возможна какая угодно среда передачи данных, с точки зрения Linux сеть начинается в месте подключения к этой среде, то есть на сетевом интерфейсе. Список сетевых интерфейсов и их настроек в системе можно посмотреть с помощью команды ip link show:

methody@localhost:~ $ ip link show
bash: ip: команда не найдена
methody@localhost:~ $ /sbin/ip link show
 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue 
     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 qlen 1000
     link/ether 00:0C:29:56:C1:36 brd ff:ff:ff:ff:ff:ff

Запуск ip link

Утилитой ip пользуется, в основном, сама система или администратор. Эта утилита -- "универсальная": первый её параметр указывает группу настроек сетевой подсистемы, а второй -- действие, производимое с этими настройками. В примере утилита ip показывает ("show") настройки сети на интерфейсном уровне ("link"). Названия групп и команды в утилите ip можно сокращать до нескольких первых букв, наиболее часто употребляемые -- и до одной; команду show можно вовсе опускать. Так что ip link show и ip l означают одно и то же. Ошибка в начале примера вызвана тем, что в дистрибутиве, которым пользуется Мефодий, каталог /sbin, не входит по умолчанию в значение переменной PATH у обычного пользователя.

Название сетевого интерфейса состоит из его типа и порядкового номера (каким по счёту его когда-то распознало ядро). Все сетевые интерфейсы ethernet в Linux обычно называются ethномер, начиная с eth0. Параметр mtu (maximum transfer unit) определяет наибольший размер фрейма, а большинство прочих параметров описывают куда более тонкие настройки сетевого интерфейса.

сетевой интерфейс

Точка взаимодействия утилит Linux с реализацией TCP/IP в ядре системы. Как правило, имеет уникальный сетевой адрес. Интерфейсу может соответствовать некоторое сетевое оборудование (например, карта ethernet), в этом случае определён также и интерфейсный его адрес.

Значение параметра link/ether -- уникальный внутри среды передачи данных идентификатор сетевого устройства (или аппаратный адрес), в данном случае -- отвечающий протоколу Ethernet. В Ethernet аппаратный адрес называется MAC-address (от Media Access Control, управление доступом к среде), и состоит из шести байтов, которые принято записывать в шестнадцатеричной системе счисления и разделять двоеточиями. Каждая ethernet-карта имеет собственный уникальный MAC-address (в примере -- 00:0C:29:56:C1:36), поэтому его легко использовать для определения отправителя и получателя в рамках одной ethernet-среды. Если идентификатор получателя неизвестен, используется аппаратный широковещательный адрес, FF:FF:FF:FF:FF:FF. Сетевая карта, получив широковещательный фрейм или фрейм, MAC-адрес получателя в котором совпадает с её MAC-адресом, обязана отправить его на обработку системе.

Термин "Media Access Control" имеет отношение к алгоритму, с помощью которого решается задача очерёдности передачи. Алгоритм базируется на трёх принципах:

  1. Прослушивание среды. Каждое устройство умеет определять, идёт ли в данное время передача данных по среде. Если среда свободна, значит устройство имеет право само передавать данные.
  2. Обнаружение коллизий. Если решение о начале передаче данных одновременно приняли несколько устройств, в среде возникнет коллизия, и распознать, где чьи были данные, становится невозможно. Зато устройства всегда замечают произошедшую коллизию, и передают данные повторно.

  3. Случайное время ожидания перед повтором. Если бы после коллизии все устройства начали одновременно повторять передачу данных, случилась бы новая коллизия. Поэтому каждое устройство выжидает некоторое случайное время, и только после этого повторяет передачу. Если повторная коллизия всё-таки возникает, устройство ждёт вдвое дольше(4), и т. д. до тех пор, пока не превысится допустимое время ожидания, после чего системе сообщается об ошибке.

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

Сетевой уровень

Создатели первых сетей, объединяющих несколько сред передачи данных, для идентификации абонента таких сетей пытались использовать те же аппаратные адреса. Это оказалось делом неблагодарным: если в ethernet аппаратный адрес уникален всегда, то в других сетях аппаратные адреса могут быть уникальны только в рамках одной среды (например, все устройства нумеруются, начиная с 0) или даже выдаваться динамически, да и форматы аппаратных адресов в разных средах различны. Возникла необходимость присвоить каждому сетевому интерфейсу некоторый единственный на всю глобальную сеть адрес, который бы не зависел от среды передачи данных и всегда имел один и тот же формат.

Адресация

Адрес, определяемый протоколом IP (Internetwork Protocol), состоит из четырёх байтов, записываемых традиционно в десятичной системе счисления и разделяемых точкой. Адреса, присвоенные сетевым интерфейсам, можно просмотреть командой ip address show (сокращается до ip a). Чтобы не писать каждый раз полный путь утилиты ip, Мефодий просто добавил /sbin к содержимому переменной PATH:

 methody@localhost:~ $ export PATH="$PATH:/sbin"
 methody@localhost:~ $ ip address show
 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue 
     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
     inet 127.0.0.1/8 scope host lo
 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
     link/ether 00:0C:29:56:C1:36 brd ff:ff:ff:ff:ff:ff
     inet 192.168.102.125/24 brd 192.168.102.255 scope global eth0

Запуск ip addr

Адрес сетевого интерфейса eth0 из примера -- 192.168.102.125. Первый сетевой интерфейс из примера, lo, -- так называемая заглушка (loopback), которая используется для организации сетевых взаимодействий компьютера с самим собой: любой посланный в заглушку пакет немедленно обрабатывается как принятый оттуда. Заглушка обычно имеет адрес 127.0.0.1.

Отдельная среда передачи данных (локальная сеть) также имеет собственный адрес. Если представить IP-адрес в виде линейки из 32 битов, она строго разделяется на две части: столько-то битов слева отводится под адрес сети, а оставшиеся -- под адрес абонента в этой сети. Для того, чтобы определить размер адреса сети, используется сетевая маска -- линейка из 32 битов, в которой на месте адреса сети стоят единицы, а на месте адреса компьютера -- нули. При наложении маски на IP-адрес все единицы в нём, которым соответствуют нули в маске, превращаются в нули(5). Таким образом вычисляется IP-адрес сети. В примере сетевая маска интерфейса eth0 состоит из 24 единиц и 8 нулей, о чём свидетельствует окончание /24, приписанное к адресу сетевого интерфейса. Мефодий заметил, что если сетевая маска выравнена по границе байта, производить двоичные операции вообще не надо: так, в примере можно было просто сказать, что адрес сети занимает первые три байта, 192.168.102.0, а адрес абонента -- оставшийся один, 0.0.0.125.

Сетевую маску нередко записывают непосредственно в числовом виде. Так, маска /24 выглядит как 255.255.255.0, /8 -- как 255.0.0.0, а допустим, /27 -- как 255.255.255.224. При этом стоит отдельно обращать внимание на то, какие нули в адресе сети -- значащие, а какие -- часть адреса абонента. Например, в адресе 10.0.0.1 при сетевой маске 255.255.0.0 адрес сети (10.0.0.0) имеет два значащих байта, из которых второй -- полностью нулевой. Запись вида 10.0.0.0/16 в данном случае более наглядна.

IP-адрес, составленный из адреса сети, за которым следуют все единицы (в примере -- 192.168.102.255), называется широковещательным адресом: любой принадлежащий сети 192.168.102.0 компьютер, получивший IP-пакет с адресом получателя 192.168.102.255, должен обработать его, как если бы в поле "получатель" стоял его собственный IP-адрес.

В более ранних дистрибутивах Linux для работы с сетевыми интерфейсами использовалась утилита ifconfig. Эта утилита входит в состав современных дистрибутивов и вполне работоспособна, однако ip link и ip address обладают существенно большими возможностями и потому пользоваться ip предпочтительнее, чем ifconfig.

Когда компьютер с некоторым IP-адресом решает отправить пакет другому компьютеру, он выясняет, принадлежит ли адресат той же локальной сети, что и отправитель (т. е. подключены ли они к одной среде передачи данных). Делается это так: на IP-адрес получателя накладывается сетевая маска, и таким образом вычисляется адрес сети, которой принадлежит получатель. Если этот адрес совпадает с адресом сети отправителя, значит, оба находятся в одной локальной сети. Это, в свою очередь, означает, что аппаратный адрес (MAC) получателя должен быть отправителю известен.

MAC-адреса компьютеров локальной сети хранятся в специальной таблице ядра, называемой "таблицей соседей" или, как это принято в протоколе IP, ARP-таблицей/APR-таблица. Просмотреть содержимое этой таблицы можно с помощью команды ip neighbour show (сокращается до ip n):

[root@localhost ~]# ip neighbour show
 192.168.102.1 dev eth0 lladdr 00:50:56:C0:00:01 STALE
 192.168.102.7 dev eth0 lladdr 00:50:56:C3:11:a2 REACHABLE
[root@localhost ~]# sleep 60
[root@localhost ~]# ip n
 192.168.102.7 dev eth0 lladdr 00:50:56:C3:11:a2 DELAY
[root@localhost ~]# ping -c1 192.168.102.1
 PING 192.168.102.1 (192.168.102.1) 56(84) bytes of data.
 64 bytes from 192.168.102.1: icmp_seq=1 ttl=64 time=0.217 ms

 --- 192.168.102.1 ping statistics ---
 1 packets transmitted, 1 received, 0% packet loss, time 0ms
 rtt min/avg/max/mdev = 0.217/0.217/0.217/0.000 ms
[root@localhost ~]# ip n
 192.168.102.1 dev eth0 lladdr 00:50:56:C0:00:01 REACHABLE

Просмотр таблицы ARP

Более точно, ARP-таблица отражает соответствие между IP- и MAC-адресами. Таблица эта динамическая: устаревшие соответствия из неё удаляются, так как компьютеру может быть назначен другой IP-адрес, интерфейс можно отключить от сети, заменить и т. д. Если вновь понадобится связаться с компьютером, чей MAC-адрес устарел, соответствие IP и MAC придётся устанавливать по новой. В примере была использована команда ping, посылающая на указанный IP-адрес пакеты служебного протокола ICMP, на который адресат обязан ответить. Если ответа нет, значит, связь по каким-то причинам невозможна. Соответствие между MAC-адресом 00:50:56:C0:00:01 и IP-адресом 192.168.102.1 к моменту первого вызова ip neighbour уже было довольно устаревшим (пометка STALE), а через 60 секунд и вовсе просрочилось, но после обмена ICMP-пакетами свежее соответствие снова появилось в таблице.

Устанавливать соответствие между адресами сетевого и интерфейсного уровня -- дело протокола ARP (Address Resolution Protocol, "протокол преобразования адресов"). В случае преобразования IP в MAC он работает так: отправляется широковещательный ethernet-фрейм типа "ARP-запрос", внутри которого -- IP-адрес, что означает "Эй! У кого такой IP?". Каждый работающий компьютер обрабатывает этот фрейм и тот, чей IP-адрес совпадает с запрошенным, возвращает отправителю пустой фрейм типа "ARP-ответ", в поле "отправитель" которого указан искомый MAC-адрес. Это означает "У меня. А что?". Тут ARP-таблица заполняется и первый компьютер готов к инкапсуляции IP-пакета.

В более ранних версиях Linux для работы с ARP-таблицей используется команда arp. Как и в случае с ifconfig, эта команда никуда не делать, просто её возможности уже возможностей ip.

Маршрутизация

Более сложный вопрос встаёт, если IP-адрес компьютера-адресата не входит в локальную сеть компьютера-отправителя. Ведь и в этом случае пакет необходимо отослать какому-то абоненту локальной сети, с тем, чтобы тот перенаправил его дальше. Этот абонент, маршрутизатор, подключён к нескольким сетям, и ему вменяется в обязанность пересылать пакеты между ними по определённым правилам. В самом простом случае таких сетей две: "внутренняя", к которой подключены компьютеры, и "внешняя", соединяющая маршрутизатор со всей глобальной сетью. Таблицу, управляющую маршрутизацией пакетов, можно просмотреть с помощью команды ip route show (сокращается до ip r):

[root@localhost ~]# ip route show
 192.168.102.0/24 dev eth0  proto kernel  scope link  src 192.168.102.102
 default via 192.168.102.1 dev eth0 

Простая таблица маршрутизации

На машине Мефодия в таблице маршрутизации всего две записи: одна -- про сеть 192.168.102.0/24, доступную по интерфейсу eth0, вторая -- про сеть default, доступную через маршрутизатор с адресом 192.168.102.1. Сеть default -- это и есть "весь интернет", потому что ей принадлежат любые IP-адреса: в этом случае ни одного бита на сетевую маску не отводится (получается /0). Такая запись в таблице называется маршрут по умолчанию. Если маршрут по умолчанию не задан, попытка связаться с удалённым компьютером может окончиться ошибкой "No route to host": система не сможет определить, кому пересылать пакет.

На маршрутизаторе таблица выглядит чуть сложнее:

[root@fuji ~]# ip r
 192.168.102/24 dev eth1  proto kernel  scope link  src 192.168.102.1
 10.13.0.0/16 dev eth0  proto kernel  scope link  src 10.13.102.1
 default via 10.13.0.1 dev eth0
[root@fuji ~]# ip a
 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 08:00:27:50:7a:b1 brd ff:ff:ff:ff:ff:ff
    inet 10.13.102.1/16 brd 10.13.255.255 scope global eth0
 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 08:00:27:7f:75:e2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.102.1/24 brd 192.168.102.255 scope global eth1

Сложная таблица маршрутизации

Помимо сетевого интерфейса eth1 с адресом 192.168.102.1, который "смотрит" в ту же локальную сеть, что и машина Мефодия, имеется интерфейс eth0 с адресом 10.13.102.1. Локальная сеть, подключённая к этому интерфейсу, имеет маску /16. Скорее всего, к этой сети не подключено ни 65534 компьютера, ни даже в сто раз меньше: для сети ethernet и 500 компьютеров -- слишком много. Мефодий заметил, что в IP-адресе обоих сетевых интерфейсов третий байт равен 102; сетевые администраторы часто так настраивают свои серверы, дабы не перегружать память избыточными данными.

По умолчанию система обрабатывает таблицу маршрутизации так. Получив IP-пакет, сначала проверяет, не предназначен ли он самому маршрутизатору. В этом случае пакет следует "поднять" на транспортный уровень. Иначе система начинает "примерять" его поочерёдно ко всем записям таблицы маршрутизации, отсортированным в порядке убывания размера сетевой маски (в том же порядке выдаёт их команда ip route show). Если сеть адресата совпадает с сетью из таблицы, можно принимать решение, куда пересылать пакет. Параметр scope link означает, что получатель находится в одной локальной сети с отправителем, и пакет пора "спускать" на интерфейсный уровень (например, выяснять MAC-адрес получателя и заниматься пересылкой ethernet-фреймов). В примере три локальных сети: на "заглушке" lo -- 127.0.0.0/8, на интерфейсе eth0 -- 10.13.0.0/16, и на интерфейсе eth1 -- 192.168.102.0/24.

Параметр via IP-адрес говорит о том, что в доступных локальных сетях абонента нет, зато есть маршрутизатор, отвечающий за пересылку пакетов с соответствующим адресом сети. Таблица маршрутизации просматривается заново: процесс должен закончиться выяснением, куда передавать данные на интерфейсном уровне. В противном случае выдаётся сообщение об ошибке. В примере все пакеты, не предназначенные сетям 192.168.102.0/24, 10.13.0.0/16 и 127.0.0.0/8, отправляются на маршрутизатор по умолчанию с адресом 10.13.0.1.

Относительно IP-адресов на маршрутизаторе Гуревич как-то заметил, что ни один из них не "настоящий". Он имел в виду стандарт RFC1918, описывающий, какие диапазоны IP-адресов можно использовать в любой внутренней сети. Задача системного администратора -- сделать так, чтобы при работе с сетью Internet ни в одном пакете не стояло такого внутреннего адреса отправителя: например, подменять внутренние адреса на единственный внешний ("настоящий"). Задача эта решается с помощью межсетевого экрана (firewall), который в Linux называется iptables, но когда Мефодий попросил Гуревича рассказать поподробнее, тот только рукой махнул: надо хорошо знать TCP/IP.

Служебный протокол ICMP

Есть такие протоколы уровня IP, действие которых этим уровнем и ограничиваются. Например, служебный протокол ICMP (Internet Control Message Protocol), предназначенный для передачи служебных сообщений. С одним примером применения ICMP Мефодий уже знаком: это утилита ping. Другое применение ICMP -- сообщать отправителю, почему его пакет невозможно доставить адресату, или передавать информацию об изменении маршрута, о возможности фрагментации и т. п. Протоколом ICMP пользуется утилита traceroute, позволяющая приблизительно определять маршрут следования пакета (ключ "-n" означает, что преобразовывать IP-адреса в доменные имена не надо):

[root@localhost ~]# traceroute www.ru -n   
 traceroute to www.ru (194.87.0.50), 30 hops max, 38 byte packets
  1  192.168.102.1  0.223 ms  0.089 ms  0.105 ms
  2  10.13.0.1  25.599 ms  21.390 ms  21.812 ms
  3  195.34.53.53  24.111 ms  21.213 ms  25.778 ms
  4  195.34.53.53  23.614 ms  33.172 ms  22.238 ms
  5  195.34.53.10  43.552 ms  48.731 ms  44.402 ms
  6  195.34.53.81  26.805 ms  21.307 ms  22.138 ms
  7  213.248.67.93  41.737 ms  41.565 ms  42.265 ms
  8  213.248.66.9  50.239 ms  47.081 ms  64.781 ms
  9  213.248.65.42  99.002 ms  81.968 ms  62.771 ms
 10  213.248.78.170  62.768 ms  63.751 ms  78.959 ms
 11  194.87.0.66  101.865 ms  88.289 ms  66.340 ms
 12  194.87.0.50  70.881 ms  67.340 ms  63.791 ms

Определения маршрута пакета

Утилита traceroute показывает список абонентов, через которых проходит пакет по пути к адресату, и потраченное на это время. Однако список этот приблизительный. Дело в том, что первому пакету (точнее, первым трём, так как по умолчанию traceroute шлёт пакеты по три) в специальное поле TTL (Time To Live, время жизни) выставляется значение "1". Каждый маршрутизатор должен уменьшать это значение на 1, и если оно обнулилось, передавать отправителю ICMP-пакет о том, что время жизни закончилось, а адресат так и не найден. Так что на первую серию пакетов отреагирует первый же маршрутизатор, и traceroute выдаст первую строку маршрута. Второй пакет посылается с TTL=2, и, если за две пересылки адресат не достигнут, об этом рапортует второй маршрутизатор. Процесс продолжается до тех пор, пока очередной пакет не "доживёт" до места назначения. Строго говоря, неизвестно, каким маршрутом шла очередная группа пакетов, потому что с тех пор, как посылалась предыдущая группа, какой-нибудь из промежуточных маршрутизаторов мог передумать и послать новые пакеты другим путём.

Транспортный уровень

Транспортных протоколов в TCP/IP два -- это TCP (Transmission Control Protocol, протокол управления соединением) и UDP (User Datagram Protocol). UDP устроен просто. Пользовательские данные помещаются в единственный транспортный пакет-датаграмму, которой приписываются обычные для транспортного уровня данные: адреса и порты отправителя и получателя, после чего пакет уходит в сеть искать адресата. Проверять, был ли адресат способен этот пакет принять, дошёл ли пакет до него и не испортился ли по дороге, предоставляется следующему -- прикладному -- уровню.

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

Устанавливается соединение

  • Перед тем, как начать передавать данные, TCP проверяет, способен ли адресат их принимать. Если адресат отвечает согласием на открытие соединения, устанавливается двусторонняя связь между ним и отправителем. Помимо адресов отправителя и адресата и номеров порта на отправителе и адресате, в TCP-соединении участвуют два номера последовательности (SEQuential Number, SEQN), с помощью которых каждая сторона проверяет, не потерялись ли пакеты по пути, не перепутались ли.

Обрабатываются подтверждения

  • Двусторонняя связь нужна ещё и потому, что на каждый TCP-пакет с любой стороны требуется подтверждение того, что этот пакет принят. Упрощённо можно представить дело так, что отправитель и адресат по очереди обмениваются пакетами, каждый из которых содержит подтверждение только что принятого, и, возможно, полезные данные. Если происходит какая-то ошибка, она возвращается вместо подтверждения и отправитель обрабатывает её (например, посылает пакет ещё раз).

Отслеживаются состояния абонентов

  • С первым же подтверждением каждый из абонентов передаёт размер т. н. скользящего окна (sliding window). Этот размер показывает, сколько ещё данных готов принять адресат. Отправитель посылает сразу несколько пакетов суммарным размером с это окно, а после ждёт подтверждения об их принятии. Когда приходит подтверждение первого из пакетов в окне, окно "скользит" вперёд: теперь оно начинается со второго пакета, и в него попадает один или несколько ещё не посланных пакетов. Если адресат может принять больше данных, он сообщает о большем размере окна, а если данные перерабатываться не успевают -- о меньшем.

Кажется, что TCP -- протокол по всем статьям удобнее UDP. Однако в случаях, когда пользовательские данные всегда помещаются в один пакет, зато самих пакетов идёт очень много, посылать всего одну датаграмму намного выгоднее, чем всякий раз устанавливать соединение, пересылать данные и закрывать соединение (что как минимум требует по три пакета в каждую сторону). Очень трудно использовать TCP для широковещательных передач, когда число абонентов-адресатов весьма велико или вовсе неизвестно. Посмотреть параметры всех передаваемых через сетевой интерфейс пакетов можно с помощью команды tcpdump -pi интерфейс, хотя Мефодию не хватило поверхностного знания TCP/IP для того, чтобы понять выдачу этой команды.

Прикладной уровень

Как бы не был надёжен протокол TCP, он не имеет никакого понятия о том, что же, собственно, за данные с его помощью передаются. Да и не должен: принцип разделения уровней не позволяет заглядывать "внутрь" передаваемого пакета, и способов наверняка распознать используемый в нём прикладной протокол нет. Прикладной уровень, в отличие от транспортного, предусматривает сколько угодно протоколов передачи данных. Интерпретация данных, в конце концов, дело уже не ядра, а какой-нибудь программы ("приложения", как правило, демона). Для того, чтобы можно было предположить, какой протокол используется при передаче данных и чтобы система могла передать эти данные соответствующей программе, ещё на транспортном уровне было введено понятие порт.

Клиент-серверная модель

С точки зрения прикладного уровня, порт -- это идентификатор сервиса, предоставляемого системой. В самом деле, практически любой акт передачи данных выглядит, как если бы некий клиент, которому эти данные нужны, запрашивал их у сервера, который может их предоставить(6). Отношения между программами, которые связываются по сети друг с другом, почти всегда асимметричны: одной что-то надо, у другой это что-то есть. При установлении соединения и приложение (программа-клиент), и служба (программа-сервер) используют механизм сокетов, описанный в лекции Работа с внешними устройствами, однако ведут себя по-разному.

Служба, запускаясь на сервере, создаёт сетевой сокет и прикрепляет его к определённому порту сервера с помощью системного вызова bind(). Затем она регистрируется в качестве обработчика запросов (listener), приходящих на этот порт. Служба ждёт запросов, и когда они поступают, предпринимает какие-нибудь действия, например, считывает пришедшие данные и анализирует их в соответствии со своим протоколом, отсылает какие-то данные абоненту, пославшему запрос и т. п.

Приложение, запускаясь на клиенте, также создаёт сокет и присоединяется с его помощью к тому же порту на сервере, где запущена служба, используя системный вызов connect(). Затем оно, как и служба, посылает и получает данные. Разницы между обменом данными по сетевому сокету и по сокету в файловой системе нет. Очерёдность обмена данными определяется прикладным протоколом.

Как приложение узнаёт, к какому именно порту необходимо подключиться? За большинством прикладных протоколов закреплён постоянный номер порта. Постоянные номера портов и названия соответствующих протоколов хранятся в файле /etc/services:

[root@localhost ~]# wc /etc/services
  553  2794 19869 /etc/services
[root@localhost ~]# egrep "^(ftp|http|smtp|ssh).*tcp" /etc/services 
 ftp             21/tcp                      # File Transfer [Control]
 ssh             22/tcp                      # SSH Remote Login Protocol
 smtp            25/tcp      mail            # Simple Mail Transfer Protocol
 http            80/tcp      www www-http    # World Wide Web HTTP

Постоянные номера портов для некоторых протоколов

Этот файл -- не догма, а руководство к действию: каждый может организовать, допустим, сервис HTTP по 25-му порту. Только как об этом узнают другие клиенты, и что подумают почтовые программы, ожидая по этому порту встретить сервис SMTP (пересылка почты)? Вывести разнообразную информацию о сетевых соединениях можно командой netstat. В примере используются ключи -a (выводить как установленные соединения, так и службы, готовые принять соединение), -n (не преобразовывать числовую информацию в символьную), -t и -u (показывать информацию только о TCP и UDP):

[root@localhost ~]# netstat -antu
 Active Internet connections (servers and established)
 Proto Recv-Q Send-Q Local Address        Foreign Address         State      
 tcp        0      0 0.0.0.0:111          0.0.0.0:*               LISTEN      
 tcp        0      0 0.0.0.0:22           0.0.0.0:*               LISTEN      
 tcp        0      0 192.168.102.125:22   192.168.102.1:33208     ESTABLISHED
 udp        0      0 0.0.0.0:111          0.0.0.0:*

Просмотр установленных соединений и служб

Здесь видно, что на компьютере зарегистрировано два TCP-обработчика (на портах 111 и 22), один UDP-обработчик по 11-му порту (понятие Listener, то есть обработчик соединения для UDP не имеет смысла), а также установлено одно соединение с компьютера 192.168.102.1, исходящий порт 33208, к 22-му порту (это порт службы Secure Shell, предоставляющей удалённый терминальный доступ... видимо, Гуревич работает?). В более сложных случаях, когда номер порта заранее неизвестен, а известно только название и версия сервиса, используется служба portmap, которая раздаёт незанятые порты службам и сообщает приложениям, к какому из них надо обратиться. Порт 111 соответствует именно этой службе.

Обслуживание прикладного уровня в Linux

Самый простой способ проверить, предоставляет ли некий сервер услуги по некоему TCP-порту -- это подключиться к нему. Если под рукой нет приложения, работающего по требуемому протоколу, не беда: подойдёт утилита telnet. В качестве первого параметра следует указать адрес компьютера, к которому нужно подключиться, а в качестве второго (необязательного) -- номер порта. Когда-то эта утилита использовалась в качестве клиента к терминальной службе, однако от неё пришлось отказаться: пароль пользователя передавался по сети нешифрованным. Но в качестве клиента других служб, многие из которых используют текстовые протоколы, telnet используется и поныне. Если даже протокол и не текстовый -- не беда: можно выйти в командный режим telnet, нажав "^[", и подать команду close, которая закроет соединение:

[root@localhost ~]# telnet 192.168.102.1 112
 Trying 192.168.102.1...
 telnet: connect to address 192.168.102.1: Connection refused
[root@localhost ~]# telnet 192.168.102.1 111
 Trying 192.168.102.1...
 Connected to 192.168.102.1.
 Escape character is '^]'.
 ^]
 telnet> close
 Connection closed.

Использование telnet

В сценариях, а также в случае взаимодействия по нетекстовым протоколам вместо интерактивной утилиты telnet стоит использовать netcat, которая работает как cat в указанный сокет или из него.

Как уже говорилось, интерпретацией прикладных протоколов занимаются разнообразные программы. Прикладной протокол можно представить как обмен сообщениями, часто текстовыми, между клиентом и сервером. Было бы естественно оформлять такие программы в виде фильтров, чтобы пользоваться простейшими функциями ввода-вывода. Однако механизм сокетов предусматривает асинхронную передачу данных, для чего используются другие функции. Программа, желающая обслуживать сетевые соединения по определённому порту, должна удовлетворять четырём требованиям:

  1. Быть демоном, то есть постоянно находиться в памяти;

  2. Создавать сокет, прикреплять его к порту;
  3. Регистрироваться как обработчик по этому сокету и принимать соединения (возможно, придётся обрабатывать несколько соединений одновременно);
  4. Анализировать прикладной протокол и действовать по результатам анализа.

Нетрудно заметить, что первые три свойства -- общие для большинства сервисов. В Linux есть метадемон inetd, который берёт на себя всю общую сетевую часть работы, а программам предоставляет разбираться в прикладном протоколе. Сделать свой сетевой сервис с помощью inetd становится очень просто: пользователь программирует фильтр, задача которого -- обмениваться командами прикладного протокола с помощью стандартного ввода и стандартного вывода. Этот фильтр регистрируется в настройках inetd с указанием порта, с которого будут приниматься запросы. После чего сам inted становится обработчиком запросов по всем указанным портам, сам открывает соединение, запуская соответствующий фильтр, а данные из сокета пересылает туда и обратно по двум каналам. При этом фильтр-обработчик даже не должен быть демоном: это обычная программа, которая завершается, когда это предусмотрено прикладным протоколом, или когда закрывается входной поток.

Мефодий минут за пять написал службу, которая в ответ на подключение передаёт календарь на текущий месяц. В его системе используется модернизированная версия inetd -- xinted, обученная чтению конфигурационных файлов по схеме ". d":

[root@localhost ~]# grep quake /etc/services 
 quake           26000/tcp
 quake           26000/udp
[root@localhost ~]# cat /etc/xinetd.d/calendar 
 service quake
 {
        socket_type     = stream
        protocol        = tcp
        wait            = no
        user            = nobody
        server          = /usr/bin/cal
        disable         = no
 }

Настройка cal в качестве сетевой службы

Вместо номера порта можно использовать название протокола из /etc/services. Мефодий воспользовался портом 26000 (чем мог создать некоторые трудности поклонникам одной компьютерной игры). Осталось только перезагрузить xinetd, чтобы он нашёл новый конфигурационный файл, и подключиться к 26000 порту:

[root@localhost ~]# service xinetd restart
 Stopping xinetd service: [ DONE ]
 Starting xinetd service: [ DONE ]
[root@localhost ~]# telnet localhost quake
 Trying 127.0.0.1...
 Connected to localhost.
 Escape character is '^]'.
    December 2004
 Su Mo Tu We Th Fr Sa 
           1  2  3  4
  5  6  7  8  9 10 11
 12 13 14 15 16 17 18
 19 20 21 22 23 24 25
 26 27 28 29 30 31

Подключение к самодельной службе "календарь"

Служба доменных имён

В предыдущих примерах Мефодий использовал ключ "-n" многих сетевых утилит, чтобы избежать путаницы между IP-адресами и доменными именами компьютеров. С другой стороны, доменные имена -- несколько слов (часто осмысленных)--запоминать гораздо удобнее, чем адреса (четыре каких-то числа).

Когда-то имена всех компьютеров в сети, соответствующие IP-адресам, хранились в файле /etc/hosts. Пока абоненты Internet были наперечёт, поддерживать правильность его содержимого не составляло труда. Как только сеть начала расширяться, неувязок стало больше. Трудность была не только в том, что содержимое hosts быстро менялось, но и в том, что за соответствие имён адресам в различных сетях отвечали разные люди и разные организации. появилась необходимость структурировать глобальную сеть не только топологически (с помощью IP и сетевых масок), но и административно, с указанием, за какие группы адресов кто отвечает.

Проще всего было структурировать сами имена компьютеров. Вся сеть была поделена на домены -- зоны ответственности отдельных государств ("ru", "de", "us", "uk", "it" и т. п.) или независимые зоны ответственности ("com", "org", "net", "edu", "info" и т. п.). Для каждого из таких доменов первого уровня должно присутствовать подразделение, выдающее всем желающим абонентам имена, заканчивающиеся на ".домен". Подразделение обязано организовать и поддерживать службу, заменяющую файл hosts: любой желающий имеет право узнать, какой IP-адрес соответствует имени компьютера в этом домене или какому доменному имени соответствует определённый IP-адрес.

Такая служба называется DNS (Domain Name Service, служба доменных имён). Она имеет иерархическую структуру. Если за какую-то группу абонентов домена отвечают не хозяева домена, а кто-то другой, ему выделяется поддомен (или домен второго уровня), и он сам распоряжается именами вида "имя_компьютера.поддомен.домен". Например, за компьютеры в домене ". ru", принадлежащие корпорации "Dried Bugs" отвечают сотрудники соответствующего подразделения этой корпорации. Корпорация владеет поддоменом dbugs.ru. В домене ru не обязаны знать, какие именно адреса есть в поддомене, но обязаны предоставить информацию о том, как обратиться к серверу имён поддомена dbugs.ru. Сами сотрудники "Dried Bugs" тоже отвечают только за несколько собственных компьютеров, а всю ответственность за компьютеры в подразделениях перекладывают на сетевых администраторов этих подразделений, выделив им поддомены третьего уровня pr.dbugs.ru, cook.dbugs.ru и warehouse.dbugs.ru. Таким образом получается нечто вроде распределённой сетевой базы данных, хранящей короткие записи о соответствии доменных имён IP-адресам.

доменное имя

Имя абонента Internet, имеющее текстовый формат и используемое вместо IP-адреса. Состоит из собственного имени абонента в домене и имени домена, определяющего административную принадлежность абонента. В отличие от IP-адреса, доменное имя не задаётся самим абонентом сети, а устанавливается службой доменных имён.

Все программы, работающие с доменными именами, оказываются клиентами какого-нибудь сервера доменных имён (DNS-сервера). Для этого они обращаются к функциям из библиотеки libresolv (или им подобным), а те уже определяют, как превратить доменное имя в адрес. Функции используют файл /etc/host.conf, описывающий, какими способами они должны выполнять преобразование доменных имён в адреса и обратно, а также формат выдачи данных в различных случаях. Обычно сначала проверяется файл /etc/hosts, а если там соответствий не найдено -- /etc/resosv.conf. В resolv.conf указан домен по умолчанию (он приписывается в конец имени, если другим способом имя никак не удаётся преобразовать в адрес) и один-два адреса DNS-серверов, к которым и обращаются функции. Такими клиентами выступили утилиты ping и traceroute в предыдущих примерах, преобразуя имя www.ru в адрес 194.87.0.50. Если утилите traceroute не указывать ключ "-n", она подаст несколько DNS-запросов, по одному на каждый маршрутизатор, на обратное преобразование -- из IP-адреса в доменное имя.

[root@localhost ~]# cat /etc/host.conf 
 order hosts,bind
 multi on
[root@localhost ~]# cat /etc/resolv.conf
 domain nipponman.ru
 nameserver 192.168.102.1
[root@localhost ~]# traceroute -q1 www.ru
 traceroute to www.ru (194.87.0.50), 30 hops max, 38 byte packets
  1  fuji.nipponman.ru (192.168.102.1)  1.378 ms
  2  gateway.nipponman.ru (10.13.0.1)  41.155 ms
  3  195.34.53.53 (195.34.53.53)  48.503 ms
  4  195.34.53.53 (195.34.53.53)  24.033 ms
  5  M9-cr01-A197-cr01.core.mtu.ru (195.34.53.10)  33.414 ms
  6  M9-gw2-M9-cr01.core.mtu.ru (195.34.53.81)  26.259 ms
  7  s-b3-pos0-0.telia.net (213.248.67.93)  59.791 ms
  8  s-bb1-pos5-0-0.telia.net (213.248.66.1)  67.011 ms
  9  mow-b1-pos1-0.telia.net (213.248.101.10)  76.138 ms
 10  demos-101566-mow-okt-i1.c.telia.net (213.248.78.170)  78.591 ms
 11  m9-3-GE4-0-0-vl10.Demos.net (194.87.0.66)  69.813 ms
 12  www.ru (194.87.0.50)  70.583 ms

Работа DNS-клиента, встроенного в traceroute

Как видно из примера, обратное преобразование в современной сети работает не всегда. Отсутствие обратной зоны не поощряется сообществом, но и не считается преступлением. Мефодий заметил, что компьютер, не имеющий обратного преобразования адреса, вообще какой-то странный: один раз он передал пакет сам себе (здесь Мефодий не совсем прав: на самом деле этот маршрутизатор отчего-то уменьшает TTL пакета на 2, поэтому-то и на третьем, и на четвёртом шаге именно он возвращает ICMP-сообщение). Кстати сказать, именно по причине того, что DNS-запрос невелик, зато даже один абонент сети может выдать их множество, основным транспортным протоколом для DNS выбран UDP, а не TCP (это не касается протоколов обмена целыми зонами между DNS-серверами, там, конечно, господствует TCP).

Если вся задача пользователя -- это послать DNS-запрос, то лучше воспользоваться утилитой host, специально для этого предназначенной:

methody@localhost:~ $ host www.ru      
 www.ru has address 194.87.0.50
methody@localhost:~ $ host 194.87.0.51
 51.0.87.194.in-addr.arpa domain name pointer www.demos-internet.ru.
methody@localhost:~ $ host -t ns www.ru
 www.ru name server ns.demos.su.
 www.ru name server ns1.demos.net.
methody@localhost:~ $ host -t mx www.ru
 www.ru mail is handled by 5 hq.demos.ru.

Утилита host

Довольно необычен формат, в котором хранятся таблицы обратного преобразования адресов. Оказывается, IP-адрес представлен в такой таблице как имя в домене in-addr.arpa, причём это имя совпадает с адресом, записанным задом наперёд. Такой формат идёт от иерархической структуры DNS. Если некоторая организация получает во владение сеть, допустим, 194.0.0.0/8, она должна обслуживать DNS-запросы к домену 194.in-addr.arpa. Если при этом сеть 194.87.0.0/16 передана другой организации, ей же передаётся обязанность обслуживать DNS-запросы к поддомену этого домена -- 87.194.in-addr.arpa, и так вплоть до собственно IP-адресов. Вместо host можно использовать утилиту dig, которая выводит больше информации о том, как проходил сам запрос.

Помимо записей типа "адрес" (A, прямое преобразование) и "указатель ни имя" (PTR, обратное преобразование) в системе DNS может храниться и другая информация. Таблица (зона) некоторого домена должна содержать адреса доменных серверов всех его поддоменов (записи типа NS). Кроме того в домене должно быть определено имя почтового пересыльщика (запись типа MX). Если почтовый пересыльщик домена не указан, электронная почта направляется почтовому пересыльщику родительского домена.

В зоне DNS есть даже запись типа "просто текст", TXT: при желании можно самому определить интерпретацию полей этой записи и организовать поверх DNS предназначенную для каких угодно целей базу данных по IP-адресам или доменным именам(7). В отличие от dig, которой для запроса к обратной зоне требуется ключ "-x", утилита host различает запросы к прямой и обратной зонам по тому, задан ли в качестве параметра адрес или доменное имя. Для указания конкретного типа искомой записи обеим утилитам требуется этот тип передать явно. Тип any означает поиск всех записей с указанным именем:

methody@localhost:~ $ dig www.us any

 ; <<>> DiG 9.2.4rc5 <<>> www.us any
 ;; global options:  printcmd
 ;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6451
 ;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 0, ADDITIONAL: 4

 ;; QUESTION SECTION:
 ;www.us.                                IN      ANY

 ;; ANSWER SECTION:
 www.us.                 1766    IN      A       209.173.57.26
 www.us.                 1766    IN      A       209.173.53.26
 www.us.                 1767    IN      NS      pine.neustar.com.
 www.us.                 1767    IN      NS      willow.neustar.com.
 www.us.                 1767    IN      NS      cypress.neustar.com.
 www.us.                 1767    IN      NS      oak.neustar.com.
 www.us.                 1771    IN      MX      20 pine.neustar.com.
 www.us.                 1771    IN      MX      5 oak.neustar.com.
 www.us.                 1771    IN      MX      5 willow.neustar.com.
 www.us.                 1771    IN      MX      10 cypress.neustar.com.

 ;; ADDITIONAL SECTION:
 pine.neustar.com.       135024  IN      A       209.173.57.70
 willow.neustar.com.     135024  IN      A       209.173.53.84
 cypress.neustar.com.    135024  IN      A       209.173.57.84
 oak.neustar.com.        135024  IN      A       209.173.53.70

 ;; Query time: 932 msec
 ;; SERVER: 192.168.102.1#53(192.168.102.1)
 ;; WHEN: Wed Dec 22 22:01:24 2004
 ;; MSG SIZE  rcvd: 281

Утилита dig


(1) Ethernet с коаксиальным кабелем имеет топологию "общая шина": все абоненты подключаются к единому кабелю, "врезая" в него Т-образный отводок; ethernet с витой парой имеет топологию "звезда": от каждого абонента идёт собственный кабель к центральному устройству-концентратору.

(2) Организация TCP/IP с помощью почтовых голубей описана в RFC1149.

(3) Поэтому, если в книге написано, что TPC/IP имеет четыре уровня, это тоже будет правдой -- с учётом двойственности самого нижнего.

(4) Время ожидания не удваивается а выбирается, опять-таки случайно, но из другого временного диапазона.

(5) Применяется побитовая операция "И".

(6) Обратная ситуация, когда клиент хочет передать что-то серверу, сути дела не меняет: сервер предоставляет услугу клиенту, на этот раз -- по приёму данных.

(7) Так поступают, например, при создании "чёрных списков" абонентов сети, от которых почтовый сервер не принимает писем.