Страница 1 из 1

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 02 Март 2025, 11:07
finsoftrz
Это, наверно, надо смотреть в сторону WinStationQueryInformation. Может у кого есть пример работы на кларионе? Или другие способы без вызова внешних скриптов.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 02 Март 2025, 17:22
Игорь Столяров
А через штатные функции Winsock API здесь не получится работать ?
У меня нет терминального сервера для проверки ...
Например как вот здесь: https://attryde.com/clarion/col_tcpip.htm

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 02 Март 2025, 22:55
kreator
Мы вытаскивали из реестра. Вроде проблем не наблюдали. Правильно ли я понимаю. Рабочая станция, которая вошла через rdp, должна сообщить свой ip-адрес?

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 02 Март 2025, 23:07
finsoftrz
kreator писал(а): 02 Март 2025, 22:55 Мы вытаскивали из реестра. Вроде проблем не наблюдали. Правильно ли я понимаю. Рабочая станция, которая вошла через rdp, должна сообщить свой ip-адрес?
Да, правильно. Из того, что я успел прочитать, есть 2 адреса. Один, который передает удаленный компьютер, второй реальный адрес, который определяет система при подключении. Винда знает оба. Нужен второй. Смысл в том, чтобы можно на уровне приложения устанавливать разрешение для пользователя входить с определенного ip адреса или блокировать какие-то ip адреса. Обычно для этих целей используют отдельные сторонние продукты, но хотелось бы все иметь в одном флаконе, проще управлять и контролировать.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 8:57
finsoftrz
В интернете есть такой пример на c. ХЗ, как это в кларионе может выглядеть.

Код: Выделить всё

typedef enum _WINSTATIONINFOCLASS {
    // ...
    WinStationRemoteAddress = 29,
    // ...
} WINSTATIONINFOCLASS;

#define LOGONID_CURRENT     ((ULONG)-1)

typedef struct {
    unsigned short sin_family;
    union {
        struct {
            USHORT sin_port;
            ULONG in_addr;
            UCHAR sin_zero[8];
        } ipv4;
        struct {
            USHORT sin6_port;
            ULONG sin6_flowinfo;
            USHORT sin6_addr[8];
            ULONG sin6_scope_id;
        } ipv6;
    };
} WINSTATIONREMOTEADDRESS,
*PWINSTATIONREMOTEADDRESS;

EXTERN_C
DECLSPEC_IMPORT
BOOLEAN
WINAPI
WinStationQueryInformationW(
                            _In_opt_ HANDLE hServer,
                            _In_ ULONG SessionId,
                            _In_ WINSTATIONINFOCLASS WinStationInformationClass,
                            _Out_writes_bytes_(WinStationInformationLength) PVOID pWinStationInformation,
                            _In_ ULONG WinStationInformationLength,
                            _Out_ PULONG pReturnLength
                            );

ULONG GetRdpClientAddressFromServerView()
{
    ULONG dwError = NOERROR;
    ULONG cb;

    union {
        SOCKADDR sa;
        SOCKADDR_IN sa4;
        SOCKADDR_IN6 sa6;
    };

    WINSTATIONREMOTEADDRESS ra;

    if (WinStationQueryInformationW(0, LOGONID_CURRENT, WinStationRemoteAddress, &ra, sizeof(ra), &cb))
    {
        switch (sa.sa_family = ra.sin_family)
        {
        case AF_INET:
            sa4.sin_port = ra.ipv4.sin_port;
            sa4.sin_addr.S_un.S_addr = ra.ipv4.in_addr;
            RtlZeroMemory(sa4.sin_zero, sizeof(sa4.sin_zero));
            cb = sizeof(SOCKADDR_IN);
            break;
        case AF_INET6:
            sa6.sin6_port = ra.ipv6.sin6_port;
            sa6.sin6_flowinfo = ra.ipv6.sin6_flowinfo;
            memcpy(&sa6.sin6_addr, &ra.ipv6.sin6_addr, sizeof(in6_addr));
            sa6.sin6_scope_id = ra.ipv6.sin6_scope_id;
            cb = sizeof(SOCKADDR_IN6);
            break;
        default:
            dwError = ERROR_GEN_FAILURE;
        }

        if (dwError == NOERROR)
        {
            // assume that WSAStartup already called
            // WSADATA wd;
            // WSAStartup(WINSOCK_VERSION, &wd);

            char AddressString[64];
            ULONG dwAddressStringLength = _countof(AddressString);
            if (WSAAddressToStringA(&sa, cb, 0, AddressString, &dwAddressStringLength) == NOERROR)
            {
                DbgPrint("client ip is %s\n", AddressString);
            }
            else
            {
                dwError = WSAGetLastError();
            }
        }
    }
    else
    {
        dwError = GetLastError();
    }

    return dwError;
}


Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 12:55
finsoftrz
Решил спросить у DeepSeek, давно была мысль его на перевод с win api попробовать. :-) Вот что выдал (прототип и пример использования).

Код: Выделить всё

MODULE('USER32')
  WinStationQueryInformationW(ULONG, ULONG, WSTRING, ULONG, ULONG),BOOL,RAW,PASCAL,NAME('WinStationQueryInformationW')
END

Код: Выделить всё

LOCAL(infoBuffer AS WSTRING(256))
LOCAL(bufferSize AS ULONG)
LOCAL(result AS BOOL)

bufferSize = SIZEOF(infoBuffer)
result = WinStationQueryInformationW(0, 0, 'WinStationInfo', infoBuffer, bufferSize)

IF result THEN
  MESSAGE('Информация успешно получена: ' & infoBuffer)
ELSE
  MESSAGE('Ошибка при получении информации')
