[Ненормальное программирование, Программирование] Развлечения с парсингом IP-адресов (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Решив заняться созданием быстрого парсера IPv4+6, я написал медленный, но правильный парсер, который можно было бы использовать как базу для сравнения. В процессе его создания я узнал множество ужасных способов записи IP-адресов, о которых раньше не знал. Давайте изучим их вместе!
Начнём с самого простого, того, что я называю «канонической формой» IPv4 и IPv6: 192.168.0.1 и 1:2:3:4:5:6:7:8. В разных спецификациях они называются «dotted quad» (а конкретнее «dotted decimal»), разделёнными точками полями, каждое из которых содержит 1 байт и разделёнными двоеточиями полями «colon-hex», каждое из которых содержит 2 байта.
Первые сложности возникают из-за IPv6. В канонической форме посередине многих адресов возникают длинные последовательности нулей. Поэтому обозначение ::
позволяет пропустить один или несколько 16-битных блоков нулей: 1:2::3:4 означает 1:2:0:0:0:0:3:4.
Во-вторых, так сложилось исторически, что IPv6 позволяет записывать последние 32 байта адреса в виде dotted quad. По сути, можно приклеивать адрес IPv4 в конец адресов IPv6!
1:2:3:4:5:6:77.77.88.88 означает 1:2:3:4:5:6:4d4d:5858.
И, разумеется, можно комбинировать оба подхода! fe80::1.2.3.4 означает fe80:0:0:0:0:0:102:304
Существование :: добавляет в парсинг раздражающий пограничный случай:
:: может находиться в начале или конце адреса, а «пустая» сторона адреса может и не быть одним из 16-битных полей. ::1 означает 0:0:0:0:0:0:0:1, 1:: означает 1:0:0:0:0:0:0:0, а :: означает 0:0:0:0:0:0:0:0. Это естественным образом следует из правила ::, однако немного усложняет написание парсера.
Последнее правило для IPv6: строго говоря, каждое поле colon-hex состоит из 4 шестнадцатеричных чисел, но можно опустить нули в начале, что я и сделал выше. В полной канонической форме :: обозначает 0000:0000:0000:0000:0000:0000:0000:0000. Прошу прощения у всех читателей-трипофобов.
В целом, с IPv6 разобрались. Теперь перейдём к IPv4!
Забавный факт: текстовое представление IPv4 не было стандартизировано ни в одном документе до того, как стандарту IPv6 не потребовалась грамматика для его странной записи «trailing dotted quad». То есть это стандарт де-факто, смысл которого в основном сводится к «что понимал 4.2BSD?» и «как поступали другие ОС при копировании у 4.2BSD?»
А уж в 4.2BSD использовались довольно эксцентричные решения! Давайте для примера возьмём 192.168.140.255. Это адрес IPv4, на который люди смотрят и понимают, что это действительно адрес IPv4. Как ещё можно записать этот же самый адрес?
Вот тот же самый IP-адрес: 3232271615. Мы получаем его, интерпретировав 4 байта IP-адреса как беззнаковое 32-битное целое число в big-endian. Этот приводит к возможности классического дешёвого трюка: если попробовать зайти на http://3232271615, Chrome загрузит http://192.168.140.255.
Ну ладно, но ведь это как будто логично? Адрес IPv4 — это 4 байта, поэтому запись его как одного числа немного неудобна для человека, но в целом вполне возможна?
А как насчёт 0300.0250.0214.0377? Это всё тот же адрес. Dotted quad, только теперь каждое поле записано в восьмеричной системе.
Если поддерживается восьмеричная система, то можно подумать и задаться вопросом о шестнадцатеричной. И вы будете правы! Согласно правилам 4.2BSD, 192.168.140.255 записывается и как 0xc0.0xa8.0x8c.0xff.
Теперь вспомним о том, что когда-то у нас был CIDR (Classless Inter-Domain Routing). Адреса IPv4 имели классы: Class A, Class B или Class C. Странное было время.
И это странное время нашло отражение в IP-адресах! Знакомая нам запись 192.168.140.255, строго говоря, является записью «Class C». Можно также записать этот адрес в формате «class B» как 192.168.36095, или в формате «Class A» как 192.11046143. Здесь мы объединяем последние байты адреса или в 16-битное, или в 24-битное целочисленное поле.
Кстати, из-за этого утилиты типа ping могут принимать странно выглядящие адреса наподобие 127.1 вместо 127.0.0.1. В отличие от IPv6, они не реализуют расширение по типу «пропущенные поля — это нули». 127.1 — это запись Class A, обозначающая «хост 1 сети 127», где 1 — это 24-битное число.
Наконец, мы добрались до последней особенности не указанного в спецификациях поведения: можно ли в каждом из четырёх чисел адресов IPv4 использовать неограниченное количество нулей в начале? Или максимум — это три цифры? Форма 001.002.003.004 считается допустимой. А как насчёт 0000000001.0000000002.0000000003.000000004?
Также можно задаться вопросом, должны ли какие-то из этих чисел читаться как восьмеричные, потому что ранее мы говорили, что нули в начале могут интерпретироваться как восьмеричные. Ответ: это зависит от ситуации! Существуют реализации, где используются обе формы, однако в большинстве современных реализаций отказались от восьмеричной и шестнадцатеричной записи, а нули в начале считаются десятичными.
Споры о нулях в начале частично заразили и IPv6. Является ли 000001::00001.00002.00003.00004 допустимым адресом IPv6 (его «стандартный» вид — 1::1.2.3.4 или 1::102:304)? Похоже, большинство современных парсеров допускает бесконечное количество нулей в начале, вероятно, потому что используют какую-то библиотеку парсинга integer, реализующую такое поведение.
Итак, мы пришли к неутешительному выводу. Если вы хотите реализовать правильный парсинг IP-адресов, то вам придётся иметь дело со всей этой галиматьёй.
На данный момент мой медленный парсер обрабатывает с помощью jettison кучу старого багажа, и придерживается того, что я считаю разумным подмножеством всех этих вариантов.
- Он понимает классический IPv4 с разделёнными точками десятичными значениями и любым количеством нулей в начале.
- Он не обрабатывает запись Class A/B, а также шестнадцатеричную и восьмеричную запись.
- Он не обрабатывает запись uint32.
- Что касается IPv6, то он понимает каноническую форму colon-hex, а также :: и стиль с записью IPv4 в конце (где IPv4 в конце следует тем же правилам, что описаны выше). В каждом поле допускается любое количество нулей в начале.
Я в сомнениях относительно последнего пункта — «формы IPv6 со встроенными десятичными числами, разделёнными точками». Парсер, который я взял за основу (net.ParseIP из Go) понимает его, но в реальном мире эта запись практически бесполезна. В начале развития IPv6 идея заключалась в том, что можно «проапгрейдить» адрес до IPv6, добавив в начале пару двоеточий, например, ::1.2.3.4, однако современные механизмы перехода больше не обеспечивают столь чётко выраженного, поэтому в реальности такая запись почти не встречается.
оригинал
===========
Источник:
habr.com
===========
===========
Автор оригинала: David Anderson
===========Похожие новости:
- [Информационная безопасность, Python, Программирование, Машинное обучение] Вышла библиотека PyWhat для автоматического парсинга трафика
- [Python, Программирование, Алгоритмы, Визуализация данных, Учебный процесс в IT] Как я пытался придумать новый подход к изучению алгоритмов через интерактивные визуализации
- [Программирование, Проектирование и рефакторинг, Разработка игр, Unity] Подпишись, чтобы не пропустить — События
- [Программирование, Java] Сравнение Java-записей, Lombok @Data и Kotlin data-классов (перевод)
- [C, Программирование микроконтроллеров, Matlab] Лаконичная реализация конечных автоматов в Matlab, Octave, C
- [Тестирование IT-систем, PHP, Программирование] «Дело было вечером, делать было нечего» или краткая история о сравнении производительности языков программирования
- [Программирование, Java, Kotlin] Увеличиваем throughput приложения в 2 раза или неблокирующая работа с Elasticsearch с использованием Kotlin coroutines
- [PostgreSQL, Программирование, SQL, Администрирование баз данных] Опыт хранения IP-адресов в PostgreSQL
- [Программирование, Разработка игр, Игры и игровые приставки, Интервью] Подкаст «Хочу в геймдев» #4 — текстовая версия
- [Open source, Программирование микроконтроллеров, DIY или Сделай сам, Электроника для начинающих] я подарю тебе маленькую вселенную
Теги для поиска: #_nenormalnoe_programmirovanie (Ненормальное программирование), #_programmirovanie (Программирование), #_parsing (парсинг), #_parser (парсер), #_ipadres (IP-адрес), #_timeweb, #_blog_kompanii_timeweb (
Блог компании Timeweb
), #_nenormalnoe_programmirovanie (
Ненормальное программирование
), #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 03:43
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Решив заняться созданием быстрого парсера IPv4+6, я написал медленный, но правильный парсер, который можно было бы использовать как базу для сравнения. В процессе его создания я узнал множество ужасных способов записи IP-адресов, о которых раньше не знал. Давайте изучим их вместе! Начнём с самого простого, того, что я называю «канонической формой» IPv4 и IPv6: 192.168.0.1 и 1:2:3:4:5:6:7:8. В разных спецификациях они называются «dotted quad» (а конкретнее «dotted decimal»), разделёнными точками полями, каждое из которых содержит 1 байт и разделёнными двоеточиями полями «colon-hex», каждое из которых содержит 2 байта. Первые сложности возникают из-за IPv6. В канонической форме посередине многих адресов возникают длинные последовательности нулей. Поэтому обозначение :: позволяет пропустить один или несколько 16-битных блоков нулей: 1:2::3:4 означает 1:2:0:0:0:0:3:4. Во-вторых, так сложилось исторически, что IPv6 позволяет записывать последние 32 байта адреса в виде dotted quad. По сути, можно приклеивать адрес IPv4 в конец адресов IPv6! 1:2:3:4:5:6:77.77.88.88 означает 1:2:3:4:5:6:4d4d:5858. И, разумеется, можно комбинировать оба подхода! fe80::1.2.3.4 означает fe80:0:0:0:0:0:102:304 Существование :: добавляет в парсинг раздражающий пограничный случай: :: может находиться в начале или конце адреса, а «пустая» сторона адреса может и не быть одним из 16-битных полей. ::1 означает 0:0:0:0:0:0:0:1, 1:: означает 1:0:0:0:0:0:0:0, а :: означает 0:0:0:0:0:0:0:0. Это естественным образом следует из правила ::, однако немного усложняет написание парсера. Последнее правило для IPv6: строго говоря, каждое поле colon-hex состоит из 4 шестнадцатеричных чисел, но можно опустить нули в начале, что я и сделал выше. В полной канонической форме :: обозначает 0000:0000:0000:0000:0000:0000:0000:0000. Прошу прощения у всех читателей-трипофобов. В целом, с IPv6 разобрались. Теперь перейдём к IPv4! Забавный факт: текстовое представление IPv4 не было стандартизировано ни в одном документе до того, как стандарту IPv6 не потребовалась грамматика для его странной записи «trailing dotted quad». То есть это стандарт де-факто, смысл которого в основном сводится к «что понимал 4.2BSD?» и «как поступали другие ОС при копировании у 4.2BSD?» А уж в 4.2BSD использовались довольно эксцентричные решения! Давайте для примера возьмём 192.168.140.255. Это адрес IPv4, на который люди смотрят и понимают, что это действительно адрес IPv4. Как ещё можно записать этот же самый адрес? Вот тот же самый IP-адрес: 3232271615. Мы получаем его, интерпретировав 4 байта IP-адреса как беззнаковое 32-битное целое число в big-endian. Этот приводит к возможности классического дешёвого трюка: если попробовать зайти на http://3232271615, Chrome загрузит http://192.168.140.255. Ну ладно, но ведь это как будто логично? Адрес IPv4 — это 4 байта, поэтому запись его как одного числа немного неудобна для человека, но в целом вполне возможна? А как насчёт 0300.0250.0214.0377? Это всё тот же адрес. Dotted quad, только теперь каждое поле записано в восьмеричной системе. Если поддерживается восьмеричная система, то можно подумать и задаться вопросом о шестнадцатеричной. И вы будете правы! Согласно правилам 4.2BSD, 192.168.140.255 записывается и как 0xc0.0xa8.0x8c.0xff. Теперь вспомним о том, что когда-то у нас был CIDR (Classless Inter-Domain Routing). Адреса IPv4 имели классы: Class A, Class B или Class C. Странное было время. И это странное время нашло отражение в IP-адресах! Знакомая нам запись 192.168.140.255, строго говоря, является записью «Class C». Можно также записать этот адрес в формате «class B» как 192.168.36095, или в формате «Class A» как 192.11046143. Здесь мы объединяем последние байты адреса или в 16-битное, или в 24-битное целочисленное поле. Кстати, из-за этого утилиты типа ping могут принимать странно выглядящие адреса наподобие 127.1 вместо 127.0.0.1. В отличие от IPv6, они не реализуют расширение по типу «пропущенные поля — это нули». 127.1 — это запись Class A, обозначающая «хост 1 сети 127», где 1 — это 24-битное число. Наконец, мы добрались до последней особенности не указанного в спецификациях поведения: можно ли в каждом из четырёх чисел адресов IPv4 использовать неограниченное количество нулей в начале? Или максимум — это три цифры? Форма 001.002.003.004 считается допустимой. А как насчёт 0000000001.0000000002.0000000003.000000004? Также можно задаться вопросом, должны ли какие-то из этих чисел читаться как восьмеричные, потому что ранее мы говорили, что нули в начале могут интерпретироваться как восьмеричные. Ответ: это зависит от ситуации! Существуют реализации, где используются обе формы, однако в большинстве современных реализаций отказались от восьмеричной и шестнадцатеричной записи, а нули в начале считаются десятичными. Споры о нулях в начале частично заразили и IPv6. Является ли 000001::00001.00002.00003.00004 допустимым адресом IPv6 (его «стандартный» вид — 1::1.2.3.4 или 1::102:304)? Похоже, большинство современных парсеров допускает бесконечное количество нулей в начале, вероятно, потому что используют какую-то библиотеку парсинга integer, реализующую такое поведение. Итак, мы пришли к неутешительному выводу. Если вы хотите реализовать правильный парсинг IP-адресов, то вам придётся иметь дело со всей этой галиматьёй. На данный момент мой медленный парсер обрабатывает с помощью jettison кучу старого багажа, и придерживается того, что я считаю разумным подмножеством всех этих вариантов.
Я в сомнениях относительно последнего пункта — «формы IPv6 со встроенными десятичными числами, разделёнными точками». Парсер, который я взял за основу (net.ParseIP из Go) понимает его, но в реальном мире эта запись практически бесполезна. В начале развития IPv6 идея заключалась в том, что можно «проапгрейдить» адрес до IPv6, добавив в начале пару двоеточий, например, ::1.2.3.4, однако современные механизмы перехода больше не обеспечивают столь чётко выраженного, поэтому в реальности такая запись почти не встречается. оригинал =========== Источник: habr.com =========== =========== Автор оригинала: David Anderson ===========Похожие новости:
Блог компании Timeweb ), #_nenormalnoe_programmirovanie ( Ненормальное программирование ), #_programmirovanie ( Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 03:43
Часовой пояс: UTC + 5