Опубликован: 30.07.2013 | Доступ: свободный | Студентов: 1713 / 59 | Длительность: 24:05:00
Лекция 2:

Адресация IPv6

Текстовое представление адреса IPv6

Итак, адрес IPv6 получил свое первичное, то есть двоичное воплощение — простите за невольный каламбур. Теперь подходящее время привести на печатной странице пример адреса IPv6, но как нам его записать? В виде нулей и единиц? Да, это возможно, но довольно неудобно. Почему? Во-первых, избыточность такой записи очень велика, ведь эта запись основана на двухбуквенном алфавите, тогда как в распоряжении систем человеческой письменности куда больше символов. Во-вторых, направление письменности не одинаково в разных традициях, и упорядоченную цепочку символов разные народы будут вправе записать по-разному, а в управлении вычислительными системами такой разнобой совершенно неприемлем.

Поэтому давайте следующим шагом предложим лаконичное и однозначное текстовое представление адреса IPv6. В первую очередь, оно поможет людям записывать, читать и, по мере возможности, запоминать такие адреса. Однако записывают адреса не только на бумаге — их также вводят в память ЭВМ. В частности, именно к этому сводится ручная настройка адресов. Кроме того, адреса считывают с экрана и выводят на печать. Следовательно, текстовое представление адреса должно использовать только печатаемые символы, но в какой кодировке? Ведь их набор в разных кодировках отличается. К счастью, на практике можно выбрать подмножество символов, которое будет "по зубам" любой существующей ЭВМ, например: буквы латинского алфавита (без определенного регистра), десятичные цифры и основные знаки препинания.

Какие знаки препинания считать основными? Сегодня можно сказать, что это знаки препинания из кодировки ASCII — базовой кодировки, принятой в Internet [RFC 20] и до сих пор не сдавшей все свои позиции универсальной кодировке UTF 8 [RFC 5198]. А еще более мудрый выбор — это символы пунктуации, присутствующие одновременно и в ASCII, и в EBCDIC.

В копилке нашего опыта уже есть подобное решение для адреса IPv4, а именно формат "десятичный с точками" (dotted decimal):

  • На входе дан адрес IPv4 как упорядоченная цепочка из 32 бит.
  • Сначала биты адреса делят на четыре группы по восемь бит в каждой, то есть байты. При этом сохраняют относительный порядок битов.
  • Затем находят численное значение каждого байта и записывают его как десятичное число, руководствуясь при этом целым беззнаковым кодом и сетевым порядком битов: первый бит по порядку — самый старший, то есть наиболее значимый (MSB).
  • Наконец, перечисляют эти значения байтов так, чтобы слева стоял самый первый, он же наиболее значимый, байт. Между значениями ставят точки.

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

Обсудите применение такой нотации в системах вертикальной письменности.

В связи с десятичной записью байтов адреса IPv4 возникает вот какой вопрос: может ли она содержать ведущие нули? С одной стороны, арифметика позиционной записи гарантирует, что такие нули не меняют численного значения. Но, с другой стороны, на практике ведущие нули могут вызывать сложности. Скажем, в языке Си ведущий ноль означает, что число записано по основанию 8, а из языка Си через его стандартную библиотеку (см. функцию strtol) эта интерпретация вполне может проникнуть и в приложения, если программист не зафиксирует основание счисления явным образом, а позволит библиотеке угадывать его. Например, функции inet(3) из библиотеки BSD libc позволяют вводить октеты адреса IPv4 по любому основанию, принятому в языке Си: 8, 10, 1615 http://www.freebsd.org/cgi/man.cgi?query=inet&apropos=0&sektion=3&manpath=4.4BSD+Lite2&arch=default&format=html , — используя префиксы 0 и 0x для выбора оснований 8 и 16, соответственно. В результате существует риск, что разные приложения могут интерпретировать ведущий ноль по-разному. Чтобы избежать неоднозначности, современная трактовка, основанная на формате URI, такова: в общепринятой записи адреса IPv4 ведущие нули недопустимы [§3.2.2 RFC 3986]. Конечно, эти соображения обусловлены историческими причинами, а не желанием оправдать небрежность разработчиков. Поэтому в IPv6 мы оставим корректную обработку ведущих нулей в текстовой записи адреса на совести программиста, а нам останется четко определить, что эти нули означают.

Что в этом рецепте можно улучшить? Во-первых, у десятичной записи довольно высокая избыточность; шестнадцатеричная запись может быть короче в \lg{16}\thickapprox1,2 раза. Для длинного адреса это плюс.

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

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

К примеру, адрес 203.0.113.42 как 32 битное целое беззнаковое число равен 3405803818 десятичному или 0xCB00712A шестнадцатеричному, и только в шестнадцатеричной записи значения отдельных байтов видны невооруженным глазом: 0xCB — 203, 0x00 — 0, 0x71 — 113 и 0x2A — 42

Вместе этих аргументов более чем достаточно, чтобы выбрать основанием текстовой нотации IPv6 число 16.

