/* * 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. * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. * * 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. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef FRAGMENT_H #define FRAGMENT_H /** * @file * Data Channel Fragmentation module header file. */ #ifdef ENABLE_FRAGMENT /** * @addtogroup fragmentation * @{ */ #include "common.h" #include "buffer.h" #include "interval.h" #include "mtu.h" #include "shaper.h" #include "error.h" #define N_FRAG_BUF 25 /**< Number of packet buffers for * reassembling incoming fragmented * packets. */ #define FRAG_TTL_SEC 10 /**< Time-to-live in seconds for a %fragment. */ #define FRAG_WAKEUP_INTERVAL 5 /**< Interval in seconds between calls to * wakeup code. */ /**************************************************************************/ /** * Structure for reassembling one incoming fragmented packet. */ struct fragment { bool defined; /**< Whether reassembly is currently * taking place in this structure. */ int max_frag_size; /**< Maximum size of each %fragment. */ # 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. */ time_t timestamp; /**< Timestamp for time-to-live purposes. */ struct buffer buf; /**< Buffer in which received datagrams * are reassembled. */ }; /** * List of fragment structures for reassembling multiple incoming packets * concurrently. */ struct fragment_list { int seq_id; /**< Highest fragmentation sequence ID of * the packets currently being * reassembled. */ int index; /**< Index of the packet being reassembled * 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. */ struct fragment fragments[N_FRAG_BUF]; }; /** * 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 { 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 * explicitly recommended an MTU value. */ # 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 * 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. */ # 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 * 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. */ int outgoing_frag_id; /**< The fragment ID of the next part to * be sent. Must have a value between 0 * and \c MAX_FRAGS-1. */ struct buffer outgoing; /**< Buffer containing the remaining parts * of the fragmented packet being sent. */ 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. */ }; /**************************************************************************/ /** @name Fragment header * @todo Add description of %fragment header format. *//** @{ *//*************************************/ typedef uint32_t fragment_header_type; /**< Fragmentation information is stored in * a 32-bit packet header. */ #define hton_fragment_header_type(x) htonl(x) /**< Convert a fragment_header_type from * host to network order. */ #define ntoh_fragment_header_type(x) ntohl(x) /**< Convert a \c fragment_header_type * from network to host order. */ #define FRAG_TYPE_MASK 0x00000003 /**< Bit mask for %fragment type info. */ #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. */ #define FRAG_SEQ_ID_MASK 0x000000ff /**< Bit mask for %fragment sequence ID. */ #define FRAG_SEQ_ID_SHIFT 2 /**< Bit shift for %fragment sequence ID. */ #define FRAG_ID_MASK 0x0000001f /**< Bit mask for %fragment ID. */ #define FRAG_ID_SHIFT 10 /**< Bit shift for %fragment ID. */ /* * FRAG_SIZE 14 bits * * IF FRAG_YES_LAST (FRAG_SIZE): * 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, * max_frag_size is only sent over the wire if FRAG_LAST is set. Otherwise it is assumed * to be the actual %fragment size received. */ #define FRAG_SIZE_MASK 0x00003fff /**< Bit mask for %fragment size. */ #define FRAG_SIZE_SHIFT 15 /**< Bit shift for %fragment size. */ #define FRAG_SIZE_ROUND_SHIFT 2 /**< Bit shift for %fragment size rounding. */ #define FRAG_SIZE_ROUND_MASK ((1 << FRAG_SIZE_ROUND_SHIFT) - 1) /**< Bit mask for %fragment size rounding. */ /* * FRAG_EXTRA 16 bits * * IF FRAG_WHOLE or FRAG_YES_NOTLAST, these 16 bits are available (not currently used) */ #define FRAG_EXTRA_MASK 0x0000ffff /**< Bit mask for extra bits. */ #define FRAG_EXTRA_SHIFT 15 /**< Bit shift for extra bits. */ /** @} name Fragment header *//********************************************/ /**************************************************************************/ /** @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. */ struct fragment_master *fragment_init (struct frame *frame); /** * 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. */ void fragment_frame_init (struct fragment_master *f, const struct frame *frame); /** * Free a \c fragment_master structure and its internal packet buffers. * * @param f - The \c fragment_master structure to free. */ void fragment_free (struct fragment_master *f); /** @} 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. */ void fragment_incoming (struct fragment_master *f, struct buffer *buf, const struct frame* frame); /** @} 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. */ void fragment_outgoing (struct fragment_master *f, struct buffer *buf, const struct frame* frame); /** * 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. */ bool fragment_ready_to_send (struct fragment_master *f, struct buffer *buf, const struct frame* frame); /** * 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. */ static inline bool fragment_outgoing_defined (struct fragment_master *f) { return f->outgoing.len > 0; } /** @} name Functions for processing packets going out through a VPN tunnel */ void fragment_wakeup (struct fragment_master *f, struct frame *frame); /**************************************************************************/ /** @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. */ static inline void fragment_housekeeping (struct fragment_master *f, struct frame *frame, struct timeval *tv) { if (event_timeout_trigger (&f->wakeup, tv, ETT_DEFAULT)) fragment_wakeup (f, frame); } /** @} name Functions for regular housekeeping *//*************************/ /** @} addtogroup fragmentation *//****************************************/ #endif #endif