mirror of
https://github.com/xnite/MCSeeker.git
synced 2026-05-02 12:54:50 -07:00
Compare commits
25 Commits
v0.0.1-alp
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1379038a4 | ||
|
|
d522d490eb | ||
|
|
625567ae1a | ||
|
|
344b583499 | ||
|
|
2451ec794a | ||
|
|
a5dc543cf4 | ||
|
|
b13e690eda | ||
|
|
73afc74074 | ||
|
|
f05b17ee9a | ||
|
|
0a73fb77af | ||
|
|
a801231a84 | ||
|
|
d060605253 | ||
|
|
1be7bcda44 | ||
|
|
2bc8640c0b | ||
|
|
e7a59b2e97 | ||
|
|
4a08a5ce14 | ||
|
|
cbfea276f3 | ||
|
|
c14d2fbb8c | ||
|
|
c6e5f6fb25 | ||
|
|
8a68e61c0f | ||
|
|
dddb5fbba9 | ||
|
|
aac11cd570 | ||
|
|
4d9542e268 | ||
|
|
a9e7e3b230 | ||
|
|
0d2f83db70 |
38
README.md
38
README.md
@@ -1,24 +1,43 @@
|
||||
# What is this?
|
||||
This scans for MineCraft servers... really really fast!
|
||||
This scans for MineCraft servers... really really fast! [but this scans even faster](https://github.com/xnite/BBCrawler)
|
||||
|
||||
# Getting Started
|
||||
* Clone this repository somewhere.
|
||||
* Run `npm install` from within this directory.
|
||||
|
||||
## Getting Help
|
||||
You can get help through our [Discord server](https://discord.gg/3RUjaRzdKv)
|
||||
|
||||
## Usage
|
||||
Run `node ./scanner.js [options] --ip <ip range>`
|
||||
|
||||
### Example
|
||||
### Examples
|
||||
`node ./scanner.js --ip 192.168.1.0/24 --port 25565-25569 --show-desc --min-players 1 --max-players 100 --out report.csv`
|
||||
`node ./scanner.js --ip 192.168.1.0/24 --port 25565-25569 --show-desc --min-players 1 --max-players 100 --version '1.8.*' --out 1.8.x-servers.csv`
|
||||
`node ./scanner.js --ip 192.168.1.0/24 --port 25565-25569 --show-desc --min-players 1 --max-players 100 --version '*forge*' --out forge-servers.csv`
|
||||
|
||||
### CLI Options
|
||||
### Options
|
||||
* `--ip <ip>` - IP Address or Range of IP Addresses with CIDR notation (eg- 192.168.1.0/24)
|
||||
* `--port <ports>` - Ports to look for minecraft servers on. (Default: `25565-25566`)
|
||||
* `--min-players <count>` - Minimum number of players.
|
||||
* `--max-players <count>` - Maximum player count.
|
||||
* `--version <glob expression>` - Glob expression to filter version (eg- `1.19.*`, or `1.1*.*`). (Default: `*`)
|
||||
* `--conc <howmany>` - How many concurrent connections to use for scanning. (Default is 256)
|
||||
|
||||
#### Output Options
|
||||
* `--show-desc` - Enable showing of server description in output.
|
||||
* `--quiet` - Silence terminal output.
|
||||
* `--min-players <count>` - Minimum number of players to display.
|
||||
* `--max-players <count>` - Only show servers with max player count or below.
|
||||
|
||||
|
||||
#### Output File Options
|
||||
* `--out <filename>` - Output to CSV file (Can be opened as a spreadsheet in MS Office, Google Docs, etc.)
|
||||
* `--format <csv|txt|txt-connect-only>` - Output format (`txt-connect-only` for `ip:port` list format)
|
||||
* `--log-desc` - Output server discription to output file.
|
||||
|
||||
#### Geo Location
|
||||
* `--geo-ip` - Use IP Geolocation database.
|
||||
* `--geo-coords` - Add geo-coordinates to output.
|
||||
* `--maxmind-key` - Provide a key for maxmind database download.
|
||||
|
||||
## By really fast, I mean really fast!
|
||||
# time node ./scanner.js --ip 135.148.60.0/24 --show-desc --quiet --out example.csv
|
||||
@@ -28,8 +47,11 @@ Run `node ./scanner.js [options] --ip <ip range>`
|
||||
real 0m3.183s
|
||||
user 0m0.825s
|
||||
sys 0m0.334s
|
||||
At this speed, a full /16 (123.45.0.0 - 123.45.255.255) will take about 13 and a half minutes to scan.
|
||||
# cat example.csv | wc -l
|
||||
85
|
||||
In this example it took `3.183` seconds to scan `255` IP addresses, and find `85` MineCraft servers. At this speed, a full `/16` (`123.45.0.0 - 123.45.255.255`) will take about `13.5` minutes to scan.
|
||||
|
||||
## Limitations
|
||||
* Fails to scan more than a /16 without kicking the bucket... so you should probably stick to that or smaller ranges.
|
||||
* Working on a Minecraft bot client... doesn't work though... you can see how badly it doesn't work by using `--enable-client` flag... it is totally broken. **Don't use it**.
|
||||
* Fails to scan more than a /10 without kicking the bucket... so you should probably stick to that or smaller ranges.
|
||||
* Working on a Minecraft bot client... doesn't work though... you can see how badly it doesn't work by using `--enable-client` flag... it is totally broken. **Don't use it**.
|
||||
* Above limitations are solved by running [BBCrawler](https://github.com/xnite/BBCrawler) instead but that is more complex than most people will want.
|
||||
12
package.json
12
package.json
@@ -1,8 +1,18 @@
|
||||
{
|
||||
"name": "mcseeker",
|
||||
"version": "0.0.2",
|
||||
"description": "A Minecraft server scanner",
|
||||
"author": "Robert Whitney <Me@Rob.cat>",
|
||||
"main": "scanner.js",
|
||||
"license": "GPL V3",
|
||||
"dependencies": {
|
||||
"commandos": "^0.10.1",
|
||||
"evilscan": "^1.8.1",
|
||||
"maxmind": "^4.3.5",
|
||||
"minecraft-status": "^1.1.0",
|
||||
"mineflayer": "^4.0.0"
|
||||
"mineflayer": "^4.0.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"node-mcpe-color-parser": "^0.1.1",
|
||||
"tar-stream": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
120
scanner.js
120
scanner.js
@@ -1,7 +1,10 @@
|
||||
var Scanner = require('evilscan');
|
||||
var status = require('minecraft-status').MinecraftServerListPing;
|
||||
var mc = require('mineflayer');
|
||||
var minimatch = require("minimatch");
|
||||
var fs = require('fs');
|
||||
var maxmind;
|
||||
var mcp = require('node-mcpe-color-parser');
|
||||
//var mcClient = require('minecraft-protocol');
|
||||
process.params = (require('commandos')).parse(process.argv);
|
||||
var MINECRAFT_DEFAULT_PORT = '25565-25566';
|
||||
@@ -9,8 +12,50 @@ var SCAN_MIN_PLAYERS = (process.params['min-players'] || 0);
|
||||
var SCAN_OPTS_HOSTS = (process.params['ip']||'0.0.0.0/0').toString();
|
||||
var SCAN_OPTS_PORTS = (process.params['port'] || MINECRAFT_DEFAULT_PORT).toString();
|
||||
var SCAN_OPTS_OUTPUT_CSV = (process.params['out']||null);
|
||||
var SCAN_OPTS_VERSION_FILTER = (process.params['version']||'*');
|
||||
var SCAN_OPTS_CONCURRENCY = (process.params['conc'] || 256);
|
||||
var CLIENT_TOKEN;
|
||||
|
||||
if(process.params['geo-ip'])
|
||||
{
|
||||
if (!fs.existsSync("./GeoLite2.mmdb"))
|
||||
{
|
||||
if(!process.params['maxmind-key'])
|
||||
{
|
||||
return console.log("NO MAXMIND DOWNLOAD KEY WAS PROVIDED! CANNOT DOWNLOAD THE DATABASE WITHOUT A KEY!");
|
||||
}
|
||||
return require('https').get("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key="+ process.params['maxmind-key'] +"&suffix=tar.gz", function(resp){
|
||||
const zlib = require('zlib');
|
||||
const tar = require('tar-stream');
|
||||
|
||||
const tarFile = fs.createWriteStream("./GeoLite2.tar");
|
||||
const dbfile = fs.createWriteStream('./GeoLite2.mmdb');
|
||||
resp.pipe(zlib.createGunzip()).pipe(tarFile);
|
||||
|
||||
tarFile.on("close", function(){
|
||||
console.log("Wrote tar to disk. Extracting DB file...");
|
||||
var extract = tar.extract();
|
||||
extract.on('entry', function(header, stream, next){
|
||||
if (header.name.match(/.*?\.mmdb/))
|
||||
{
|
||||
stream.pipe(dbfile);
|
||||
dbfile.on('close', function(){
|
||||
fs.unlinkSync("./GeoLite2.tar");
|
||||
console.log("Extracted GeoIP database. Please rerun your scan to continue.");
|
||||
return process.exit(0);
|
||||
})
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
stream.resume();
|
||||
});
|
||||
fs.createReadStream("./GeoLite2.tar").pipe(extract);
|
||||
})
|
||||
});
|
||||
}
|
||||
maxmind = require('maxmind');
|
||||
}
|
||||
|
||||
if(process.params['quiet'] && !SCAN_OPTS_OUTPUT_CSV)
|
||||
{
|
||||
console.log("Error:\tYou have asked for --quiet output, but did not specify an --out file. This scan is pointless!\nRefusing to run a pointless operation.");
|
||||
@@ -44,14 +89,14 @@ if(process.params['enable-client'] && !process.params['client-token'])
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Scanning ports " + SCAN_OPTS_PORTS + " on " + SCAN_OPTS_HOSTS);
|
||||
console.log("Scanning ports " + SCAN_OPTS_PORTS + " on " + SCAN_OPTS_HOSTS + " with " + SCAN_OPTS_CONCURRENCY + " connections.");
|
||||
|
||||
var options = {
|
||||
target: SCAN_OPTS_HOSTS,
|
||||
port: SCAN_OPTS_PORTS,
|
||||
states: 'O',
|
||||
banner: false,
|
||||
concurrency: 255
|
||||
concurrency: SCAN_OPTS_CONCURRENCY
|
||||
}
|
||||
var scan = new Scanner(options);
|
||||
|
||||
@@ -69,23 +114,86 @@ function placeTabs(string)
|
||||
return string;
|
||||
}
|
||||
|
||||
if (SCAN_OPTS_OUTPUT_CSV) {
|
||||
var outStream = fs.createWriteStream(SCAN_OPTS_OUTPUT_CSV, { flags: 'a' });
|
||||
}
|
||||
|
||||
scan.on('result', function(data){
|
||||
//console.log(data);
|
||||
status.ping(757, data.ip, data.port, (process.params['timeout']||15)*1000).then(function(pingRes){
|
||||
if(!minimatch(pingRes.version.name, SCAN_OPTS_VERSION_FILTER)) { return; } // Does not match version filter
|
||||
if (pingRes.players.online >= SCAN_MIN_PLAYERS && (!process.params['max-players'] || (process.params['max-players'] && pingRes.players.max <= process.params['max-players'])))
|
||||
{
|
||||
var theText = data.ip + ":" + data.port + "\t" + pingRes.version.name + "\t" + pingRes.players.online + " of " + pingRes.players.max + " players";
|
||||
if(process.params['show-desc'])
|
||||
{
|
||||
theText += "\t"+pingRes.description.text;
|
||||
theText += "\t"+mcp(pingRes.description).replace(/\n/g, ' ');
|
||||
// pingRes.description is a string, not an object
|
||||
}
|
||||
if (SCAN_OPTS_OUTPUT_CSV)
|
||||
{
|
||||
fs.appendFileSync(SCAN_OPTS_OUTPUT_CSV, data.ip+":"+data.port+","+pingRes.version.name.replace(/\,/g, '+')+","+pingRes.players.online+"/"+pingRes.players.max+"\n");
|
||||
var line;
|
||||
switch(process.params['format']||'csv')
|
||||
{
|
||||
case "txt":
|
||||
line = data.ip + ":" + data.port + "\t" + pingRes.version.name.replace(/\,/g, '+');
|
||||
if (process.params['log-desc']) {
|
||||
line += "\t" + mcp(pingRes.description.text).replace(/\n/g, ' ');
|
||||
}
|
||||
break;
|
||||
case "txt-connect-only":
|
||||
line = data.ip + ":" + data.port;
|
||||
break;
|
||||
case "csv":
|
||||
default:
|
||||
line = data.ip + ":" + data.port + "," + pingRes.version.name.replace(/\,/g, '+') + "," + pingRes.players.online + "/" + pingRes.players.max;
|
||||
if (process.params['log-desc']) {
|
||||
line += "," + mcp(pingRes.description.text).replace(/\n/g, ' ').replace(/\,/g, ';');
|
||||
}
|
||||
}
|
||||
if(process.params['geo-ip'])
|
||||
{
|
||||
maxmind.open('./GeoLite2.mmdb').then(function(geoip){
|
||||
var geoLoc = geoip.get(data.ip);
|
||||
var geoText = geoLoc.country.iso_code;
|
||||
if (process.params['geo-coords']) {
|
||||
geoText += " (" + geoLoc.location.latitude + "," + geoLoc.location.longitude + ")";
|
||||
}
|
||||
switch (process.params['format'] || 'csv')
|
||||
{
|
||||
case "txt":
|
||||
line += " " + geoText;
|
||||
case "csv":
|
||||
line += "," + geoText;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
outStream.write(line.toString().normalize() + "\n");
|
||||
}).catch(function(err){
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
outStream.write(line + "\n");
|
||||
}
|
||||
}
|
||||
if(!process.params['quiet'])
|
||||
{
|
||||
console.log(theText);
|
||||
if (process.params['geo-ip'])
|
||||
{
|
||||
maxmind.open('./GeoLite2.mmdb').then(function (geoip) {
|
||||
var geoLoc = geoip.get(data.ip);
|
||||
var geoText = geoLoc.country.iso_code;
|
||||
if(process.params['geo-coords'])
|
||||
{
|
||||
geoText += " (" + geoLoc.location.latitude + "," + geoLoc.location.longitude + ")";
|
||||
}
|
||||
console.log("[" + geoText + "] " + theText);
|
||||
}).catch(function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
console.log(theText);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(process.params['enable-client'] && (CLIENT_TOKEN||process.params['client-token']))
|
||||
@@ -122,4 +230,4 @@ scan.on('error', err => {
|
||||
scan.on('done', () => {
|
||||
console.log("Scan finished!");
|
||||
});
|
||||
scan.run();
|
||||
scan.run();
|
||||
|
||||
Reference in New Issue
Block a user