Process packet seenby/path/via lines when saving echomail/netmail

This commit is contained in:
2023-09-20 20:29:23 +10:00
parent 7fedf88d8c
commit 612efda945
11 changed files with 337 additions and 230 deletions

View File

@@ -11,8 +11,7 @@ use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Validator as ValidatorResult;
use App\Classes\FTN as FTNBase;
use App\Http\Controllers\DomainController;
use App\Models\{Address,Domain,System,Zone};
use App\Models\{Address,Domain,Zone};
use App\Rules\{TwoByteInteger,TwoByteIntegerWithZero};
use App\Traits\EncodeUTF8;
@@ -138,10 +137,7 @@ class Message extends FTNBase
private Collection $rescanned; // Message was created as a result of a rescan
private Collection $path; // FTS-0004.001 The message PATH lines
private Collection $pathaddress; // Collection of Addresses after parsing seenby
private Collection $rogue_seenby; // Collection of FTNs in the Seen-by that are not defined
private Collection $seenby; // FTS-0004.001 The message SEEN-BY lines
private Collection $seenaddress; // Collection of Addresses after parsing seenby
private Collection $via; // The path the message has gone using Via lines (Netmail)
private Collection $unknown; // Temporarily hold attributes we have no logic for.
@@ -224,10 +220,7 @@ class Message extends FTNBase
$this->kludge = collect();
$this->rescanned = collect();
$this->path = collect();
$this->rogue_seenby = collect();
$this->seenby = collect();
$this->seenaddress = collect();
$this->pathaddress = collect();
$this->via = collect();
$this->unknown = collect();
}
@@ -364,9 +357,6 @@ class Message extends FTNBase
case 'rescanned':
case 'path':
case 'seenby':
case 'pathaddress':
case 'rogue_seenby':
case 'seenaddress':
case 'unknown':
case 'via':
@@ -556,6 +546,7 @@ class Message extends FTNBase
}
$ptr = 0;
// To User
$o->user_to = strstr(substr($msg,self::HEADER_LEN+$ptr),"\x00",TRUE);
$ptr += strlen($o->user_to)+1;
@@ -670,77 +661,6 @@ class Message extends FTNBase
return ($this->flags & $flag);
}
/**
* Parse the Seenby/path lines and return a collection of addresses
*
* @param string $type Type of address, ie: seenby/path
* @param Collection $addresses
* @param Collection $rogue
* @return Collection
* @throws \Exception
*/
private function parseAddresses(string $type,Collection $addresses,Collection &$rogue): Collection
{
$nodes = collect();
$net = NULL;
foreach ($addresses as $line) {
foreach (explode(' ',$line) as $item) {
if (($x=strpos($item,'/')) !== FALSE) {
$net = (int)substr($item,0,$x);
$node = (int)substr($item,$x+1);
} else {
$node = (int)$item;
}
$aoid = NULL;
// If domain should be flattened, look for node regardless of zone (within the list of zones for the domain)
if ($this->fdomain && $this->fdomain->flatten) {
$ao = Address::findZone($this->fdomain,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,0);
$ftn = sprintf('%d:%d/%d@%s',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$this->fdomain->name);
$aoid = $ao?->id;
} elseif ($this->fdomain) {
$ftn = sprintf('%d:%d/%d@%s',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$this->fdomain->name);
} else {
$ftn = sprintf('%d:%d/%d',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX);
}
if (! $aoid) {
if (! ($ao=Address::findFTN($ftn))) {
Log::alert(sprintf('%s:! Undefined Node [%s] in [%s] - auto created.',self::LOGKEY,$ftn,$type));
$ao = Address::createFTN($ftn,System::createUnknownSystem());
}
$aoid = $ao?->id;
}
switch ($type) {
case 'seenby':
if (! $ao) {
$rogue->push(sprintf('%d:%d/%d',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX));
continue 2;
}
case 'path':
if (! $aoid)
throw new \Exception(sprintf('Didnt get an address for [%s]',$ftn));
break;
}
$nodes->push($aoid);
}
}
return $nodes;
}
/**
* Process the data after the ORIGIN
* There may be kludge lines after the origin - notably SEEN-BY
@@ -785,48 +705,6 @@ class Message extends FTNBase
}
}
/**
* Parse the via address and return a collection of addresses
*
* <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] <Program Name> <Version> [Serial Number]
*
* @param Collection $via
* @return Collection
* @throws \Exception
*/
private function parseVia(Collection $via): Collection
{
$nodes = collect();
foreach ($via as $line) {
$m = [];
if (preg_match('/^([0-9]+:[0-9]+\/[0-9]+(\..*)?)\s+@([0-9.a-zA-Z]+)\s+(.*)$/',$line,$m)) {
// Address
$ao = Address::findFTN($m[1]);
// Time
$t = [];
$datetime = '';
if (! preg_match('/^([0-9]+\.[0-9]+)(\.?(.*))?$/',$m[3],$t))
Log::alert(sprintf('%s:! Unable to determine time from [%s]',self::LOGKEY,$m[3]));
else
$datetime = Carbon::createFromFormat('Ymd.His',$t[1],$t[3] ?? '');
if (! $ao) {
Log::alert(sprintf('%s:! Undefined Node [%s] for Netmail.',self::LOGKEY,$m[1]));
//$rogue->push(['node'=>$m[1],'datetime'=>$datetime,'program'=>$m[4]]);
} else {
$nodes->push(['node'=>$ao,'datetime'=>$datetime,'program'=>$m[4]]);
}
}
}
return $nodes;
}
/**
* Extract information out of the message text.
*
@@ -1009,19 +887,6 @@ class Message extends FTNBase
} elseif ($this->zone) {
$this->src = Address::parseFTN(sprintf('%d:%d/%d.%d@%s',$this->zone->zone_id,$this->fn,$this->ff,$this->fp,$this->zone->domain->name));
}
// Parse SEEN-BY
if ($this->seenby->count())
$this->seenaddress = $this->parseAddresses('seenby',$this->seenby,$this->rogue_seenby);
$dummy = collect();
// Parse PATH
if ($this->path->count())
$this->pathaddress = $this->parseAddresses('path',$this->path,$dummy);
// Parse VIA
if ($this->via->count())
$this->pathaddress = $this->parseVia($this->via);
}
/**
@@ -1061,6 +926,15 @@ class Message extends FTNBase
]);
$validator->after(function($validator) {
if ($this->zone->domain->flatten) {
if (! $this->zone->domain->zones->pluck('zone_id')->contains($this->fz))
$validator->errors()->add('invalid-zone',sprintf('Message zone [%d] doesnt match any zone in domain for packet zone [%d].',$this->fz,$this->zone->zone_id));
} else {
if ($this->zone->zone_id !== $this->fz)
$validator->errors()->add('invalid-zone',sprintf('Message zone [%d] doesnt match packet zone [%d].',$this->fz,$this->zone->zone_id));
}
if (! $this->fboss_o)
$validator->errors()->add('from',sprintf('Undefined Node [%s] sent message.',$this->fboss));
if (! $this->tboss_o)

View File

@@ -5,12 +5,13 @@ namespace App\Classes\FTN;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Symfony\Component\HttpFoundation\File\File;
use App\Classes\FTN as FTNBase;
use App\Models\{Address,Software,System,Zone};
use App\Models\{Address,Domain,Software,System,Zone};
use App\Notifications\Netmails\EchomailBadAddress;
/**
* Represents a Fidonet Packet, that contains an array of messages.
@@ -172,11 +173,11 @@ class Packet extends FTNBase implements \Iterator, \Countable
* @param mixed $f
* @param string $name
* @param int $size
* @param System|null $system
* @param Domain|null $domain
* @return Packet
* @throws InvalidPacketException
*/
public static function process(mixed $f,string $name,int $size,System $system=NULL): self
public static function process(mixed $f,string $name,int $size,Domain $domain=NULL): self
{
Log::debug(sprintf('%s:+ Opening Packet [%s] with size [%d]',self::LOGKEY,$name,$size));
@@ -223,11 +224,29 @@ class Packet extends FTNBase implements \Iterator, \Countable
else if (! strlen($x))
throw new InvalidPacketException('No message in packet: '.bin2hex($x));
$o->zone = $system?->zones->firstWhere('zone_id',$o->fz);
// Work out the packet zone
if ($o->fz && ($o->fd || $domain)) {
$o->zone = Zone::select('zones.*')
->join('domains',['domains.id'=>'zones.domain_id'])
->where('zone_id',$o->fz)
->where('name',$o->fd ?: $domain->name)
->single();
// If zone is null, we'll take the zone from the packet
if (! $o->zone)
$o->zone = Zone::where('zone_id',$o->fz)->where('default',TRUE)->single();
// We need not knowing the domain, we use the default zone
} else {
$o->zone = Zone::where('zone_id',$o->fz)
->where('default',TRUE)
->single();
}
// If zone is not set, then we need to use a default zone - the messages may not be from this zone.
if (! $o->zone) {
Log::alert(sprintf('%s:! We couldnt work out the packet zone, so we have fallen back to the default for [%d]',self::LOGKEY,$o->fz));
$o->zone = Zone::where('zone_id',$o->fz)
->where('default',TRUE)
->singleOrFail();
}
$buf_ptr = 0;
$message = '';
@@ -415,15 +434,27 @@ class Packet extends FTNBase implements \Iterator, \Countable
*/
private function parseMessage(string $message): void
{
Log::info(sprintf('%s:+ Processing message [%d] bytes',self::LOGKEY,strlen($message)));
Log::info(sprintf('%s:+ Processing packet message [%d] bytes',self::LOGKEY,strlen($message)));
$msg = Message::parseMessage($message,$this->zone);
// If the message from domain is different to the packet address domain, we'll skip this message
// If the message is invalid, we'll ignore it
if ($msg->errors) {
Log::info(sprintf('%s:- Message [%s] has errors',self::LOGKEY,$msg->msgid));
// If the from address doenst exist, we'll create a new entry
// If the messages is not for the right zone, we'll ignore it
if ($msg->errors->messages()->has('invalid-zone')) {
Log::alert(sprintf('%s:! Message is from an invalid zone [%s], packet is from [%s] - ignoring it',self::LOGKEY,$msg->fftn,$msg->zone->domain->name));
if (! $msg->rescanned->count())
Notification::route('netmail',$this->fftn_o)->notify(new EchomailBadAddress($msg));
return;
}
// If the to address doenst exist, we'll create a new entry
if ($msg->errors->messages()->has('to') && $msg->tzone) {
try {
// @todo Need to work out the correct region for the host_id
@@ -450,15 +481,13 @@ class Packet extends FTNBase implements \Iterator, \Countable
$ao->role = Address::NODE_UNKNOWN;
$so = System::createUnknownSystem();
// @todo Remove this debugging line
if ($so->id !== 443)
Log::alert(sprintf('%s:? Just created Discovered System for MSGID [%s] A',self::LOGKEY,$msg->msgid));
$so->addresses()->save($ao);
Log::alert(sprintf('%s:- To FTN is not defined, creating new entry for [%s] (%d)',self::LOGKEY,$msg->tboss,$ao->id));
}
// If the from address doenst exist, we'll create a new entry
if ($msg->errors->messages()->has('from') && $msg->tzone) {
try {
// @todo Need to work out the correct region for the host_id
@@ -485,9 +514,6 @@ class Packet extends FTNBase implements \Iterator, \Countable
$ao->role = Address::NODE_UNKNOWN;
$so = System::createUnknownSystem();
// @todo Remvoe this debugging line
if ($so->id !== 443)
Log::alert(sprintf('%s:? Just created Discovered System for MSGID [%s] B',self::LOGKEY,$msg->msgid));
$so->addresses()->save($ao);