END

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 12:58
finsoftrz
Пример для получения ip адреса. Правда пишет, что нужны права администратора.

Код: Выделить всё

MODULE('USER32')
  WinStationQueryInformationW(ULONG, ULONG, ULONG, *GROUP, ULONG, *ULONG),BOOL,RAW,PASCAL,NAME('WinStationQueryInformationW')
END

WTS_CLIENT_ADDRESS GROUP, TYPE
  AddressFamily  ULONG
  Address       BYTE(20)
END

LOCAL(clientAddress AS WTS_CLIENT_ADDRESS)
LOCAL(returnedLength AS ULONG)
LOCAL(result AS BOOL)

! Запрашиваем информацию о клиентском адресе
result = WinStationQueryInformationW(0, 0, 14, ADDRESS(clientAddress), SIZEOF(clientAddress), ADDRESS(returnedLength))

IF result THEN
  ! Извлекаем IP-адрес из структуры
  LOCAL(ipAddress AS STRING(16))
  ipAddress = FORMAT(clientAddress.Address[2]) & '.' & FORMAT(clientAddress.Address[3]) & '.' & FORMAT(clientAddress.Address[4]) & '.' & FORMAT(clientAddress.Address[5])
  MESSAGE('IP-адрес клиента: ' & ipAddress)
ELSE
  MESSAGE('Ошибка при получении IP-адреса клиента')
END

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 16:37
Дед Пахом
А это не смущает?
[WinStationQueryInformationW is not supported and may be altered or unavailable in the future. Instead, use the GetSystemMetrics function with SM_REMOTESESSION to obtain this information (see Detecting the Remote Desktop Services Environment). ]

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 17:15
finsoftrz
Дед Пахом писал(а): 03 Март 2025, 16:37 А это не смущает?
[WinStationQueryInformationW is not supported and may be altered or unavailable in the future. Instead, use the GetSystemMetrics function with SM_REMOTESESSION to obtain this information (see Detecting the Remote Desktop Services Environment). ]
Автор примера написал, что это работает на всех версиях винды. Ему такой же вопрос задали. Потом автор вопроса попробовал, отписался, что все норм.
DeepSeek, конечно, полную ахинею написал.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 17:16
finsoftrz
В списке запросов GetSystemMetrics получения адреса не увидел, специально проверил.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 03 Март 2025, 22:16
finsoftrz
На всякий случай напишу, что утилита GETTSCIP.exe не подходит для этих целей, так как она возвращает адрес компьютера в локальной сети, а не внешний ip адрес компьютера, с которого делается терминальное подключение.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 04 Март 2025, 0:40
finsoftrz
Подумал, подумал, сделал пока проверку через GETTSCIP.exe. Может, позже что-то получится с определением внешнего ip адреса.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 04 Март 2025, 1:37
Admin
Смысл в том, чтобы можно на уровне приложения устанавливать разрешение для пользователя входить с определенного ip адреса или блокировать какие-то ip адреса.

Обратите внимание что клиент(ы) может сидеть за NAT и в таком случае в получите не совсем верную информацию.
Обычно для этих целей используют отдельные сторонние продукты, но хотелось бы все иметь в одном флаконе, проще управлять и контролировать.
Сторонние продукты м.б. заточены на идентификацию по многим признакам.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 04 Март 2025, 8:14
finsoftrz
Там 2 варианта задачи.
Первый сделать возможным вход в приложение пользователя, подключающегося только с определенного ip адреса. Сейчас я сделал, как написал, через gettscip.exe. Эта утилита возвращает тот ip адрес, который передает на сервер удаленный компьютер. Если она за роутером, то это будет адрес компьютера в локальной сети, то есть что-то типа 192.168.1.88. Внешний ip адрес, с которого происходит подключение к серверу, будет другой. Для первого варианта задачи, в принципе, такой вариант можно использовать, так как внутренний адрес в сети можно согласовать с клиентом.

Второй это запрет или разрешение входа в программу с определенных ip адресов. Для этих целей нужен внешний ip адрес удаленного компьютера, и gettscip.exe не подойдет. В интернете я нашел только информацию с WinStationQueryInformationW, про это как-то очень скудно пишут. Может, есть и еще какие-то варианты. Нужно ли включать в приложение такую проверку, это открытый вопрос, так как эта проверка будет работать после запуска кларионовского приложения, предпочтительнее ее проводить до этого. Для tsplus есть отдельный продукт tsplus advanced security (за отдельную плату), который как раз таким, в том числе, и занимается. По сути, это все держится на достаточно простой настройке, если удастся определить внешний ip адрес.

Другие фишки для входа в приложение у меня есть. Это отключение выбора из списка пользователей и ввод имени пользователя напрямую в окне подключения (как в винде), запрет подключения определенным пользователям в режиме терминального сервера, запрет доступа к файловой системе сервера из приложения, ограничение подключения по часам в течении дня, запрет подключения в выходные дни, автоматическая блокировка на определенное время после заданного количества неудачных попыток авторизации.

Определение ip адреса удаленного компьютера в терминальной сессии через win api

Добавлено: 28 Март 2025, 8:33
finsoftrz
Может кому пригодиться как пример кода. Определяет имя и ip адрес удаленного компьютера в терминальной сессии. IP адрес это тот, который сообщает удаленный компьютер и может отличаться от внешнего ip адреса, если подключение через роутер (его же возвращает и утилита gettscip.exe).

Код: Выделить всё

fsWinApiExtL.init(2)
loc:name = fsWinApiExtL.TSGetClientName()
loc:address = fsWinApiExtL.TSGetClientAddress()
fsWinApiExtL.kill  
fswinapiext.zip
(3.58 КБ) 114 скачиваний