Skip to content

Commit

Permalink
Merge branch 'master' into rs-pairing
Browse files Browse the repository at this point in the history
  • Loading branch information
barryo committed Feb 10, 2024
2 parents a6cc783 + 65326d5 commit 93c53d2
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 40 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,7 @@ tools/docker/containers/mysql/docker.sql
tests/Browser/ExampleTest.php
app/Console/Commands/Redcentric.php
.env.sage

.idea/httpRequests
.phpactor.json

11 changes: 10 additions & 1 deletion app/Console/Commands/Irrdb/UpdateAsnDb.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* http://www.gnu.org/licenses/gpl-2.0.html
*/

use Exception;
use IXP\Tasks\Irrdb\UpdateAsnDb as UpdateAsnDbTask;

/**
Expand Down Expand Up @@ -68,7 +69,15 @@ public function handle(): int
$customers = $this->resolveCustomers();

foreach( $customers as $c ) {
$task = new UpdateAsnDbTask( $c );
try {
$task = new UpdateAsnDbTask( $c );
} catch( Exception $e ) {
$this->error( "IRRDB ASN update failed for {$c->name}/AS{$c->autsys}" );
$this->error( $e->getMessage() );
$this->info( "Continuing to next customer...");
continue;
}

$this->printResults( $c, $task->update(), 'asn' );
}

Expand Down
12 changes: 11 additions & 1 deletion app/Console/Commands/Irrdb/UpdatePrefixDb.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* http://www.gnu.org/licenses/gpl-2.0.html
*/

use Exception;
use IXP\Tasks\Irrdb\UpdatePrefixDb as UpdatePrefixDbTask;

/**
Expand Down Expand Up @@ -68,10 +69,19 @@ public function handle(): int
$customers = $this->resolveCustomers();

foreach( $customers as $c ) {
$task = new UpdatePrefixDbTask( $c );
try {
$task = new UpdatePrefixDbTask( $c );
} catch( Exception $e ) {
$this->error( "IRRDB ASN update failed for {$c->name}/AS{$c->autsys}" );
$this->error( $e->getMessage() );
$this->info( "Continuing to next customer...");
continue;
}

$this->printResults( $c, $task->update(), 'prefix' );
}


if( count( $customers ) > 1 && $this->isVerbosityVerbose() ) {
$this->info( "Total time for net/database/processing: "
. sprintf( "%0.6f/", $this->netTime )
Expand Down
66 changes: 66 additions & 0 deletions app/Console/Commands/PeeringDB/AsnLookup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace IXP\Console\Commands\PeeringDB;

use Illuminate\Console\Command;
use IXP\Services\PeeringDb;

class AsnLookup extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'peeringdb:asn-lookup {asn}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Lookup an ASN in PeeringDB';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
// are we set up for auth?
if( !config('ixp_api.peeringDB.api-key') ) {
$this->warn(
str_repeat( '-', 70 )
. "\nNo API key defined in .env for PeeringDB.\n\n"
. "See https://docs.peeringdb.com/howto/api_keys/ and set IXP_API_PEERING_DB_API_KEY in .env.\n\n"
. "Without an API key, only public information will be returned and PeeringDB request throttling will apply.\n"
. str_repeat( '-', 70 ) . "\n\n"
);
}

if( config('ixp_api.peeringDB.username') && config('ixp_api.peeringDB.password') ) {
$this->warn(
str_repeat( '-', 70 ) . "\n"
. "Username and password are set in .env for PeeringDB. This is deprecated and they should be replaced with an API key.\n\n"
. "See https://docs.peeringdb.com/howto/api_keys/ and set IXP_API_PEERING_DB_API_KEY in .env.\n"
. str_repeat( '-', 70 ) . "\n\n"
);
}

$pdb = new PeeringDb();

if( $pdb->getNetworkByAsn($this->argument('asn')) ) {
echo $pdb->netAsAscii();
return 0;
}

if( $pdb->status === 404 ) {
$this->line( $pdb->error );
return 0;
}

$this->error( $pdb->error );
return -1;
}
}
8 changes: 7 additions & 1 deletion app/Http/Controllers/Api/V4/CustomerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,13 @@ public function switches( Request $r, Customer $cust ): JsonResponse
*/
public function queryPeeringDbWithAsn( string $asn ): JsonResponse
{
return response()->json( App::make( PeeringDb::class )->getNetworkByAsn( $asn ) );
$pdb = App::make( PeeringDb::class );

if( $pdb->getNetworkByAsn( $asn ) ) {
return response()->json( [ 'net' => $pdb->net ] );
}

return response()->json( [ 'error' => $pdb->error ] );
}

