Кратко

  • Активная DNS Push-подписка заменяет обычное старение TTL обязанностью сервера доставлять изменения выбранного NAME/TYPE/CLASS в пределах одной DSO-сессии.
  • Закрытие соединения прекращает все подписки. TLS resumption сокращает новую криптографическую процедуру, но не восстанавливает состояние Push; нужны новые SUBSCRIBE и новое начальное состояние.
  • Вердикт «актуально» должен связывать discovery, TLS-аутентификацию, DSO, ответ на подписку, упорядоченные добавления/удаления, состояние таймера кэша и отдельную проверку сервиса.

Продолжение канала без продолжения обязательства

Рассмотрим условный, а не реальный инцидент. Клиент подписывается на SRV RRset и получает в первом PUSH адрес с TTL 120. Подписка работает десять минут, поэтому сохранённые 120 секунд не уменьшаются. Затем владелец удаляет адрес, а промежуточное устройство почти одновременно разрывает долгоживущее соединение.

TLS быстро возобновляется. Монитор защищённого транспорта снова зелёный. Но на новой DSO-сессии не принят ни один новый SUBSCRIBE. Обязанность прежнего сервера прислать удаление закончилась вместе со старой сессией. Если кэш оставит TTL замороженным, локальная программа сама превратит двухминутную публикацию в бессрочное утверждение.

RFC 8765 прямо говорит: закрытие TLS заканчивает DSO, а после resumption сервер не имеет состояния подписок и обращается с соединением как с новым. Экономия handshake не является наследованием прикладного договора.

Основание для остановки TTL

Обычный DNS-кэш уменьшает TTL, заданный издателем зоны. В нуле запись теряет статус свежей до следующего запроса. Частый polling быстрее замечает динамику, но создаёт нагрузку даже без изменений.

DNS Push держит состояние вместо повторных запросов. SUBSCRIBE задаёт один NAME, TYPE и CLASS; сервер принимает или отклоняет каждую подписку отдельно. Если набор уже непуст, сразу после успешного ответа приходит начальный PUSH. Следующие дельты идут по упорядоченному TLS/TCP-потоку.

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

UNSUBSCRIBE прекращает одну подписку, закрытие DSO — все. После этого старение продолжается с сохранённого TTL, а в нуле запись удаляется. Моменты остановки и запуска часов должны быть отдельными аудируемыми событиями.

Цепочка до SUBSCRIBE

Обычно клиент начинает с настроенного recursive resolver по DNS over TLS на порту 853. Resolver может поддерживать upstream-подписку и ретранслировать результаты. Если это невозможно, используется discovery через _dns-push-tls._tcp.<zone>. Ответ, TTL, DNSSEC, resolver и vantage сохраняются.

Strict Privacy обязателен, но TLS защищает выбранного по исходным данным peer. Подменённый SRV способен привести к идеально шифрованному соединению с неправильным сервером. Поэтому target, SNI, сертификат/TLSA и фактический адрес нельзя сворачивать в одно TLS valid.

DSO устанавливается Keepalive или первой операцией Push. SUBSCRIBE несёт ненулевой MESSAGE ID и точный тройной ключ. RCODE ответа создаёт подписку или отказывает. Сервер может знать DSO, но не Push; поддерживать Push, но не быть authoritative; либо ограничить подписки из-за памяти, сети и файловых дескрипторов.

Так возникают четыре независимых факта: TCP доступен, TLS удовлетворяет профилю, DSO существует, конкретная подписка принята. Остановить TTL позволяет только последний.

Дельты без межсессионной нумерации

PUSH направлен от сервера и имеет MESSAGE ID ноль. TTL от нуля до 0x7FFFFFFF добавляет RR; 0xFFFFFFFF удаляет отдельный RR; 0xFFFFFFFE выполняет коллективное удаление с пустым RDATA и областью по TYPE/CLASS.