Тем временем в Австралии ведутся эксперименты с записью адресов IPv6 по основанию 85 [RFC 1924].

Пообещав наглядную связь между численным значением адреса IPv6 и его записью, перейдем к осуществлению нашего плана. Что мы понимаем под численным значением адреса? Как мы уже говорили, цепочку битов можно рассматривать как число в целом беззнаковом коде, если определить старшинство битов в ней. В TCP/IP принят сетевой порядок старшинства: первый бит — наиболее значимый. Это позволяет нам найти численное значение адреса IPv6, равно как и адреса IPv4, поскольку оба они — упорядоченные цепочки битов.

Следующий шаг — от абстрактного численного значения к его шестнадцатеричной записи. Чтобы записать цепочку из 128 битов как беззнаковое число в шестнадцатеричном представлении, потребуется 32 знака, включая возможные ведущие нули. Давайте для удобства добавим нейтральные символы-разделители через каждые несколько знаков, как это делают с телефонными номерами. Пусть в группе будет четыре знака, а разделяет группы знак двоеточия, а не точка — это позволит не спутать адрес IPv6 с адресом IPv4. Тогда, например, адрес с таким численным значением по основанию 16:

20010DB800000000000000100006789

можно записать так:

2001:0DB8:0000:0000:0000:0001:0000:6789

Выбор двоеточия на роль разделителя групп может показаться неудачным, потому что двоеточие уже нагружено несколькими смежными ролями и возможна путаница. Во-первых, двоеточие разделяет адрес хоста и номер порта в формате URL. По этой причине адрес IPv6 в составе URL приходится заключать в квадратные скобки [§3.2.2 RFC 3986 ]16 Обратите внимание, как создатели электронной почты Internet за много лет до IPv6 предусмотрели и обошли эту трудность: формат доменного литерала с самого начала требовал заключать адрес узла в квадратные скобки, независимо от сетевого протокола [§3.3 и §6.2.3 RFC 822]. . Во-вторых, двоеточие — это альтернативный разделитель в текстовой записи адресов MAC17 Согласно букве IEEE 802, стандартный разделитель — это дефис, тогда как двоеточие указывает на обратный порядок битов [§3.1.2 и §3.1.8 IEEE 802-2001]. Тем не менее, на практике двоеточие часто применяется вместо тире при прямом порядке битов. (В IEEE 802 принят порядок, обратный сетевому, то есть LSB.) Например, этой традиции следуют операционные системы семейства Unix. Но, если перебрать все символы пунктуации ASCII, то среди них окажется не так уж много удобных вариантов. Одно из требований к хорошему разделителю — это чтобы он был нейтральным в командной строке Unix. Ведь адреса часто бывают аргументами сетевых утилит, например, ping, telnet и tcpdump. Если теперь адреса IPv6 придется постоянно закавычивать или экранировать, то это нарушит уже сложившуюся практику, что было бы крайне нежелательно (т.н. правило наименьшего удивления).

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

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

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

После этой простой поправки тот же самый адрес можно записать заметно короче:

2001:DB8:0:0:0:1:0:6789

Теперь мы замечаем, что в этом адресе подряд идут три нулевых группы. А что будет, если мы их вообще опустим? Мы точно знаем, что в полной записи адреса IPv6 восемь групп; благодаря этому мы можем элементарно вычислить длину пропущенной цепочки нулей. Например, давайте опустим нулевые группы, идущие подряд в нашем образцовом адресе:

2001:DB8::1:0:6789

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

При необходимости пара двоеточий может находиться не только в середине, но также и в начале или в конце адреса. Например, следующие две записи эквивалентны между собой — но отличны от 2001:DB8::1:0:6789:

2001:DB8:1:0:6789::

2001:DB8:1:0:6789:0:0:0

А что будет, если мы сделаем больше одного пропуска? Например, так:

2001:DB8::1::6789

Попробуем восстановить полный адрес. Мы легко видим, что пропущено четыре группы, но мы не знаем, как они распределены между пропусками: одна и три, две и две, три и одна. Эта неоднозначность мешает нам восстановить полный адрес. Так мы убеждаемся, что в сокращенной записи допустим только один пропуск, и никак не более.

Между тем, опустить можно любую цепочку нулей, а не только самую длинную. К примеру, наш образцовый адрес 2001:DB8::1:0:6789 можно записать и так:

2001:DB8:0:0:0:1::6789

Как нетрудно видеть, теперь опущена всего одна нулевая группа, потому что остальные семь записаны явно.

Только что составленное нами правило сокращенной записи позволит легче запоминать адреса IPv6. Если вам пожалуются на то, что адрес IPv6 невозможно запомнить, расскажите собеседнику об этом правиле.

