Порт dns запроса: DNS использует UDP или TCP? Что говорит RFC

DNS использует UDP или TCP? Что говорит RFC

DNS использует UDP или TCP? Что говорит RFC

Как правило, считается, что DNS использует UDP port 53, но TCP port 53 также зарезервирован под использование для DNS.  

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

В каком случае DNS работает по UDP, а в каком — по TCP?

На этот вопрос отвечает действующий документ RFC5966 , раздел 4. Transport Protocol Selection , в котором фигурируют следующие утверждения:

Most DNS [  RFC1034  ] transactions take place over UDP [  RFC0768  ].  TCP
[ RFC0793 ] is always used for zone transfers and is often used for
messages whose sizes exceed the DNS protocol's original 512-byte
limit.

То есть, большинство DNS-запросов будет обрабатываться с использованием протокола UDP, исключение составляют трансфер зоны (Query type AXFR) и ответы сервера, превышающие 512 байт на одно сообщение. На вопрос «зачем» ответ простой: чтобы не использовались для DDoS.


All general-purpose DNS implementations MUST support both UDP and TCP
transport.

Это означает, что все реализации DNS-серверов в общем случае должны поддерживать использование обоих протоколов транспортного уровня: TCP и UDP.

Теперь более частные случаи:

Authoritative server implementations MUST support TCP so that they
do not limit the size of responses to what fits in a single UDP
packet.

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

Recursive server (or forwarder) implementations MUST support TCP
so that they do not prevent large responses from a TCP-capable
server from reaching its TCP-capable clients.

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

Stub resolver implementations (e.g., an operating system's DNS
resolution library) MUST support TCP since to do otherwise would
limit their interoperability with their own clients and with
upstream servers. 

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

Stub resolver implementations MAY omit support for TCP when
specifically designed for deployment in restricted environments where
truncation can never occur or where truncated DNS responses are
acceptable.

Как видим, RFC дает поблажку производителям маломощных устройств для того, чтобы снизить нагрузку на сервера в том окружении, где либо большие ответы от DNS маловероятны, либо они предполагается, что не будут вредить. Например, домашний маршрутизатор доступа, к которому подключены пользователи одной квартиры (2-3 устройства). В этом случае попытка выполнить DDoS второго устройства бессмысленна, и, как следствие, маловероятна.

Ну и, конечно, порядок использования протоколов:

A resolver SHOULD send a UDP
query first, but MAY elect to send a TCP query instead if it has good
reason to expect the response would be truncated if it were sent over
UDP (with or without EDNS0) or for other operational reasons, in
particular, if it already has an open TCP connection to the server.

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



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


Составляем DNS-запрос вручную / Хабр

Об авторе. Джеймс Рутли — бэкенд-разработчик в компании Monzo.

В этой статье мы изучим двочиный формат сообщений Domain Name Service (DNS) и напишем вручную одно сообщение. Это больше, чем вам нужно для использования DNS, но я подумал, что для развлечения и в образовательных целях интересно посмотреть, что находится под капотом.

Мы узнаем, как:

  • Написать запросы DNS в двоичном формате
  • Отправить сообщение в теле датаграммы UDP с помощью Python
  • Прочитать ответ от DNS-сервера

Писать в двоичном формате кажется сложным, но в реальности я обнаружил, что это вполне доступно. Документация DNS хорошо написана и понятна, а писать мы будем маленькое сообщение — всего 29 байт.

DNS используется для перевода человекочитаемых доменных имён (таких как example.

com) в машиночитаемые IP-адреса (такие как 93.184.216.34). Для использования DNS нужно отправить запрос на DNS-сервер. Этот запрос содержит доменное имя, которое мы ищем. DNS-сервер пытается найти IP-адрес этого домена в своём внутреннем хранилище данных. Если находит, то возвращает его. Если не может найти, то перенаправляет запрос на другой DNS-сервер, и процесс повторяется до тех пор, пока IP-адрес не будет найден. Сообщения DNS обычно отправляются по протоколу UDP.

