Index: init.c =================================================================== --- init.c (révision 5523) +++ init.c (copie de travail) @@ -1361,16 +1361,23 @@ } #endif -#ifdef USE_LZO if (found & OPT_P_COMP) { +#ifdef USE_ROHC + if (rohc_defined (&c->c2.rohc_compwork)) + { + msg (D_PUSH, "OPTIONS IMPORT: ROHC parms modified"); + rohc_modify_flags (&c->c2.rohc_compwork, c->options.rohc); + } +#endif +#ifdef USE_LZO if (lzo_defined (&c->c2.lzo_compwork)) { msg (D_PUSH, "OPTIONS IMPORT: LZO parms modified"); lzo_modify_flags (&c->c2.lzo_compwork, c->options.lzo); } +#endif } -#endif if (found & OPT_P_SHAPER) { @@ -2107,6 +2114,11 @@ b->decrypt_buf = alloc_buf (BUF_SIZE (frame)); #endif +#ifdef USE_ROHC + b->rohc_compress_buf = alloc_buf (BUF_SIZE (frame)); + b->rohc_decompress_buf = alloc_buf (BUF_SIZE (frame)); +#endif + #ifdef USE_LZO b->lzo_compress_buf = alloc_buf (BUF_SIZE (frame)); b->lzo_decompress_buf = alloc_buf (BUF_SIZE (frame)); @@ -2129,6 +2141,11 @@ free_buf (&b->lzo_decompress_buf); #endif +#ifdef USE_ROHC + free_buf (&b->rohc_compress_buf); + free_buf (&b->rohc_decompress_buf); +#endif + #ifdef USE_CRYPTO free_buf (&b->encrypt_buf); free_buf (&b->decrypt_buf); @@ -2951,6 +2968,12 @@ goto sig; } +#ifdef USE_ROHC + /* initialize ROHC compression library. */ + if ((options->rohc & ROHC_SELECTED) && (c->mode == CM_P2P || child)) + rohc_compress_init (&c->c2.rohc_compwork, options->rohc); +#endif + #ifdef USE_LZO /* initialize LZO compression library. */ if ((options->lzo & LZO_SELECTED) && (c->mode == CM_P2P || child)) @@ -3073,6 +3096,11 @@ lzo_compress_uninit (&c->c2.lzo_compwork); #endif +#ifdef USE_ROHC + if (rohc_defined (&c->c2.rohc_compwork)) + rohc_compress_uninit (&c->c2.rohc_compwork); +#endif + /* free buffers */ do_close_free_buf (c); Index: configure.ac =================================================================== --- configure.ac (révision 5523) +++ configure.ac (copie de travail) @@ -63,6 +63,12 @@ ;; esac +AC_ARG_ENABLE(rohc, + [ --disable-rohc Disable ROHC compression support], + [ROHC="$enableval"], + [ROHC="yes"] +) + AC_ARG_ENABLE(lzo, [ --disable-lzo Disable LZO compression support], [LZO="$enableval"], @@ -223,6 +229,19 @@ [LDFLAGS="$LDFLAGS -L$withval"] ) +AC_ARG_WITH(rohc-headers, + [ --with-rohc-headers=DIR ROHC Include files location], + [ROHC_HDR_DIR="$withval"] + [CPPFLAGS="$CPPFLAGS -I$withval"], + [CPPFLAGS="$CPPFLAGS $(pkg-config --cflags rohc 2>/dev/null)"] +) + +AC_ARG_WITH(rohc-lib, + [ --with-rohc-lib=DIR ROHC Library location], + [LDFLAGS="$LDFLAGS -L$withval"], + [LDFLAGS="$LDFLAGS $(pkg-config --libs-only-L rohc 2>/dev/null)"] +) + AC_ARG_WITH(lzo-headers, [ --with-lzo-headers=DIR LZO Include files location], [LZO_HDR_DIR="$withval"] @@ -654,6 +673,40 @@ fi dnl +dnl check for ROHC library +dnl + +if test "$ROHC" = "yes"; then + AC_CHECKING([for ROHC header files]) + ROHC_HEADERS=1 + AC_CHECK_HEADER(rohc.h, [], [ROHC_HEADERS=0]) + AC_CHECK_HEADER(rohc_comp.h, [], [ROHC_HEADERS=0]) + AC_CHECK_HEADER(rohc_decomp.h, [], [ROHC_HEADERS=0]) + if test $ROHC_HEADERS != 1 ; then + AC_MSG_RESULT([ROHC headers were not found]) + AC_MSG_RESULT([ROHC library available from https://launchpad.net/rohc]) + AC_MSG_ERROR([Or try ./configure --disable-rohc]) + fi + + AC_CHECKING([for ROHC library]) + ROHC_LIBS=1 + AC_CHECK_LIB(rohc_common, crc_init_table, [], [ROHC_LIBS=0]) + AC_CHECK_LIB(rohc_comp, rohc_alloc_compressor, [], [ROHC_LIBS=0], [-lm]) + AC_CHECK_LIB(rohc_comp, rohc_compress, [], [ROHC_LIBS=0], [-lm]) + AC_CHECK_LIB(rohc_comp, rohc_free_compressor, [], [ROHC_LIBS=0], [-lm]) + AC_CHECK_LIB(rohc_decomp, rohc_alloc_decompressor, [], [ROHC_LIBS=0], [-lm]) + AC_CHECK_LIB(rohc_decomp, rohc_decompress, [], [ROHC_LIBS=0], [-lm]) + AC_CHECK_LIB(rohc_decomp, rohc_free_decompressor, [], [ROHC_LIBS=0], [-lm]) + if test $ROHC_LIBS = 1 ; then + OPENVPN_ADD_LIBS($(pkg-config --libs rohc)) + AC_DEFINE(USE_ROHC, 1, [Use ROHC compression library]) + AC_DEFINE_UNQUOTED(ROHC_VERSION_NUM, "[$(pkg-config rohc --modversion)]", [ROHC version number]) + else + AC_MSG_ERROR([ROHC headers were found but ROHC library was not found]) + fi +fi + +dnl dnl check for LZO library dnl Index: sig.c =================================================================== --- sig.c (révision 5523) +++ sig.c (copie de travail) @@ -264,6 +264,10 @@ status_printf (so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes); status_printf (so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes); status_printf (so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth); +#ifdef USE_ROHC + if (rohc_defined (&c->c2.rohc_compwork)) + rohc_print_stats (&c->c2.rohc_compwork, so); +#endif #ifdef USE_LZO if (lzo_defined (&c->c2.lzo_compwork)) lzo_print_stats (&c->c2.lzo_compwork, so); Index: openvpn.h =================================================================== --- openvpn.h (révision 5523) +++ openvpn.h (copie de travail) @@ -31,6 +31,7 @@ #include "crypto.h" #include "ssl.h" #include "packet_id.h" +#include "rohc.h" #include "lzo.h" #include "tun.h" #include "interval.h" @@ -104,6 +105,12 @@ struct buffer decrypt_buf; #endif + /* workspace buffers for ROHC compression */ +#ifdef USE_ROHC + struct buffer rohc_compress_buf; + struct buffer rohc_decompress_buf; +#endif + /* workspace buffers for LZO compression */ #ifdef USE_LZO struct buffer lzo_compress_buf; @@ -339,6 +346,13 @@ #endif /* USE_CRYPTO */ /* + * ROHC compression library workspace. + */ +#ifdef USE_ROHC + struct rohc_compress_workspace rohc_compwork; +#endif + + /* * LZO compression library workspace. */ #ifdef USE_LZO Index: Makefile.am =================================================================== --- Makefile.am (révision 5523) +++ Makefile.am (copie de travail) @@ -93,6 +93,7 @@ integer.h \ interval.c interval.h \ list.c list.h \ + rohc.c rohc.h \ lzo.c lzo.h \ manage.c manage.h \ mbuf.c mbuf.h \ Index: rohc.c =================================================================== --- rohc.c (révision 0) +++ rohc.c (révision 0) @@ -0,0 +1,276 @@ +/* + * 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-2009 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2011 Didier Barvaux + * + * 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 + */ + +#include "syshead.h" + +#ifdef USE_ROHC + +#ifdef DEBUG_ROHC +# include +#endif + +#include "rohc.h" +#include "error.h" // TODO: needed ? +#include "otime.h" // TODO: needed ? + +#include "memdbg.h" // TODO: needed ? + +void +rohc_compress_init (struct rohc_compress_workspace *rohcwork, + unsigned int flags) +{ + CLEAR (*rohcwork); + + rohcwork->flags = flags; + + /* init the CRC tables for ROHC compression/decompression */ + crc_init_table(crc_table_3, crc_get_polynom(CRC_TYPE_3)); + crc_init_table(crc_table_7, crc_get_polynom(CRC_TYPE_7)); + crc_init_table(crc_table_8, crc_get_polynom(CRC_TYPE_8)); + + /* create the ROHC compressor */ + rohcwork->comp = rohc_alloc_compressor(15, 0, 0, 0); + if(rohcwork->comp == NULL) + { + msg (M_FATAL, "Cannot initialize ROHC compression library"); + return; + } + + /* activate ROHC compression profiles */ + rohc_activate_profile(rohcwork->comp, ROHC_PROFILE_UNCOMPRESSED); + rohc_activate_profile(rohcwork->comp, ROHC_PROFILE_UDP); + rohc_activate_profile(rohcwork->comp, ROHC_PROFILE_IP); + rohc_activate_profile(rohcwork->comp, ROHC_PROFILE_UDPLITE); + rohc_activate_profile(rohcwork->comp, ROHC_PROFILE_RTP); + + /* create the ROHC decompressor in unidrectional mode */ + rohcwork->decomp = rohc_alloc_decompressor(NULL); + if(rohcwork->decomp == NULL) + { + msg (M_FATAL, "Cannot initialize ROHC decompression library"); + rohc_free_compressor(rohcwork->comp); + return; + } + + msg (M_INFO, "ROHC header compression initialized"); + rohcwork->defined = true; +} + +void +rohc_compress_uninit (struct rohc_compress_workspace *rohcwork) +{ + if (rohcwork) + { + ASSERT (rohcwork->defined); + rohc_free_decompressor(rohcwork->decomp); + rohc_free_compressor(rohcwork->comp); + rohcwork->defined = false; + } +} + +static inline bool +rohc_compression_enabled (struct rohc_compress_workspace *rohcwork) +{ + if ((rohcwork->flags & (ROHC_SELECTED|ROHC_ON)) == (ROHC_SELECTED|ROHC_ON)) + { + return true; + } + return false; +} + +void +openvpn_rohc_compress (struct buffer *buf, + struct buffer work, + struct rohc_compress_workspace *rohcwork, + const struct frame* frame) +{ + int max_rohc_size; + int rohc_size; + + ASSERT (rohcwork->defined); + + if (buf->len <= 0) + return; + + ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + + if (buf->len > PAYLOAD_SIZE (frame)) + { + dmsg (D_COMP_ERRORS, "ROHC compression buffer overflow"); + buf->len = 0; + return; + } + + /* max size of the ROHC packet we can generate */ + max_rohc_size = BCAP (&work); + + /* compress the uncompressed IP packet to ROHC packet */ + rohc_size = rohc_compress (rohcwork->comp, + BPTR (buf), BLEN (buf), + BPTR (&work), max_rohc_size); + if(rohc_size <= 0) + { +#define DEBUG_ROHC +#ifdef DEBUG_ROHC + int i; +#endif + dmsg (D_COMP_ERRORS, "ROHC compression error: %d", rohc_size); +#ifdef DEBUG_ROHC + dmsg (D_COMP_ERRORS, "%d-byte network packet: ", BLEN (buf)); + for(i = 0; i < BLEN (buf); i++) + { + dmsg (D_COMP_ERRORS, "%02x", *(BPTR (buf) + i)); + } + assert(0); +#endif + buf->len = 0; + return; + } + ASSERT (buf_safe (&work, rohc_size)); + work.len = rohc_size; + + dmsg (D_COMP, "ROHC header compression %d -> %d", buf->len, work.len); + + /* update stats */ + rohcwork->pre_compress += buf->len; + rohcwork->post_compress += work.len; + + /* replace uncompressed buffer with compressed one */ + *buf = work; +} + +void +openvpn_rohc_decompress (struct buffer *buf, + struct buffer work, + struct rohc_compress_workspace *rohcwork, + const struct frame* frame) +{ + int max_decomp_size; + int decomp_size; + + ASSERT (rohcwork->defined); + + if (buf->len <= 0) + return; + + ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + + /* max size of the decompressed packet we can generate */ + max_decomp_size = EXPANDED_SIZE (frame); + ASSERT (buf_safe (&work, max_decomp_size)); + + /* decompress the ROHC packet to IP packet */ + decomp_size = rohc_decompress(rohcwork->decomp, + BPTR (buf), BLEN (buf), + BPTR (&work), max_decomp_size); + if(decomp_size <= 0) + { + if(decomp_size == ROHC_ERROR_NO_CONTEXT) + { + dmsg (D_COMP_ERRORS, "ROHC decompression failed because no " + "decompression context was found for the ROHC packet\n"); + } + else + { +#ifdef DEBUG_ROHC + int i; +#endif + dmsg (D_COMP_ERRORS, "ROHC decompression error: %d", decomp_size); +#ifdef DEBUG_ROHC + dmsg (D_COMP_ERRORS, "%d-byte ROHC packet: ", BLEN (buf)); + for(i = 0; i < BLEN (buf); i++) + { + dmsg (D_COMP_ERRORS, "%02x", *(BPTR (buf) + i)); + } + assert(0); + } +#endif + buf->len = 0; + return; + } + ASSERT (buf_safe (&work, decomp_size)); + work.len = decomp_size; + + dmsg (D_COMP, "ROHC header decompression %d -> %d", buf->len, work.len); + + /* update stats */ + rohcwork->pre_decompress += buf->len; + rohcwork->post_decompress += work.len; + + /* replace compressed buffer with decompressed one */ + *buf = work; +} + +void +rohc_modify_flags (struct rohc_compress_workspace *rohcwork, + unsigned int flags) +{ + ASSERT (rohcwork->defined); + rohcwork->flags = flags; +} + +/* + * Print statistics + */ +void +rohc_print_stats (const struct rohc_compress_workspace *rohc_compwork, + struct status_output *so) +{ + ASSERT (rohc_compwork->defined); + + status_printf (so, "pre-rohc-compress bytes," counter_format, + rohc_compwork->pre_compress); + status_printf (so, "post-rohc-compress bytes," counter_format, + rohc_compwork->post_compress); + if (rohc_compwork->pre_compress != 0) + { + status_printf (so, "rohc-compress ratio," counter_format, + rohc_compwork->post_compress * 100 / + rohc_compwork->pre_compress); + } + else + { + status_printf (so, "rohc-compress ratio,0"); + } + + status_printf (so, "pre-rohc-decompress bytes," counter_format, + rohc_compwork->pre_decompress); + status_printf (so, "post-rohc-decompress bytes," counter_format, + rohc_compwork->post_decompress); + if (rohc_compwork->pre_decompress != 0) + { + status_printf (so, "rohc-decompress ratio," counter_format, + rohc_compwork->post_decompress * 100 / + rohc_compwork->pre_decompress); + } + else + { + status_printf (so, "rohc-decompress ratio,0"); + } +} + +#else +static void dummy(void) {} +#endif /* USE_ROHC */ Index: options.c =================================================================== --- options.c (révision 5523) +++ options.c (copie de travail) @@ -58,6 +58,9 @@ " [CRYPTO]" #endif #endif +#ifdef USE_ROHC + " [ROHC" ROHC_VERSION_NUM "]" +#endif #ifdef USE_LZO " [LZO" LZO_VERSION_NUM "]" #endif @@ -312,6 +315,9 @@ #ifdef ENABLE_DEBUG "--gremlin mask : Special stress testing mode (for debugging only).\n" #endif +#ifdef USE_ROHC + "--comp-rohc : Use ROHC robust and efficient header compression.\n" +#endif #ifdef USE_LZO "--comp-lzo : Use fast LZO compression -- may add up to 1 byte per\n" " packet for uncompressible data.\n" @@ -1257,6 +1263,10 @@ SHOW_BOOL (fast_io); +#ifdef USE_ROHC + SHOW_INT (rohc); +#endif + #ifdef USE_LZO SHOW_INT (lzo); #endif @@ -2299,6 +2309,11 @@ tt = NULL; } +#ifdef USE_ROHC + if (o->rohc & ROHC_SELECTED) + buf_printf (&out, ",comp-rohc"); +#endif + #ifdef USE_LZO if (o->lzo & LZO_SELECTED) buf_printf (&out, ",comp-lzo"); @@ -5187,6 +5202,26 @@ options->passtos = true; } #endif +#ifdef USE_ROHC + else if (streq (p[0], "comp-rohc")) + { + VERIFY_PERMISSION (OPT_P_COMP); + if (p[1]) + { + if (streq (p[1], "yes")) + options->rohc = ROHC_SELECTED|LZO_ON; + else if (streq (p[1], "no")) + options->rohc = ROHC_SELECTED; + else + { + msg (msglevel, "bad comp-rohc option: %s -- must be 'yes' or 'no'", p[1]); + goto err; + } + } + else + options->rohc = ROHC_SELECTED|ROHC_ON; + } +#endif /* USE_ROHC */ #ifdef USE_LZO else if (streq (p[0], "comp-lzo")) { Index: options.h =================================================================== --- options.h (révision 5523) +++ options.h (copie de travail) @@ -276,6 +276,11 @@ /* optimize TUN/TAP/UDP writes */ bool fast_io; +#ifdef USE_ROHC + /* ROHC_x flags from rohc.h */ + unsigned int rohc; +#endif + #ifdef USE_LZO /* LZO_x flags from lzo.h */ unsigned int lzo; Index: rohc.h =================================================================== --- rohc.h (révision 0) +++ rohc.h (révision 0) @@ -0,0 +1,90 @@ +/* + * 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-2009 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2011 Didier Barvaux + * + * 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 OPENVPN_ROHC_H +#define OPENVPN_ROHC_H + +#ifdef USE_ROHC + +#include +#include +#include + +#include "buffer.h" +#include "mtu.h" // TODO: needed ? +#include "common.h" +#include "status.h" // TODO: needed ? + +/* ROHC flags */ +#define ROHC_SELECTED (1<<0) +#define ROHC_ON (1<<1) + +/* + * Compress and Uncompress routines. + */ + +struct rohc_compress_workspace +{ + struct rohc_comp *comp; + struct rohc_decomp *decomp; + unsigned int flags; + bool defined; + + /* statistics */ + counter_type pre_decompress; + counter_type post_decompress; + counter_type pre_compress; + counter_type post_compress; +}; + +void rohc_compress_init (struct rohc_compress_workspace *rohcwork, + unsigned int flags); + +void rohc_compress_uninit (struct rohc_compress_workspace *rohcwork); + +void rohc_modify_flags (struct rohc_compress_workspace *rohcwork, + unsigned int flags); + +void openvpn_rohc_compress (struct buffer *buf, + struct buffer work, + struct rohc_compress_workspace *lzowork, + const struct frame* frame); + +void openvpn_rohc_decompress (struct buffer *buf, + struct buffer work, + struct rohc_compress_workspace *rohcwork, + const struct frame* frame); + +void rohc_print_stats (const struct rohc_compress_workspace *rohc_compwork, + struct status_output *so); + +static inline bool +rohc_defined (const struct rohc_compress_workspace *rohcwork) +{ + return rohcwork->defined; +} + +#endif /* USE_ROHC */ +#endif Index: forward.c =================================================================== --- forward.c (révision 5523) +++ forward.c (copie de travail) @@ -435,6 +435,12 @@ if (comp_frag) { +#ifdef USE_ROHC + /* Compress the IP, UDP, UDP-Lite, RTP headers of the packet. */ + if (rohc_defined (&c->c2.rohc_compwork)) + openvpn_rohc_compress (&c->c2.buf, b->rohc_compress_buf, + &c->c2.rohc_compwork, &c->c2.frame); +#endif #ifdef USE_LZO /* Compress the packet. */ if (lzo_defined (&c->c2.lzo_compwork)) @@ -842,6 +848,13 @@ lzo_decompress (&c->c2.buf, c->c2.buffers->lzo_decompress_buf, &c->c2.lzo_compwork, &c->c2.frame); #endif +#ifdef USE_ROHC + /* decompress the IP, UDP, UDP-Lite, RTP headers of the packet. */ + if (rohc_defined (&c->c2.rohc_compwork)) + openvpn_rohc_decompress (&c->c2.buf, c->c2.buffers->rohc_decompress_buf, + &c->c2.rohc_compwork, &c->c2.frame); +#endif + #ifdef PACKET_TRUNCATION_CHECK /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ ipv4_packet_size_verify (BPTR (&c->c2.buf),