Disassembler

Artificial intelligence is no match for natural stupidity.
04února2017

Miniaturní socket server v PowerShellu


Je tomu už téměř rok, co jsem potřeboval malou nenáročnou utilitku pro AIX, která by si sedla na mnou zvolený TCP port a já tak s její pomocí mohl zjistit, zda jsem schopný se na socket připojit, i pokud sedím za devatero firewally, devatero proxynami a devatero NATy. Dnes se mi přihodilo, že jsem něco podobného potřeboval odladit na Windows Serverech. A světe div se, ani pro ně neexistuje slušná a nenáročná náhrada netcatu.

Ťuk ťuk. Kdo tam?


Abych čtenáře nemystifikoval příliš, prozradím, že netcat, stejně jako nmap, existují i ve formě zkompilovaných binárek pro Windows, ale na Windows Server 2012 R2 se mi tvrdošíjně odmítaly spustit. Stejně jako v případě perlu na AIXu, i zde mě v zápětí napadlo zkusit přemluvit nativní systémové funkce, a s pomocí zaklínadel ve formě skriptovacího jazyka je zřetězit tak, aby dělaly, co zrovna potřebuju. PowerShell, který je od dob Windows Server 2008 ve standardní výbavě operačního systému, se k takovému kousku výborně hodí, protože umožňuje vypůjčit si potřebné objekty z .NET knihoven. Podotýkám, že účelem kódu bylo co nejméně se nadřít a vyrobit jej co nejpodobněji jako dříve publikovanou perlovskou variantu, takže k nějakému mistrovskému dílu má hodně daleko. Například neřeší žádné timeouty a metoda AcceptTcpClient() blokuje vlákno, takže skript je potřeba ukončit násilím. Případně se také dá použít metoda Pending() a napsat okolo ní vlastní polling.

$endpoint = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Parse("192.168.12.34"), 12345)
$server = New-Object System.Net.Sockets.TcpListener $endpoint
$server.Start()
Write-Host "Server started on $endpoint"

While ($client = $server.AcceptTcpClient()) {
	Write-Host "Connection received from $($client.Client.RemoteEndPoint)"
	$writer = New-Object System.IO.StreamWriter $client.GetStream()
	$writer.Write("Welcome to {0}", $endpoint);
	$writer.Flush()
	$client.Close()
}

Pro ještě menší dřinu je možno v definici endpointu použít [System.Net.IPAddress]::All, které systém donutí naslouchat na všech síťových rozhraních, což ovšem nemusí být vždy žádoucí.