Клиент применяет изменение только при совпадении с активной подпиской той же сессии. Поздний PUSH, пересёкшийся с UNSUBSCRIBE, может быть проигнорирован, если подписки уже нет. Следовательно, дельта без контекста сессии не доказывает правомерность изменения кэша.

TCP сохраняет порядок внутри соединения, но не даёт курсора через разрыв. Нулевой MESSAGE ID — не sequence number; один PUSH может содержать изменения нескольких подписок. Новая сессия должна получить новый начальный снимок, а не объявлять себя продолжением неизвестной полноты.

Успех SUBSCRIBE также не означает непустой RRset. Начальный PUSH обязателен для непустого ответа. Тишина после успешного RCODE может корректно означать пустое состояние. Нужны две метрики: принятие и содержимое.

Узкие значения Keepalive и RECONFIRM

Keepalive поддерживает состояние NAT/firewall и проверяет взаимную достижимость. Активная подписка не считается idle даже при долгой тишине. Но успешный Keepalive не доказывает целостность upstream, отсутствие потерянного удаления, правильность кэша или работоспособность endpoint.

RECONFIRM в Discovery Proxy может запустить новые multicast-запросы для сомнительной записи; после подтверждённого исчезновения последуют удаления. Для прочих серверов действие не определено, и NOERROR может ничего не запускать. Это просьба проверить, а не универсальный сертификат истины.

Восстановление без наследования

Наблюдаемая последовательность восстановления начинается с конца старой DSO и возобновления старения. Затем создаются TCP/TLS, фиксируется full или resumed handshake, устанавливается новая DSO, отправляются все SUBSCRIBE, классифицируются RCODE и принимается новое начальное состояние. Только тогда разрешается снова заморозить TTL.

SUBSCRIBE допустим в TLS early data. Однако 0-RTT не гарантирует отсутствие replay между соединениями и не обладает той же forward secrecy. Повтор может создать кратковременное лишнее состояние. Поэтому ранняя отправка не является exactly-once-квитанцией; решает принятый ответ в реальной сессии.

При невозможности Push используется явный polling. RFC 8765 рекомендует для того же NAME/TYPE/CLASS ждать не меньше меньшего из 900 секунд и TTL плюс две секунды и перед каждым poll снова пробовать Push. Это ограничивает нагрузку, но не даёт мгновенную свежесть.

Из чего складывается доказательство

Журнал содержит discovery-запрос, ответ, TTL, DNSSEC и vantage; TLS target, SNI, peer, сертификат/TLSA и тип handshake; начало/конец DSO, Keepalive, inactivity, Retry Delay. Для подписки сохраняются MESSAGE ID, NAME, TYPE, CLASS, запрос, RCODE и время принятия.

Для PUSH сохраняются порядок, форма add/remove, RR, сохранённый TTL, совпавшая подписка и решение кэша. Причина конца различает UNSUBSCRIBE, close_notify, FIN, timeout, reset и fatal error. Прямой запрос authoritative и отдельный endpoint probe завершают цепочку.

Тогда можно говорить точно: peer аутентифицирован; DSO активна; подписка принята; RRset актуален по Push; authoritative-ответ наблюдался; сервис доступен. Эти утверждения не взаимозаменяемы.

Минимальный стандарт и локальная ответственность

В терминах Heng Lu общий минимум задаёт OPCODE, TLV, роли, идентичность подписки, таймеры, безопасность и завершение. Capacity budget, телеметрия, UI, fallback и rollback остаются localized future decisions. RFC и IANA-регистрация сами по себе не доказывают voluntary adoption; её доказывают работающие реализации и тесты разрыва.

Running-code primacy требует смотреть на исполнение и последствия. Если код продолжает замораживать TTL после исчезновения подписки, именно работающий результат доказывает нарушение полномочий. Каждая роль должна оставаться узкой: publisher владеет RRset, TLS каналом, DSO сессией, сервер обязательством по принятой подписке, кэш часами, приложение проверкой сервиса.

Источники