Стандарт DNS описан в RFC 1035. Все диаграммы и бóльшая часть информации для этой статьи взята в данном RFC. Я бы рекомендовал обратиться к нему, если что-то непонятно.

В этой статье мы используем шестнадцатеричный формат для упрощения работы с бинарником. Ниже я добавил краткое пояснение, как они переводятся друг в друга [1].

У всех сообщений DNS одинаковый формат:

+---------------------+
|       Заголовок     |
+---------------------+
|        Вопрос       | Вопрос для сервера имён
+---------------------+
|         Ответ       | Ресурсные записи (RR) с ответом на вопрос
+---------------------+
|       Authority     | Записи RR с указанием на уполномоченный сервер
+---------------------+
|     Дополнительно   | Записи RR с дополнительной информацией
+---------------------+

Вопрос и ответ находятся в разных частях сообщения. В нашем запросе будут секции «Заголовок» и «Вопрос».

Заголовок

У заголовка следующий формат:

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

На этой диаграмме каждая ячейка представляет единственный бит. В каждой строчке 16 колонок, что составляет два байта данных. Диаграмма поделена на строки для простоты восприятия, но реальное сообщение представляет собой непрерывный ряд байтов.

Поскольку у запросов и ответов одинаковый формат заголовка, некоторые поля не имеют отношения к запросу и будут установлены в значение 0. Полное описание каждого из полей см. в RFC1035, раздел 4.1.1.

Для нас имеют значение следующие поля:

  • ID: Произвольный 16-битный идентификатор запроса. Такой же ID используется в ответе на запрос, так что мы можем установить соответствие между ними. Возьмём AA AA.
  • QR: Однобитный флаг для указания, является сообщение запросом (0) или ответом (1). Поскольку мы отправляем запрос, то установим 0.
  • Opcode: Четырёхбитное поле, которое определяет тип запроса. Мы отправляем стандартный запрос, так что указываем 0. Другие варианты:
    • 0: Стандартный запрос
    • 1: Инверсный запрос
    • 2: Запрос статуса сервера
    • 3-15: Зарезервированы для будущего использования
  • TC: Однобитный флаг, указывающий на обрезанное сообщение. У нас короткое сообщение, его не нужно обрезать, так что указываем 0.
  • RD: Однобитный флаг, указывающий на желательную рекурсию. Если DNS-сервер, которому мы отправляем вопрос, не знает ответа на него, он может рекурсивно опросить другие DNS-серверы. Мы хотим активировать рекурсию, так что укажем 1.
  • QDCOUNT: 16-битное беззнаковое целое, определяющее число записей в секции вопроса. Мы отправляем 1 вопрос.

Полный заголовок

Совместив все поля, можно записать наш заголовок в шестнадцатеричном формате:

AA AA - ID
01 00 – Параметры запроса
00 01 – Количество вопросов
00 00 – Количество ответов
00 00 – Количество записей об уполномоченных серверах
00 00 – Количество дополнительных записей

Для получения параметров запроса мы объединяем значения полей от QR до RCODE, помня о том, что не упомянутые выше поля установлены в 0. Это даёт последовательность 0000 0001 0000 0000, которая в шестнадцатеричном формате соответствует

01 00. Так выглядит стандартный DNS-запрос.

Вопрос

Секция вопроса имеет следующий формат:

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                                               |
/                     QNAME                     /
/                                               /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     QTYPE                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     QCLASS                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  • QNAME: Эта секция содержит URL, для которого мы хотим найти IP-адрес. Она закодирована как серия надписей (labels). Каждая надпись соответствует секции URL. Так, в адресе example.com две секции: example и com.

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

    Секция QNAME завершается нулевым байтом (00).

  • QTYPE: Тип записи DNS, которую мы ищем. Мы будем искать записи A, чьё значение 1.
  • QCLASS: Класс, который мы ищем. Мы используем интернет, IN, у которого значение класса 1.

