Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UPnP: error 2 #2094

Open
wants to merge 1 commit into
base: openssl
Choose a base branch
from
Open

Conversation

self-related
Copy link

Проблема:
UPnP: Unable to find valid Internet Gateway Device: error 2

Подробнее:
Предположительно, проблема в нестандартном IGD - dappnode/DNP_DAPPMANAGER#312

Ручной форвард в miniupnpc выдает "Not connected IGD":

$ upnpc -r 11111 11111 UDP
upnpc : miniupnpc library test client, version .
...
List of UPNP devices found on the network :
 desc: http://192.168.31.1:5351/rootDesc.xml
 st: urn:schemas-upnp-org:device:InternetGatewayDevice:1

Found a (not connected?) IGD : http://192.168.31.1:5351/ctl/IPConn
No valid UPNP Internet Gateway Device found.

Однако с флагом -i (игнор) все корректно форвардится:

$ upnpc -i -r 11111 11111 UDP

upnpc : miniupnpc library test client, version .
...
List of UPNP devices found on the network :
 desc: http://192.168.31.1:5351/rootDesc.xml
 st: urn:schemas-upnp-org:device:InternetGatewayDevice:1

Found a (not connected?) IGD : http://192.168.31.1:5351/ctl/IPConn
Trying to continue anyway
Local LAN ip address : 192.168.31.*
ExternalIPAddress = *.*.*.*
InternalIP:Port = 192.168.31.*:11111
external *.*.*.*:11111 UDP is redirected to internal 192.168.31.*:11111 (duration=0)

В i2pd/daemon/UPnP.h случай с not connected соответствует:
UPNP_IGD_VALID_NOT_CONNECTED = 2

Лог i2pd до фикса:

22:01:33@480/none - i2pd v2.53.1 (0.9.63) starting...
22:01:35@827/warn - Transports: 15 ephemeral keys generated at the time
22:01:35@106/error - UPnP: Unable to find valid Internet Gateway Device: error 2

После:

$ ./i2pd 
22:02:51@613/none - i2pd v2.53.1 (0.9.63) starting...
success022:02:54@33/warn - Transports: 15 ephemeral keys generated at the time
22:02:54@581/error - UPnP: Found Internet Gateway Device http://192.168.31.1:5351/ctl/IPConn

Форвард проходит.

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

Как я понимаю, роутер выдаёт Not connected когда считает, что у него нету прямого подключения к Интернету.
Понятно, что у роутера могут быть ложные определения доступности сети, но если предположить, что в среднем у пользователей доступность чаще определяется верно, то такой патч позволит им пробрасывать порт из недоступной сети в недоступную.
Точно не помню, какие от этого негативные последствия, но это как минимум неверно логически.

@self-related
Copy link
Author

Что интересно, в Transmission порт пробрасывается всегда и там тоже используется miniupnc с проверкой только на UPNP_IGD_VALID_CONNECTED - https://github.com/transmission/transmission/blob/1e16912ae4a20ca338cfe89c72418cd37eac0102/libtransmission/port-forwarding-upnp.cc#L270

Я не разобрался, как у них это реализовано. Возможно ли такое решение?

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

Я не разобрался, как у них это реализовано.

Наверно, с этого места стоит изучать:
transmission/transmission#6718

@self-related
Copy link
Author

Пришлось собрать transmission-daemon и добавить в дебаг вывод после проверки UPNP_IGD_VALID_CONNECTED - там тоже всегда статус 2 и он не изменяется. Спустя несколько попыток реконнекта у меня он просто забивает на статус, хотя в коде не совсем понял, при каком условии, и кажется там Fail вообще не обрабатывается.
transmission/transmission@2698cac

        if (
            UPNP_GetValidIGD(devlist, &handle->urls, &handle->data, std::data(lanaddr), std::size(lanaddr) - 1, nullptr, 0)
            == UPNP_IGD_VALID_CONNECTED)
        {
            ...
        }
        else
        {
            handle->state = UpnpState::WillDiscover;  //вот здесь новая попытка
            ...
        }

