Skip to content

Instantly share code, notes, and snippets.

@dadodasyra
Created April 16, 2022 17:30
Show Gist options
  • Save dadodasyra/dc1164772f529260f5b28048be269c2a to your computer and use it in GitHub Desktop.
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
<?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