Logo Search packages:      
Sourcecode: ike version File versions

libip.frag.cpp

/*
 * Copyright (c) 2007
 *      Shrew Soft Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Redistributions in any form must be accompanied by information on
 *    how to obtain complete source code for the software and any
 *    accompanying software that uses the software.  The source code
 *    must either be included in the distribution or be available for no
 *    more than the cost of distribution plus a nominal fee, and must be
 *    freely redistributable under reasonable conditions.  For an
 *    executable file, complete source code means the source code for all
 *    modules it contains.  It does not include source code for modules or
 *    files that typically accompany the major components of the operating
 *    system on which the executable file runs.
 *
 * THIS SOFTWARE IS PROVIDED BY SHREW SOFT INC ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SHREW SOFT INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * AUTHOR : Matthew Grooms
 *          mgrooms@shrew.net
 *
 */

#include "libip.h"
#include <stdio.h>

_IPFRAG::_IPFRAG()
{
      lastchk = 0;
}

//
// is this packet a fragment
//

bool _IPFRAG::isfrag( PACKET_IP & packet )
{
      //
      // obtain the packet ip header
      //

      IP_HEADER * ip_header = ( IP_HEADER * ) packet.buff();

      //
      // is this packet a fragment
      //

      unsigned short flags = htons( ip_header->flags );

      if( ( flags & IP_FLAG_MORE ) ||
            ( flags & IP_MASK_OFFSET ) )
            return true;

      return false;
}

//
// check for the do not fragment flag
//

bool _IPFRAG::dnfrag( PACKET_IP & packet )
{
      //
      // obtain the packet ip header
      //

      IP_HEADER * ip_header = ( IP_HEADER * ) packet.buff();

      //
      // is this packet a fragment
      //

      unsigned short flags = htons( ip_header->flags );

      if( flags & IP_FLAG_DONT_FRAG )
            return true;

      return false;
}

bool _IPFRAG::dofrag( PACKET_IP & packet, PACKET_IP & fragment, size_t & offset, size_t max_size )
{
      //
      // determine packet ip header size
      //

      IP_HEADER *       ip_header = ( IP_HEADER * ) packet.buff();
      unsigned short    ip_hdsize = 4 * ( ip_header->verlen & 0xF );

      //
      // determine total payload size
      //

      size_t pld_size;
      pld_size = packet.size();
      pld_size -= ip_hdsize;

      //
      // determine fragment payload size
      //

      size_t frg_size;
      frg_size = pld_size;
      frg_size -= offset;

      if( frg_size > ( max_size - sizeof( IP_HEADER ) ) )
            frg_size = ( max_size - sizeof( IP_HEADER ) );

      //
      // calculate payload left
      //

      size_t pld_left = 0;
      pld_left = pld_size;
      pld_left -= ( offset + frg_size );

      //
      // will this be the last fragment
      //

      bool more = false;

      if( pld_left != 0 )
      {
            more = true;

            //
            // there are more packet fragments to
            // follow, the ip standard states that
            // the three least significant bits are
            // discarded in the fragment offset
            //

            frg_size &= ( ~7 );
      }

      //
      // calculate fragment buffer start
      //

      unsigned char * frg_buff;
      frg_buff = packet.buff();
      frg_buff += ip_hdsize;
      frg_buff += offset;

      //
      // create the new packet fragment
      //

      in_addr addr_src;
      in_addr addr_dst;

      addr_src.s_addr = ip_header->ip_src;
      addr_dst.s_addr = ip_header->ip_dst;

      fragment.write(
            addr_src,
            addr_dst,
            ip_header->ident,
            ip_header->protocol );

      fragment.add(
            frg_buff,
            frg_size );

      fragment.frag( more, offset );
      fragment.done();

      //
      // determine next packet offset
      //

      offset += frg_size;

      return more;
}

bool _IPFRAG::defrag_add( PACKET_IP & fragment, unsigned short & id )
{
      //
      // cleanup any stale fragments
      // but only once per second
      //

      time_t current = time( NULL );

      if( lastchk < current )
      {
            lastchk = current;

            //
            // step through all our fragments
            //

            long count = used.count();
            long index = 0;

            for( ; index < count; index++ )
            {
                  //
                  // get the next fragment in our list
                  //

                  IPFRAG_ENTRY * entry = static_cast<IPFRAG_ENTRY*>( used.get_entry( index ) );
                  assert( entry != NULL );

                  //
                  // ckeck this fragment to see if
                  // it has expired
                  //

                  if( entry->expire <= current )
                  {
                        //
                        // remove the fragment from the used
                        // list and move it to the free list
                        //

                        used.del_entry( entry );
                        free.add_entry( entry );

                        //
                        // correct for our change in list
                        // index and item count
                        //

                        index--;
                        count--;
                  }
            }
      }

      //
      // attempt to aquire a frag entry from
      // our free list. if none are available
      // then create one if appropriate
      //

      IPFRAG_ENTRY * entry = NULL;

      if( free.count() > 0 )
      {
            entry = static_cast<IPFRAG_ENTRY*>( free.del_entry( 0 ) );
            entry->packet.size( 0 );
      }
      else
      {
            long count = used.count() + free.count();
            if( count < IPFRAG_MAX_FRAGCOUNT )
                  entry = new IPFRAG_ENTRY();
      }

      if( entry == NULL )
            return false;

      //
      // store the ip packet data in our entry
      //

      entry->expire = current + IPFRAG_MAX_LIFETIME;
      entry->packet.add( fragment );

      //
      // obtain the packet ip header and record
      // the ip identity
      //

      IP_HEADER * ip_header = ( IP_HEADER * ) fragment.buff();
      id = ip_header->ident;

      //
      // add this fragment to our used list
      //

      return used.add_entry( entry );
}