enum class UpnpState : uint8_t
{
    Idle,
    WillDiscover, // next action is upnpDiscover()
inf port-forwarding.cc:216 State changed from 'Starting' to 'Not forwarded' (port-forwarding.cc:216)
inf port-forwarding.cc:216 State changed from 'Not forwarded' to 'Starting' (port-forwarding.cc:216)

Да, там все странно - отключил сейчас upnp на роутере и transmission бесконечно сыпет в лог уже больше получаса:

dbg port-forwarding-natpmp.cc:46 readnatpmpresponseorretry failed. Natpmp returned -7 (the gateway does not support nat-pmp); errno is 111 (Connection refused) (port-forwarding-natpmp.cc:46)
inf port-forwarding.cc:216 State changed from 'Starting' to 'Not forwarded' (port-forwarding.cc:216)
inf port-forwarding.cc:216 State changed from 'Not forwarded' to 'Starting' (port-forwarding.cc:216)

Возможно, проблема с пробросом в самом miniupnpc. Например qbittorrent судя по логам пробрасывает сразу же и без ошибок.

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

Возможно, проблема с пробросом в самом miniupnpc. Например qbittorrent судя по логам пробрасывает сразу же и без ошибок.

miniupnpc использует команду GetStatusInfo для проверки статуса:
https://github.com/miniupnp/miniupnp/blob/d07b0a1a9d4ce62f36040d64a4b629a914950f9c/miniupnpc/src/miniupnpc.c#L494-L501

В libtorrent я вообще фразы GetStatusInfo не нахожу. Видимо, ему всё равно.

Вот тут есть кое какое упоминание этой команды:
http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

Интересно. Оказывается, в новой версии miniupnpc другие константы.
Как пользователям библиотеки предполагается об этом узнавать?

Правда, дополнительный код - он всё равно "не единица".

https://github.com/miniupnp/miniupnp/blob/d07b0a1a9d4ce62f36040d64a4b629a914950f9c/miniupnpc/src/miniupnpc.c#L505-L520

@self-related
Copy link
Author

Хм, на версии 2.2.8 клиент upnpc корректно пробрасывает сразу без флага -i.
I2pd и transmission по прежнему отбрасывают state 2 .

ОДНАКО вот что я заметил в miniupnpc: miniupnp/miniupnp@c0a50ce#diff-f4321c7c8d1e7ee67ca583dcc83ef3e391e233aa97c502fca50b32535d9cf936R624

Было:

/* in state 2 and 3 we don't test if device is connected ! */
if(state >= 2)

Стало:

/* in state 3 and 4 we don't test if device is connected ! */
if(state >= 3)

Видимо, в этом и суть новых констант, теперь state 2 считается приемлемым? Если так, то патч к i2pd это и делает, только тогда надо еще добавить в условие API 18, чтобы было корректно

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

I2pd и transmission по прежнему отбрасывают state 2 .

Отбрасывают не единицу.

Видимо, в этом и суть новых констант, теперь state 2 считается приемлемым?

Как я понял, состояние 2 теперь разбито на состояние 2 и 3.
Но это по-прежнему не единица.

Может, ещё какое-то изменение есть.

Было:
Стало:

Я это понимаю так: раз дошли до состояния 2 (или 3), то всё плохо и уже мелкие проблемы проверять смысла нету.

@self-related
Copy link
Author

раз дошли до состояния 2 (или 3), то всё плохо

Но теперь это 3 и 4 в новой версии, а статус 2 проверяется вместе со статусом 1 по-умолчанию

Добавил вывод статуса в конец UPNP_GetValidIGD
printf("final state: %d\n", state);

Теперь вывод такой:

$ ./build/upnpc-static -r 12345 12345 udp
upnpc: miniupnpc library test client, version 2.2.8.
 (c) 2005-2024 Thomas Bernard.
More information at https://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/

List of UPNP devices found on the network :
 desc: http://192.168.31.1:5351/rootDesc.xml
 st: urn:schemas-upnp-org:device:InternetGatewayDevice:1

final state: 2
Found an IGD with a reserved IP address (*.*.*.*) : http://192.168.31.1:5351/ctl/IPConn
Local LAN ip address : 192.168.31.*
ExternalIPAddress = *.*.*.*
InternalIP:Port = 192.168.31.*:12345
external *.*.*.*:12345 UDP is redirected to internal 192.168.31.*:12345 (duration=0)

Т.е. статус 2 теперь не not connected, а reserved ip и проходит по умолчанию (место звездочек в первом случае тоже внешний айпи).

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

Но теперь это 3 и 4 в новой версии, а статус 2 проверяется вместе со статусом 1 по-умолчанию

Только это касается не библиотеки, а утилиты.
Вот "правильная" строчка:
https://github.com/miniupnp/miniupnp/blob/d07b0a1a9d4ce62f36040d64a4b629a914950f9c/miniupnpc/src/upnpc.c#L757

Кстати, они таки добавили константы.

Т.е. статус 2 теперь не not connected, а reserved ip и проходит по умолчанию

Так всё же - зачем i2pd нужен проброс с reserved ip?
i2pd ведь белый ip нужен, доступный из Интернета.

Если же miniupnpc или железка отмечают белый IP как серый, то надо разбираться, почему.

@self-related
Copy link
Author

i2pd ведь белый ip нужен

За nat ведь тоже можно получать прямые udp соединения. У меня на джава роутере upnp работал и показывал прямые SSU соединения в статистике. Соответственно, порт надо открыть, особенно, когда он меняется с каждым рестартом

@Vort
Copy link
Contributor

Vort commented Aug 19, 2024

"Пробитие" NAT к UPnP, насколько я знаю, не относится.
Этим занимаются отдельные механизмы внутри i2pd (интродьюсеры).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants