Kailangan ng RDP session ng address ng kliyente, at hindi nagkakasundo ang halatang mga pinagmulan. Ang CLIENTNAME ay nagbibigay ng pangalan ng computer, ang rehistro ay may mga halaga mula sa ibang mga session, at ang kabilang dulo ng socket ay maaaring address ng gateway o NAT sa halip na ang kliyente. Talagang inilalantad ng Windows ang iniulat na address ng kliyente kada session, ngunit kailangan mong itanong ang tamang session at i-decode nang tama ang sagot.

Iangkla ang paghahanap sa isang session

Magsimula sa session, hindi sa tao. Ang Windows RDP host ay maaaring magdala ng ilang session para sa isang account, at ang address na nakita bago ang muling pagkonekta ay maaaring hindi na tumugma sa aktibong link. Itala nang sama-sama ang session ID, ang user at ang oras ng pagmamasid. Ang session ID ang susi na inaasahan ng API, at ito ang halagang pumipigil sa dalawang session na magkalito.

Sa host, inililista ng mga naka-install na kasangkapan sa session kung ano ang umiiral; gamitin ang administratibong tanawin lamang kapag may karapatan ka rito. Kumpirmahin ang piniling ID kaagad bago ang query, dahil ang na-recycle na ID ay nagbabalik ng datos ng ibang session.

qwinsta

Tawagin ang WTSQuerySessionInformationW para sa ID na iyon

Sinasagot ng Terminal Services API ang tanong sa pamamagitan ng information class 14, WTSClientAddress. Sapat ang maliit na ctypes wrapper sa Windows, at iniiwasan nito ang pagbasa ng hive ng ibang user. Ang code sa ibaba ay kumukuha ng tahasang session ID at nagtatanong sa lokal na host.

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)

Ipasa ang integer na session ID na kababang-verify mo lang, at panatilihin ang null server handle para sa lokal na makina. Ituring na error ang nabigong tawag at hindi bilang nawawalang address, dahil magkaiba ang patutunguhan ng dalawa. Ang pagtatanong sa session ng ibang user ay nangangailangan ng naaangkop na pahintulot na Query Information, kaya patakbuhin ang kasangkapan sa ilalim ng account na binigyan nito sa halip na mag-escalate nang ad hoc. Ang ibinalik na buffer ay pag-aari ng API at dapat ilabas kahit nabigo ang pag-decode.

I-decode ang pamilya, pagkatapos ilabas ang buffer

Ang istruktura ay hindi IP string. Ang field ng pamilya ang nagtatakda kung paano babasahin ang dalawampung byte ng address: nagsisimula ang IPv4 sa offset dalawa, samantalang ang IPv6 ay nagsisimula sa offset sero. Ang hindi tinukoy na address ay nangangahulugang walang iniulat ang kliyente, na hindi katulad ng walang laman na string. Ang mga koneksyon sa Remote Desktop Gateway ay nakadokumento bilang kaso kung saan hindi available ang address, kaya ang session na dumadaan sa gateway ay walang iniuulat na kapaki-pakinabang tungkol sa tunay na address ng kliyente. Kailangan nang lumipat ang ugnayan sa sariling mga talaan ng gateway.

I-print ang pamilya sa tabi ng address habang nagde-debug, dahil ang pagkakaiba ng dalawa ang karaniwang dahilan ng makatwirang ngunit maling halaga. Ilabas ang buffer gamit ang WTSFreeMemory sa loob ng finally block upang hindi ito tumagas ng isang exception.

Ihiwalay ang iniulat na address sa ebidensiya

Ang iniulat na address ng kliyente ay isang pahayag na ibinibigay ng kliyente, hindi isang mapagkakatiwalaang obserbasyon. Hindi ito ang kabilang dulo ng TCP, hindi ang talahanayan ng lease ng VPN gateway, at hindi ang pampublikong address ng kliyente. Kapag ang tunay na tanong ay kung aling VPN lease ang pag-aari ng isang tao, iugnay ang authenticated na talaan ng session ng VPN server sa parehong oras. Kapag ang tanong ay kung aling pinagmulan ang nakarating sa tagapakinig, basahin ang talahanayan ng koneksyon o ang pinapayagang server-side logs.

Panatilihing hiwalay ang mga label ng mga halagang ito sa anumang kasangkapan sa suporta. Ang nawawalang resulta ng WTS ay dapat manatiling nawawala sa halip na bumalik sa arbitraryong halaga ng rehistro mula sa ibang session. I-log ang session ID sa tabi ng address, dahil ang parehong user ay maaaring muling kumonekta at makakuha ng bagong halaga. Ni ang pangalan ng kliyente ni ang iniulat na address ay hindi sapat na ebidensiya para magbigay ng access.

Kaugnay na mga artikulo