Некоторые парсеры формата "десятичный с точками" IPv4 допускали сокращенную запись адресов на входе. Наиболее известный, а возможно, и единственный случай такого поведения — это функции inet(3) из библиотеки BSD libc, которые позволяли, к примеру, сократить запись адреса 10.0.0.1 до 10.1, а 192.168.0.1 до 192.168.1. Правила такого сокращения были сложнее, чем простой пропуск нулевых октетов — см. соответствующую страницу руководства man .18 http://www.freebsd.org/cgi/man.cgi?query=inet&apropos=0&sektion=3&manpath=4.4BSD+Lite2&arch=default&format=html Однако все подобные расширения нотации IPv4 были нестандартными и зависели от реализации, в отличие от общепринятых правил записи адресов IPv6. Проверьте себя, ответив на такой вопрос: какое максимальное число двоеточий может содержать запись адреса IPv6, отвечающая стандарту? (Ответ: 8. Пример можно найти в [§2.7.1 RFC 4291].)

Помимо полных, 128 битных адресов, в ряде случаев нам понадобится запись префиксов IPv6. Так, к примеру, префиксами будут представлены записи в таблицах маршрутов или просто блоки адресов, выделенные для каких-то целей. По своей сути, префикс — это цепочка битов, длина которой не больше, чем длина адреса. Как мы знаем, одна такая цепочка обозначает все адреса, старшие разряды которых совпадают с этой цепочкой. Из-за их тесной связи с адресами, префиксы удобно записывать в том же формате, только с явным указанием длины. Пусть десятичная длина префикса пишется после адреса через косую черту, как и в нотации IPv4 CIDR [§3.1 RFC 4632].

Допустим, нам дан такой двоичный префикс длиной 58 бит:

0010000000000001000011011011100000000000000000001100110110

Чтобы превратить его в полный, 128 битный адрес IPv6, который мы должны записать перед косой чертой, этот префикс надо дополнить 70 нулевыми битами справа — ведь префикс означает старшие биты адреса. Шестнадцатеричное значение искомого адреса таково:

20010DB800000CD800000000000000000

Записав этот адрес по недавно сформулированным правилам, мы ставим косую черту и пишем длину, 58. Вот что у нас получается:

2001:0DB8:0000:CD80:0000:0000:0000:0000/58

Это и есть текстовое представление данного префикса. А теперь мы можем переписать адрес IPv6 лаконичнее и получить краткий, но полностью эквивалентный вариант:

2001:DB8:0:CD80::/58

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

2001:DB8:0:CD9F::123/58 означает адрес 2001:DB8:0:CD9F::123 в контексте префикса 2001:DB8:0:CD80::/58.

Убедитесь, что адрес 2001:DB8:0:CD9F::123 действительно содержит префикс 2001:DB8:0:CD80::/58.

Отличить запись адреса с префиксом от записи чистого префикса в общем случае можно только по контексту. Конечно, в записях адресов довольно часто встречается ненулевой остаток (разряды справа от префикса), а в правильных записях префиксов его нет никогда; однако адрес, в котором остаток нулевой, тоже имеет право на существование.

Типичная ошибка, которую можно допустить, записывая префикс, — это отбросить в последней значащей группе концевые нули [§2.3 RFC 4291]. Например, следующие две записи не эквивалентны:

2001:DB8:0:CD80::/60

2001:DB8:0:CD8::/60

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

Таблица 1.1. Развернутое представление префиксов IPv6
Текстовая нотация Префикс(по основанию 16) Остаток(по основанию 16)
2001:DB8:0:CD80::/60 20010DB800000CD8 00000000000000000
2001:DB8:0:CD8::/60 20010DB800000CD 80000000000000000

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

"Составленные" нами правила записи адресов и префиксов IPv6 зафиксированы в §2.2 и §2.3 RFC 4291. А вот что RFC 4291 забывает сказать, так это что текстовая нотация IPv6 нечувствительна к регистру: знаки-буквы могут быть как прописными (A–F), так и строчными (a–f) [§2.3 RFC 5952]. Это обычная практика шестнадцатеричной нотации.

Читая RFC 5952, имейте в виду, что речь идет только о формате адреса IPv6 , то есть в выводе программ. Авторы стандарта делают на этом слабое ударение, из-за чего §4.3 можно трактовать так, что заглавные буквы A–F в текстовой нотации IPv6 вообще запрещены. Не стоит удивляться, если завтра появится приложение или библиотека IPv6, которые откажутся принимать заглавные буквы на выходе.

Существует еще одна нотация, в которой младшие 4 байта адреса IPv6 записаны как адрес IPv4 [п. 3 §2.2 RFC 4291]. Например, наш первый адрес IPv6 будет записан как 2001:DB8::1:0.0.103.137. Она может быть полезна во время перехода, когда в сети сосуществуют IPv4 и IPv6, а некоторые адреса IPv6 содержат в себе адреса IPv4.

Сергей Субботин
Сергей Субботин

"Теоретически канал с адресацией EUI 64 может соединить порядка 2^63 "

запись вида 2^63  не понятна и отнимает время на попытку ее осмыслить.

ее можно заменить например на записи вида  264  или 1,8 * 1019

 

Павел Афиногенов
Павел Афиногенов

Курс IPv6, в тексте имеются ссылки на параграфы. Разбиения курса на параграфы нет.