src/openvpn/fragment.h
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  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.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
 #ifndef FRAGMENT_H
 #define FRAGMENT_H
 
15bd346c
 /**
  * @file
  * Data Channel Fragmentation module header file.
  */
 
 
6fbf66fa
 #ifdef ENABLE_FRAGMENT
 
15bd346c
 /**
  * @addtogroup fragmentation
  * @{
  */
 
 
6fbf66fa
 #include "common.h"
 #include "buffer.h"
 #include "interval.h"
 #include "mtu.h"
 #include "shaper.h"
 #include "error.h"
 
 
15bd346c
 #define N_FRAG_BUF                   25
81d882d5
 /**< Number of packet buffers for
  *   reassembling incoming fragmented
  *   packets. */
15bd346c
 
 #define FRAG_TTL_SEC                 10
81d882d5
 /**< Time-to-live in seconds for a %fragment. */
15bd346c
 
 #define FRAG_WAKEUP_INTERVAL         5
81d882d5
 /**< Interval in seconds between calls to
  *   wakeup code. */
15bd346c
 
 /**************************************************************************/
 /**
  * Structure for reassembling one incoming fragmented packet.
  */
6fbf66fa
 struct fragment {
81d882d5
     bool defined;               /**< Whether reassembly is currently
15bd346c
                                  *   taking place in this structure. */
6fbf66fa
 
81d882d5
     int max_frag_size;          /**< Maximum size of each %fragment. */
6fbf66fa
 
81d882d5
 #define FRAG_MAP_MASK 0xFFFFFFFF
     /**< Mask for reassembly map. */
 #define MAX_FRAGS 32            /**< Maximum number of fragments per packet. */
     unsigned int map;
     /**< Reassembly map for recording which
      *   fragments have been received.
      *
      *   A bit array where each bit
      *   corresponds to a %fragment.  A 1 bit
      *   in element n means that the %fragment
      *   n has been received.  Needs to have
      *   at least \c MAX_FRAGS bits. */
15bd346c
 
81d882d5
     time_t timestamp;           /**< Timestamp for time-to-live purposes. */
15bd346c
 
81d882d5
     struct buffer buf;          /**< Buffer in which received datagrams
15bd346c
                                  *   are reassembled. */
6fbf66fa
 };
 
15bd346c
 
 /**
  * List of fragment structures for reassembling multiple incoming packets
  * concurrently.
  */
6fbf66fa
 struct fragment_list {
81d882d5
     int seq_id;                 /**< Highest fragmentation sequence ID of
15bd346c
                                  *   the packets currently being
                                  *   reassembled. */
81d882d5
     int index;                  /**< Index of the packet being reassembled
15bd346c
                                  *   with the highest fragmentation
                                  *   sequence ID into the \c
                                  *   fragment_list.fragments array. */
 
 /** Array of reassembly structures, each can contain one whole packet.
  *
  *  The fragmentation sequence IDs of the packets being reassembled in
  *  this array are linearly increasing. \c
  *  fragment_list.fragments[fragment_list.index] has an ID of \c
  *  fragment_list.seq_id.  This means that one of these \c fragment_list
  *  structures can at any one time contain at most packets with the
  *  fragmentation sequence IDs in the range \c fragment_list.seq_id \c -
  *  \c N_FRAG_BUF \c + \c 1 to \c fragment_list.seq_id, inclusive.
  */
81d882d5
     struct fragment fragments[N_FRAG_BUF];
6fbf66fa
 };
 
 