bool _IPFRAG::defrag_chk( unsigned short ident )
{
      //
      // check to see if we have a complete list
      // of ip fragments for a given ip identity
      //

      unsigned short offset = 0;

      while( true )
      {
            //
            // find the next fragment based
            // on the fragmentation offset
            //

            long count = used.count();
            long index = 0;
            bool found = false;

            for( ; index < count; index++ )
            {
                  //
                  // get the next fragment in our list
                  //

                  IPFRAG_ENTRY * entry = static_cast<IPFRAG_ENTRY*>( used.get_entry( index ) );
                  assert( entry != NULL );

                  //
                  // ckeck the ip header identity to
                  // see if it matches our identity
                  //

                  IP_HEADER *       ip_header = ( IP_HEADER * ) entry->packet.buff();
                  unsigned short    ip_hdsize = 4 * ( ip_header->verlen & 0xF );

                  if( ip_header->ident != ident )
                        continue;

                  //
                  // evaluate this fragments offset to
                  // determine if its the next fragment
                  // in our packet
                  //

                  unsigned short flags = ntohs( ip_header->flags );

                  if( offset == ( ( flags & IP_MASK_OFFSET ) << 3 ) )
                  {
                        //
                        // we found at least one fragment
                        // during this sweep of our queue
                        //

                        found = true;

                        //
                        // calculate this fragments data size
                        // to our running total and determine
                        // if this was the last fragment in
                        // our packet
                        //

                        offset += ntohs( ip_header->size ) - ip_hdsize;

                        //
                        // complete packet is available
                        //

                        if( !( flags & IP_FLAG_MORE ) )
                              return true;
                  }
            }

            //
            // make sure we matched at least
            // one packet fragment
            //

            if( !found )
                  break;
      }

      //
      // complete packet is not available
      //

      return false;
}

bool _IPFRAG::defrag_get( unsigned short ident, PACKET_IP & packet )
{
      //
      // make sure we have a clean packet
      //

      packet.del();

      //
      // assemble a complete packet from
      // a list of ip fragments given the
      // ip packet identity
      //

      unsigned short offset = 0;

      while( true )
      {
            //
            // find the next fragment based
            // on the fragmentation offset
            //

            long count = used.count();
            long index = 0;
            bool found = false;

            for( ; index < count; index++ )
            {
                  //
                  // get the next fragment in our list
                  //

                  IPFRAG_ENTRY * entry = static_cast<IPFRAG_ENTRY*>( used.get_entry( index ) );
                  assert( entry != NULL );

                  //
                  // ckeck the ip header identity to
                  // see if it matches our identity
                  //

                  IP_HEADER *       ip_header = ( IP_HEADER * ) entry->packet.buff();
                  unsigned short    ip_hdsize = 4 * ( ip_header->verlen & 0xF );

                  if( ip_header->ident != ident )
                        continue;

                  //
                  // evaluate this fragments offset to
                  // determine if its the next fragment
                  // in our packet
                  //

                  unsigned short flags = ntohs( ip_header->flags );

                  if( offset == ( ( flags & IP_MASK_OFFSET ) << 3 ) )
                  {
                        //
                        // if this is the first fragment,
                        // build a new ip header based on
                        // first fragments ip header info
                        //

                        if( offset == 0 )
                        {
                              in_addr addr_s;
                              in_addr addr_d;

                              addr_s.s_addr = ip_header->ip_src;
                              addr_d.s_addr = ip_header->ip_dst;

                              packet.write(
                                    addr_s,
                                    addr_d,
                                    ip_header->ident,
                                    ip_header->protocol );
                        }

                        //
                        // we found at least one fragment
                        // during this sweep of our queue
                        //

                        found = true;

                        //
                        // correct for our change in list
                        // index and item count
                        //

                        index--;
                        count--;

                        //
                        // calculate this fragments data size
                        // and add it to our complete packet
                        //

                        unsigned short fragsize = ntohs( ip_header->size ) - ip_hdsize;

                        packet.add(
                              entry->packet.buff() + ip_hdsize,
                              fragsize );

                        //
                        // add this fragments data size to our
                        // running offset
                        //
                        
                        offset += ntohs( ip_header->size ) - ip_hdsize;

                        //
                        // remove the fragment from our list
                        // and free its resources
                        //

                        used.del_entry( entry );
                        free.add_entry( entry );

                        //
                        // determine if this was the last
                        // fragment in our full packet
                        //

                        if( !( flags & IP_FLAG_MORE ) )
                        {
                              //
                              // finished building the packet
                              //

                              packet.done();

                              return true;
                        }
                  }
            }

            //
            // make sure we matched at least
            // one packet fragment
            //

            if( !found )
            {
                  //
                  // we shouldn't ever get here but break
                  // if we are missing a packet fragment
                  //

                  break;
            }
      }

      //
      // return error
      //

      return false;
}

Generated by  Doxygen 1.6.0   Back to index