fix(admin): считать достижимым только тот адрес Traffic Stats API, который админка действительно опрашивает
Проверка принимала любой ip.IsLoopback(), то есть считала рабочим и 127.0.0.5. Это неверно: слушатель на конкретном адресе принимает соединения только на него, а слой proxy обращается строго к http://127.0.0.1:<port>. bind 127.0.0.5:38712 -> dial 127.0.0.1:38712 -> connection refused bind 0.0.0.0:38713 -> dial 127.0.0.1:38713 -> connected Такой адрес выглядел локальным, ломал контур доступа целиком (лимит устройств fail-closed => не подключается никто) и не вызывал у админки ни одного возражения. Принимаются ровно 127.0.0.1, 0.0.0.0 и пустой хост. IPv6-wildcard не принимается сознательно: соединение он принял бы, но HY2XS объявлен IPv4-only, а зависеть в ответе «достучусь» от net.ipv6.bindv6only нельзя. На странице конфигурации мягкое состояние nonCanonicalLoopback убрано: прочий loopback — это ошибка, а не предупреждение. Осталось три состояния: канон профиля, wildcard, недостижим. Свойство закреплено тестом с настоящими сокетами, а гейт приёмки запрещает возврат IsLoopback() и требует негативного случая 127.0.0.5 в тестах.
This commit is contained in:
@@ -176,16 +176,46 @@ host === "" || host === "127.0.0.1" || host === "0.0.0.0"
|
||||
поведение это не влияло (wildcard включает loopback, поэтому обмен состоится),
|
||||
но описание контракта было ложным и исправлено.
|
||||
|
||||
**Как закрыто.** Backend не тронут: он по-прежнему отвечает ровно на вопрос
|
||||
достижимости, и превращать лишнюю публикацию в отказ обслуживания нельзя — это
|
||||
отключило бы всех пиров. Разделены понятия на стороне панели:
|
||||
**Как закрыто.** Панель отвечает на оба вопроса раздельно, backend продолжает
|
||||
отвечать только на вопрос достижимости — превращать лишнюю публикацию в отказ
|
||||
обслуживания нельзя, это отключило бы всех пиров.
|
||||
|
||||
| адрес | состояние | что показано |
|
||||
| --- | --- | --- |
|
||||
| `127.0.0.1` | `canonical` | без пометки |
|
||||
| `0.0.0.0`, пустой хост | `wildcard` | предупреждение: API доступен, но слушает все интерфейсы |
|
||||
| `127.0.0.x` | `nonCanonicalLoopback` | предупреждение: доступен, но оркестратор такого не создаёт |
|
||||
| прочее | `unreachable` | ошибка: доступ пиров уже не работает |
|
||||
| прочее, включая `127.0.0.5` | `unreachable` | ошибка: доступ пиров уже не работает |
|
||||
|
||||
### DIAG-01a — «прочий loopback» был не предупреждением, а отказом
|
||||
|
||||
Первая редакция этого же фикса завела мягкое состояние
|
||||
`nonCanonicalLoopback` для адресов вида `127.0.0.5`, а backend принимал их
|
||||
через `ip.IsLoopback()`. **Это неверно, и проверено экспериментом:**
|
||||
|
||||
```text
|
||||
bind 127.0.0.5:38712 → dial 127.0.0.1:38712 → connection refused
|
||||
bind 0.0.0.0:38713 → dial 127.0.0.1:38713 → connected
|
||||
bind [::]:38714 → dial 127.0.0.1:38714 → connected
|
||||
```
|
||||
|
||||
Слушатель на конкретном адресе принимает соединения только на него, а слой
|
||||
proxy обращается строго к `http://127.0.0.1:<port>`. То есть `127.0.0.5`
|
||||
выглядит «локальным», но control plane при нём уже не работает — и админка
|
||||
молчала бы об этом, отказывая при этом всем пирам.
|
||||
|
||||
Проверка стала точной: принимаются ровно `127.0.0.1`, `0.0.0.0` и пустой хост.
|
||||
IPv6-wildcard (`[::]`) не принимается, хотя эксперимент показал, что соединение
|
||||
он принял бы: HY2XS объявлен IPv4-only, а достижимость такого слушателя зависит
|
||||
от `net.ipv6.bindv6only`, которым продукт не управляет — отвечать «достучусь» на
|
||||
основании чужого sysctl нельзя, а указанное в отказе `reconfigure` для этой
|
||||
конфигурации всё равно верное действие.
|
||||
|
||||
Гейт приёмки закрепляет именно семантику: `ip.IsLoopback()` в файле запрещён,
|
||||
обе принимаемые формы названы литералами, а негативный случай `127.0.0.5`
|
||||
обязан присутствовать в тестах. Само свойство «bind на конкретный loopback не
|
||||
принимает соединение на 127.0.0.1» зафиксировано отдельным тестом с настоящими
|
||||
сокетами — иначе правило выглядит произвольным ужесточением, и следующий
|
||||
читатель вернёт `IsLoopback()` обратно.
|
||||
|
||||
## ADM-HY2-02 — JSON-журнал не разбирался ни одной строкой
|
||||
|
||||
|
||||
Reference in New Issue
Block a user