An overview
===========

KSniffer is composed by two executables:

 1. ksniff
 2. ksniffer

ksniff is the background sniffer that reads an XML file produced by the ksniffer GUI to start sniffing. ksniff parses the file and then start sniffing according to the options recognized in the file. A typical file is:

<?xml version="1.0"?>
<options>
 <standard>
  <interface capturefile="/tmp/kde-user/ksniffer.pcap" dev="eth0" />
 </standard>
 <extras>
  <capture type="manually" />
 </extras>
</options>

that says to ksniff to start sniffing into the /tmp/kde-user/ksniffer.pcap file listening the eth0 network interface. The capture go on till the ksniff executable receive a signal to stop sniffing.

ksniffer is the frontend sniffer application. It is a GUI for the ksniff application. It simply let manage the packets captured by the ksniff application to the user. It's written using Qt 3.3 and KDE 3.3 libraries. It starts the ksniff executable, can put it in pause, remove it from the pause, stop it, than it shows the captured packets and let apply some features on them, for example you can do a "nslookup" on a source or destination IP address of a captured packets and so on. Each ksniffer class is specialized in its feature.




Starting from the main
======================

In the main() function (in the file main.cpp) you can find the following code lines that make works all KSniffer:

      mainWidget = new KSniffer();
      app.setMainWidget( mainWidget );
      mainWidget->show();

mainWidget is the KSniffer class defined in the file ksniffer.h . The KSniffer class is derived from KMainWindow as public. So this class defines the "main widget" of the application, but if you want the full application is defined by it now, of course changing it you can redefine the application "main widget".

   mainWidget = new KSniffer();

 defines a new instance of KSniffer for mainWidget (its first instance).

   app.setMainWidget( mainWidget );

 defines the main widget of the application.

   mainWidget->show();

 shows the defined main widget.




class KSniffer : public KMainWindow
===================================

This class defines variables and instances new classes to make work the whole application using its constructor:

KSniffer::KSniffer() :

  setAcceptDrops(true);

 let load a pcap file into KSniffer dragging and dropping it from the file manager


  m_config = kapp->config();

 assign to m_config a reference to read the ksniffer configuration.


  setupActions();

 setup actions for the menu, ...


  readSettings();

 reads the application settings directly from the ksnifferrc configuration file


  m_portNumberNameList = new PortNumberNameList();

 define the list of the services (the application protocols as FTP->21, HTTP->80, ...) parsing the /etc/services system file


  m_mainWidgetUI = new KSnifferMainWidget( this );
  setCentralWidget( m_mainWidgetUI );
  m_mainWidgetUI->setOptions( m_options );
  m_mainWidgetUI->setPortNumberNameList( m_portNumberNameList );

 defines the main widget, that is the KSniffer main view, and assign the related view options and give the services list reference


 ...some code to display the Splash screen if needed


 assigns some variales and application options


  // we need a PacketManager to "store" packets and manage them for the View
  // and we had to specify the temporary directory in the constructor parameters
  m_packets = new PacketManager( this, "packetmanager" );
  m_packets->setFilePath( m_options->tmpFilePath() );

  m_sniffer = new Sniffer( m_options );

  // we define how to manage new captured packets:
    //  1 - store the packet in a PacketList (calling savePacket)
  connect( m_sniffer, SIGNAL(gotPacket(ptrPacketType, struct pcap_pkthdr, long, int, int)),
             m_packets, SLOT(savePacket(ptrPacketType, struct pcap_pkthdr, long, int, int)) );
    //  2 - display the packet into the View
  connect( m_packets, SIGNAL(savedPacket(long, PacketManager *)), m_mainWidgetUI, SLOT(displayPacket(long, PacketManager *)) );


 define how KSniffer captures the packets


 ...some code for the system tray bar


 ...some code for the system tray bar popup menu


 ...some member variable assignments


  m_timer = new QTimer(this);
  connect( m_timer, SIGNAL(timeout()), this, SLOT(checkIfSniffing()));

 define to call checkIfSniffing() if the m_timer timer had a timeout (the timer is actived when the sniffing starts, so this timer slot check if the sniffing is in progress or not, so to update view if the filter edit box has some text)




Parsing the /etc/services file
==============================

