Added whois client, renamed parsers to providers & more

This commit is contained in:
Filip Znachor 2024-09-04 22:04:19 +02:00
parent 1b45a5b6c9
commit c186760831
10 changed files with 192 additions and 40 deletions

View file

@ -5,7 +5,7 @@
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"CodeSpace\\WhoisParser\\": "src/", "CodeSpace\\WhoisParser\\": "src/",
"CodeSpace\\WhoisParser\\Parser\\": "src/parser/" "CodeSpace\\WhoisParser\\Provider\\": "src/provider/"
} }
}, },
"require": { "require": {

View file

@ -1,19 +0,0 @@
<?php namespace CodeSpace\WhoisParser;
interface ParserInterface {
public function parseAsn(WhoisParser $whois): ?array;
public function parseAbuse(WhoisParser $whois): ?array;
public function parseOrg(WhoisParser $whois): ?array;
public function parseRoute(WhoisParser $whois): ?array;
public function parseInet(WhoisParser $whois): ?array;
public function findAsn(WhoisParser $whois): ?string;
public function findAbuseContact(WhoisParser $whois): ?string;
}

11
src/Provider.php Normal file
View file

@ -0,0 +1,11 @@
<?php namespace CodeSpace\WhoisParser;
enum Provider: string {
const APNIC_WHOIS = "whois.apnic.net";
const RIPE_WHOIS = "whois.ripe.net";
case APNIC = self::APNIC_WHOIS;
case RIPE = self::RIPE_WHOIS;
}

19
src/ProviderInterface.php Normal file
View file

@ -0,0 +1,19 @@
<?php namespace CodeSpace\WhoisParser;
interface ProviderInterface {
public function parseAsn(): ?array;
public function parseAbuse(): ?array;
public function parseOrg(): ?array;
public function parseRoute(): ?array;
public function parseInet(): ?array;
public function findAsn(): ?string;
public function findAbuseContact(): ?string;
}

33
src/Whois.php Normal file
View file

@ -0,0 +1,33 @@
<?php namespace CodeSpace\WhoisParser;
class Whois {
public function getIpAddress(string $ip): array {
$whois = WhoisClient::query($ip);
$list = new WhoisList($whois);
$this->addAsn($list);
$this->addAbuse($list);
return [
"network" => $list->parseInet(),
"route" => $list->parseRoute(),
"asn" => $list->parseAsn(),
"org" => $list->parseOrg(),
"abuse" => $list->parseAbuse()
];
}
private function addAsn(WhoisList $list) {
$asn = $list->findAsn();
if (!$asn) return;
$asn_whois = WhoisClient::query($asn);
$list->addResponse($asn_whois);
}
private function addAbuse(WhoisList $list) {
$abuse_c = $list->findAbuseContact();
if (!$abuse_c) return;
$abuse_whois = WhoisClient::query($abuse_c);
$list->addResponse($abuse_whois);
}
}

26
src/WhoisClient.php Normal file
View file

@ -0,0 +1,26 @@
<?php namespace CodeSpace\WhoisParser;
use MallardDuck\Whois\Client;
class WhoisClient {
public static function query(string $q): ?WhoisParser {
$server = self::getServer($q);
if (!$server) return null;
return self::queryServer("$q -B", $server);
}
public static function queryServer(string $q, string $server): WhoisParser {
$client = new Client($server);
$response = $client->makeRequest($q);
return WhoisParser::fromString($response, Provider::tryFrom($server));
}
public static function getServer(string $q): ?string {
if (str_ends_with($q, "-RIPE")) return Provider::RIPE_WHOIS;
if (str_ends_with($q, "-AP")) return Provider::APNIC_WHOIS;
$res = self::queryServer($q, "whois.iana.org");
return $res->getKeysValue(["refer", "whois"]);
}
}

57
src/WhoisList.php Normal file
View file

@ -0,0 +1,57 @@
<?php namespace CodeSpace\WhoisParser;
class WhoisList implements ProviderInterface {
private array $responses = [];
private array $providers = [];
public function __construct(?WhoisParser $response = null) {
$this->addResponse($response);
}
public function addResponse(?WhoisParser $response) {
if (!$response) return;
$provider = $response->getProvider();
if (!$provider) return;
$this->responses[] = $response;
$this->providers[] = $provider;
}
private function providerIter(string $fn) {
foreach ($this->providers as $provider) {
$res = $provider->$fn();
if ($res) return $res;
}
return null;
}
public function parseAsn(): ?array {
return $this->providerIter("parseAsn");
}
public function parseAbuse(): ?array {
return $this->providerIter("parseAbuse");
}
public function parseOrg(): ?array {
return $this->providerIter("parseOrg");
}
public function parseRoute(): ?array {
return $this->providerIter("parseRoute");
}
public function parseInet(): ?array {
return $this->providerIter("parseInet");
}
public function findAsn(): ?string {
return $this->providerIter("findAsn");
}
public function findAbuseContact(): ?string {
return $this->providerIter("findAbuseContact");
}
}

View file

@ -1,21 +1,32 @@
<?php namespace CodeSpace\WhoisParser; <?php namespace CodeSpace\WhoisParser;
use CodeSpace\WhoisParser\Provider\ApNicProvider;
use CodeSpace\WhoisParser\Provider\RipeProvider;
class WhoisParser { class WhoisParser {
public array $lines = []; public array $lines = [];
public string $provider; public ?Provider $provider;
public static function fromArray(array $lines, string $provider) { public static function fromArray(array $lines, ?Provider $provider = null) {
$parser = new self(); $parser = new self();
$parser->lines = $lines; $parser->lines = $lines;
$parser->provider = $provider; $parser->provider = $provider;
return $parser; return $parser;
} }
public static function fromString(string $whois, string $provider) { public static function fromString(string $whois, ?Provider $provider = null) {
return self::fromArray(explode("\n", $whois), $provider); return self::fromArray(explode("\n", $whois), $provider);
} }
public function getProvider(): ?ProviderInterface {
if (!$this->provider) return null;
return match ($this->provider) {
Provider::RIPE => new RipeProvider($this),
Provider::APNIC => new ApNicProvider($this)
};
}
private function getOffset(array $arr, int $index): mixed { private function getOffset(array $arr, int $index): mixed {
return count($arr) > $index ? $arr[$index] : null; return count($arr) > $index ? $arr[$index] : null;
} }

View file

@ -0,0 +1,3 @@
<?php namespace CodeSpace\WhoisParser\Provider;
class ApNicProvider extends RipeProvider {}

View file

@ -1,12 +1,19 @@
<?php namespace CodeSpace\WhoisParser\Parser; <?php namespace CodeSpace\WhoisParser\Provider;
use CodeSpace\WhoisParser\ParserInterface; use CodeSpace\WhoisParser\ProviderInterface;
use CodeSpace\WhoisParser\WhoisParser; use CodeSpace\WhoisParser\WhoisParser;
class RipeParser implements ParserInterface { class RipeProvider implements ProviderInterface {
public function parseAsn(WhoisParser $whois): ?array { private $whois;
$as = $whois->getSectionWithKey("aut-num");
public function __construct(WhoisParser $whois) {
$this->whois = $whois;
}
public function parseAsn(): ?array {
$as = $this->whois->getSectionWithKey("aut-num");
if (!$as) return null;
return [ return [
"asn" => $as->getKeyValue("aut-num"), "asn" => $as->getKeyValue("aut-num"),
"name" => $as->getKeyValue("as-name"), "name" => $as->getKeyValue("as-name"),
@ -14,8 +21,9 @@ class RipeParser implements ParserInterface {
]; ];
} }
public function parseAbuse(WhoisParser $whois): ?array { public function parseAbuse(): ?array {
$abuse = $whois->getSectionWithKey("abuse-mailbox"); $abuse = $this->whois->getSectionWithKey("abuse-mailbox");
if (!$abuse) return null;
return [ return [
"role" => $abuse->getKeyValue("role"), "role" => $abuse->getKeyValue("role"),
"address" => $abuse->getKeyValues("address"), "address" => $abuse->getKeyValues("address"),
@ -25,8 +33,9 @@ class RipeParser implements ParserInterface {
]; ];
} }
public function parseOrg(WhoisParser $whois): ?array { public function parseOrg(): ?array {
$org = $whois->getSectionWithKey("organisation"); $org = $this->whois->getSectionWithKey("organisation");
if (!$org) return null;
return [ return [
"id" => $org->getKeyValue("organisation"), "id" => $org->getKeyValue("organisation"),
"name" => $org->getKeyValue("org-name"), "name" => $org->getKeyValue("org-name"),
@ -37,8 +46,9 @@ class RipeParser implements ParserInterface {
]; ];
} }
public function parseRoute(WhoisParser $whois): ?array { public function parseRoute(): ?array {
$section = $whois->getSectionWithKeys(["route", "route6"]); $section = $this->whois->getSectionWithKeys(["route", "route6"]);
if (!$section) return null;
$range = $section->getKeysValue(["route", "route6"]); $range = $section->getKeysValue(["route", "route6"]);
return [ return [
"range" => $range, "range" => $range,
@ -47,8 +57,9 @@ class RipeParser implements ParserInterface {
]; ];
} }
public function parseInet(WhoisParser $whois): ?array { public function parseInet(): ?array {
$section = $whois->getSectionWithKeys(["inetnum", "inet6num"]); $section = $this->whois->getSectionWithKeys(["inetnum", "inet6num"]);
if (!$section) return null;
$range = $section->getKeysValue(["inetnum", "inet6num"]); $range = $section->getKeysValue(["inetnum", "inet6num"]);
return [ return [
"range" => $range, "range" => $range,
@ -58,12 +69,12 @@ class RipeParser implements ParserInterface {
]; ];
} }
public function findAsn(WhoisParser $whois): ?string { public function findAsn(): ?string {
return $whois->getKeyValue("origin"); return $this->whois->getKeyValue("origin");
} }
public function findAbuseContact(WhoisParser $whois): ?string { public function findAbuseContact(): ?string {
return $whois->getKeyValue("abuse-c"); return $this->whois->getKeyValue("abuse-c");
} }
} }