/**
Expand Down
22 changes: 14 additions & 8 deletions app/Http/Controllers/Api/V4/WhoisController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

use Cache;

use IXP\Services\PeeringDb;
use Illuminate\Http\{Request,Response};

use IXP\Utils\Whois;
Expand Down Expand Up @@ -52,17 +53,22 @@ class WhoisController extends Controller
public function asn( Request $r, string $asn ): Response
{
$response = Cache::remember( 'api-v4-whois-asn-' . $asn, config('ixp_api.whois.cache_ttl'), function () use ( $asn ) {
$whois = new Whois( config( 'ixp_api.whois.asn.host' ), config( 'ixp_api.whois.asn.port' ) );
$response = $whois->whois( 'AS' . (int)$asn );

// nicer error message than PeeringDB's
if( $whois->host() === 'whois.peeringdb.com' && stripos( $response, "network matching query does not exist" ) !== false ) {
// sigh, nothing in PeeringDB. Try Team Cymru (which is asn2 by default) to get at least some info.
$whois = new Whois( config( 'ixp_api.whois.asn2.host' ), config( 'ixp_api.whois.asn2.port' ) );
$response = $whois->whois( 'AS' . (int)$asn );
$response = "{$asn} does not appear to have a record in PeeringDB.\n\nTrying {$whois->host()}:\n\n" . $response;
// try PeeringDB first
$pdb = new PeeringDb();
if( $pdb->getNetworkByAsn( $asn ) ) {
return $pdb->netAsAscii();
}

if( $pdb->status === 404 ) {
$response = "ASN not registered in PeeringDB. Trying " . config( 'ixp_api.whois.asn2.host' ) . ":\n\n";
} else {
$response = "Querying PeeringDB failed:\n\nError:{$pdb->error}\n\nTrying " . config( 'ixp_api.whois.asn2.host' ) . ":\n\n";
}

$whois = new Whois( config( 'ixp_api.whois.asn2.host' ), config( 'ixp_api.whois.asn2.port' ) );
$response .= $whois->whois( 'AS' . (int)$asn );

return $response;
});

Expand Down
112 changes: 85 additions & 27 deletions app/Services/PeeringDb.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@
* http://www.gnu.org/licenses/gpl-2.0.html
*/

use Log;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

use GuzzleHttp\{
Client as GuzzleHttp,
Exception\RequestException
};