15bd346c
 /**
  * Fragmentation and reassembly state for one VPN tunnel instance.
  *
  * This structure contains all the state necessary for sending and
  * receiving fragmented data channel packets associated with one VPN
  * tunnel.
  *
  * The fragmented packet currently being sent to a remote OpenVPN peer is
  * stored in \c fragment_master.outgoing.  It is copied into that buffer
  * by the \c fragment_outgoing() function and the remaining parts to be
  * sent can be retrieved by successive calls to \c
  * fragment_ready_to_send().
  *
  * The received packets currently being reassembled are stored in the \c
  * fragment_master.incoming array of \c fragment structures.  The \c
  * fragment_incoming() function adds newly received parts into this array
  * and returns the whole packets once reassembly is complete.
  */
 struct fragment_master {
81d882d5
     struct event_timeout wakeup; /**< Timeout structure used by the main
                                   *   event loop to know when to do
                                   *   fragmentation housekeeping. */
     bool received_os_mtu_hint;  /**< Whether the operating system has
15bd346c
                                  *   explicitly recommended an MTU value. */
81d882d5
 #define N_SEQ_ID            256
     /**< One more than the maximum fragment
      *   sequence ID, above which the IDs wrap
      *   to zero.  Should be a power of 2. */
     int outgoing_seq_id;        /**< Fragment sequence ID of the current
15bd346c
                                  *   fragmented packet waiting to be sent.
                                  *
                                  *   All parts of a fragmented packet
                                  *   share the same sequence ID, so that
                                  *   the remote OpenVPN peer can determine
                                  *   which parts belong to which original
                                  *   packet. */
81d882d5
 #define MAX_FRAG_PKT_SIZE 65536
     /**< (Not used) Maximum packet size before
      *   fragmenting. */
     int outgoing_frag_size;     /**< Size in bytes of each part to be
15bd346c
                                  *   sent, except for the last part which
                                  *   may be smaller.
                                  *
                                  *   This value is computed by the \c
                                  *   optimal_fragment_size() function. Its
                                  *   value is sent to the remote peer in
                                  *   the fragmentation header of the last
                                  *   part (i.e. with %fragment type \c
                                  *   FRAG_YES_LAST) using the \c
                                  *   FRAG_SIZE_MASK and \c FRAG_SIZE_SHIFT
                                  *   bits. */
81d882d5
     int outgoing_frag_id;       /**< The fragment ID of the next part to
15bd346c
                                  *   be sent.  Must have a value between 0
                                  *   and \c MAX_FRAGS-1. */
81d882d5
     struct buffer outgoing;     /**< Buffer containing the remaining parts
15bd346c
                                  *   of the fragmented packet being sent. */
81d882d5
     struct buffer outgoing_return;
     /**< Buffer used by \c
      *   fragment_ready_to_send() to return a
      *   part to send. */
 
     struct fragment_list incoming;
     /**< List of structures for reassembling
      *   incoming packets. */
6fbf66fa
 };
 
15bd346c
 
 /**************************************************************************/
 /** @name Fragment header
  *  @todo Add description of %fragment header format.
  *//** @{ *//*************************************/
6fbf66fa
 
 typedef uint32_t fragment_header_type;
81d882d5
 /**< Fragmentation information is stored in
  *   a 32-bit packet header. */
6fbf66fa
 
 #define hton_fragment_header_type(x) htonl(x)
81d882d5
 /**< Convert a fragment_header_type from
  *   host to network order. */
6fbf66fa
 
 #define ntoh_fragment_header_type(x) ntohl(x)
81d882d5
 /**< Convert a \c fragment_header_type
  *   from network to host order. */
6fbf66fa
 
 #define FRAG_TYPE_MASK        0x00000003
81d882d5
 /**< Bit mask for %fragment type info. */
15bd346c
 #define FRAG_TYPE_SHIFT       0 /**< Bit shift for %fragment type info. */
 
 #define FRAG_WHOLE            0 /**< Fragment type indicating packet is
                                  *   whole. */
 #define FRAG_YES_NOTLAST      1 /**< Fragment type indicating packet is
                                  *   part of a fragmented packet, but not
                                  *   the last part in the sequence. */
 #define FRAG_YES_LAST         2 /**< Fragment type indicating packet is
                                  *   the last part in the sequence of
                                  *   parts. */
 #define FRAG_TEST             3 /**< Fragment type not implemented yet.
                                  *   In the future might be used as a
                                  *   control packet for establishing MTU
                                  *   size. */
6fbf66fa
 
 #define FRAG_SEQ_ID_MASK      0x000000ff
81d882d5
 /**< Bit mask for %fragment sequence ID. */
15bd346c
 #define FRAG_SEQ_ID_SHIFT     2 /**< Bit shift for %fragment sequence ID. */
6fbf66fa
 
 #define FRAG_ID_MASK          0x0000001f
81d882d5
 /**< Bit mask for %fragment ID. */
6fbf66fa
 #define FRAG_ID_SHIFT         10
81d882d5
 /**< Bit shift for %fragment ID. */
6fbf66fa
 
 /*
  * FRAG_SIZE  14 bits
  *
  * IF FRAG_YES_LAST (FRAG_SIZE):
15bd346c
  *   The max size of a %fragment.  If a %fragment is not the last %fragment in the packet,
  *   then the %fragment size is guaranteed to be equal to the max %fragment size.  Therefore,
6fbf66fa
  *   max_frag_size is only sent over the wire if FRAG_LAST is set.  Otherwise it is assumed
15bd346c
  *   to be the actual %fragment size received.
6fbf66fa
  */
 #define FRAG_SIZE_MASK        0x00003fff
81d882d5
 /**< Bit mask for %fragment size. */
6fbf66fa
 #define FRAG_SIZE_SHIFT       15
81d882d5
 /**< Bit shift for %fragment size. */
15bd346c
 #define FRAG_SIZE_ROUND_SHIFT 2 /**< Bit shift for %fragment size rounding. */
6fbf66fa
 #define FRAG_SIZE_ROUND_MASK ((1 << FRAG_SIZE_ROUND_SHIFT) - 1)
