RDP-sesio bezonas klientan adreson, kaj la evidentaj fontoj malkonsentas. CLIENTNAME donas komputilan nomon, la registrejo tenas valorojn el aliaj sesioj, kaj la soketa kunulo povas esti pordega aŭ NAT-adreso anstataŭ la kliento. Windows ja elmontras raportitan klientan adreson por ĉiu sesio, sed vi devas demandi la ĝustan sesion kaj malĉifri la respondon ĝuste.

Ankru la serĉadon al unu sesio

Komencu per la sesio, ne per la persono. Windows RDP-gastiganto povas porti plurajn sesiojn por unu konto, kaj adreso vidita antaŭ rekonekto eble jam ne kongruas kun la viva ligilo. Notu kune la sesian ID-on, la uzanton kaj la observan tempon. La sesia ID estas la ŝlosilo, kiun la API atendas, kaj ĝi estas la valoro, kiu malhelpas konfuzi du sesiojn.

Sur la gastiganto, la instalitaj sesiaj iloj listigas tion, kio ekzistas; uzu la administran vidon nur kiam vi rajtas al ĝi. Konfirmu la elektitan ID-on tuj antaŭ la demando, ĉar reciklita ID resendigas datumojn de alia sesio.

qwinsta

Voku WTSQuerySessionInformationW por tiu ID

La API de Terminalaj Servoj respondas la demandon per informa klaso 14, WTSClientAddress. Malgranda ctypes-ĉirkaŭaĵo sufiĉas en Windows, kaj ĝi evitigas legi la abelujon de alia uzanto. La suba kodo prenas eksplicitan sesian ID-on kaj demandas la lokan gastiganton.

import ctypes
import ipaddress
import socket
from ctypes import wintypes

class WTS_CLIENT_ADDRESS(ctypes.Structure):
    _fields_ = [("AddressFamily", wintypes.DWORD),
                ("Address", ctypes.c_ubyte * 20)]

wts = ctypes.WinDLL("Wtsapi32", use_last_error=True)
query = wts.WTSQuerySessionInformationW
query.argtypes = [wintypes.HANDLE, wintypes.DWORD, ctypes.c_int,
                  ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(wintypes.DWORD)]
query.restype = wintypes.BOOL
free = wts.WTSFreeMemory
free.argtypes = [ctypes.c_void_p]

def client_address(session_id):
    buf = ctypes.c_void_p()
    size = wintypes.DWORD()
    if not query(None, session_id, 14, ctypes.byref(buf), ctypes.byref(size)):
        raise ctypes.WinError(ctypes.get_last_error())
    try:
        if size.value < ctypes.sizeof(WTS_CLIENT_ADDRESS):
            raise RuntimeError("short WTS buffer")
        value = ctypes.cast(buf, ctypes.POINTER(WTS_CLIENT_ADDRESS)).contents
        raw = bytes(value.Address)
        if value.AddressFamily == socket.AF_INET:
            addr = ipaddress.ip_address(raw[2:6])
        elif value.AddressFamily == socket.AF_INET6:
            addr = ipaddress.ip_address(raw[:16])
        else:
            return None
        return None if addr.is_unspecified else str(addr)
    finally:
        free(buf)

Transdonu la entjeran sesian ID-on, kiun vi ĵus kontrolis, kaj konservu la nulan servilan tenilon por la loka maŝino. Traktu malsukcesan vokon kiel eraron, ne kiel forestantan adreson, ĉar la du kondukas al malsamaj konkludoj. Demando pri la sesio de alia uzanto postulas la taŭgan permeson Query Information, do rulu la ilon sub konto, al kiu ĝi estis donita, anstataŭ eskali ad hoc. La resendita bufro apartenas al la API kaj devas esti liberigita eĉ kiam la malĉifrado malsukcesas.

Malĉifru la familion, poste liberigu la bufron

La strukturo ne estas IP-ĉeno. Ĝia familia kampo decidas kiel legi la dudek adresajn bajtojn: IPv4 komenciĝas ĉe ofseto du, dum IPv6 komenciĝas ĉe ofseto nulo. La nespecifita adreso signifas, ke la kliento ne raportis unu, kio ne samas al malplena ĉeno. Konektoj tra Remote Desktop Gateway estas dokumentitaj kiel kazo, kie la adreso ne disponeblas, do pordego-perita sesio raportas nenion utilan pri la reala adreso de la kliento. La korelacio tiam devas translokiĝi al la propraj rikordoj de la pordego.

Presu la familion apud la adreso dum vi sencimigas, ĉar malkongruo inter la du estas la kutima kaŭzo de kredebla sed malĝusta valoro. Liberigu la bufron per WTSFreeMemory en finally-bloko, por ke escepto ne liku ĝin.

Apartigu la raportitan adreson de pruvo

Raportita klienta adreso estas deklaro liverita de la kliento, ne fidinda observo. Ĝi ne estas la TCP-kunulo, ne la luo-tabelo de la VPN-pordego, kaj ne la publika adreso de la kliento. Kiam la vera demando estas, kiu VPN-luo apartenas al persono, korelaciu samtempe la aŭtentikigitan sesian rikordon de la VPN-servilo. Kiam la demando estas, kiu fonto atingis la aŭskultanton, legu la koneksan tabelon aŭ la permesitajn servilflankajn protokolojn.

Tenu ĉi tiujn valorojn aparte etikeditaj en ajna subtena ilo. Mankanta WTS-rezulto devus resti mankanta anstataŭ reiri al arbitra registreja valoro el alia sesio. Protokolu la sesian ID-on apud la adreso, ĉar la sama uzanto povas rekonekti kaj ricevi novan valoron. Nek la klienta nomo nek la raportita adreso estas sufiĉa pruvo por doni aliradon.

Rilataj artikoloj