Теперь можно записать всю секцию вопроса:

07 65 – у 'example' длина 7, e
78 61 – x, a
6D 70 – m, p
6C 65 – l, e
03 63 – у 'com' длина 3, c
6F 6D – o, m
00    - нулевой байт для окончания поля QNAME 
00 01 – QTYPE
00 01 – QCLASS

В секции QNAME разрешено нечётное число байтов, так что набивка байтами не требуется перед началом секции QTYPE.

Мы отправляем наше DNS-сообщение в теле UDP-запроса. Следующий код Python возьмёт наш шестнадцатеричный DNS-запрос, преобразует его в двоичный формат и отправит на сервер Google DNS по адресу 8. 8.8.8:53.

import binascii
import socket
def send_udp_message(message, address, port):
    """send_udp_message sends a message to UDP server
    message should be a hexadecimal encoded string
    """
    message = message.replace(" ", "").replace("\n", "")
    server_address = (address, port)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        sock.sendto(binascii.unhexlify(message), server_address)
        data, _ = sock.recvfrom(4096)
    finally:
        sock.close()
    return binascii.hexlify(data).decode("utf-8")
def format_hex(hex):
    """format_hex returns a pretty version of a hex string"""
    octets = [hex[i:i+2] for i in range(0, len(hex), 2)]
    pairs = [" ".join(octets[i:i+2]) for i in range(0, len(octets), 2)]
    return "\n".join(pairs)
message = "AA AA 01 00 00 01 00 00 00 00 00 00 " \
"07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01"
response = send_udp_message(message, "8.8.8.8", 53)
print(format_hex(response)) 

Можете запустить этот скрипт, скопировав код в файл query. py и запустив в консоли команду $ python query.py. У него нет никаких внешних зависимостей, и он должен работать на Python 2 или 3.

После выполнения скрипт выводит ответ от DNS-сервера. Разобьём его на части и посмотрим, что можно выяснить.

Заголовок

Сообщение начинается с заголовка, как и наше сообщение с запросом:

AA AA – Тот же ID, как и раньше
81 80 – Другие флаги, разберём их ниже
00 01 – 1 вопрос
00 01 – 1 ответ
00 00 – Нет записей об уполномоченных серверах
00 00 – Нет дополнительных записей

Преобразуем 81 80 в двоичный формат:

8    1    8    0
1000 0001 1000 0000

Преобразуя эти биты по вышеуказанной схеме, можно увидеть:

  • QR = 1: Это сообщение является ответом
  • AA = 0: Этот сервер не является уполномоченным для доменного имени example. com
  • RD = 1: Для этого запроса желательна рекурсия
  • RA = 1: На этом DNS-сервере поддерживается рекурсия
  • RCODE = 0: Ошибки не обнаружены

Секция вопроса

Секция вопроса идентична такой же секции в запросе:

07 65 – у 'example' длина 7, e
78 61 – x, a
6D 70 – m, p
6C 65 – l, e
03 63 – у 'com' длина 3, c
6F 6D – o, m
00    - нулевой байт для окончания поля QNAME 
00 01 – QTYPE
00 01 – QCLASS

Секция ответа

У секции ответа формат ресурсной записи:

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                                               |
/                                               /
/                      NAME                     /
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      TYPE                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     CLASS                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      TTL                      |
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                   RDLENGTH                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/                     RDATA                     /
/                                               /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
C0 0C - NAME
00 01 - TYPE
00 01 - CLASS
00 00 
18 4C - TTL
00 04 - RDLENGTH = 4 байта
5D B8 
D8 22 - RDDATA


Мы увидели, как составить DNS-запрос. Теперь можно попробовать следующее:

  • Составить запрос для произвольного доменного имени
  • Запрос на другой тип записи
  • Отправить запрос с отключенной рекурсией
  • Отправить запрос с доменным именем, которое не зарегистрировано