The C++ code that parse the /etc/services file (as you've seen in the KSniffer class constructor) is:

  m_portNumberNameList = new PortNumberNameList();




The KSniffer configuration classes
==================================

The C++ code that read and assign settings (as you've seen in the KSniffer class constructor) is:

  readSettings();
  m_mainWidgetUI->setOptions( m_options );
  m_packets->setFilePath( m_options->tmpFilePath() );
  m_sniffer = new Sniffer( m_options );

The options are needed by the sniffer application (ksniff binary) because an XML file with configuration options is created from the ksniffer GUI for it. In addition the View needs to know some things to proceed, that's why the "setOption" call. The m_packets member variable is a PacketManager class defined with:

  m_packets = new PacketManager( this, "packetmanager" );

and

  m_packets->setFilePath( m_options->tmpFilePath() );

 says to the PacketManager to access to the file m_options->tmpFilePath() to reads the captured packets. Usually it's the /tmp/kde-user/ksniffer.pcap file, where 'user' is the name identifier of the user that runs the ksniffer executable.

  readSettings();

 does:

void KSniffer::readSettings()
{
  // reading application settings
  m_options = new CaptureOptions();

  m_actOpenRecent->loadEntries( m_config );
  m_actOpenRecent->setEnabled( true ); // force enabling
  m_actOpenRecent->setToolTip( i18n("Click to open a file\nClick and hold to open a recent file") );

  // set into m_options the sniffer options (ShowAfter, TrayBar, TmpDirectory, Warn, PassivePopUp, ShowSplash)
  m_snifferOption->getOptions( m_options );

  m_mustShowPacketsNow = !m_options->showAfter();
  m_showTrayBar = m_options->showTrayBar();
}

 pratically an instance of the class CaptureOptions is created, the recent entries in the Recent menu items are loaded, the sniffer options are loaded into m_options by its reference (it's called setShowAfter, setTmpDir, setTrayBar, setWarning, setPassiveWarn, setShowSplash, setSniffingType, setPacketsNumber, setPacketsSize, setPacketsInfoSizeUnits, setPacketsTime, setPacketsInfoTimeUnits) and the m_mustShowPacketsNow and the m_showTrayBar member variables are assigned. Infact m_snifferOption is a SnifferOptionTab class instance:

  SnifferOptionTab *m_snifferOption;

The call "m_snifferOption->getOptions( m_options )" comes from:

void SnifferOptionTab::getOptions( CaptureOptions *options )
{
  KConfig* c = kapp->config();
  c->setGroup( "General Options" );
  options->setShowAfter( c->readBoolEntry( "Show packets after stopped capture" , false ) );

  options->setTmpDir( c->readPathEntry( "Temp dir", KGlobal::dirs()->resourceDirs( "tmp" ).first() ) );
  options->setTrayBar( c->readBoolEntry( "Show Tray Bar", false ) );
  options->setWarning( c->readBoolEntry( "Warn with no packets", true ) );
  options->setPassiveWarn( c->readBoolEntry( "Passive pop up warning with no packets", false ) );
  options->setShowSplash( c->readBoolEntry( "Show splash", true ) );

  // load stopping capture type: manually, ...
  c->setGroup( "Capture Type Options" );
  QString strWhichStopType = c->readEntry( "Stopping Type", "manually" );
  options->setSniffingType( strWhichStopType );

  c->setGroup( "Capture After Packets" );
  options->setPacketsNumber( c->readLongNumEntry( "packets number", 0 ) );

  c->setGroup( "Capture After Size" );
  options->setPacketsSize( c->readLongNumEntry( "size", 0 ) );
  options->setPacketsInfoSizeUnits( c->readNumEntry( "unit", 0 ) );

  c->setGroup( "Capture After Time" );
  options->setPacketsTime( c->readLongNumEntry( "time", 0 ) );
  options->setPacketsInfoTimeUnits( c->readNumEntry( "unit", 0 ) );
}

The m_mustShowPacketsNow member variable is needed by KSniffer class to know if the captured packets are imediatelly showed or if they are showed when the capture process has stopped.
The m_showTrayBar member variable is needed to know if the KSniffer icon has to appear in the system tray bar.

  m_sniffer = new Sniffer( m_options )

 does:

Sniffer::Sniffer( CaptureOptions *options ) : QThread()
{
  setCaptureOptions( options );
  m_bSniffing = false;       // not sniffing yet
  m_frameNumber = 1;         // set the frame number
  m_bFromFile = false;       // the default sniffing is live, not from file
  m_canSniff = true;         // ok, now you can sniff
  m_bPauseSniffing = false;  // no pause at start-up
  m_packetsTotalSize = 0;    // 0 bytes sniffed
}

The call "setCaptureOptions( options )" comes from:

void Sniffer::setCaptureOptions(CaptureOptions *captOpt)
{
  m_strInterface = captOpt->sniffingInterface();
  m_strFilename = captOpt->sniffingFilename();
  m_strTmpFilePath = captOpt->tmpFilePath();
}

This means that the Sniffer class just need three parameters:

  1. m_strInterface;
  2. m_strFilename;
  3. m_strTmpFilePath;

m_strInterface is the "network interface" needed to start sniffing packets; m_strFilename is the file name where to get the sniffed data when opening an existing file; m_strTmpFilePath is the temporary file (complete of the directory path) where the captured information is saved during a live sniffing (the GUI will read that file while ksniff will write it).
The member function "setCaptureOptions(CaptureOptions *captOpt)" will be called from differents member functions so not always all the parameters are needed for the assignment. Just when start a live sniffing you have to set m_strInterface and m_strTmpFilePath. m_strFilename is assigned when you load a file directly or when you use the drag and drop.






The KSniffer core
=================

The C++ core code that make KSniffer sniffs and manage packets is the following (as you've seen in the KSniffer class constructor) is:

  // we need a PacketManager to "store" packets and manage them for the View
  // and we had to specify the temporary directory in the constructor parameters
  m_packets = new PacketManager( this, "packetmanager" );
  m_packets->setFilePath( m_options->tmpFilePath() );

  m_sniffer = new Sniffer( m_options );

  // we define how to manage new captured packets:
    //  1 - store the packet in a PacketList (calling savePacket)
  connect( m_sniffer, SIGNAL(gotPacket(ptrPacketType, struct pcap_pkthdr, long, int, int)),
             m_packets, SLOT(savePacket(ptrPacketType, struct pcap_pkthdr, long, int, int)) );
    //  2 - display the packet into the View
  connect( m_packets, SIGNAL(savedPacket(long, PacketManager *)), m_mainWidgetUI, SLOT(displayPacket(long, PacketManager *)) );

Before start to comment these steps it's better to get a description on how KSniffer GUI acts with the packets. According the Object Oriented Programming concepts each class has to do its work without to know how the other classes works, so each class is specialized to do its job, than:

 - PacketManager manages the packet analyzing them, so it extracts the information from the protocol that's incapsulated into the packet.
 - Sniffer manages the QThread for the sniffing from file or from a live sniffing.