diff --git a/app/Classes/Node.php b/app/Classes/Node.php index 8effdaf..ce90e5e 100644 --- a/app/Classes/Node.php +++ b/app/Classes/Node.php @@ -35,6 +35,7 @@ class Node private Collection $ftns; // The FTNs of the remote system private Collection $ftns_authed; // The FTNs we have validated + private Collection $ftns_other; // Other FTN addresses presented private bool $authed; // Have we authenticated the remote. private int $options; // This nodes capabilities/options @@ -46,6 +47,7 @@ class Node $this->start_time = Carbon::now(); $this->ftns = collect(); $this->ftns_authed = collect(); + $this->ftns_other = collect(); } /** @@ -72,6 +74,10 @@ class Node case 'aka_authed': return $this->authed; + // FTNs that we dont know about + case 'aka_other': + return $this->ftns_other; + // The nodes password case 'password': return ($this->ftns->count() && ($x=$this->ftns->first()->session('sespass'))) ? $x : '-'; @@ -125,6 +131,17 @@ class Node break; + case 'ftn_other': + // Ignore any duplicate FTNs that we get + if ($this->ftns_other->search($value) !== FALSE) { + Log::debug(sprintf('%s: - Ignoring Duplicate FTN [%s]',__METHOD__,$value->ftn)); + break; + } + + $this->ftns_other->push($value); + + break; + case 'system': case 'sysop': case 'location': @@ -159,26 +176,40 @@ class Node public function auth(string $password,string $challenge=''): int { Log::debug(sprintf('%s:+ auth [%s]',self::LOGKEY,$password)); + $so = NULL; // Make sure we havent been here already if ($this->ftns_authed->count()) throw new Exception('Already authed'); foreach ($this->ftns as $o) { - if (! $o->session('sespass')) + if (! $sespass=$o->session('sespass')) continue; // If we have challenge, then we are doing MD5 - $exp_pwd = $challenge ? $this->md5_challenge($o->session('sespass'),$challenge) : $o->session('sespass'); + $exp_pwd = $challenge ? $this->md5_challenge($sespass,$challenge) : $sespass; if ($exp_pwd === $password) { - $o->system->last_session = Carbon::now(); - $o->system->save(); + if (! $so) + $so = $o->system; + + // Make sure we are the same system + if ($so->id !== $o->system->id) { + Log::alert(sprintf('%s:! AKA [%s] is from a different system?',self::LOGKEY,$o->ftn),['so'=>$so->name]); + + continue; + } + $this->ftns_authed->push($o); $this->authed = TRUE; } } + if ($this->authed) { + $o->system->last_session = Carbon::now(); + $o->system->save(); + } + Log::debug(sprintf('%s:= auth, we authed [%d] addresses',self::LOGKEY,$this->ftns_authed->count())); return $this->ftns_authed->count(); } diff --git a/app/Classes/Protocol.php b/app/Classes/Protocol.php index 8a1a6d3..998bc38 100644 --- a/app/Classes/Protocol.php +++ b/app/Classes/Protocol.php @@ -9,7 +9,7 @@ use Illuminate\Support\Facades\Log; use App\Classes\File\{Receive,Send}; use App\Classes\Sock\SocketClient; use App\Classes\Sock\SocketException; -use App\Models\{Address,Setup}; +use App\Models\{Address,Setup,System}; abstract class Protocol { @@ -313,6 +313,19 @@ abstract class Protocol (($rc & self::S_MASK) == self::S_OK) ? 'Successful' : 'Failed', )); + // Add unknown FTNs to the DB + if ($this->node->aka_remote_authed->count()) { + $so = $this->node->aka_remote_authed->first()->system; + } else { + $so = System::where('name','Discovered System')->single(); + } + + if ($so && $so->exists) { + foreach ($this->node->aka_other as $aka) { + Address::findFTN($aka,TRUE,$so); + } + } + // @todo Log to history log in the DB. //if ($this->node->start_time && $this->setup->cfg('CFG_HISTORY')) {} diff --git a/app/Classes/Protocol/Binkp.php b/app/Classes/Protocol/Binkp.php index 93fa2c1..081fc98 100644 --- a/app/Classes/Protocol/Binkp.php +++ b/app/Classes/Protocol/Binkp.php @@ -632,6 +632,7 @@ final class Binkp extends BaseProtocol if (! ($o = Address::findFTN($rem_aka))) { Log::debug(sprintf('%s: ? AKA is UNKNOWN [%s]',self::LOGKEY,$rem_aka)); + $this->node->ftn_other = $rem_aka; continue; } diff --git a/app/Classes/Protocol/EMSI.php b/app/Classes/Protocol/EMSI.php index cf144b3..82722eb 100644 --- a/app/Classes/Protocol/EMSI.php +++ b/app/Classes/Protocol/EMSI.php @@ -303,6 +303,8 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface try { if (! ($o = Address::findFTN($rem_aka))) { Log::debug(sprintf('%s: ? AKA is UNKNOWN [%s]',self::LOGKEY,$rem_aka)); + + $this->node->ftn_other = $rem_aka; continue; } diff --git a/app/Models/Address.php b/app/Models/Address.php index 918334e..60cddff 100644 --- a/app/Models/Address.php +++ b/app/Models/Address.php @@ -343,13 +343,15 @@ class Address extends Model /** * Find a record in the DB for a node string, eg: 10:1/1.0 * - * @param string $ftn + * @param string $address + * @param bool $create + * @param System|null $so * @return Address|null * @throws Exception */ - public static function findFTN(string $ftn): ?self + public static function findFTN(string $address,bool $create=FALSE,System $so=NULL): ?self { - $ftn = self::parseFTN($ftn); + $ftn = self::parseFTN($address); // Are we looking for a region address if (($ftn['f'] === 0) && $ftn['p'] === 0) { @@ -411,6 +413,60 @@ class Address extends Model }) ->single(); + if ($create) { + if (! $so) + throw new Exception(sprintf('%s:AKA create requested for [%s], but system not provided',self::LOGKEY,$address)); + + if (! $ftn['d']) { + Log::alert(sprintf('%s:! Refusing to create address [%s] no domain available',self::LOGKEY,$address)); + + return NULL; + } + + Log::debug(sprintf('%s:Creating AKA [%s] for [%s]',self::LOGKEY,$address,$so->name)); + + // Check Domain exists + Domain::unguard(); + $do = Domain::singleOrNew(['name'=>$ftn['d']]); + Domain::reguard(); + + if (! $do->exists) { + $do->public = TRUE; + $do->active = TRUE; + $do->notes = 'Auto created'; + $do->save(); + } + + // Create zone + Zone::unguard(); + $zo = Zone::singleOrNew(['domain_id'=>$do->id,'zone_id'=>$ftn['z']]); + Zone::reguard(); + + if (! $zo->exists) { + $zo->active = TRUE; + $zo->notes = 'Auto created'; + $zo->system_id = System::where('name','Discovered System')->single()->id; + $do->zones()->save($zo); + } + + if (! $zo->active || ! $do->active) { + Log::alert(sprintf('%s:! Refusing to create address [%s] in disabled zone or domain',self::LOGKEY,$address)); + + return NULL; + } + + // Create Address, assigned to $so + $o = new self; + $o->active = TRUE; + $o->zone_id = $zo->id; + $o->region_id = 0; + $o->host_id = $ftn['n']; + $o->node_id = $ftn['f']; + $o->point_id = $ftn['p']; + $o->role = self::NODE_UNKNOWN; + $so->addresses()->save($o); + } + return ($o && $o->system->active) ? $o : NULL; } diff --git a/app/Models/Domain.php b/app/Models/Domain.php index fcb0e1f..d286ff7 100644 --- a/app/Models/Domain.php +++ b/app/Models/Domain.php @@ -56,7 +56,7 @@ class Domain extends Model /* ATTRIBUTES */ - public function getHomePageAttribute(string $value): string + public function getHomePageAttribute(?string $value): string { //0xFD2FB528 return $this->castAttribute('homepage',$value) ?: 'No available information at the moment.';