1. Шестнадцатеричные числа (base 16) часто используются как удобная краткая запись для 4 битов двоичных данных. Вы можете конвертировать данные между этими форматами по следующей таблице:

Десятичный Hex Двоичный Десятичный Hex Двоичный
0 0 0000 8 8 1000
1 1 0001 9 9 1001
2 2 0010 10 A 1010
3 3 0011 11 B 1011
4 4 0100 12 C 1100
5 5 0101 13 D 1101
6 6 0110 14 E 1110
7 7 0111 15 F 1111

Как видите, можно представить любой байт (8 бит) двумя шестнадцатеричными символами.

DNS TCP или UDP порт 53?

Ответ: DNS в основном использует UDP-порт 53, но со временем DNS будет все больше полагаться на TCP-порт 53. DNS всегда проектировался для использования как UDP, так и TCP-порта 53 с самого начала 1 , причем UDP используется по умолчанию, и возвращается к использованию TCP, когда он не может обмениваться данными по UDP, как правило, когда размер пакета слишком велик для протолкнуть в одном пакете UDP.

Когда DNS переключается на TCP?

Следующий естественный вопрос: когда сообщения DNS превысят 512 байт? На самом деле, это происходит довольно часто в сегодняшних условиях. Когда DNS была впервые реализована, единственной вещью, которая была настолько большой, что превышала ограничение в 512 байт, была передача зоны, при которой один DNS-сервер отправляет каждую отдельную запись ресурса в зоне на другой компьютер, обычно другой DNS-сервер.

Однако в современных системах DNS мы все чаще видим наборы записей ресурсов (или наборы RR), которые имеют больший общий размер. Например, на рисунке FAQ-5 показано, что запрос для www.example.com может привести к таким результатам (AAAA — это записи IPv6):

Или тот же запрос может вернуть следующие записи TXT, каждая из которых обеспечивает определенную функцию, например обнаружение спама. или проверка сайта, как показано на рисунке FAQ-6:

Если зона подписана DNSSEC, она будет регулярно возвращать большие ответы из-за криптографических ключей и подписей, как показано на рисунке FAQ-7:

Поскольку все больше и больше людей внедряют новые функции, такие как IPv6, предотвращение спама и DNSSEC, DNS с большей вероятностью переключится на TCP из-за большего размера ответа.

Что произойдет, если TCP заблокирован?

В любом случае, когда размер сообщения превышает 512 байт, это инициирует установку бита «TC» (усечение) в DNS, информируя клиента о том, что длина сообщения превысила допустимый размер. В таких ситуациях клиенту необходимо выполнить повторную передачу по протоколу TCP, размер которого не ограничен. Если DNS-серверы и сетевое окружение не могут поддерживать большие пакеты UDP, это вызовет повторную передачу через TCP; если TCP заблокирован, большой ответ UDP приведет либо к фрагментации IP, либо к полному отбрасыванию. Конечным симптомом для конечного клиента обычно является медленное разрешение DNS или невозможность разрешения определенных доменных имен вообще.

Размер имеет значение: EDNS

Вам может быть интересно, откуда взялось ограничение размера в 512 байт. Размер полезной нагрузки UDP в 512 байт зависит от IPv4. Стандарт IPv4 2 указывает, что каждый хост должен иметь возможность пересобирать пакеты размером 576 байт или меньше, удалять заголовок и другие параметры, оставляя 512 байтов для данных полезной нагрузки. Именно по этой причине изначально существует ровно 13 корневых серверов DNS 3 : 13 доменных имен и 13 IPv4-адресов прекрасно вписываются в один UDP-пакет.

Это ограничение размера давно признано проблемой. В 1999 году был предложен механизм расширения DNS (EDNS), который с годами обновлялся, увеличивая размер до 4096 байт или 4 килобайт. Таким образом, если вы используете относительно современный DNS-сервер, шансы на его переключение на TCP должны быть небольшими.

