Created
April 16, 2022 17:30
-
-
Save dadodasyra/dc1164772f529260f5b28048be269c2a to your computer and use it in GitHub Desktop.
A simple PHP tool to scan IP ranges and looking for online minecraft bedrock servers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
error_reporting(E_ERROR | E_PARSE); | |
use JetBrains\PhpStorm\ArrayShape; | |
class TestWork extends Thread { | |
//updated version that works with pThreads v3.2.1 and php 7.3.23 | |
protected $complete; | |
protected $result; | |
//$pData is the data sent to your worker thread to do it's job. | |
public function __construct($ip) { | |
//transfer all the variables to local variables | |
$this->complete = false; | |
$this->ip = $ip; | |
} | |
//This is where all of your work will be done. | |
public function run() { | |
$ip = long2ip($this->ip); | |
try { | |
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); | |
if($socket === false) { | |
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; | |
return; | |
} | |
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>5, 'usec'=>5000)); | |
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec'=>5, 'usec'=>5000)); | |
socket_connect($socket, $ip, 19132); | |
$tosend = implode(array_map("chr", [1, 0, 0, 0, 0, 0, 0, 0, 0])). | |
implode(array_map("chr", [0x00, 0xff, 0xff, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0x12, 0x34, 0x56, 0x78])) . | |
implode(array_map("chr", [0, 0, 0, 0, 0, 0, 0, 0])); | |
if(socket_send($socket, $tosend, strlen($tosend), 0) === false) return; | |
$microtime = microtime(true); | |
$buffer = socket_read($socket, 1248); | |
if($buffer === false) return; | |
$bytearray = unpack("C*", $buffer); | |
if (!isset($bytearray[1]) || $bytearray[1] != 28) | |
throw new Exception("Invalid response from : $ip:19132"); | |
$buffer = substr($buffer, 35); | |
$ping = microtime(true) - $microtime; | |
$args = explode(";", $buffer); | |
$return["ip"] = $ip; | |
$return["servertype"] = $args[0]; | |
$return["motd"] = $args[1]; | |
$return["protocol"] = (int)$args[2]; | |
$return["version"] = $args[3]; | |
$return["playercount"] = (int)$args[4]; | |
$return["playermax"] = (int)$args[5]; | |
$return["serverid"] = $args[6]; | |
$return["motd2"] = $args[7]; | |
$return["gamemode"] = $args[8]?? ""; | |
$return["gamemodeid"] = (int)$args[9]?? ""; | |
$return["ipv4port"] = $args[10]?? ""; //Non supporté par Pocketmine | |
$return["ipv6port"] = $args[11]?? ""; | |
$return["ping"] = round($ping * 1000); | |
} catch (Exception $e) { | |
//var_dump($e->getMessage()); //Throw error | |
//var_dump(socket_strerror(socket_last_error($socket))); | |
} finally { | |
socket_close($socket); | |
if(isset($return)){ | |
echo $return["ip"]." - ".$return["motd"]."\n"; | |
$this->result = (array)$return; | |
} | |
$this->complete = true; | |
} | |
} | |
public function isDone() { | |
return $this->complete; | |
} | |
} | |
class ExamplePool extends Pool { | |
public $data = array(); // used to return data after we're done | |
private $numTasks = 0; // counter used to know when we're done | |
/** | |
* override the submit function from the parent | |
* to keep track of our jobs | |
*/ | |
public function submit(Threaded $task) { | |
$this->numTasks++; | |
parent::submit($task); | |
} | |
/** | |
* used to wait until all workers are done | |
*/ | |
public function process() { | |
// Run this loop as long as we have | |
// jobs in the pool | |
$start = time(); | |
while (count($this->data) < $this->numTasks) { | |
if($start + 25 < time()) { | |
echo "Timeout\n"; | |
break; | |
} | |
$this->collect(function (TestWork $task) { | |
// If a task was marked as done | |
// collect its results | |
if ($task->isDone()) { | |
//this is how you get your completed data back out [accessed by $pool->process()] | |
if(isset($task->result)) $this->data[] = $task->result; | |
} | |
return $task->isDone(); | |
}); | |
} | |
// All jobs are done | |
// we can shutdown the pool | |
echo "Shutdown\n"; | |
$this->shutdown(); | |
return $this->data; | |
} | |
} | |
$ranges = [ | |
"146.19.168.0/24", | |
"194.11.20.0/23", | |
"194.9.172.0/23", | |
"194.9.172.0/24", | |
"45.145.164.0/24", | |
"45.145.166.0/24", | |
"45.145.167.0/24", | |
"45.158.77.0/24" | |
]; | |
$port = 19132; | |
$ips = []; | |
foreach ($ranges as $blockOfIps){ | |
$cidr = cidr2range($blockOfIps); | |
$min = $cidr["min"]; | |
$max = $cidr["max"]; | |
//Scan ip in range | |
for ($i = $min; $i <= $max; $i++){ | |
$ips[] = $i; | |
} | |
} | |
$pool = new ExamplePool(count($ips)); | |
$i = 0; | |
foreach ($ips as $ip){ | |
$pool->submit(new TestWork($ip)); | |
$i++; | |
if($i % 50 === 0){ | |
echo "Scanning $i/".count($ips)."\nSleeping for 5 secs\n"; | |
sleep(5); | |
} | |
} | |
$retArr = $pool->process(); | |
//Format text by writing every key as a line separed by " - " | |
$text = ""; | |
foreach ($retArr as $key => $value){ | |
unset($value["servertype"]); | |
unset($value["protocol"]); | |
unset($value["serverid"]); | |
unset($value["gamemodeid"]); | |
unset($value["ipv4port"]); | |
unset($value["ipv6port"]); | |
unset($value["ping"]); | |
foreach($value as $key2 => $value2){ | |
$text .= $key2.": ".$value2.", "; | |
} | |
$text .= "\n"; | |
} | |
//write result to an output file | |
$file = fopen("output.json", "w"); | |
fwrite($file, $text); | |
fclose($file); | |
var_dump($text); | |
#[ArrayShape(["min" => "int", "max" => "int"])] | |
function cidr2range($ipv4): array | |
{ | |
if ($ip=strpos($ipv4,'/')) { | |
$n_ip = (1<<(32-substr($ipv4,1+$ip)))-1; | |
$ip_dec = ip2long(substr($ipv4,0,$ip)); | |
} else { | |
$n_ip = 0; | |
$ip_dec = ip2long($ipv4); | |
} | |
$ip_min = $ip_dec&~$n_ip; | |
$ip_max = $ip_min+$n_ip; | |
return ["min" => $ip_min, "max" => $ip_max]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment