Alamat apa yang dilaporkan Windows untuk sesi RDP?
API WTS mengembalikan alamat klien yang dilaporkan untuk satu sesi RDP, sedangkan registri tidak. Tanyakan ID sesi yang tepat dan dekodekan IPv4 atau IPv6 dengan benar.
Sesi RDP membutuhkan alamat klien, dan sumber yang tampak jelas tidak sepakat. CLIENTNAME memberi nama komputer, registri menyimpan nilai dari sesi lain, dan ujung soket bisa berupa alamat gateway atau NAT, bukan klien. Windows memang mengekspos alamat klien yang dilaporkan per sesi, tetapi Anda harus meminta sesi yang tepat dan mendekode balasannya dengan benar.
Jangkarkan pencarian pada satu sesi
Mulailah dari sesinya, bukan orangnya. Host RDP Windows dapat membawa beberapa sesi untuk satu akun, dan alamat yang terlihat sebelum penyambungan ulang mungkin tidak lagi cocok dengan tautan yang aktif. Catat ID sesi, pengguna, dan waktu pengamatan bersama-sama. ID sesi adalah kunci yang diharapkan API, dan nilai itulah yang mencegah dua sesi tertukar.
Di host, perkakas sesi yang terpasang mendaftar apa yang ada; gunakan tampilan administratif hanya ketika Anda berhak atasnya. Konfirmasi ID yang dipilih tepat sebelum kueri, karena ID yang didaur ulang mengembalikan data sesi lain.
qwinsta
Panggil WTSQuerySessionInformationW untuk ID itu
API Terminal Services menjawab pertanyaan itu dengan kelas informasi 14, WTSClientAddress. Pembungkus ctypes kecil sudah cukup di Windows, dan itu menghindari pembacaan hive pengguna lain. Kode di bawah mengambil ID sesi eksplisit dan bertanya kepada host lokal.
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)
Teruskan ID sesi bilangan bulat yang baru Anda verifikasi, dan pertahankan handle server nol untuk mesin lokal. Perlakukan panggilan yang gagal sebagai kesalahan, bukan sebagai alamat yang tidak ada, karena keduanya mengarah ke kesimpulan berbeda. Kueri sesi pengguna lain memerlukan izin Query Information yang sesuai, jadi jalankan perkakas di bawah akun yang telah diberinya alih-alih menaikkan hak secara ad hoc. Buffer yang dikembalikan milik API dan harus dilepaskan bahkan ketika pendekodean gagal.
Dekodekan famili, lalu lepaskan buffer
Struktur itu bukan string IP. Bidang familinya menentukan bagaimana dua puluh bita alamat dibaca: IPv4 mulai pada offset dua, sedangkan IPv6 mulai pada offset nol. Alamat yang tidak ditentukan berarti klien tidak melaporkan satu pun, yang tidak sama dengan string kosong. Koneksi Remote Desktop Gateway didokumentasikan sebagai kasus di mana alamat tidak tersedia, sehingga sesi yang dimediasi gateway tidak melaporkan apa pun yang berguna tentang alamat klien yang sebenarnya. Korelasi lalu harus berpindah ke catatan gateway itu sendiri.
Cetak famili di samping alamat saat Anda men-debug, karena ketidakcocokan antara keduanya adalah penyebab umum nilai yang masuk akal tetapi salah. Lepaskan buffer dengan WTSFreeMemory dalam blok finally agar pengecualian tidak membocorkannya.
Pisahkan alamat yang dilaporkan dari bukti
Alamat klien yang dilaporkan adalah pernyataan yang diberikan klien, bukan pengamatan yang tepercaya. Itu bukan rekan TCP, bukan tabel sewa gateway VPN, dan bukan alamat publik klien. Ketika pertanyaan sebenarnya adalah sewa VPN mana yang milik seseorang, korelasikan catatan sesi terautentikasi server VPN pada waktu yang sama. Ketika pertanyaannya adalah sumber mana yang mencapai pendengar, bacalah tabel koneksi atau log sisi server yang diizinkan.
Simpan nilai-nilai ini berlabel terpisah di perkakas dukungan mana pun. Hasil WTS yang hilang harus tetap hilang alih-alih jatuh ke nilai registri sembarang dari sesi lain. Catat ID sesi di samping alamat, karena pengguna yang sama dapat menyambung ulang dan menerima nilai baru. Nama klien maupun alamat yang dilaporkan bukan bukti yang cukup untuk memberikan akses.