81d882d5
 /**< Bit mask for %fragment size rounding. */
6fbf66fa
 
 /*
  * FRAG_EXTRA 16 bits
  *
  * IF FRAG_WHOLE or FRAG_YES_NOTLAST, these 16 bits are available (not currently used)
  */
 #define FRAG_EXTRA_MASK         0x0000ffff
81d882d5
 /**< Bit mask for extra bits. */
6fbf66fa
 #define FRAG_EXTRA_SHIFT        15
81d882d5
 /**< Bit shift for extra bits. */
6fbf66fa
 
15bd346c
 /** @} name Fragment header *//********************************************/
6fbf66fa
 
15bd346c
 
 /**************************************************************************/
 /** @name Functions for initialization and cleanup *//** @{ *//************/
 
 /**
  * Allocate and initialize a \c fragment_master structure.
  *
  * This function also modifies the \a frame packet geometry parameters to
  * include space for the fragmentation header.
  *
  * @param frame        - The packet geometry parameters for this VPN
  *                       tunnel, modified by this function to include the
  *                       fragmentation header.
  *
  * @return A pointer to the new \c fragment_master structure.
  */
81d882d5
 struct fragment_master *fragment_init(struct frame *frame);
6fbf66fa
 
15bd346c
 
 /**
  * Allocate internal packet buffers for a \c fragment_master structure.
  *
  * @param f            - The \c fragment_master structure for which to
  *                       allocate the internal buffers.
  * @param frame        - The packet geometry parameters for this VPN
  *                       tunnel, used to determine how much memory to
  *                       allocate for each packet buffer.
  */
81d882d5
 void fragment_frame_init(struct fragment_master *f, const struct frame *frame);
6fbf66fa
 
15bd346c
 
 /**
  * Free a \c fragment_master structure and its internal packet buffers.
  *
  * @param f            - The \c fragment_master structure to free.
  */
81d882d5
 void fragment_free(struct fragment_master *f);
6fbf66fa
 
15bd346c
 /** @} name Functions for initialization and cleanup *//*******************/
 
 
 /**************************************************************************/
 /** @name Functions for processing packets received from a remote OpenVPN peer */
 /** @{ */
 
 /**
  * Process an incoming packet, which may or may not be fragmented.
  *
  * This function inspects the fragmentation header of the incoming packet
  * and processes the packet accordingly. Depending on the %fragment type
  * bits (\c FRAG_TYPE_MASK and \c FRAG_TYPE_SHIFT) the packet is processed
  * in the following ways:
  *  - \c FRAG_WHOLE: the packet is not fragmented, and this function does
  *    not modify its contents, except for removing the fragmentation
  *    header.
  *  - \c FRAG_YES_NOTLAST or \c FRAG_YES_LAST: the packet is part of a
  *    fragmented packet.  This function copies the packet into an internal
  *    reassembly buffer.  If the incoming part completes the packet being
  *    reassembled, the \a buf argument is modified to point to the fully
  *    reassembled packet.  If, on the other hand, reassembly is not yet
  *    complete, then the the \a buf buffer is set to empty.
  *  - Any other value: error.
  *
  * If an error occurs during processing, an error message is logged and
  * the length of \a buf is set to zero.
  *
  * @param f            - The \c fragment_master structure for this VPN
  *                       tunnel.
  * @param buf          - A pointer to the buffer structure containing the
  *                       incoming packet.  This pointer will have been
  *                       modified on return either to point to a
  *                       completely reassembled packet, or to have length
  *                       set to zero if reassembly is not yet complete.
  * @param frame        - The packet geometry parameters for this VPN
  *                       tunnel.
  *
  * @return Void.\n On return, the \a buf argument will point to a buffer.
  *     The buffer will have nonzero length if the incoming packet passed
  *     to this function was whole and unfragmented, or if it was the final
  *     part of a fragmented packet thereby completing reassembly.  On the
  *     other hand, the buffer will have a length of zero if the incoming
  *     packet was part of a fragmented packet and reassembly is not yet
  *     complete.  If an error occurs during processing, the buffer length
  *     is also set to zero.
  */
81d882d5
 void fragment_incoming(struct fragment_master *f, struct buffer *buf,
                        const struct frame *frame);
6fbf66fa
 
