summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opienet/opcap.cpp21
-rw-r--r--libopie2/opienet/opcap.h35
2 files changed, 32 insertions, 24 deletions
diff --git a/libopie2/opienet/opcap.cpp b/libopie2/opienet/opcap.cpp
index 7463320..fdd519c 100644
--- a/libopie2/opienet/opcap.cpp
+++ b/libopie2/opienet/opcap.cpp
@@ -65,165 +65,170 @@ OPacket::OPacket( int datalink, packetheaderstruct header, const unsigned char*
break;
case DLT_IEEE802_11:
odebug << "OPacket::OPacket(): Received Packet. Datalink = IEEE802.11" << oendl;
new OWaveLanPacket( _end, (const struct ieee_802_11_header*) data, this );
break;
case DLT_PRISM_HEADER:
odebug << "OPacket::OPacket(): Received Packet. Datalink = PRISM_HEADER" << oendl;
new OPrismHeaderPacket( _end, (const struct prism_hdr*) (unsigned char*) data, this );
break;
default:
owarn << "OPacket::OPacket(): Received Packet over unsupported datalink, type " << datalink << "!" << oendl;
}
}
OPacket::~OPacket()
{
}
timevalstruct OPacket::timeval() const
{
return _hdr.ts;
}
int OPacket::caplen() const
{
return _hdr.caplen;
}
void OPacket::updateStats( QMap<QString,int>& stats, QObjectList* l )
{
if (!l) return;
QObject* o = l->first();
while ( o )
{
stats[o->name()]++;
updateStats( stats, const_cast<QObjectList*>( o->children() ) );
o = l->next();
}
}
-void OPacket::dumpStructure( QObjectList* l )
+QString OPacket::dumpStructure() const
{
- QString packetString( "[ |" + _dumpStructure( l ) + " ]" );
- odebug << "OPacket::dumpStructure: " << packetString << oendl;
+ return "[ |" + _dumpStructure( const_cast<QObjectList*>( this->children() ) ) + " ]";
}
-QString OPacket::_dumpStructure( QObjectList* l )
+QString OPacket::_dumpStructure( QObjectList* l ) const
{
if (!l) return QString::null;
QObject* o = l->first();
QString str(" ");
while ( o )
{
str.append( o->name() );
str.append( " |" );
str += _dumpStructure( const_cast<QObjectList*>( o->children() ) );
o = l->next();
}
return str;
}
QString OPacket::dump( int bpl ) const
{
static int index = 0;
index++;
int len = _hdr.caplen;
QString str;
str.sprintf( "\n<----- Packet #%04d Len = 0x%X (%d) ----->\n\n", index, len, len );
str.append( "0000: " );
QString tmp;
QString bytes;
QString chars;
for ( int i = 0; i < len; ++i )
{
tmp.sprintf( "%02X ", _data[i] ); bytes.append( tmp );
if ( (_data[i] > 31) && (_data[i]<128) ) chars.append( _data[i] );
else chars.append( '.' );
if ( !((i+1) % bpl) )
{
str.append( bytes );
str.append( ' ' );
str.append( chars );
str.append( '\n' );
tmp.sprintf( "%04X: ", i+1 ); str.append( tmp );
bytes = "";
chars = "";
}
}
if ( (len % bpl) )
{
str.append( bytes.leftJustify( 1 + 3*bpl ) );
str.append( chars );
}
str.append( '\n' );
return str;
}
int OPacket::len() const
{
return _hdr.len;
}
+QTextStream& operator<<( QTextStream& s, const OPacket& p )
+{
+ s << p.dumpStructure();
+}
+
+
/*======================================================================================
* OEthernetPacket
*======================================================================================*/
OEthernetPacket::OEthernetPacket( const unsigned char* end, const struct ether_header* data, QObject* parent )
:QObject( parent, "Ethernet" ), _ether( data )
{
odebug << "Source = " << sourceAddress().toString();
odebug << "Destination = " << destinationAddress().toString();
if ( sourceAddress() == OMacAddress::broadcast )
odebug << "Source is broadcast address" << oendl;
if ( destinationAddress() == OMacAddress::broadcast )
odebug << "Destination is broadcast address" << oendl;
switch ( type() )
{
case ETHERTYPE_IP: new OIPPacket( end, (const struct iphdr*) (data+1), this ); break;
case ETHERTYPE_ARP: new OARPPacket( end, (const struct myarphdr*) (data+1), this ); break;
case ETHERTYPE_REVARP: { odebug << "OPacket::OPacket(): Received Ethernet Packet : Type = RARP" << oendl; break; }
default: odebug << "OPacket::OPacket(): Received Ethernet Packet : Type = UNKNOWN" << oendl;
}
}
OEthernetPacket::~OEthernetPacket()
{
}
OMacAddress OEthernetPacket::sourceAddress() const
{
return OMacAddress( _ether->ether_shost );
}
OMacAddress OEthernetPacket::destinationAddress() const
{
return OMacAddress( _ether->ether_dhost );
}
int OEthernetPacket::type() const
{
return ntohs( _ether->ether_type );
}
@@ -684,97 +689,97 @@ int OWaveLanPacket::type() const
int OWaveLanPacket::version() const
{
return FC_VERSION( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) );
}
bool OWaveLanPacket::fromDS() const
{
return FC_FROM_DS( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) );
}
bool OWaveLanPacket::toDS() const
{
return FC_TO_DS( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) );
}
bool OWaveLanPacket::usesPowerManagement() const
{
return FC_POWER_MGMT( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) );
}
bool OWaveLanPacket::usesWep() const
{
return FC_WEP( EXTRACT_LE_16BITS( &_wlanhdr->frame_control ) );
}
/*======================================================================================
* OWaveLanManagementPacket
*======================================================================================*/
OWaveLanManagementPacket::OWaveLanManagementPacket( const unsigned char* end, const struct ieee_802_11_mgmt_header* data, OWaveLanPacket* parent )
:QObject( parent, "802.11 Management" ), _header( data ),
_body( (const struct ieee_802_11_mgmt_body*) (data+1) )
{
odebug << "OWaveLanManagementPacket::OWaveLanManagementPacket(): decoding frame..." << oendl;
odebug << "Detected subtype is " << managementType() << oendl;
// Grab tagged values.
// Beacons contain a 12 byte long fixed parameters set before the tagged parameters come,
// Other management frames don't - which is why we have to inspect the subtype here.
const unsigned char* ptr = managementType() == "Beacon" ? (const unsigned char*) (_body+1) : (const unsigned char*) (_header+1);
-
+
while (ptr < end)
{
switch ( *ptr )
{
case E_SSID: new OWaveLanManagementSSID( end, (struct ssid_t*) ptr, this ); break;
case E_FH: new OWaveLanManagementFH( end, (struct fh_t*) ptr, this ); break;
case E_DS: new OWaveLanManagementDS( end, (struct ds_t*) ptr, this ); break;
case E_RATES: new OWaveLanManagementRates( end, (struct rates_t*) ptr, this ); break;
case E_CF: new OWaveLanManagementCF( end, (struct cf_t*) ptr, this ); break;
case E_TIM: new OWaveLanManagementTim( end, (struct tim_t*) ptr, this ); break;
case E_IBSS: new OWaveLanManagementIBSS( end, (struct ibss_t*) ptr, this ); break;
case E_CHALLENGE: new OWaveLanManagementChallenge( end, (struct challenge_t*) ptr, this ); break;
}
ptr+= ( ( struct ssid_t* ) ptr )->length; // skip length of tagged value
ptr+= 2; // skip tag ID and length
}
}
OWaveLanManagementPacket::~OWaveLanManagementPacket()
{
}
QString OWaveLanManagementPacket::managementType() const
{
switch ( FC_SUBTYPE( EXTRACT_LE_16BITS( &_header->fc ) ) )
{
case ST_ASSOC_REQUEST: return "AssociationRequest"; break;
case ST_ASSOC_RESPONSE: return "AssociationResponse"; break;
case ST_REASSOC_REQUEST: return "ReassociationRequest"; break;
case ST_REASSOC_RESPONSE: return "ReassociationResponse"; break;
case ST_PROBE_REQUEST: return "ProbeRequest"; break;
case ST_PROBE_RESPONSE: return "ProbeResponse"; break;
case ST_BEACON: return "Beacon"; break;
case ST_ATIM: return "Atim"; break;
case ST_DISASSOC: return "Disassociation"; break;
case ST_AUTH: return "Authentication"; break;
case ST_DEAUTH: return "Deathentication"; break;
default: owarn << "OWaveLanManagementPacket::managementType(): unhandled subtype " << FC_SUBTYPE( EXTRACT_LE_16BITS( &_header->fc ) ) << oendl; return "Unknown";
}
}
int OWaveLanManagementPacket::beaconInterval() const
{
return EXTRACT_LE_16BITS( &_body->beacon_interval );
}
@@ -1143,99 +1148,97 @@ void OPacketCapturer::dump( OPacket* p )
}
int OPacketCapturer::fileno() const
{
if ( _open )
{
return pcap_fileno( _pch );
}
else
{
return -1;
}
}
OPacket* OPacketCapturer::next( int time )
{
fd_set fds;
struct timeval tv;
FD_ZERO( &fds );
FD_SET( pcap_fileno( _pch ), &fds );
tv.tv_sec = time / 1000;
tv.tv_usec = time % 1000;
int retval = select( pcap_fileno( _pch )+1, &fds, NULL, NULL, &tv);
if ( retval > 0 ) // clear to read!
return next();
else
return 0;
}
OPacket* OPacketCapturer::next()
{
packetheaderstruct header;
odebug << "==> OPacketCapturer::next()" << oendl;
const unsigned char* pdata = pcap_next( _pch, &header );
odebug << "<== OPacketCapturer::next()" << oendl;
if ( pdata && header.len )
{
OPacket* p = new OPacket( dataLink(), header, pdata, 0 );
// packets shouldn't be inserted in the QObject child-parent hierarchy,
// because due to memory constraints they will be deleted as soon
// as possible - that is right after they have been processed
// by emit() [ see below ]
//TODO: make gathering statistics optional, because it takes time
p->updateStats( _stats, const_cast<QObjectList*>( p->children() ) );
- #ifndef NODEBUG
- p->dumpStructure( const_cast<QObjectList*>( p->children() ) );
- #endif
+ odebug << "OPacket::dumpStructure: " << p->dumpStructure() << oendl;
return p;
}
else
{
owarn << "OPacketCapturer::next() - no packet received!" << oendl;
return 0;
}
}
bool OPacketCapturer::open( const QString& name )
{
if ( _open )
{
if ( name == _name ) // ignore opening an already openend device
{
return true;
}
else // close the last opened device
{
close();
}
}
_name = name;
// open libpcap
pcap_t* handle = pcap_open_live( const_cast<char*>( (const char*) name ), 1024, 0, 0, &_errbuf[0] );
if ( !handle )
{
owarn << "OPacketCapturer::open(): can't open libpcap with '" << name << "': " << _errbuf << oendl;
return false;
}
odebug << "OPacketCapturer::open(): libpcap [" << name << "] opened successfully." << oendl;
_pch = handle;
_open = true;
_stats.clear();
// in case we have an application object, create a socket notifier
if ( qApp ) //TODO: I don't like this here...
{
_sn = new QSocketNotifier( fileno(), QSocketNotifier::Read );
connect( _sn, SIGNAL( activated(int) ), this, SLOT( readyToReceive() ) );
}
return true;
@@ -1293,52 +1296,52 @@ bool OPacketCapturer::open( const QFile& file )
return true;
}
else
{
odebug << "OPacketCapturer::open(): can't open libpcap with '" << name << "': " << _errbuf << oendl;
return false;
}
}
bool OPacketCapturer::isOpen() const
{
return _open;
}
void OPacketCapturer::readyToReceive()
{
odebug << "OPacketCapturer::readyToReceive(): about to emit 'receivePacket(p)'" << oendl;
OPacket* p = next();
emit receivedPacket( p );
// emit is synchronous - packet has been dealt with, now it's safe to delete
delete p;
}
const QMap<QString,int>& OPacketCapturer::statistics() const
{
return _stats;
}
int OPacketCapturer::snapShot() const
{
return pcap_snapshot( _pch );
}
bool OPacketCapturer::swapped() const
{
return pcap_is_swapped( _pch );
}
QString OPacketCapturer::version() const
{
- return QString().sprintf( "%s.%s", pcap_major_version( _pch ), pcap_minor_version( _pch ) );
+ return QString().sprintf( "%d.%d", pcap_major_version( _pch ), pcap_minor_version( _pch ) );
}
diff --git a/libopie2/opienet/opcap.h b/libopie2/opienet/opcap.h
index f5dc5c0..b873b49 100644
--- a/libopie2/opienet/opcap.h
+++ b/libopie2/opienet/opcap.h
@@ -1,190 +1,195 @@
/*
                This file is part of the Opie Project
              Copyright (C) 2003 by Michael 'Mickey' Lauer <mickey@Vanille.de>
=.
.=l.
           .>+-=
 _;:,     .>    :=|. This program is free software; you can
.> <`_,   >  .   <= redistribute it and/or modify it under
:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
.="- .-=="i,     .._ License as published by the Free Software
 - .   .-<_>     .<> Foundation; either version 2 of the License,
     ._= =}       : or (at your option) any later version.
    .%`+i>       _;_.
    .i_,=:_.      -<s. 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
..}^=.=       =       ; Library General Public License for more
++=   -.     .`     .: details.
 :     =  ...= . :.=-
 -.   .:....=;==+<; You should have received a copy of the GNU
  -_. . .   )=.  = Library General Public License along with
    --        :-=` this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#ifndef OPCAP_H
#define OPCAP_H
-/* LINUX */
-extern "C" // work around a bpf/pcap conflict in recent headers
-{
- #include <pcap.h>
-}
-#include <netinet/ether.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/tcp.h>
-#include <time.h>
+/* OPIE */
+#include <opie2/onetutils.h>
/* QT */
#include <qevent.h>
#include <qfile.h>
#include <qhostaddress.h>
#include <qobject.h>
#include <qstring.h>
+#include <qtextstream.h>
#include <qmap.h>
-/* OPIE */
-#include <opie2/onetutils.h>
+/* STD */
+extern "C" // work around a bpf/pcap conflict in recent headers
+{
+ #include <pcap.h>
+}
+#include <netinet/ether.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <time.h>
-/* Custom Network Includes */
+/* Custom Network Includes (must go here, don't reorder!) */
#include "802_11_user.h"
#include "dhcp.h"
+
/* TYPEDEFS */
typedef struct timeval timevalstruct;
typedef struct pcap_pkthdr packetheaderstruct;
/* FORWARDS */
class OPacketCapturer;
class QSocketNotifier;
/*======================================================================================
* OPacket - A frame on the wire
*======================================================================================*/
/** @brief A class representing a data frame on the wire.
*
* The whole family of the packet classes are used when capturing frames from a network.
* Most standard network protocols in use share a common architecture, which mostly is
* a packet header and then the packet payload. In layered architectures, each lower layer
* encapsulates data from its upper layer - that is it
* treats the data from its upper layer as payload and prepends an own header to the packet,
* which - again - is treated as the payload for the layer below. The figure below is an
* example for how such a data frame is composed out of packets, e.g. when sending a mail.
*
* <pre>
* | User Data | == Mail Data
* | SMTP Header | User Data | == SMTP
* | TCP Header | SMTP Header | User Data | == TCP
* | IP Header | TCP Header | SMTP Header | User Data | == IP
* | MAC Header | IP Header | TCP Header | SMTP Header | User Data | == MAC
*
* </pre>
*
* The example is trimmed for simplicity, because the MAC (Medium Access Control) layer
* also contains a few more levels of encapsulation.
* Since the type of the payload is more or less independent from the encapsulating protocol,
* the header must be inspected before attempting to decode the payload. Hence, the
* encapsulation level varies and can't be deduced without actually looking into the packets.
*
* For actually working with captured frames, it's useful to identify the packets via names and
* insert them into a parent/child - relationship based on the encapsulation. This is why
* all packet classes derive from QObject. The amount of overhead caused by the QObject is
* not a problem in this case, because we're talking about a theoratical maximum of about
* 10 packets per captured frame. We need to stuff them into a searchable list anyway and the
* QObject also cares about destroying the sub-, (child-) packets.
*
* This enables us to perform a simple look for packets of a certain type:
* @code
* OPacketCapturer* pcap = new OPacketCapturer();
* pcap->open( "eth0" );
* OPacket* p = pcap->next();
* OIPPacket* ip = (OIPPacket*) p->child( "IP" ); // returns 0, if no such child exists
* odebug << "got ip packet from " << ip->fromIPAddress().toString() << " to " << ip->toIPAddress().toString() << oendl;
*
*/
class OPacket : public QObject
{
Q_OBJECT
friend class OPacketCapturer;
+ friend QTextStream& operator<<( QTextStream& s, const OPacket& p );
public:
OPacket( int datalink, packetheaderstruct, const unsigned char*, QObject* parent );
virtual ~OPacket();
timevalstruct timeval() const;
int caplen() const;
int len() const;
QString dump( int = 32 ) const;
void updateStats( QMap<QString,int>&, QObjectList* );
private:
- void dumpStructure( QObjectList* );
- QString _dumpStructure( QObjectList* );
+ QString dumpStructure() const;
+ QString _dumpStructure( QObjectList* ) const;
private:
const packetheaderstruct _hdr; // pcap packet header
const unsigned char* _data; // pcap packet data
const unsigned char* _end; // end of pcap packet data
};
+QTextStream& operator<<( QTextStream& s, const OPacket& p );
+
/*======================================================================================
* OEthernetPacket - DLT_EN10MB frame
*======================================================================================*/
class OEthernetPacket : public QObject
{
Q_OBJECT
public:
OEthernetPacket( const unsigned char*, const struct ether_header*, QObject* parent = 0 );
virtual ~OEthernetPacket();
OMacAddress sourceAddress() const;
OMacAddress destinationAddress() const;
int type() const;
private:
const struct ether_header* _ether;
};
/*======================================================================================
* OPrismHeaderPacket - DLT_PRISM_HEADER frame
*======================================================================================*/
class OPrismHeaderPacket : public QObject
{
Q_OBJECT
public:
OPrismHeaderPacket( const unsigned char*, const struct prism_hdr*, QObject* parent = 0 );
virtual ~OPrismHeaderPacket();
unsigned int signalStrength() const;
private:
const struct prism_hdr* _header;
};
/*======================================================================================
* OWaveLanPacket - DLT_IEEE802_11 frame
*======================================================================================*/
class OWaveLanPacket : public QObject
{
Q_OBJECT
public:
OWaveLanPacket( const unsigned char*, const struct ieee_802_11_header*, QObject* parent = 0 );