Однако, несмотря на то, что EDNS существует уже давно, его поддержка не была столь универсальной, как должна была бы быть 4 . Некоторое сетевое оборудование, такое как брандмауэры, может по-прежнему делать предположения о размере пакета DNS. Брандмауэр может отбросить или отклонить большой DNS-пакет, думая, что это атака. Это поведение, возможно, не вызывало видимых проблем в прошлом (или вызывало, но никто не понимал почему), но поскольку размер данных DNS продолжает увеличиваться, важно, чтобы все сетевое оборудование было правильно настроено для поддержки больших размеров пакетов DNS. Если сетевая среда не полностью поддерживает большие DNS-сообщения, это может привести к тому, что DNS-сообщение будет отклонено сетевым оборудованием или частично отброшено во время фрагментации. Для конечного пользователя это выглядит так: DNS-запросы остаются без ответа или занимают очень много времени, создавая впечатление, что «DNS/сеть очень медленные».

Хотя EDNS необходим для работы современных DNS, возможность отправки сообщений большего размера способствовала объемным атакам, таким как Amplification and Reflection .

1 RFC 1034, написанный в 1987 году, указал использование TCP для DNS в качестве требования.

2 RFC 791, который был опубликован в 1981 году

3 Хотя на сегодняшний день существует только 13 IPv4-адресов для корневого DNS-сервера, фактически он распределен по многим узлам по всему миру с использованием таких методов, как Anycast и балансировка нагрузки.

4 Признавая эту проблему, сообщество DNS провело мероприятие «День флага DNS» 1 февраля 2019 г., объявив его днем, когда EDNS должна полностью поддерживаться в будущем.

система доменных имен — преобразователь DNS и фильтрация портов запросов

спросил

Изменено 1 год, 3 месяца назад

Просмотрено 361 раз

Во время DNS-амплификации DNS-сервера я заметил, что некоторые DNS-запросы имеют для пары IP/порт что-то вроде 104. 49.96.196:80 . Я понимаю, что это поддельный IP-адрес, но можно ли рассмотреть возможность фильтрации порта DNS-запроса? Я считаю, что нам не следует ожидать порт> 1023. Это безопасное предположение? В этом случае я считаю, что это легко обнаружить и не отвечать на атаку с усилением DNS (если пакет достигает DNS-сервера и не отбрасывается WAF).

  • система доменных имен

Нет, это небезопасное предположение. Не пытайтесь фильтровать по портам, полезных последствий это не даст. Как клиент обрабатывает свои локальные порты, это его личное дело, и, следовательно, как сервер вы можете ожидать получения трафика со всех портов. Разделение Unix на 1024 — это архаичное наследие прошлого, которое сегодня практически ничего не значит.

Если вы хотите бороться с усилением DNS, помимо «стандартных» мер (например, убедитесь, что вам действительно нужно обрабатывать весь трафик, который вы получаете, то есть вы не широко открыты), одним из наиболее часто используемых способов в настоящее время является RRL или в основном ограничение скорости.

См. https://www.infoblox.com/dns-security-resource-center/dns-security-solutions/dns-security-solutions-response-rate-limiting-rrl/ для ознакомления с предметом и на https://www.isc.org/docs/DNS-RRL-LISA14.pdf для более технической презентации.

11

DNS-клиенты должны иметь исходный порт > 1023.

Если он < 1024, это должен быть только исходный порт 53, если он исходит от какого-либо другого DNS-сервера, но это маловероятно.

Проверка с помощью tcpdump port 53

Глядя на RFC6056 и упрощая некоторые примеры, мы можем пойти дальше и сказать, что любой хорошо работающий стек IP не должен иметь (иметь) исходный порт ниже 49152 (первый эфемерный порт). Однако раздел 3.2 противоречит этому, как и образцы.

Но пока кто-нибудь не предоставит ссылку на RFC, который переопределяет RFC6056, можно с уверенностью сказать, что спорт <= 1023 недействителен.

Если по какой-то причине происходит сбой запроса, клиент должен повторить попытку и, надеюсь, получить успешный запрос.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *