From 4d701cb36e27e376a1b198cb59a7ec413855e341 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sat, 5 May 2012 23:52:59 +0000 Subject: [PATCH] Decoding of raw package message basicly finished, external public ip now included in announcement --- .gitattributes | 1 + application/hub/config.php | 3 + .../class_InvalidDataChecksumException.php | 48 ++++++ .../interfaces/package/class_Receivable.php | 8 + .../node/class_NodeListDatabaseWrapper.php | 33 ++++ .../decoder/package/class_PackageDecoder.php | 2 +- .../hub/main/listener/class_BaseListener.php | 1 + .../hub/main/nodes/class_BaseHubNode.php | 6 +- .../hub/main/package/class_NetworkPackage.php | 155 ++++++++++++++++-- application/hub/main/tools/class_HubTools.php | 17 ++ 10 files changed, 255 insertions(+), 19 deletions(-) create mode 100644 application/hub/exceptions/package/class_InvalidDataChecksumException.php diff --git a/.gitattributes b/.gitattributes index 6382e8404..5e40db56e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18,6 +18,7 @@ application/hub/exceptions/lists/class_ListGroupAlreadyAddedException.php svneol application/hub/exceptions/lists/class_NoListGroupException.php svneol=native#text/plain application/hub/exceptions/package/.htaccess -text svneol=unset#text/plain application/hub/exceptions/package/class_FinalChunkVerificationException.php svneol=native#text/plain +application/hub/exceptions/package/class_InvalidDataChecksumException.php svneol=native#text/plain application/hub/exceptions/package/class_UnexpectedPackageStatusException.php -text application/hub/exceptions/package/class_UnsupportedPackageCodeHandlerException.php svneol=native#text/plain application/hub/exceptions/peer/.htaccess -text svneol=unset#text/plain diff --git a/application/hub/config.php b/application/hub/config.php index b1505b352..8353a61c5 100644 --- a/application/hub/config.php +++ b/application/hub/config.php @@ -549,6 +549,9 @@ $cfg->setConfigEntry('session_id', ''); // CFG: EXTERNAL-IP $cfg->setConfigEntry('external_ip', ''); +// CFG: NODE-STATUS +$cfg->setConfigEntry('node_status', 'invalid'); + // CFG: PACKAGE-FRAGMENTER-CLASS $cfg->setConfigEntry('package_fragmenter_class', 'PackageFragmenter'); diff --git a/application/hub/exceptions/package/class_InvalidDataChecksumException.php b/application/hub/exceptions/package/class_InvalidDataChecksumException.php new file mode 100644 index 000000000..0d93da82c --- /dev/null +++ b/application/hub/exceptions/package/class_InvalidDataChecksumException.php @@ -0,0 +1,48 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +class InvalidDataChecksumException extends FrameworkException { + /** + * The super constructor for all exceptions + * + * @param $messageArray Error message array + * @param $code Error code + * @return void + */ + public function __construct (array $messageArray, $code) { + // Construct the message + $message = sprintf("[%s:%d] The checksum %s doesn't match the checksum of the content: %s", + $messageArray[0]->__toString(), + $this->getLine(), + $messageArray[0]->getHashFromContentSessionId($messageArray[1], $messageArray[2][NetworkPackage::PACKAGE_DATA_SENDER]), + $messageArray[1][NetworkPackage::PACKAGE_CONTENT_CHECKSUM] + ); + + // Call parent exception constructor + parent::__construct($message, $code); + } +} + +// [EOF] +?> diff --git a/application/hub/interfaces/package/class_Receivable.php b/application/hub/interfaces/package/class_Receivable.php index fe1be45b8..72149c532 100644 --- a/application/hub/interfaces/package/class_Receivable.php +++ b/application/hub/interfaces/package/class_Receivable.php @@ -92,6 +92,14 @@ interface Receivable extends FrameworkInterface { * @return void */ function handleAssemblerPendingData (); + + /** + * Handles decoded data for this node + * + * @param $decodedData An array with decoded raw package data + * @return void + */ + function handleDecodedData (array $decodedData); } // [EOF] diff --git a/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php b/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php index 8b0214c3c..c9d47e4f6 100644 --- a/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php +++ b/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php @@ -90,6 +90,39 @@ class NodeListDatabaseWrapper extends BaseDatabaseWrapper implements Registerabl // Return result return $recipient; } + + /** + * Resolves a ip:port combination into a session id + * + * @param $ipPort Ip:port combination + * @return $sessionId A valid session id + */ + public function resolveSessionIdByIpPort ($ipPort) { + // Set invalid session id as default + $sessionId = 'invalid'; + + // Now get a search criteria instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Search for the node session id + $searchInstance->addCriteria(NodeListDatabaseWrapper::DB_COLUMN_NODE_IP_PORT, $ipPort); + $searchInstance->setLimit(1); + + // Get a result back + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Is it valid? + if ($resultInstance->next()) { + // Save the result instance in this class + $this->setResultInstance($resultInstance); + + // Get the session from result + $sessionId = $this->getField(NodeListDatabaseWrapper::DB_COLUMN_NODE_SESSION_ID); + } // END - if + + // Return result + return $sessionId; + } } // [EOF] diff --git a/application/hub/main/decoder/package/class_PackageDecoder.php b/application/hub/main/decoder/package/class_PackageDecoder.php index 4d663454b..93f3c14cc 100644 --- a/application/hub/main/decoder/package/class_PackageDecoder.php +++ b/application/hub/main/decoder/package/class_PackageDecoder.php @@ -130,7 +130,7 @@ class PackageDecoder extends BaseDecoder implements Decodeable { $decodedData = $this->getStackerInstance()->popNamed(self::STACKER_NAME_DECODED_PACKAGE); // Handle it - die('decodedData='.print_r($decodedData,true)); + $this->getPackageInstance()->handleDecodedData($decodedData); } } diff --git a/application/hub/main/listener/class_BaseListener.php b/application/hub/main/listener/class_BaseListener.php index fdae47c8d..2906ef426 100644 --- a/application/hub/main/listener/class_BaseListener.php +++ b/application/hub/main/listener/class_BaseListener.php @@ -31,6 +31,7 @@ class BaseListener extends BaseHubSystem implements Visitable { const EXCEPTION_UNEXPECTED_PACKAGE_STATUS = 0xa05; const EXCEPTION_UNSUPPORTED_PACKAGE_CODE_HANDLER = 0xa06; const EXCEPTION_FINAL_CHUNK_VERIFICATION = 0xa07; + const EXCEPTION_INVALID_DATA_CHECKSUM = 0xa08; /** * Used protocol (Default: invalid, which is indeed invalid...) diff --git a/application/hub/main/nodes/class_BaseHubNode.php b/application/hub/main/nodes/class_BaseHubNode.php index bbd63bf6a..bbec7957e 100644 --- a/application/hub/main/nodes/class_BaseHubNode.php +++ b/application/hub/main/nodes/class_BaseHubNode.php @@ -390,6 +390,9 @@ class BaseHubNode extends BaseHubSystem implements Updateable { throw new HubAlreadyAnnouncedException($this, self::EXCEPTION_HUB_ALREADY_ANNOUNCED); } // END - if + // Set some dummy configuration entries, e.g. node_status + $this->getConfigInstance()->setConfigEntry('node_status', $this->getStateInstance()->getStateName()); + // Debug output $this->debugOutput('HUB-Announcement: START (taskInstance=' . $taskInstance->__toString(). ')'); @@ -399,9 +402,6 @@ class BaseHubNode extends BaseHubSystem implements Updateable { // Load the announcement descriptor $helperInstance->loadDescriptorXml(); - // Set some dummy configuration entries, e.g. node_status - $this->getConfigInstance()->setConfigEntry('node_status', $this->getStateInstance()->getStateName()); - // Compile all variables $helperInstance->getTemplateInstance()->compileConfigInVariables(); diff --git a/application/hub/main/package/class_NetworkPackage.php b/application/hub/main/package/class_NetworkPackage.php index 87be5cb99..67cc10b79 100644 --- a/application/hub/main/package/class_NetworkPackage.php +++ b/application/hub/main/package/class_NetworkPackage.php @@ -52,7 +52,13 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R const PACKAGE_MASK_SEPARATOR = '^'; /** - * SEPARATOR for checksum + * Size of an array created by invoking + * explode(NetworkPackage::PACKAGE_MASK_SEPARATOR, $content). + */ + const PACKAGE_CONTENT_ARRAY_SIZE = 4; + + /** + * Separator for checksum */ const PACKAGE_CHECKSUM_SEPARATOR = '_'; @@ -73,6 +79,19 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R const INDEX_PACKAGE_STATUS = 3; const INDEX_PACKAGE_SIGNATURE = 4; + /** + * Size of the decoded data array ('status' is not included) + */ + const DECODED_DATA_ARRAY_SIZE = 4; + + /** + * Named array elements for decoded package content + */ + const PACKAGE_CONTENT_EXTENSION = 'compressor'; + const PACKAGE_CONTENT_MESSAGE = 'message'; + const PACKAGE_CONTENT_TAGS = 'tags'; + const PACKAGE_CONTENT_CHECKSUM = 'checksum'; + /** * Named array elements for package data */ @@ -114,11 +133,6 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R */ const TCP_PACKAGE_SIZE = 512; - /** - * Size of the decoded data array - */ - const DECODED_DATA_ARRAY_SIZE = 4; - /************************************************************************** * Stacker for out-going packages * **************************************************************************/ @@ -244,12 +258,10 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R } /** - * "Getter" for hash from given content and helper instance + * "Getter" for hash from given content * - * @param $content Raw package content - * @param $helperInstance An instance of a HelpableHub class - * @param $nodeInstance An instance of a NodeHelper class - * @return $hash Hash for given package content + * @param $content Raw package content + * @return $hash Hash for given package content */ private function getHashFromContent ($content) { // Debug message @@ -269,6 +281,24 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R return $hash; } + /** + * Checks whether the checksum (sometimes called "hash") is the same + * + * @param $decodedContent Package raw content + * @param $decodedData Whole raw package data array + * @return $isChecksumValid Whether the checksum is the same + */ + private function isChecksumValid (array $decodedContent, array $decodedData) { + // Get checksum + $checksum = $this->getHashFromContentSessionId($decodedContent, $decodedData[self::PACKAGE_DATA_SENDER]); + + // Is it the same? + $isChecksumValid = ($checksum == $decodedContent[self::PACKAGE_CONTENT_CHECKSUM]); + + // Return it + return $isChecksumValid; + } + /** * Change the package with given status in given stack * @@ -287,7 +317,7 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R // Pop the entry (it should be it) $nextData = $this->getStackerInstance()->popNamed($stackerName); - // Compare both arrays + // Compare both signatures assert($nextData[self::PACKAGE_DATA_SIGNATURE] == $packageData[self::PACKAGE_DATA_SIGNATURE]); // Temporary set the new status @@ -297,6 +327,31 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R $this->getStackerInstance()->pushNamed($stackerName, $packageData); } + /** + * "Getter" for hash from given content and sender's session id + * + * @param $decodedContent Decoded package content + * @param $sessionId Session id of the sender + * @return $hash Hash for given package content + */ + public function getHashFromContentSessionId (array $decodedContent, $sessionId) { + // Debug message + //* NOISY-DEBUG: */ $this->debugOutput('NETWORK-PACKAGE: content[md5]=' . md5($decodedContent[self::PACKAGE_CONTENT_MESSAGE]) . ',sender=' . $sessionId . ',compressor=' . $decodedContent[self::PACKAGE_CONTENT_EXTENSION]); + + // Create the hash + // @TODO crc32() is very weak, but it needs to be fast + $hash = crc32( + $decodedContent[self::PACKAGE_CONTENT_MESSAGE] . + self::PACKAGE_CHECKSUM_SEPARATOR . + $sessionId . + self::PACKAGE_CHECKSUM_SEPARATOR . + $decodedContent[self::PACKAGE_CONTENT_EXTENSION] + ); + + // And return it + return $hash; + } + /////////////////////////////////////////////////////////////////////////// // Delivering packages / raw data /////////////////////////////////////////////////////////////////////////// @@ -470,6 +525,23 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R return $signature; } + /** + * Checks whether the signature of given package data is 'valid', here that + * means it is the same or not. + * + * @param $decodedArray An array with 'decoded' (explode() was mostly called) data + * @return $isSignatureValid Whether the signature is valid + * @todo Unfinished area, signature are currently not supported + */ + private function isPackageSignatureValid (array $decodedArray) { + // Generate the signature of comparing it + $signature = $this->generatePackageSignature($decodedArray[self::INDEX_PACKAGE_CONTENT], $decodedArray[self::INDEX_PACKAGE_SENDER]); + + // Is it the same? + //$isSignatureValid = + die('signature='.$signature.print_r($decodedArray,true)); + } + /** * "Enqueues" raw content into this delivery class by reading the raw content * from given template instance and pushing it on the 'undeclared' stack. @@ -884,18 +956,71 @@ class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, R // Assert on count (should be always 3) assert(count($decodedArray) == self::DECODED_DATA_ARRAY_SIZE); - // Create 'decodedData' array with all assoziative array elements + // Generate the signature of comparing it + /* + * @todo Unsupported feature commented out + if (!$this->isPackageSignatureValid($decodedArray)) { + // Is not valid, so throw an exception here + die('INVALID SIG! UNDER CONSTRUCTION!' . chr(10)); + } // END - if + */ + + /* + * Create 'decodedData' array with all assoziative array elements, + * except signature. + */ $decodedData = array( self::PACKAGE_DATA_SENDER => $decodedArray[self::INDEX_PACKAGE_SENDER], self::PACKAGE_DATA_RECIPIENT => $decodedArray[self::INDEX_PACKAGE_RECIPIENT], self::PACKAGE_DATA_CONTENT => $decodedArray[self::INDEX_PACKAGE_CONTENT], - self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED, - self::PACKAGE_DATA_SIGNATURE => $this->generatePackageSignature($decodedArray[self::INDEX_PACKAGE_CONTENT], $decodedArray[self::INDEX_PACKAGE_SENDER]) + self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED ); // And return it return $decodedData; } + + /** + * Handles decoded data for this node by "decoding" the 'content' part of + * it. Again this method uses explode() for the "decoding" process. + * + * @param $decodedData An array with decoded raw package data + * @return void + * @throws InvalidDataChecksumException If the checksum doesn't match + */ + public function handleDecodedData (array $decodedData) { + /* + * "Decode" the package's content by a simple explode() call, for + * details of the array elements, see comments for constant + * PACKAGE_MASK. + */ + $decodedContent = explode(self::PACKAGE_MASK_SEPARATOR, $decodedData[self::PACKAGE_DATA_CONTENT]); + + // Assert on array count for a very basic validation + assert(count($decodedContent) == self::PACKAGE_CONTENT_ARRAY_SIZE); + + // Convert the indexed array into an associative array + $decodedContent = array( + // Compressor's extension used to compress the data + self::PACKAGE_CONTENT_EXTENSION => $decodedContent[self::INDEX_COMPRESSOR_EXTENSION], + // Package data (aka "message") in BASE64-decoded form + self::PACKAGE_CONTENT_MESSAGE => base64_decode($decodedContent[self::INDEX_PACKAGE_DATA]), + // Tags as an indexed array for "tagging" the message + self::PACKAGE_CONTENT_TAGS => explode(self::PACKAGE_TAGS_SEPARATOR, $decodedContent[self::INDEX_TAGS]), + // Checksum of the _decoded_ data + self::PACKAGE_CONTENT_CHECKSUM => $decodedContent[self::INDEX_CHECKSUM] + ); + + // Is the checksum valid? + if (!$this->isChecksumValid($decodedContent, $decodedData)) { + // Is not the same, so throw an exception here + throw new InvalidDataChecksumException(array($this, $decodedContent, $decodedData), BaseListener::EXCEPTION_INVALID_DATA_CHECKSUM); + } // END - if + + // It is the same, then decompress it, the original message is than fully decoded + $decodedContent[self::PACKAGE_CONTENT_MESSAGE] = $this->getCompressorInstance()->decompressStream($decodedContent[self::PACKAGE_CONTENT_MESSAGE]); + die('decodedContent='.print_r($decodedContent,true)); + } } // [EOF] diff --git a/application/hub/main/tools/class_HubTools.php b/application/hub/main/tools/class_HubTools.php index c7063ece5..2580a0582 100644 --- a/application/hub/main/tools/class_HubTools.php +++ b/application/hub/main/tools/class_HubTools.php @@ -108,6 +108,23 @@ class HubTools extends BaseHubSystem { return $recipient; } + /** + * Resolves a ip:port combination into a session id + * + * @param $ipPort Ip:port combination + * @return $sessionId Valid session id + */ + public static function resolveSessionIdByIpPort ($ipPort) { + // Get a wrapper instance + $wrapperInstance = DatabaseWrapperFactory::createWrapperByConfiguredName('node_list_db_wrapper_class'); + + // And ask it for the session id + $sessionId = $wrapperInstance->resolveSessionIdByIpPort($ipPort); + + // Return result + return $sessionId; + } + /** * Resolves given session id into an ip:port combination, if ip:port is set, it won't be translated * -- 2.39.5