mirror of
https://github.com/OpenVPN/openvpn.git
synced 2025-05-09 05:31:05 +08:00

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@5599 e7ae566f-a301-0410-adde-c780ea21d3b5
394 lines
11 KiB
C
394 lines
11 KiB
C
/*
|
|
* OpenVPN -- An application to securely tunnel IP networks
|
|
* over a single TCP/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. <sales@openvpn.net>
|
|
*
|
|
* 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 ENABLE_OCC
|
|
|
|
#include "occ.h"
|
|
|
|
#include "memdbg.h"
|
|
|
|
#include "forward-inline.h"
|
|
#include "occ-inline.h"
|
|
|
|
/*
|
|
* This random string identifies an OpenVPN
|
|
* Configuration Control packet.
|
|
* It should be of sufficient length and randomness
|
|
* so as not to collide with other tunnel data.
|
|
*
|
|
* The OCC protocol is as follows:
|
|
*
|
|
* occ_magic -- (16 octets)
|
|
*
|
|
* type [OCC_REQUEST | OCC_REPLY] (1 octet)
|
|
* null terminated options string if OCC_REPLY (variable)
|
|
*
|
|
* When encryption is used, the OCC packet
|
|
* is encapsulated within the encrypted
|
|
* envelope.
|
|
*
|
|
* OCC_STRING_SIZE must be set to sizeof (occ_magic)
|
|
*/
|
|
|
|
const uint8_t occ_magic[] = {
|
|
0x28, 0x7f, 0x34, 0x6b, 0xd4, 0xef, 0x7a, 0x81,
|
|
0x2d, 0x56, 0xb8, 0xd3, 0xaf, 0xc5, 0x45, 0x9c
|
|
};
|
|
|
|
static const struct mtu_load_test mtu_load_test_sequence[] = {
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -1000},
|
|
{OCC_MTU_LOAD, -1000},
|
|
{OCC_MTU_LOAD_REQUEST, -1000},
|
|
{OCC_MTU_LOAD, -1000},
|
|
{OCC_MTU_LOAD_REQUEST, -1000},
|
|
{OCC_MTU_LOAD, -1000},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -750},
|
|
{OCC_MTU_LOAD, -750},
|
|
{OCC_MTU_LOAD_REQUEST, -750},
|
|
{OCC_MTU_LOAD, -750},
|
|
{OCC_MTU_LOAD_REQUEST, -750},
|
|
{OCC_MTU_LOAD, -750},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -500},
|
|
{OCC_MTU_LOAD, -500},
|
|
{OCC_MTU_LOAD_REQUEST, -500},
|
|
{OCC_MTU_LOAD, -500},
|
|
{OCC_MTU_LOAD_REQUEST, -500},
|
|
{OCC_MTU_LOAD, -500},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -400},
|
|
{OCC_MTU_LOAD, -400},
|
|
{OCC_MTU_LOAD_REQUEST, -400},
|
|
{OCC_MTU_LOAD, -400},
|
|
{OCC_MTU_LOAD_REQUEST, -400},
|
|
{OCC_MTU_LOAD, -400},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -300},
|
|
{OCC_MTU_LOAD, -300},
|
|
{OCC_MTU_LOAD_REQUEST, -300},
|
|
{OCC_MTU_LOAD, -300},
|
|
{OCC_MTU_LOAD_REQUEST, -300},
|
|
{OCC_MTU_LOAD, -300},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -200},
|
|
{OCC_MTU_LOAD, -200},
|
|
{OCC_MTU_LOAD_REQUEST, -200},
|
|
{OCC_MTU_LOAD, -200},
|
|
{OCC_MTU_LOAD_REQUEST, -200},
|
|
{OCC_MTU_LOAD, -200},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -150},
|
|
{OCC_MTU_LOAD, -150},
|
|
{OCC_MTU_LOAD_REQUEST, -150},
|
|
{OCC_MTU_LOAD, -150},
|
|
{OCC_MTU_LOAD_REQUEST, -150},
|
|
{OCC_MTU_LOAD, -150},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -100},
|
|
{OCC_MTU_LOAD, -100},
|
|
{OCC_MTU_LOAD_REQUEST, -100},
|
|
{OCC_MTU_LOAD, -100},
|
|
{OCC_MTU_LOAD_REQUEST, -100},
|
|
{OCC_MTU_LOAD, -100},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, -50},
|
|
{OCC_MTU_LOAD, -50},
|
|
{OCC_MTU_LOAD_REQUEST, -50},
|
|
{OCC_MTU_LOAD, -50},
|
|
{OCC_MTU_LOAD_REQUEST, -50},
|
|
{OCC_MTU_LOAD, -50},
|
|
|
|
{OCC_MTU_LOAD_REQUEST, 0},
|
|
{OCC_MTU_LOAD, 0},
|
|
{OCC_MTU_LOAD_REQUEST, 0},
|
|
{OCC_MTU_LOAD, 0},
|
|
{OCC_MTU_LOAD_REQUEST, 0},
|
|
{OCC_MTU_LOAD, 0},
|
|
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
{OCC_MTU_REQUEST, 0},
|
|
|
|
{-1, 0}
|
|
};
|
|
|
|
void
|
|
check_send_occ_req_dowork (struct context *c)
|
|
{
|
|
if (++c->c2.occ_n_tries >= OCC_N_TRIES)
|
|
{
|
|
if (c->options.ce.remote)
|
|
/*
|
|
* No OCC_REPLY from peer after repeated attempts.
|
|
* Give up.
|
|
*/
|
|
msg (D_SHOW_OCC,
|
|
"NOTE: failed to obtain options consistency info from peer -- "
|
|
"this could occur if the remote peer is running a version of "
|
|
PACKAGE_NAME
|
|
" before 1.5-beta8 or if there is a network connectivity problem, and will not necessarily prevent "
|
|
PACKAGE_NAME
|
|
" from running (" counter_format " bytes received from peer, " counter_format
|
|
" bytes authenticated data channel traffic) -- you can disable the options consistency "
|
|
"check with --disable-occ.",
|
|
c->c2.link_read_bytes,
|
|
c->c2.link_read_bytes_auth);
|
|
event_timeout_clear (&c->c2.occ_interval);
|
|
}
|
|
else
|
|
{
|
|
c->c2.occ_op = OCC_REQUEST;
|
|
|
|
/*
|
|
* If we don't hear back from peer, send another
|
|
* OCC_REQUEST in OCC_INTERVAL_SECONDS.
|
|
*/
|
|
event_timeout_reset (&c->c2.occ_interval);
|
|
}
|
|
}
|
|
|
|
void
|
|
check_send_occ_load_test_dowork (struct context *c)
|
|
{
|
|
if (CONNECTION_ESTABLISHED (c))
|
|
{
|
|
const struct mtu_load_test *entry;
|
|
|
|
if (!c->c2.occ_mtu_load_n_tries)
|
|
msg (M_INFO,
|
|
"NOTE: Beginning empirical MTU test -- results should be available in 3 to 4 minutes.");
|
|
|
|
entry = &mtu_load_test_sequence[c->c2.occ_mtu_load_n_tries++];
|
|
if (entry->op >= 0)
|
|
{
|
|
c->c2.occ_op = entry->op;
|
|
c->c2.occ_mtu_load_size =
|
|
EXPANDED_SIZE (&c->c2.frame) + entry->delta;
|
|
}
|
|
else
|
|
{
|
|
msg (M_INFO,
|
|
"NOTE: failed to empirically measure MTU (requires " PACKAGE_NAME " 1.5 or higher at other end of connection).");
|
|
event_timeout_clear (&c->c2.occ_mtu_load_test_interval);
|
|
c->c2.occ_mtu_load_n_tries = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
check_send_occ_msg_dowork (struct context *c)
|
|
{
|
|
bool doit = false;
|
|
|
|
c->c2.buf = c->c2.buffers->aux_buf;
|
|
ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
|
|
ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
|
|
ASSERT (buf_write (&c->c2.buf, occ_magic, OCC_STRING_SIZE));
|
|
|
|
switch (c->c2.occ_op)
|
|
{
|
|
case OCC_REQUEST:
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_REQUEST))
|
|
break;
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_REQUEST");
|
|
doit = true;
|
|
break;
|
|
|
|
case OCC_REPLY:
|
|
if (!c->c2.options_string_local)
|
|
break;
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_REPLY))
|
|
break;
|
|
if (!buf_write (&c->c2.buf, c->c2.options_string_local,
|
|
strlen (c->c2.options_string_local) + 1))
|
|
break;
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_REPLY");
|
|
doit = true;
|
|
break;
|
|
|
|
case OCC_MTU_REQUEST:
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REQUEST))
|
|
break;
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST");
|
|
doit = true;
|
|
break;
|
|
|
|
case OCC_MTU_REPLY:
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REPLY))
|
|
break;
|
|
if (!buf_write_u16 (&c->c2.buf, c->c2.max_recv_size_local))
|
|
break;
|
|
if (!buf_write_u16 (&c->c2.buf, c->c2.max_send_size_local))
|
|
break;
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REPLY");
|
|
doit = true;
|
|
break;
|
|
|
|
case OCC_MTU_LOAD_REQUEST:
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD_REQUEST))
|
|
break;
|
|
if (!buf_write_u16 (&c->c2.buf, c->c2.occ_mtu_load_size))
|
|
break;
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST");
|
|
doit = true;
|
|
break;
|
|
|
|
case OCC_MTU_LOAD:
|
|
{
|
|
int need_to_add;
|
|
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD))
|
|
break;
|
|
need_to_add = min_int (c->c2.occ_mtu_load_size, EXPANDED_SIZE (&c->c2.frame))
|
|
- OCC_STRING_SIZE
|
|
- sizeof (uint8_t)
|
|
- EXTRA_FRAME (&c->c2.frame);
|
|
|
|
while (need_to_add > 0)
|
|
{
|
|
/*
|
|
* Fill the load test packet with pseudo-random bytes.
|
|
*/
|
|
if (!buf_write_u8 (&c->c2.buf, get_random () & 0xFF))
|
|
break;
|
|
--need_to_add;
|
|
}
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d-%d-%d-%d,%d) size=%d",
|
|
c->c2.occ_mtu_load_size,
|
|
OCC_STRING_SIZE,
|
|
(int) sizeof (uint8_t),
|
|
EXTRA_FRAME (&c->c2.frame),
|
|
MAX_RW_SIZE_TUN (&c->c2.frame),
|
|
BLEN (&c->c2.buf));
|
|
doit = true;
|
|
}
|
|
break;
|
|
|
|
case OCC_EXIT:
|
|
if (!buf_write_u8 (&c->c2.buf, OCC_EXIT))
|
|
break;
|
|
dmsg (D_PACKET_CONTENT, "SENT OCC_EXIT");
|
|
doit = true;
|
|
break;
|
|
}
|
|
|
|
if (doit)
|
|
{
|
|
/*
|
|
* We will treat the packet like any other outgoing packet,
|
|
* compress, encrypt, sign, etc.
|
|
*/
|
|
encrypt_sign (c, true);
|
|
}
|
|
|
|
c->c2.occ_op = -1;
|
|
}
|
|
|
|
void
|
|
process_received_occ_msg (struct context *c)
|
|
{
|
|
ASSERT (buf_advance (&c->c2.buf, OCC_STRING_SIZE));
|
|
switch (buf_read_u8 (&c->c2.buf))
|
|
{
|
|
case OCC_REQUEST:
|
|
dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REQUEST");
|
|
c->c2.occ_op = OCC_REPLY;
|
|
break;
|
|
|
|
case OCC_MTU_REQUEST:
|
|
dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST");
|
|
c->c2.occ_op = OCC_MTU_REPLY;
|
|
break;
|
|
|
|
case OCC_MTU_LOAD_REQUEST:
|
|
dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST");
|
|
c->c2.occ_mtu_load_size = buf_read_u16 (&c->c2.buf);
|
|
if (c->c2.occ_mtu_load_size >= 0)
|
|
c->c2.occ_op = OCC_MTU_LOAD;
|
|
break;
|
|
|
|
case OCC_REPLY:
|
|
dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REPLY");
|
|
if (c->options.occ && !TLS_MODE (c) && c->c2.options_string_remote)
|
|
{
|
|
if (!options_cmp_equal_safe ((char *) BPTR (&c->c2.buf),
|
|
c->c2.options_string_remote,
|
|
c->c2.buf.len))
|
|
{
|
|
options_warning_safe ((char *) BPTR (&c->c2.buf),
|
|
c->c2.options_string_remote,
|
|
c->c2.buf.len);
|
|
}
|
|
}
|
|
event_timeout_clear (&c->c2.occ_interval);
|
|
break;
|
|
|
|
case OCC_MTU_REPLY:
|
|
dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY");
|
|
c->c2.max_recv_size_remote = buf_read_u16 (&c->c2.buf);
|
|
c->c2.max_send_size_remote = buf_read_u16 (&c->c2.buf);
|
|
if (c->options.mtu_test
|
|
&& c->c2.max_recv_size_remote > 0
|
|
&& c->c2.max_send_size_remote > 0)
|
|
{
|
|
msg (M_INFO, "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]",
|
|
c->c2.max_send_size_local,
|
|
c->c2.max_recv_size_remote,
|
|
c->c2.max_send_size_remote,
|
|
c->c2.max_recv_size_local);
|
|
if (!c->options.fragment
|
|
&& c->options.ce.proto == PROTO_UDPv4
|
|
&& c->c2.max_send_size_local > TUN_MTU_MIN
|
|
&& (c->c2.max_recv_size_remote < c->c2.max_send_size_local
|
|
|| c->c2.max_recv_size_local < c->c2.max_send_size_remote))
|
|
msg (M_INFO, "NOTE: This connection is unable to accomodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.",
|
|
c->c2.max_send_size_local);
|
|
}
|
|
event_timeout_clear (&c->c2.occ_mtu_load_test_interval);
|
|
break;
|
|
|
|
case OCC_EXIT:
|
|
dmsg (D_PACKET_CONTENT, "RECEIVED OCC_EXIT");
|
|
c->sig->signal_received = SIGTERM;
|
|
c->sig->signal_text = "remote-exit";
|
|
break;
|
|
}
|
|
c->c2.buf.len = 0; /* don't pass packet on */
|
|
}
|
|
|
|
#else
|
|
static void dummy(void) {}
|
|
#endif
|