Go-фича: Сравнение IP-подсетей

Часть серии Принято! В ней простыми словами объясняются новые фичи Go.

Сравнивать префиксы IP-адресов так же, как это делает IANA (администрация адресного пространства интернета).

Версия 1.26 • Станд. библиотека • Мелочь

Что

Префикс IP-адреса задает определенную подсеть. Обычно такие префиксы записывают в формате CIDR:

10.0.0.0/8
127.0.0.0/8
169.254.0.0/16
203.0.113.0/24

В Go IP-префикс представлен типом netip.Prefix.

Новый метод Prefix.Compare позволяет сравнить два IP-префикса, что упрощает их сортировку — не придется писать свой код сравнения. Порядок сравнения совпадает с реализацией в Python и с порядком, который использует IANA.

Зачем

Когда команда Go изначально разрабатывала тип IP-подсети (net/netip.Prefix), они решили не добавлять метод Compare, потому что не было общепринятого способа упорядочивать такие значения.

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

Чтобы улучшить ситуацию, в Go добавят стандартный способ сравнения IP-префиксов. Это должно уменьшить количество шаблонного кода и помочь программам сортировать IP-подсети одинаково.

Подробности

Добавить метод Compare в тип netip.Prefix:

// Compare возвращает целое число - результат сравнения двух префиксов.
// Результат будет 0, если p == p2, -1, если p < p2, и +1, если p > p2.
func (p Prefix) Compare(p2 Prefix) int

Вот как Compare сравнивает префиксы:

  • Сначала по корректности (некорректные идут перед корректными).
  • Потом по семейству адресов (IPv4 перед IPv6).
    10.0.0.0/8 < ::/8
  • Потом по маскированному IP-адресу (IP подсети).
    10.0.0.0/8 < 10.0.1.0/8
  • Потом по длине префикса.
    10.0.0.0/8 < 10.0.0.0/16
  • Потом по немаскированному адресу (оригинальный IP).
    10.0.0.0/8 < 10.0.0.1/8

Это тот же порядок, что использует netaddr.IPNetwork в Python и IANA.

Пример

Отсортировать список IP-префиксов:

prefixes := []netip.Prefix{
    netip.MustParsePrefix("10.0.1.0/8"),
    netip.MustParsePrefix("203.0.113.0/24"),
    netip.MustParsePrefix("10.0.0.0/8"),
    netip.MustParsePrefix("169.254.0.0/16"),
    netip.MustParsePrefix("203.0.113.0/8"),
}

slices.SortFunc(prefixes, func(a, b netip.Prefix) int {
    return a.Compare(b)
})

for _, p := range prefixes {
    fmt.Println(p.String())
}
10.0.0.0/8
10.0.1.0/8
169.254.0.0/16
203.0.113.0/8
203.0.113.0/24

Ссылки

𝗣 61642 • 𝗖𝗟 700355

★ Подписывайтесь на канал и проходите курсы.