mirror of
https://github.com/nmap/nmap.git
synced 2025-12-10 06:31:30 +00:00
If you have trouble updating after this revision you need to follow these instructions. You have probably just seen an error like this: svn: URL 'svn://svn.insecure.org/nping' of existing directory 'nping' does not match expected URL 'svn://svn.insecure.org/nmap/nping' This is caused by the replacement of SVN externals. Here's what you need to do. First, save any local changes you might have in the nping, nsock, nbase, ncat, and zenmap directories. (For example by running "cd nping; svn diff > ../nping.diff".) If you don't have any local changes you can skip this step. Then run these commands: rm -rf nping/ nsock/ nbase/ ncat/ zenmap/ svn update svn cleanup If all else fails, you can just delete your whole working directory and check out anew: svn co --username guest --password "" svn://svn.insecure.org/nmap There may be further discussion in the mailing list thread at http://seclists.org/nmap-dev/2011/q4/303.
1000 lines
32 KiB
C++
Executable File
1000 lines
32 KiB
C++
Executable File
|
|
/***************************************************************************
|
|
* EchoHeader.cc -- The EchoHeader Class represents packets of the Nping *
|
|
* Echo Protocol. It contains the appropriate methods to set/get all *
|
|
* header fields. In general these methods do error checking and perform *
|
|
* byte order conversions. *
|
|
* *
|
|
***********************IMPORTANT NMAP LICENSE TERMS************************
|
|
* *
|
|
* The Nmap Security Scanner is (C) 1996-2011 Insecure.Com LLC. Nmap is *
|
|
* also a registered trademark of Insecure.Com LLC. This program is free *
|
|
* software; you may redistribute and/or modify it under the terms of the *
|
|
* GNU General Public License as published by the Free Software *
|
|
* Foundation; Version 2 with the clarifications and exceptions described *
|
|
* below. This guarantees your right to use, modify, and redistribute *
|
|
* this software under certain conditions. If you wish to embed Nmap *
|
|
* technology into proprietary software, we sell alternative licenses *
|
|
* (contact sales@insecure.com). Dozens of software vendors already *
|
|
* license Nmap technology such as host discovery, port scanning, OS *
|
|
* detection, and version detection. *
|
|
* *
|
|
* Note that the GPL places important restrictions on "derived works", yet *
|
|
* it does not provide a detailed definition of that term. To avoid *
|
|
* misunderstandings, we consider an application to constitute a *
|
|
* "derivative work" for the purpose of this license if it does any of the *
|
|
* following: *
|
|
* o Integrates source code from Nmap *
|
|
* o Reads or includes Nmap copyrighted data files, such as *
|
|
* nmap-os-db or nmap-service-probes. *
|
|
* o Executes Nmap and parses the results (as opposed to typical shell or *
|
|
* execution-menu apps, which simply display raw Nmap output and so are *
|
|
* not derivative works.) *
|
|
* o Integrates/includes/aggregates Nmap into a proprietary executable *
|
|
* installer, such as those produced by InstallShield. *
|
|
* o Links to a library or executes a program that does any of the above *
|
|
* *
|
|
* The term "Nmap" should be taken to also include any portions or derived *
|
|
* works of Nmap. This list is not exclusive, but is meant to clarify our *
|
|
* interpretation of derived works with some common examples. Our *
|
|
* interpretation applies only to Nmap--we don't speak for other people's *
|
|
* GPL works. *
|
|
* *
|
|
* If you have any questions about the GPL licensing restrictions on using *
|
|
* Nmap in non-GPL works, we would be happy to help. As mentioned above, *
|
|
* we also offer alternative license to integrate Nmap into proprietary *
|
|
* applications and appliances. These contracts have been sold to dozens *
|
|
* of software vendors, and generally include a perpetual license as well *
|
|
* as providing for priority support and updates as well as helping to *
|
|
* fund the continued development of Nmap technology. Please email *
|
|
* sales@insecure.com for further information. *
|
|
* *
|
|
* As a special exception to the GPL terms, Insecure.Com LLC grants *
|
|
* permission to link the code of this program with any version of the *
|
|
* OpenSSL library which is distributed under a license identical to that *
|
|
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
|
|
* linked combinations including the two. You must obey the GNU GPL in all *
|
|
* respects for all of the code used other than OpenSSL. If you modify *
|
|
* this file, you may extend this exception to your version of the file, *
|
|
* but you are not obligated to do so. *
|
|
* *
|
|
* If you received these files with a written license agreement or *
|
|
* contract stating terms other than the terms above, then that *
|
|
* alternative license agreement takes precedence over these comments. *
|
|
* *
|
|
* Source is provided to this software because we believe users have a *
|
|
* right to know exactly what a program is going to do before they run it. *
|
|
* This also allows you to audit the software for security holes (none *
|
|
* have been found so far). *
|
|
* *
|
|
* Source code also allows you to port Nmap to new platforms, fix bugs, *
|
|
* and add new features. You are highly encouraged to send your changes *
|
|
* to nmap-dev@insecure.org for possible incorporation into the main *
|
|
* distribution. By sending these changes to Fyodor or one of the *
|
|
* Insecure.Org development mailing lists, it is assumed that you are *
|
|
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
|
|
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
|
|
* will always be available Open Source, but this is important because the *
|
|
* inability to relicense code has caused devastating problems for other *
|
|
* Free Software projects (such as KDE and NASM). We also occasionally *
|
|
* relicense the code to third parties as discussed above. If you wish to *
|
|
* specify special license conditions of your contributions, just say so *
|
|
* when you send them. *
|
|
* *
|
|
* 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 v2.0 for more details at *
|
|
* http://www.gnu.org/licenses/gpl-2.0.html , or in the COPYING file *
|
|
* included with Nmap. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "EchoHeader.h"
|
|
#include "nping.h"
|
|
#include "output.h"
|
|
#include <time.h>
|
|
#include <assert.h>
|
|
#include "Crypto.h"
|
|
|
|
EchoHeader::EchoHeader(){
|
|
this->reset();
|
|
} /* End of EchoHeader constructor */
|
|
|
|
|
|
EchoHeader::~EchoHeader(){
|
|
|
|
} /* End of EchoHeader destructor */
|
|
|
|
|
|
/** Sets every attribute to its default value. */
|
|
void EchoHeader::reset() {
|
|
memset(&this->h, 0, sizeof(echohdr_t) );
|
|
this->data_hsserv=(nep_hs_serv_data_t *)this->h.data;
|
|
this->data_hsclnt=(nep_hs_clnt_data_t *)this->h.data;
|
|
this->data_hsfinal=(nep_hs_final_data_t *)this->h.data;
|
|
this->data_pspec=(nep_packet_spec_data_t *)this->h.data;
|
|
this->data_ready=(nep_ready_data_t *)this->h.data;
|
|
this->data_echo=(nep_echo_data_t *)this->h.data;
|
|
this->data_error=(nep_error_data_t *)this->h.data;
|
|
this->fs_off=(u8 *)this->data_pspec->packetspec;
|
|
this->fs_bytes=0;
|
|
this->echo_mac=(u8 *)this->data_echo->payload_and_mac;
|
|
this->echo_bytes=0;
|
|
|
|
/* Some safe initilizations */
|
|
this->setVersion(ECHO_CURRENT_PROTO_VER);
|
|
this->setTotalLength(STD_NEP_HEADER_LEN + MAC_LENGTH);
|
|
this->length=STD_NEP_HEADER_LEN + MAC_LENGTH; /* Sets length in PacketElement superclass */
|
|
} /* End of reset() */
|
|
|
|
|
|
/** @warning This method is essential for the superclass getBinaryBuffer()
|
|
* method to work. Do NOT change a thing unless you know what you're doing. */
|
|
u8 * EchoHeader::getBufferPointer(){
|
|
return (u8*)(&h);
|
|
} /* End of getBufferPointer() */
|
|
|
|
|
|
/** Stores supplied packet in the internal buffer so the information
|
|
* can be accessed using the standard get & set methods. */
|
|
int EchoHeader::storeRecvData(const u8 *buf, size_t len){
|
|
if(buf==NULL || len>(STD_NEP_HEADER_LEN+MAX_DATA_LEN)){
|
|
return OP_FAILURE;
|
|
}else{
|
|
this->reset(); /* Re-init the object, just in case the caller had used it already */
|
|
this->length=len;
|
|
memcpy(&(this->h), buf, len);
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of storeRecvData() */
|
|
|
|
|
|
/* Returns a protocol identifier. This is used by packet parsing funtions
|
|
* that return linked lists of PacketElement objects, to determine the protocol
|
|
* the object represents. */
|
|
int EchoHeader::protocol_id() const {
|
|
return HEADER_TYPE_NEP;
|
|
} /* End of protocol_id() */
|
|
|
|
|
|
/** Sets Version.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setVersion(u8 val){
|
|
this->h.echo_ver=val;
|
|
return OP_SUCCESS;
|
|
} /* End of setVersion() */
|
|
|
|
|
|
/** Returns value of attribute h.echo_ver */
|
|
u8 EchoHeader::getVersion(){
|
|
return this->h.echo_ver;
|
|
} /* End of getVersion() */
|
|
|
|
|
|
/** Sets MessageType.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setMessageType(u8 val){
|
|
this->h.echo_mtype=val;
|
|
return OP_SUCCESS;
|
|
} /* End of setMessageType() */
|
|
|
|
|
|
/** Returns value of attribute h.echo_mtype */
|
|
u8 EchoHeader::getMessageType(){
|
|
return this->h.echo_mtype;
|
|
} /* End of getsetMessageType() */
|
|
|
|
|
|
/** Sets Total Length.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error.
|
|
* @warning the length is expressed in 32bit words. */
|
|
int EchoHeader::setTotalLength(u16 val){
|
|
this->h.echo_tlen=htons(val);
|
|
this->length=val*4; /* Also, set superclass length attribute */
|
|
return OP_SUCCESS;
|
|
} /* End of setTotalLength() */
|
|
|
|
|
|
/** Sets Total Length.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setTotalLength(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_SERVER:
|
|
this->setTotalLength(NEP_HANDSHAKE_SERVER_LEN/4);
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
this->setTotalLength(NEP_HANDSHAKE_CLIENT_LEN/4);
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
this->setTotalLength(NEP_HANDSHAKE_FINAL_LEN/4);
|
|
break;
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
this->setTotalLength(NEP_PACKETSPEC_LEN/4);
|
|
break;
|
|
case TYPE_NEP_READY:
|
|
this->setTotalLength(NEP_READY_LEN/4);
|
|
break;
|
|
case TYPE_NEP_ECHO:
|
|
this->setTotalLength( (STD_NEP_HEADER_LEN + 4 + MAC_LENGTH + this->echo_bytes)/4 );
|
|
break;
|
|
case TYPE_NEP_ERROR:
|
|
this->setTotalLength(NEP_ERROR_LEN/4);
|
|
break;
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of setTotalLength() */
|
|
|
|
|
|
/** Returns value of attribute h.echo_tlen
|
|
* @warning Returned length is expressed in 32bit words. To get a byte count
|
|
* it must be multiplied by four */
|
|
u16 EchoHeader::getTotalLength(){
|
|
return ntohs(this->h.echo_tlen);
|
|
} /* End of getTotalLength() */
|
|
|
|
|
|
/** Sets SequenceNumber.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setSequenceNumber(u32 val){
|
|
this->h.echo_seq=htonl(val);
|
|
return OP_SUCCESS;
|
|
} /* End of setSequenceNumber() */
|
|
|
|
|
|
/** Returns value of attribute h.echo_seq */
|
|
u32 EchoHeader::getSequenceNumber(){
|
|
return ntohl(this->h.echo_seq);
|
|
} /* End of getSequenceNumber() */
|
|
|
|
|
|
/** Sets Timestamp.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setTimestamp(u32 val){
|
|
this->h.echo_ts=htonl(val);
|
|
return OP_SUCCESS;
|
|
} /* End of setTimestamp() */
|
|
|
|
|
|
/** Sets Timestamp.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setTimestamp(){
|
|
u32 t=(u32)time(NULL); /* TODO: Make sure this does not cause problems */
|
|
this->h.echo_ts=htonl(t);
|
|
return OP_SUCCESS;
|
|
} /* End of setTimestamp() */
|
|
|
|
|
|
/** Returns value of attribute h.echo_ts*/
|
|
u32 EchoHeader::getTimestamp(){
|
|
return ntohl(this->h.echo_ts);
|
|
} /* End of getTimestamp() */
|
|
|
|
|
|
/** Sets Reserved.
|
|
* @return OP_SUCCESS on success and OP_FAILURE in case of error. */
|
|
int EchoHeader::setReserved(u32 val){
|
|
this->h.echo_res=htonl(val);
|
|
return OP_SUCCESS;
|
|
} /* End of setReserved() */
|
|
|
|
|
|
/** Returns value of attribute h.echo_res */
|
|
u32 EchoHeader::getReserved(){
|
|
return this->h.echo_res;
|
|
} /* End of getReserved() */
|
|
|
|
|
|
int EchoHeader::setMessageAuthenticationCode(u8 *key, size_t keylen){
|
|
u8 *macpnt=NULL;
|
|
u8 *from=(u8 *)&(this->h);
|
|
size_t bytes=0;
|
|
|
|
/* Determine where the MAC field is and the length of the data that needs
|
|
* to be authenticated, based on message type. */
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_SERVER:
|
|
macpnt=this->data_hsserv->mac;
|
|
bytes=NEP_HANDSHAKE_SERVER_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
macpnt=this->data_hsclnt->mac;
|
|
bytes=NEP_HANDSHAKE_CLIENT_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
macpnt=this->data_hsfinal->mac;
|
|
bytes=NEP_HANDSHAKE_FINAL_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
macpnt=this->data_pspec->mac;
|
|
bytes=NEP_PACKETSPEC_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_READY:
|
|
macpnt=this->data_ready->mac;
|
|
bytes=NEP_READY_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_ECHO:
|
|
macpnt=this->echo_mac;
|
|
bytes=STD_NEP_HEADER_LEN + 4 + this->echo_bytes;
|
|
break;
|
|
case TYPE_NEP_ERROR:
|
|
macpnt=this->data_error->mac;
|
|
bytes=NEP_ERROR_LEN-MAC_LENGTH;
|
|
break;
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
/* Compute the code */
|
|
Crypto::hmac_sha256(from, bytes, macpnt, key, keylen);
|
|
return OP_SUCCESS;
|
|
} /* End of setMessageAuthenticationCode() */
|
|
|
|
|
|
u8 *EchoHeader::getMessageAuthenticationCode(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_SERVER:
|
|
return this->data_hsserv->mac;
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
return this->data_hsclnt->mac;
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
return this->data_hsfinal->mac;
|
|
break;
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
return this->data_pspec->mac;
|
|
break;
|
|
case TYPE_NEP_READY:
|
|
return this->data_ready->mac;
|
|
break;
|
|
case TYPE_NEP_ECHO:
|
|
this->updateEchoInternals();
|
|
return this->echo_mac;
|
|
break;
|
|
case TYPE_NEP_ERROR:
|
|
return this->data_error->mac;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
return NULL;
|
|
} /* End of getMessageAuthenticationCode() */
|
|
|
|
|
|
|
|
int EchoHeader::verifyMessageAuthenticationCode(u8 *key, size_t keylen){
|
|
u8 mac_backup[MAC_LENGTH];
|
|
u8 *aux;
|
|
|
|
/* Make a copy of the current MAC */
|
|
if( (aux=this->getMessageAuthenticationCode())==NULL )
|
|
return OP_FAILURE;
|
|
memcpy(mac_backup, aux, MAC_LENGTH);
|
|
|
|
/* Recompute the MAC */
|
|
memset(aux, 0, MAC_LENGTH);
|
|
this->setMessageAuthenticationCode(key, keylen);
|
|
|
|
/* Try to match both MACs*/
|
|
if( (aux=this->getMessageAuthenticationCode())==NULL )
|
|
return OP_FAILURE;
|
|
if( memcmp(mac_backup, aux, MAC_LENGTH)==0 ){
|
|
return OP_SUCCESS;
|
|
}else{
|
|
/* Restore original MAC */
|
|
memcpy(aux, mac_backup, MAC_LENGTH);
|
|
return OP_FAILURE;
|
|
}
|
|
} /* End of verifyMessageAuthenticationCode() */
|
|
|
|
/******************************************************************************/
|
|
/* NEP_HANDSHAKE methods */
|
|
/******************************************************************************/
|
|
|
|
int EchoHeader::setServerNonce(u8 *nonce){
|
|
assert(nonce);
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_SERVER:
|
|
memcpy(this->data_hsserv->server_nonce, nonce, NONCE_LEN);
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
memcpy(this->data_hsclnt->server_nonce, nonce, NONCE_LEN);
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of getServerNonce() */
|
|
|
|
|
|
u8 *EchoHeader::getServerNonce(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_SERVER:
|
|
return this->data_hsserv->server_nonce;
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
return this->data_hsclnt->server_nonce;
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
} /* End of getServerNonce() */
|
|
|
|
|
|
int EchoHeader::setClientNonce(u8 *nonce){
|
|
assert(nonce);
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
memcpy(this->data_hsclnt->client_nonce, nonce, NONCE_LEN);
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
memcpy(this->data_hsfinal->client_nonce , nonce, NONCE_LEN);
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of getClientNonce() */
|
|
|
|
|
|
u8 *EchoHeader::getClientNonce(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
return this->data_hsclnt->client_nonce;
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
return this->data_hsfinal->client_nonce;
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
} /* End of getClientNonce() */
|
|
|
|
|
|
int EchoHeader::setPartnerAddress(struct in_addr val){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
memset(this->data_hsclnt->partner_ip, 0, 16);
|
|
memcpy(this->data_hsclnt->partner_ip , &val, sizeof(struct in_addr));
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
memset(this->data_hsfinal->partner_ip, 0, 16);
|
|
memcpy(this->data_hsfinal->partner_ip , &val, sizeof(struct in_addr));
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
this->setIPVersion(0x04);
|
|
return OP_SUCCESS;
|
|
} /* End of setPartnerAddress() */
|
|
|
|
|
|
int EchoHeader::setPartnerAddress(struct in6_addr val){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
memset(this->data_hsclnt->partner_ip, 0, 16);
|
|
memcpy(this->data_hsclnt->partner_ip , &val, sizeof(struct in6_addr));
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
memset(this->data_hsfinal->partner_ip, 0, 16);
|
|
memcpy(this->data_hsfinal->partner_ip , &val, sizeof(struct in6_addr));
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
this->setIPVersion(0x06);
|
|
return OP_SUCCESS;
|
|
} /* End of setPartnerAddress() */
|
|
|
|
|
|
int EchoHeader::getPartnerAddress(struct in_addr *dst){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
memcpy(dst, this->data_hsclnt->partner_ip,sizeof(struct in_addr));
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
memcpy(dst, this->data_hsfinal->partner_ip,sizeof(struct in_addr));
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of getPartnerAddress() */
|
|
|
|
|
|
int EchoHeader::getPartnerAddress(struct in6_addr *dst){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
memcpy(dst, this->data_hsclnt->partner_ip,sizeof(struct in6_addr));
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
memcpy(dst, this->data_hsfinal->partner_ip,sizeof(struct in6_addr));
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of getPartnerAddress() */
|
|
|
|
|
|
/* On failure, it returns 0xAB */
|
|
u8 EchoHeader::getIPVersion(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
return this->data_hsclnt->ip_version;
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
return this->data_hsfinal->ip_version;
|
|
break;
|
|
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
return this->data_pspec->ip_version;
|
|
break;
|
|
|
|
default:
|
|
return 0xAB;
|
|
break;
|
|
}
|
|
} /* End of getIPVersion() */
|
|
|
|
|
|
int EchoHeader::setIPVersion(u8 ver){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
this->data_hsclnt->ip_version=ver;
|
|
break;
|
|
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
this->data_hsfinal->ip_version=ver;
|
|
break;
|
|
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
this->data_pspec->ip_version=ver;
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of setIPVersion() */
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
/* NEP_PACKET_SPEC methods */
|
|
/******************************************************************************/
|
|
|
|
int EchoHeader::setProtocol(u8 proto){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
this->data_pspec->protocol=proto;
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of setProtocol() */
|
|
|
|
|
|
/* On failure, it returns 0xAB */
|
|
u8 EchoHeader::getProtocol(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
return this->data_pspec->protocol;
|
|
break;
|
|
|
|
default:
|
|
return 0xAB;
|
|
break;
|
|
}
|
|
} /* End of setProtocol() */
|
|
|
|
|
|
int EchoHeader::setPacketCount(u16 c){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
this->data_pspec->packet_count=htons(c);
|
|
break;
|
|
|
|
default:
|
|
return OP_FAILURE;
|
|
break;
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of setPacketCount() */
|
|
|
|
|
|
/* On failure, it returns 0 */
|
|
u16 EchoHeader::getPacketCount(){
|
|
switch( this->getMessageType() ){
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
return ntohs(this->data_pspec->packet_count);
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
} /* End of getPacketCount() */
|
|
|
|
|
|
int EchoHeader::getFieldLength(u8 field){
|
|
switch(field){
|
|
/* 8bit fields */
|
|
case PSPEC_IPv4_TOS:
|
|
case PSPEC_IPv4_PROTO:
|
|
case PSPEC_IPv6_FLOW:
|
|
case PSPEC_IPv6_NHDR:
|
|
case PSPEC_TCP_FLAGS:
|
|
case PSPEC_ICMP_TYPE:
|
|
case PSPEC_ICMP_CODE:
|
|
return 1;
|
|
break;
|
|
|
|
/* 16bit fields */
|
|
case PSPEC_IPv4_ID:
|
|
case PSPEC_IPv4_FRAGOFF:
|
|
case PSPEC_TCP_SPORT:
|
|
case PSPEC_TCP_DPORT:
|
|
case PSPEC_TCP_WIN:
|
|
case PSPEC_TCP_URP:
|
|
case PSPEC_UDP_SPORT:
|
|
case PSPEC_UDP_DPORT:
|
|
case PSPEC_UDP_LEN:
|
|
return 2;
|
|
break;
|
|
|
|
/* 24bit fields */
|
|
case PSPEC_IPv6_TCLASS:
|
|
return 3;
|
|
break;
|
|
|
|
/* 32bit fields */
|
|
case PSPEC_TCP_SEQ:
|
|
case PSPEC_TCP_ACK:
|
|
return 4;
|
|
break;
|
|
|
|
/* Error */
|
|
case PSPEC_PAYLOAD_MAGIC:
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
} /* End of getFieldLength() */
|
|
|
|
|
|
int EchoHeader::addFieldSpec(u8 field, u8 *val){
|
|
int flen;
|
|
/* Determine the length of the field */
|
|
if( (flen=this->getFieldLength(field))==-1 || val==NULL )
|
|
return OP_FAILURE;
|
|
else{
|
|
return this->addFieldSpec(field, val, flen);
|
|
}
|
|
} /* End of addFieldSpec() */
|
|
|
|
|
|
int EchoHeader::addFieldSpec(u8 field, u8 *val, size_t flen){
|
|
if( val==NULL ){
|
|
return OP_FAILURE;
|
|
}else{
|
|
/* Store the field spec and update internal pointers and counts */
|
|
if( (this->fs_bytes+flen) < PACKETSPEC_FIELD_LEN ){
|
|
*(this->fs_off)=field;
|
|
if(field==PSPEC_PAYLOAD_MAGIC){
|
|
/* Check length again since this field requires an extra byte */
|
|
if(this->fs_bytes+flen+1 < PACKETSPEC_FIELD_LEN){
|
|
*(this->fs_off+1)=flen;
|
|
memcpy(this->fs_off+2, val, flen);
|
|
this->fs_off+=(flen+2);
|
|
this->fs_bytes+=(flen+2);
|
|
}else{
|
|
return OP_FAILURE;
|
|
}
|
|
}else{
|
|
memcpy(this->fs_off+1, val, flen);
|
|
this->fs_off+=(flen+1);
|
|
this->fs_bytes+=(flen+1);
|
|
}
|
|
}else{
|
|
return OP_FAILURE;
|
|
}
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of addFieldSpec() */
|
|
|
|
|
|
int EchoHeader::rewindFieldSpecCounters(){
|
|
this->fs_off=(u8 *)this->data_pspec->packetspec;
|
|
this->fs_bytes=0;
|
|
return OP_SUCCESS;
|
|
} /* rewindFieldSpecCounters */
|
|
|
|
/** @warning dst_buff must be able to hold at least (PACKETSPEC_FIELD_LEN-2) bytes. */
|
|
int EchoHeader::getNextFieldSpec(u8 *field, u8 *dst_buff, size_t *final_len){
|
|
u8 nfield=0;
|
|
int nlen=0;
|
|
if(field==NULL || dst_buff==NULL || this->fs_bytes>=PACKETSPEC_FIELD_LEN)
|
|
return OP_FAILURE;
|
|
/* Determine which is the next field specifier */
|
|
nfield=*(this->fs_off);
|
|
if(nfield==PSPEC_PAYLOAD_MAGIC){
|
|
nlen=(int)*(this->fs_off+1); /* Read length from the packet */
|
|
if(nlen<=0 || nlen>(PACKETSPEC_FIELD_LEN-2) )
|
|
return OP_FAILURE;
|
|
else if( this->fs_bytes+2+nlen>PACKETSPEC_FIELD_LEN)
|
|
return OP_FAILURE;
|
|
else
|
|
memcpy(dst_buff, this->fs_off+2, nlen);
|
|
this->fs_off+=(nlen+2);
|
|
this->fs_bytes+=(nlen+2);
|
|
}else{
|
|
if((nlen=this->getFieldLength(nfield))<=0) /* Determine field length */
|
|
return OP_FAILURE;
|
|
else if(this->fs_bytes+1+nlen>PACKETSPEC_FIELD_LEN)
|
|
return OP_FAILURE;
|
|
else
|
|
memcpy(dst_buff, this->fs_off+1, nlen);
|
|
this->fs_off+=(nlen+1);
|
|
this->fs_bytes+=(nlen+2);
|
|
}
|
|
/* Store data */
|
|
*field=nfield;
|
|
if(final_len!=NULL)
|
|
*final_len=nlen;
|
|
return OP_SUCCESS;
|
|
} /* End of getNextFieldSpec() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* NEP_PACKET_ECHO methods */
|
|
/******************************************************************************/
|
|
int EchoHeader::setDLT(u16 dlt){
|
|
this->data_echo->dlt_type=htons(dlt);
|
|
return OP_SUCCESS;
|
|
} /* End of setDLT() */
|
|
|
|
|
|
u16 EchoHeader::getDLT(){
|
|
return ntohs(this->data_echo->dlt_type);
|
|
} /* End of getDLT() */
|
|
|
|
|
|
int EchoHeader::setPacketLength(u16 len){
|
|
this->data_echo->packet_len=htons(len);
|
|
return OP_SUCCESS;
|
|
} /* End of setPacketLength() */
|
|
|
|
|
|
u16 EchoHeader::getPacketLength(){
|
|
return ntohs(this->data_echo->packet_len);
|
|
} /* End of setPacketLength() */
|
|
|
|
|
|
int EchoHeader::setEchoedPacket(const u8 *pkt, size_t pktlen){
|
|
int padding=0;
|
|
if(pkt==NULL)
|
|
return OP_FAILURE;
|
|
if(pktlen>MAX_ECHOED_PACKET_LEN){
|
|
pktlen=MAX_ECHOED_PACKET_LEN;
|
|
}
|
|
memcpy(this->data_echo->payload_and_mac, pkt, pktlen);
|
|
if((pktlen+4)%16!=0){
|
|
padding=16-((pktlen+4)%16);
|
|
memset(this->data_echo->payload_and_mac+pktlen, 0, padding);
|
|
}
|
|
this->echo_bytes=pktlen+padding;
|
|
this->echo_mac+=pktlen+padding;
|
|
/* Set the packet length field automatically */
|
|
this->setPacketLength((u16)pktlen);
|
|
this->length = STD_NEP_HEADER_LEN + 4 + this->echo_bytes + MAC_LENGTH;
|
|
assert(this->length%16==0);
|
|
return OP_SUCCESS;
|
|
} /* End of setEchoedPacket() */
|
|
|
|
|
|
/* @warning value stored in final_len is not exactly the actual length of the
|
|
* returned buffer but the value stored in the "Packet Length" field of the
|
|
* NEP_ECHO message. The caller is supposed to validate received packets before
|
|
* trusting that length */
|
|
u8 *EchoHeader::getEchoedPacket(u16 *final_len){
|
|
if(final_len!=NULL)
|
|
*final_len=this->getPacketLength();
|
|
return this->data_echo->payload_and_mac;
|
|
} /* End of getEchoedPacket() */
|
|
|
|
|
|
u8 *EchoHeader::getEchoedPacket(){
|
|
return this->getEchoedPacket(NULL);
|
|
} /* End of getEchoedPacket() */
|
|
|
|
|
|
/** This method tries to update the object's internal counters for a NEP_ECHO
|
|
* packet. This should be used when storing a received NEP_ECHO message in
|
|
* the object. In that case, the internal pointers will not be set up
|
|
* correctly, as the object did not construct the message. Calling this method
|
|
* should fix the internal state of the object and make things like
|
|
* verifyMessageAuthenticationCode() work. */
|
|
int EchoHeader::updateEchoInternals(){
|
|
if( this->getMessageType()!=TYPE_NEP_ECHO )
|
|
return OP_FAILURE;
|
|
|
|
/* Fix echo bytes length */
|
|
this->echo_bytes=this->getPacketLength();
|
|
if((this->echo_bytes+4)%16!=0){
|
|
this->echo_bytes+=16-((this->echo_bytes+4)%16);
|
|
}
|
|
/* Fix MAC offset */
|
|
this->echo_mac=((u8 *)this->data_echo->payload_and_mac)+this->echo_bytes;
|
|
return OP_SUCCESS;
|
|
} /* End of updateEchoInternals() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* NEP_ERROR methods */
|
|
/******************************************************************************/
|
|
|
|
/** @warning error strings longer than MAX_NEP_ERROR_MSG_LEN-1 will be truncated */
|
|
int EchoHeader::setErrorMessage(const char *err){
|
|
if(err==NULL){
|
|
return OP_FAILURE;
|
|
}else{
|
|
strncpy((char *)this->data_error->errmsg, err, ERROR_MSG_LEN);
|
|
this->data_error->errmsg[ERROR_MSG_LEN-1]='\0';
|
|
}
|
|
return OP_SUCCESS;
|
|
} /* End of setErrorMessage() */
|
|
|
|
/* @warning Returned pointer, points to the start of the "Error Message" field
|
|
* of the NEP_ERROR message. When receiving this kind of messages, there is no
|
|
* guarantee that the field contains printable characters, or that it is NULL
|
|
* terminated. The caller should validate it's contents. It is safe to read
|
|
* MAX_NEP_ERROR_MSG_LEN bytes from the start of the returned buffer pointer. */
|
|
char *EchoHeader::getErrorMessage(){
|
|
return (char *)this->data_error->errmsg;
|
|
} /* End of getErrorMessage() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* CRYPTOGRAPHY */
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
u8 *EchoHeader::getCiphertextBounds(size_t *final_len){
|
|
return this->getCiphertextBounds(final_len, this->getMessageType());
|
|
}
|
|
|
|
|
|
u8 *EchoHeader::getCiphertextBounds(size_t *final_len, int message_type){
|
|
u8 *start=NULL;
|
|
size_t len=0;
|
|
|
|
switch( message_type ){
|
|
case TYPE_NEP_HANDSHAKE_SERVER: /* this msg is never transmitted encrypted */
|
|
len=0;
|
|
start=(u8 *)&this->h;
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_CLIENT:
|
|
start=this->data_hsclnt->partner_ip;
|
|
len=32;
|
|
break;
|
|
case TYPE_NEP_HANDSHAKE_FINAL:
|
|
start=this->data_hsfinal->partner_ip;
|
|
len=32;
|
|
break;
|
|
case TYPE_NEP_PACKET_SPEC:
|
|
start=(u8 *)(&this->h);
|
|
len=NEP_PACKETSPEC_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_READY:
|
|
start=(u8 *)(&this->h);
|
|
len=NEP_READY_LEN-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_ECHO:
|
|
start=(u8 *)(&this->h);
|
|
len=this->length-MAC_LENGTH;
|
|
break;
|
|
case TYPE_NEP_ERROR:
|
|
start=(u8 *)(&this->h);
|
|
len=NEP_ERROR_LEN-MAC_LENGTH;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
|
|
if(final_len!=NULL)
|
|
*final_len=len;
|
|
return start;
|
|
} /* End of getCiphertextBounds() */
|
|
|
|
|
|
|
|
/** Encrypts the NEP message using the supplied key and initialization vector.
|
|
* On success it returns a pointer to the beginning of the last ciphertext
|
|
* block. This should be stored by the caller and used as the IV for the
|
|
* next encrypted data. It returns NULL in case of error. */
|
|
u8 *EchoHeader::encrypt(u8 *key, size_t key_len, u8 *iv){
|
|
outPrint(DBG_4, "%s(%p, %lu, %p)", __func__, key, (long unsigned)key_len, iv);
|
|
u8 *start=NULL;
|
|
size_t len=0;
|
|
|
|
if(key==NULL || key_len==0 || iv==NULL)
|
|
return NULL;
|
|
|
|
if((start=this->getCiphertextBounds(&len))==NULL)
|
|
return NULL;
|
|
|
|
if(len>=CIPHER_BLOCK_SIZE){
|
|
if( Crypto::aes128_cbc_encrypt(start, len, (u8 *)(&this->h_tmp), key, key_len, iv) != OP_SUCCESS )
|
|
return NULL;
|
|
else{
|
|
memcpy(start, &this->h_tmp, len);
|
|
return (start+(len-CIPHER_BLOCK_SIZE));
|
|
}
|
|
}else{
|
|
return NULL;
|
|
}
|
|
} /* End of encrypt() */
|
|
|
|
|
|
u8 *EchoHeader::decrypt(u8 *key, size_t key_len, u8 *iv, int message_type){
|
|
outPrint(DBG_4, "%s(%p, %lu, %p)", __func__, key, (long unsigned)key_len, iv);
|
|
u8 *start=NULL;
|
|
size_t len=0;
|
|
static u8 lastblock[CIPHER_BLOCK_SIZE];
|
|
|
|
if(key==NULL || key_len==0 || iv==NULL)
|
|
return NULL;
|
|
|
|
if((start=this->getCiphertextBounds(&len, message_type))==NULL)
|
|
return NULL;
|
|
|
|
if(len>=CIPHER_BLOCK_SIZE){
|
|
/* Keep a copy of the last ciphertext block */
|
|
memcpy(lastblock, start+len-CIPHER_BLOCK_SIZE, CIPHER_BLOCK_SIZE);
|
|
if( Crypto::aes128_cbc_decrypt(start, len, (u8 *)(&this->h_tmp), key, key_len, iv) != OP_SUCCESS )
|
|
return NULL;
|
|
else{
|
|
memcpy(start, &this->h_tmp, len);
|
|
return lastblock;
|
|
}
|
|
}else{
|
|
return NULL;
|
|
}
|
|
} /* End of decrypt() */ |