/**
* PeeringDb
Expand All @@ -42,6 +39,15 @@
*/
class PeeringDb
{
/**
* @var array|null Network information from PeeringDB lookup
*/
public ?array $net = null;

public ?string $error = null;

public int $status = 0;

/**
* Get network information by ASN
*
Expand All @@ -52,39 +58,82 @@ class PeeringDb
*
* @param string $asn
*
* @return array
* @return bool Successful or not
*/
public function getNetworkByAsn( $asn = null ): array
public function getNetworkByAsn( $asn = null ): bool
{
$asn = trim( $asn );
$asn = (int)trim( $asn );

// reset in case of reuse
$this->reset();

if( !is_numeric( $asn ) || $asn <= 0 ) {
return [ 'error' => "Invalid ASN provided: " . $asn ];
$this->error = "Invalid ASN provided: $asn";
return false;
}

$client = new GuzzleHttp();
// api key?
if( config( 'ixp_api.peeringDB.api-key' ) ) {
$headers = [
'Authorization' => 'Api-Key ' . config( 'ixp_api.peeringDB.api-key' ),
];
} else {
$headers = [];
Log::warning( 'PeeringDB has no API key set in .env - see https://docs.peeringdb.com/howto/api_keys/ and set IXP_API_PEERING_DB_API_KEY in .env' );
}

try {
// find network by ASN
$req = $client->request( 'GET', $this->generateBasePeeringDbUrl( "/net.json?asn={$asn}" ) );
$response = Http::withHeaders( $headers )
->accept( 'application/json' )
->get( $this->generateBasePeeringDbUrl( "/net.json?asn={$asn}&depth=2" ) );

if( $req->getStatusCode() === 200 ) {
$pdb_network_id = json_decode( $req->getBody()->getContents(), false )->data[ 0 ]->id;
$req = $client->request( 'GET', $this->generateBasePeeringDbUrl( "/net/{$pdb_network_id}.json" ) );
$this->status = $response->status();

if( $req->getStatusCode() === 200 ) {
return [ 'net' => json_decode( $req->getBody()->getContents(), false )->data[ 0 ] ];
}
} else if( $req->getStatusCode() === 404 ) {
return [ 'error' => "No network with AS{$asn} found in PeeringDB" ];
}
} catch (RequestException $e) {
if( $e->hasResponse() ) {
return [ 'error' => json_decode( (string) $e->getResponse()->getBody(), true ) ];
switch( $response->status() ) {

case 200:
$this->net = $response->json()['data'][0];
return true;

case 404:
$this->error = "No network with AS{$asn} found in PeeringDB";
return false;

case 429:
$this->error = "Too many requests - PeeringDB throttling applied.";
return false;

default:
$this->error = $response->json()[ 'message' ] ?? 'Error';
return false;
}
return [ 'error' => $e->getMessage() ];
} catch( \Exception $e ) {
$this->error = $e->getMessage();
return false;
}
return [ 'error' => 'Unable to query PeeringDb / get result from PeeringDb. Check if PeeringDB is up / functioning.' ];
}

public function netAsAscii(): string {
return <<<ENDWHOIS
PeeringDB Network Details of AS{$this->net['asn']}
==================================================
Name: {$this->net['name']}
{$this->net['aka']}
{$this->net['name_long']}
Website: {$this->net['website']}
Peering Policy: {$this->net['policy_general']}
Notes:
{$this->net['notes']}
==================================================
ENDWHOIS;

}

/**
Expand All @@ -95,12 +144,21 @@ public function getNetworkByAsn( $asn = null ): array
private function generateBasePeeringDbUrl( string $query = "" ): string
{
$credentials = '';
if( ( $un = config( 'ixp_api.peeringDB.username' ) ) === null || ( $pw = config( 'ixp_api.peeringDB.password' ) ) === null ) {
Log::warning( 'PeeringDb username / password not set in .env. Only public data will be retrieved.' );
if( ( ( $un = config( 'ixp_api.peeringDB.username' ) ) === null || ( $pw = config( 'ixp_api.peeringDB.password' ) ) === null ) && config( 'ixp_api.peeringDB.api-key' ) === null ) {
Log::warning( 'Neither PeeringDb API Key nor deprecated username / password set in .env. Only public data will be retrieved. Please set an API Key' );
} else {
$credentials = urlencode( $un ) . ":" . urlencode( $pw ) . "@";
}

return sprintf( config( 'ixp_api.peeringDB.url' ), $credentials ) . $query;
}


private function reset(): void
{
$this->net = null;
$this->error = null;
$this->status = 0;
}

}
5 changes: 5 additions & 0 deletions app/Utils/Whois.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public function __construct( string $host, int $port )
$this->port = $port;
}


/**
*
*/

/**
* Do a whois lookup
*
Expand Down
3 changes: 2 additions & 1 deletion config/ixp_api.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@
'peeringDB' => [
'username' => env( 'IXP_API_PEERING_DB_USERNAME', null ),
'password' => env( 'IXP_API_PEERING_DB_PASSWORD', null ),
'api-key' => env( 'IXP_API_PEERING_DB_API_KEY', null ),
// you should not need to change this. The %s is either "$un:$pw@" or an empty string
'url' => env( 'IXP_API_PEERING_DB_URL', "https://%speeringdb.com/api" ),
'url' => env( 'IXP_API_PEERING_DB_URL', "https://%swww.peeringdb.com/api" ),

'fac_api' => env( 'IXP_API_PEERING_DB_FAC_URL', "https://api.peeringdb.com/api/fac" ),
'ixp_api' => env( 'IXP_API_PEERING_DB_IXP_URL', "https://api.peeringdb.com/api/ix" ),
Expand Down
2 changes: 1 addition & 1 deletion resources/views/customer/js/edit.foil.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
dd_peering_policy.val( peering_policy ).trigger( "change" ).addClass( 'is-valid' );

} else {
$( '#form' ).prepend( `<div id="error-message" class="alert alert-danger" role="alert"> ${response.error.meta.error} </div>` );
$( '#form' ).prepend( `<div id="error-message" class="alert alert-danger" role="alert"> ${response.error} </div>` );
}
})
.fail( function() {
Expand Down

0 comments on commit 93c53d2

Please sign in to comment.