15bd346c
 /** @} name Functions for processing packets received from a VPN tunnel */
 
 
 /**************************************************************************/
 /** @name Functions for processing packets to be sent to a remote OpenVPN peer */
 /** @{ */
 
 /**
  * Process an outgoing packet, which may or may not need to be fragmented.
  *
  * This function inspects the outgoing packet, determines whether it needs
  * to be fragmented, and processes it accordingly.
  *
  * Depending on the size of the outgoing packet and the packet geometry
  * parameters for the VPN tunnel, the packet will or will not be
  * fragmented.
  * @li Packet size is less than or equal to the maximum packet size for
  *     this VPN tunnel: fragmentation is not necessary.  The \a buf
  *     argument points to a buffer containing the unmodified outgoing
  *     packet with a fragmentation header indicating the packet is whole
  *     (FRAG_WHOLE) prepended.
  * @li Packet size is greater than the maximum packet size for this VPN
  *     tunnel: fragmentation is necessary.  The original outgoing packet
  *     is copied into an internal buffer for fragmentation.  The \a buf
  *     argument is modified to point to the first part of the fragmented
  *     packet. The remaining parts remain stored in the internal buffer,
  *     and can be retrieved using the \c fragment_ready_to_send()
  *     function.
  *
  * If an error occurs during processing, an error message is logged and
  * the length of \a buf is set to zero.
  *
  * @param f            - The \c fragment_master structure for this VPN
  *                       tunnel.
  * @param buf          - A pointer to the buffer structure containing the
  *                       outgoing packet.  This pointer will be modified
  *                       to point to a whole unfragmented packet or to the
  *                       first part of a fragmented packet on return.
  * @param frame        - The packet geometry parameters for this VPN
  *                       tunnel.
  *
  * @return Void.\n On return, the \a buf argument will point to a buffer.
  *     This buffer contains either the whole original outgoing packet if
  *     fragmentation was not necessary, or the first part of the
  *     fragmented outgoing packet if fragmentation was necessary. In both
  *     cases a fragmentation header will have been prepended to inform the
  *     remote peer how to handle the packet.
  */
81d882d5
 void fragment_outgoing(struct fragment_master *f, struct buffer *buf,
                        const struct frame *frame);
6fbf66fa
 
15bd346c
 /**
  * Check whether outgoing fragments are ready to be send, and if so make
  * one available.
  *
  * This function checks whether the internal buffer for fragmenting
  * outgoing packets contains any unsent parts.  If it does not, meaning
  * there is nothing waiting to be sent, it returns false.  Otherwise there
  * are parts ready to be sent, and it returns true.  In that case it also
  * modifies the \a buf argument to point to a buffer containing the next
  * part to be sent.
  *
  * @param f            - The \a fragment_master structure for this VPN
  *                       tunnel.
  * @param buf          - A pointer to a buffer structure which on return,
  *                       if there are parts waiting to be sent, will point
  *                       to the next part to be sent.
  * @param frame        - The packet geometry parameters for this VPN
  *                       tunnel.
  *
  * @return
  * @li True, if an outgoing packet has been fragmented and not all parts
  *     have been sent yet.  In this case this function will modify the \a
  *     buf argument to point to a buffer containing the next part to be
  *     sent.
  * @li False, if there are no outgoing fragmented parts waiting to be
  *     sent.
  */
81d882d5
 bool fragment_ready_to_send(struct fragment_master *f, struct buffer *buf,
                             const struct frame *frame);
6fbf66fa
 
15bd346c
 /**
  * Check whether a \c fragment_master structure contains fragments ready
  * to be sent.
  *
  * @param f            - The \c fragment_master structure for this VPN
  *                       tunnel.
  *
  * @return
  * @li True, if there are one or more fragments ready to be sent.
  * @li False, otherwise.
6fbf66fa
  */
15bd346c
 static inline bool
81d882d5
 fragment_outgoing_defined(struct fragment_master *f)
15bd346c
 {
81d882d5
     return f->outgoing.len > 0;
15bd346c
 }
 
 /** @} name Functions for processing packets going out through a VPN tunnel */
 
 
81d882d5
 void fragment_wakeup(struct fragment_master *f, struct frame *frame);
6fbf66fa
 
 
15bd346c
 /**************************************************************************/
 /** @name Functions for regular housekeeping *//** @{ *//******************/
 
 /**
  * Perform housekeeping of a \c fragment_master structure.
  *
  * Housekeeping includes scanning incoming packet reassembly buffers for
  * packets which have not yet been reassembled completely but are already
  * older than their time-to-live.
  *
  * @param f            - The \c fragment_master structure for this VPN
  *                       tunnel.
  * @param frame        - The packet geometry parameters for this VPN
  *                       tunnel.
  */
6fbf66fa
 static inline void
81d882d5
 fragment_housekeeping(struct fragment_master *f, struct frame *frame, struct timeval *tv)
6fbf66fa
 {
81d882d5
     if (event_timeout_trigger(&f->wakeup, tv, ETT_DEFAULT))
     {
         fragment_wakeup(f, frame);
     }
6fbf66fa
 }
 
15bd346c
 /** @} name Functions for regular housekeeping *//*************************/
 
 
 /** @} addtogroup fragmentation *//****************************************/
 
6fbf66fa
 
81d882d5
 #endif /* ifdef ENABLE_FRAGMENT */
 #endif /* ifndef FRAGMENT_H */