Merge branch 'svn-branch-2.1' into merge

Pulling in changes from James' 2.1/openvpn branch in SVN.

Conflicts:
	buffer.c
	init.c
	manage.h
	multi.c
	openvpn.8
	options.c
	ssl.c
	version.m4
	win/sign.py

Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
This commit is contained in:
David Sommerseth 2011-04-26 23:04:18 +02:00
commit 20b18fd799
39 changed files with 1707 additions and 338 deletions

View file

@ -82,7 +82,9 @@ openvpn_SOURCES = \
basic.h \
buffer.c buffer.h \
circ_list.h \
clinat.c clinat.h \
common.h \
config-win32.h \
crypto.c crypto.h \
dhcp.c dhcp.h \
errlevel.h \

View file

@ -235,22 +235,24 @@ buf_puts(struct buffer *buf, const char *str)
* This is necessary due to certain buggy implementations of snprintf,
* that don't guarantee null termination for size > 0.
*
* Return false on overflow.
*
* This function is duplicated into service-win32/openvpnserv.c
* Any modifications here should be done to the other place as well.
*/
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
{
va_list arglist;
int ret = 0;
int len = -1;
if (size > 0)
{
va_start (arglist, format);
ret = vsnprintf (str, size, format, arglist);
len = vsnprintf (str, size, format, arglist);
va_end (arglist);
str[size - 1] = 0;
}
return ret;
return (len >= 0 && len < size);
}
/*

View file

@ -284,7 +284,7 @@ bool buf_puts (struct buffer *buf, const char *str);
/*
* Like snprintf but guarantees null termination for size > 0
*/
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 3, 4)))
#endif

263
clinat.c Normal file
View file

@ -0,0 +1,263 @@
/*
* 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"
#if defined(ENABLE_CLIENT_NAT)
#include "clinat.h"
#include "proto.h"
#include "socket.h"
#include "memdbg.h"
static bool
add_entry(struct client_nat_option_list *dest,
const struct client_nat_entry *e)
{
if (dest->n >= MAX_CLIENT_NAT)
{
msg (M_WARN, "WARNING: client-nat table overflow (max %d entries)", MAX_CLIENT_NAT);
return false;
}
else
{
dest->entries[dest->n++] = *e;
return true;
}
}
void
print_client_nat_list(const struct client_nat_option_list *list, int msglevel)
{
struct gc_arena gc = gc_new ();
int i;
msg (msglevel, "*** CNAT list");
if (list)
{
for (i = 0; i < list->n; ++i)
{
const struct client_nat_entry *e = &list->entries[i];
msg (msglevel, " CNAT[%d] t=%d %s/%s/%s",
i,
e->type,
print_in_addr_t (e->network, IA_NET_ORDER, &gc),
print_in_addr_t (e->netmask, IA_NET_ORDER, &gc),
print_in_addr_t (e->foreign_network, IA_NET_ORDER, &gc));
}
}
gc_free (&gc);
}
struct client_nat_option_list *
new_client_nat_list (struct gc_arena *gc)
{
struct client_nat_option_list *ret;
ALLOC_OBJ_CLEAR_GC (ret, struct client_nat_option_list, gc);
return ret;
}
struct client_nat_option_list *
clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc)
{
struct client_nat_option_list *ret;
ALLOC_OBJ_GC (ret, struct client_nat_option_list, gc);
*ret = *src;
return ret;
}
void
copy_client_nat_option_list (struct client_nat_option_list *dest,
const struct client_nat_option_list *src)
{
int i;
for (i = 0; i < src->n; ++i)
{
if (!add_entry(dest, &src->entries[i]))
break;
}
}
void
add_client_nat_to_option_list (struct client_nat_option_list *dest,
const char *type,
const char *network,
const char *netmask,
const char *foreign_network,
int msglevel)
{
struct client_nat_entry e;
bool ok;
if (!strcmp(type, "snat"))
e.type = CN_SNAT;
else if (!strcmp(type, "dnat"))
e.type = CN_DNAT;
else
{
msg(msglevel, "client-nat: type must be 'snat' or 'dnat'");
return;
}
e.network = getaddr(0, network, 0, &ok, NULL);
if (!ok)
{
msg(msglevel, "client-nat: bad network: %s", network);
return;
}
e.netmask = getaddr(0, netmask, 0, &ok, NULL);
if (!ok)
{
msg(msglevel, "client-nat: bad netmask: %s", netmask);
return;
}
e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL);
if (!ok)
{
msg(msglevel, "client-nat: bad foreign network: %s", foreign_network);
return;
}
add_entry(dest, &e);
}
#if 0
static void
print_checksum (struct openvpn_iphdr *iph, const char *prefix)
{
uint16_t *sptr;
unsigned int sum = 0;
int i = 0;
for (sptr = (uint16_t *)iph; (uint8_t *)sptr < (uint8_t *)iph + sizeof(struct openvpn_iphdr); sptr++)
{
i += 1;
sum += *sptr;
}
msg (M_INFO, "** CKSUM[%d] %s %08x", i, prefix, sum);
}
#endif
static void
print_pkt (struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel)
{
struct gc_arena gc = gc_new ();
char *dirstr = "???";
if (direction == CN_OUTGOING)
dirstr = "OUT";
else if (direction == CN_INCOMING)
dirstr = "IN";
msg(msglevel, "** CNAT %s %s %s -> %s",
dirstr,
prefix,
print_in_addr_t (iph->saddr, IA_NET_ORDER, &gc),
print_in_addr_t (iph->daddr, IA_NET_ORDER, &gc));
gc_free (&gc);
}
void
client_nat_transform (const struct client_nat_option_list *list,
struct buffer *ipbuf,
const int direction)
{
struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR (ipbuf);
int i;
uint32_t addr, *addr_ptr;
const uint32_t *from, *to;
int accumulate = 0;
unsigned int amask;
unsigned int alog = 0;
if (check_debug_level (D_CLIENT_NAT))
print_pkt (&h->ip, "BEFORE", direction, D_CLIENT_NAT);
for (i = 0; i < list->n; ++i)
{
const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */
if (e->type ^ direction)
{
addr = *(addr_ptr = &h->ip.daddr);
amask = 2;
}
else
{
addr = *(addr_ptr = &h->ip.saddr);
amask = 1;
}
if (direction)
{
from = &e->foreign_network;
to = &e->network;
}
else
{
from = &e->network;
to = &e->foreign_network;
}
if (((addr & e->netmask) == *from) && !(amask & alog))
{
/* pre-adjust IP checksum */
ADD_CHECKSUM_32(accumulate, addr);
/* do NAT transform */
addr = (addr & ~e->netmask) | *to;
/* post-adjust IP checksum */
SUB_CHECKSUM_32(accumulate, addr);
/* write the modified address to packet */
*addr_ptr = addr;
/* mark as modified */
alog |= amask;
}
}
if (alog)
{
if (check_debug_level (D_CLIENT_NAT))
print_pkt (&h->ip, "AFTER", direction, D_CLIENT_NAT);
ADJUST_CHECKSUM(accumulate, h->ip.check);
if (h->ip.protocol == OPENVPN_IPPROTO_TCP)
{
if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_tcphdr))
{
ADJUST_CHECKSUM(accumulate, h->u.tcp.check);
}
}
else if (h->ip.protocol == OPENVPN_IPPROTO_UDP)
{
if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr))
{
ADJUST_CHECKSUM(accumulate, h->u.udp.check);
}
}
}
}
#endif

65
clinat.h Normal file
View file

@ -0,0 +1,65 @@
/*
* 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
*/
#if !defined(CLINAT_H) && defined(ENABLE_CLIENT_NAT)
#define CLINAT_H
#include "buffer.h"
#define MAX_CLIENT_NAT 64
#define CN_OUTGOING 0
#define CN_INCOMING 1
struct client_nat_entry {
# define CN_SNAT 0
# define CN_DNAT 1
int type;
in_addr_t network;
in_addr_t netmask;
in_addr_t foreign_network;
};
struct client_nat_option_list {
int n;
struct client_nat_entry entries[MAX_CLIENT_NAT];
};
struct client_nat_option_list *new_client_nat_list (struct gc_arena *gc);
struct client_nat_option_list *clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc);
void copy_client_nat_option_list (struct client_nat_option_list *dest, const struct client_nat_option_list *src);
void print_client_nat_list(const struct client_nat_option_list *list, int msglevel);
void add_client_nat_to_option_list (struct client_nat_option_list *dest,
const char *type,
const char *network,
const char *netmask,
const char *foreign_network,
int msglevel);
void client_nat_transform (const struct client_nat_option_list *list,
struct buffer *ipbuf,
const int direction);
#endif

View file

@ -86,6 +86,11 @@ typedef unsigned long ptr_type;
*/
#define PUSH_BUNDLE_SIZE 1024
/*
* In how many seconds does client re-send PUSH_REQUEST if we haven't yet received a reply
*/
#define PUSH_REQUEST_INTERVAL 5
/*
* A sort of pseudo-filename for data provided inline within
* the configuration file.

View file

@ -68,6 +68,12 @@ AC_ARG_ENABLE(lzo,
[LZO="yes"]
)
AC_ARG_ENABLE(lzo-stub,
[ --enable-lzo-stub Don't compile LZO compression support but still allow limited interoperability with LZO-enabled peers],
[LZO_STUB="$enableval"],
[LZO_STUB="no"]
)
AC_ARG_ENABLE(crypto,
[ --disable-crypto Disable OpenSSL crypto support],
[CRYPTO="$enableval"],
@ -662,7 +668,7 @@ dnl
dnl check for LZO library
dnl
if test "$LZO" = "yes"; then
if test "$LZO" = "yes" && test "$LZO_STUB" = "no"; then
LZO_H=""
AC_CHECKING([for LZO Library and Header files])
AC_CHECK_HEADER(lzo/lzo1x.h,
@ -692,10 +698,15 @@ if test "$LZO" = "yes"; then
else
AC_MSG_RESULT([LZO headers were not found])
AC_MSG_RESULT([LZO library available from http://www.oberhumer.com/opensource/lzo/])
AC_MSG_ERROR([Or try ./configure --disable-lzo])
AC_MSG_ERROR([Or try ./configure --disable-lzo OR ./configure --enable-lzo-stub])
fi
fi
dnl enable multi-client mode
if test "$LZO_STUB" = "yes"; then
AC_DEFINE(LZO_STUB, 1, [Enable LZO stub capability])
fi
dnl
dnl check for OpenSSL-crypto library
dnl

View file

@ -71,9 +71,7 @@
#define D_ALIGN_ERRORS LOGLEV(1, 14, M_NONFATAL) /* show bad struct alignments */
#define D_HANDSHAKE LOGLEV(2, 20, 0) /* show data & control channel handshakes */
#define D_MTU_INFO LOGLEV(2, 21, 0) /* show terse MTU info */
#define D_CLOSE LOGLEV(2, 22, 0) /* show socket and TUN/TAP close */
#define D_SHOW_OCC_HASH LOGLEV(2, 23, 0) /* show MD5 hash of option compatibility string */
#define D_PROXY LOGLEV(2, 24, 0) /* show http proxy control packets */
#define D_ARGV LOGLEV(2, 25, 0) /* show struct argv errors */
@ -85,7 +83,7 @@
#define D_RESTART LOGLEV(3, 33, 0) /* show certain restart messages */
#define D_PUSH LOGLEV(3, 34, 0) /* show push/pull info */
#define D_IFCONFIG_POOL LOGLEV(3, 35, 0) /* show ifconfig pool info */
#define D_BACKTRACK LOGLEV(3, 36, 0) /* show replay backtracks */
#define D_PID_DEBUG_LOW LOGLEV(3, 36, 0) /* show low-freq packet-id debugging info */
#define D_AUTH LOGLEV(3, 37, 0) /* show user/pass auth info */
#define D_MULTI_LOW LOGLEV(3, 38, 0) /* show point-to-multipoint low-freq debug info */
#define D_PLUGIN LOGLEV(3, 39, 0) /* show plugin calls */
@ -104,12 +102,19 @@
#define D_PACKET_TRUNC_ERR LOGLEV(4, 55, 0) /* PACKET_TRUNCATION_CHECK */
#define D_PF_DROPPED LOGLEV(4, 56, 0) /* packet filter dropped a packet */
#define D_MULTI_DROPPED LOGLEV(4, 57, 0) /* show point-to-multipoint packet drops */
#define D_MULTI_MEDIUM LOGLEV(4, 58, 0) /* show medium frequency multi messages */
#define D_X509_ATTR LOGLEV(4, 59, 0) /* show x509-track attributes on connection */
#define D_INIT_MEDIUM LOGLEV(4, 60, 0) /* show medium frequency init messages */
#define D_MTU_INFO LOGLEV(4, 61, 0) /* show terse MTU info */
#define D_SHOW_OCC_HASH LOGLEV(4, 62, 0) /* show MD5 hash of option compatibility string */
#define D_PID_DEBUG_MEDIUM LOGLEV(4, 63, 0) /* show medium-freq packet-id debugging info */
#define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */
#define D_LINK_RW LOGLEV(6, 60, M_DEBUG) /* show TCP/UDP reads/writes (terse) */
#define D_TUN_RW LOGLEV(6, 60, M_DEBUG) /* show TUN/TAP reads/writes */
#define D_TAP_WIN32_DEBUG LOGLEV(6, 60, M_DEBUG) /* show TAP-Win32 driver debug info */
#define D_LINK_RW LOGLEV(6, 69, M_DEBUG) /* show TCP/UDP reads/writes (terse) */
#define D_TUN_RW LOGLEV(6, 69, M_DEBUG) /* show TUN/TAP reads/writes */
#define D_TAP_WIN32_DEBUG LOGLEV(6, 69, M_DEBUG) /* show TAP-Win32 driver debug info */
#define D_CLIENT_NAT LOGLEV(6, 69, M_DEBUG) /* show client NAT debug info */
#define D_SHOW_KEYS LOGLEV(7, 70, M_DEBUG) /* show data channel encryption keys */
#define D_SHOW_KEY_SOURCE LOGLEV(7, 70, M_DEBUG) /* show data channel key source entropy */
@ -117,7 +122,6 @@
#define D_FRAG_DEBUG LOGLEV(7, 70, M_DEBUG) /* show fragment debugging info */
#define D_WIN32_IO_LOW LOGLEV(7, 70, M_DEBUG) /* low freq win32 I/O debugging info */
#define D_MTU_DEBUG LOGLEV(7, 70, M_DEBUG) /* show MTU debugging info */
#define D_PID_DEBUG_LOW LOGLEV(7, 70, M_DEBUG) /* show low-freq packet-id debugging info */
#define D_MULTI_DEBUG LOGLEV(7, 70, M_DEBUG) /* show medium-freq multi debugging info */
#define D_MSS LOGLEV(7, 70, M_DEBUG) /* show MSS adjustments */
#define D_COMP_LOW LOGLEV(7, 70, M_DEBUG) /* show adaptive compression state changes */
@ -141,6 +145,7 @@
#define D_TLS_KEYSELECT LOGLEV(7, 70, M_DEBUG) /* show information on key selection for data channel */
#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_printf %sc */
#define D_CRYPTO_DEBUG LOGLEV(7, 70, M_DEBUG) /* show detailed info from crypto.c routines */
#define D_PID_DEBUG LOGLEV(7, 70, M_DEBUG) /* show packet-id debugging info */
#define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */
#define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */
@ -158,7 +163,6 @@
#define D_READ_WRITE LOGLEV(9, 70, M_DEBUG) /* show all tun/tcp/udp reads/writes/opens */
#define D_PACKET_CONTENT LOGLEV(9, 70, M_DEBUG) /* show before/after encryption packet content */
#define D_TLS_NO_SEND_KEY LOGLEV(9, 70, M_DEBUG) /* show when no data channel send-key exists */
#define D_PID_DEBUG LOGLEV(9, 70, M_DEBUG) /* show packet-id debugging info */
#define D_PID_PERSIST_DEBUG LOGLEV(9, 70, M_DEBUG) /* show packet-id persist debugging info */
#define D_LINK_RW_VERBOSE LOGLEV(9, 70, M_DEBUG) /* show link reads/writes with greater verbosity */
#define D_STREAM_DEBUG LOGLEV(9, 70, M_DEBUG) /* show TCP stream debug info */

29
error.c
View file

@ -340,7 +340,7 @@ void x_msg (const unsigned int flags, const char *format, ...)
}
if (flags & M_FATAL)
msg (M_INFO, "Exiting");
msg (M_INFO, "Exiting due to fatal error");
if (flags & M_FATAL)
openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
@ -651,35 +651,38 @@ const struct virtual_output *x_msg_virtual_output; /* GLOBAL */
void
openvpn_exit (const int status)
{
void tun_abort();
if (!forked)
{
void tun_abort();
#ifdef ENABLE_PLUGIN
void plugin_abort (void);
void plugin_abort (void);
#endif
tun_abort();
tun_abort();
#ifdef WIN32
uninit_win32 ();
uninit_win32 ();
#endif
close_syslog ();
close_syslog ();
#ifdef ENABLE_PLUGIN
plugin_abort ();
plugin_abort ();
#endif
#if PORT_SHARE
if (port_share)
port_share_abort (port_share);
if (port_share)
port_share_abort (port_share);
#endif
#ifdef ABORT_ON_ERROR
if (status == OPENVPN_EXIT_STATUS_ERROR)
abort ();
if (status == OPENVPN_EXIT_STATUS_ERROR)
abort ();
#endif
if (status == OPENVPN_EXIT_STATUS_GOOD)
perf_output_results ();
if (status == OPENVPN_EXIT_STATUS_GOOD)
perf_output_results ();
}
exit (status);
}

View file

@ -522,10 +522,10 @@ ep_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg)
if (errno == ENOENT)
{
if (epoll_ctl (eps->epfd, EPOLL_CTL_ADD, event, &ev) < 0)
msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed");
msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed, sd=%d", (int)event);
}
else
msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed");
msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed, sd=%d", (int)event);
}
}

View file

@ -155,7 +155,9 @@ check_incoming_control_channel_dowork (struct context *c)
else if (buf_string_match_head_str (&buf, "PUSH_"))
incoming_push_message (c, &buf);
else if (buf_string_match_head_str (&buf, "RESTART"))
server_pushed_restart (c, &buf);
server_pushed_signal (c, &buf, true, 7);
else if (buf_string_match_head_str (&buf, "HALT"))
server_pushed_signal (c, &buf, false, 4);
else
msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf));
}
@ -176,8 +178,8 @@ check_push_request_dowork (struct context *c)
{
send_push_request (c);
/* if no response to first push_request, retry at 5 second intervals */
event_timeout_modify_wakeup (&c->c2.push_request_interval, 5);
/* if no response to first push_request, retry at PUSH_REQUEST_INTERVAL second intervals */
event_timeout_modify_wakeup (&c->c2.push_request_interval, PUSH_REQUEST_INTERVAL);
}
#endif /* P2MP */
@ -230,22 +232,28 @@ bool
send_control_channel_string (struct context *c, const char *str, int msglevel)
{
#if defined(USE_CRYPTO) && defined(USE_SSL)
if (c->c2.tls_multi) {
struct gc_arena gc = gc_new ();
bool stat;
/* buffered cleartext write onto TLS control channel */
stat = tls_send_payload (c->c2.tls_multi, (uint8_t*) str, strlen (str) + 1);
/* reschedule tls_multi_process */
/*
* Reschedule tls_multi_process.
* NOTE: in multi-client mode, usually the below two statements are
* insufficient to reschedule the client instance object unless
* multi_schedule_context_wakeup(m, mi) is also called.
*/
interval_action (&c->c2.tmp_int);
context_immediate_reschedule (c); /* ZERO-TIMEOUT */
msg (msglevel, "SENT CONTROL [%s]: '%s' (status=%d)",
tls_common_name (c->c2.tls_multi, false),
str,
sanitize_control_message (str, &gc),
(int) stat);
gc_free (&gc);
return stat;
}
#endif
@ -968,7 +976,7 @@ process_incoming_tun (struct context *c)
* The --passtos and --mssfix options require
* us to examine the IPv4 header.
*/
process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf);
process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
#ifdef PACKET_TRUNCATION_CHECK
/* if (c->c2.buf.len > 1) --c->c2.buf.len; */
@ -1026,6 +1034,14 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
if (flags & PIPV4_MSSFIX)
mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
#ifdef ENABLE_CLIENT_NAT
/* possibly do NAT on packet */
if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
{
const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING;
client_nat_transform (c->options.client_nat, &ipbuf, direction);
}
#endif
/* possibly extract a DHCP router message */
if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
{
@ -1188,7 +1204,7 @@ process_outgoing_tun (struct context *c)
* The --mssfix option requires
* us to examine the IPv4 header.
*/
process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_OUTGOING, &c->c2.to_tun);
process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))
{

View file

@ -76,6 +76,7 @@ bool send_control_channel_string (struct context *c, const char *str, int msglev
#define PIPV4_MSSFIX (1<<1)
#define PIPV4_OUTGOING (1<<2)
#define PIPV4_EXTRACT_DHCP_ROUTER (1<<3)
#define PIPV4_CLIENT_NAT (1<<4)
void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf);

70
init.c
View file

@ -102,13 +102,6 @@ update_options_ce_post (struct options *options)
options->ping_rec_timeout_action = PING_RESTART;
}
#endif
#ifdef USE_CRYPTO
/*
* Don't use replay window for TCP mode (i.e. require that packets be strictly in sequence).
*/
if (link_socket_proto_connection_oriented (options->ce.proto))
options->replay_window = options->replay_time = 0;
#endif
}
#if HTTP_PROXY_FALLBACK
@ -521,7 +514,9 @@ init_port_share (struct context *c)
if (!port_share && (c->options.port_share_host && c->options.port_share_port))
{
port_share = port_share_open (c->options.port_share_host,
c->options.port_share_port);
c->options.port_share_port,
MAX_RW_SIZE_LINK (&c->c2.frame),
c->options.port_share_journal_dir);
if (port_share == NULL)
msg (M_FATAL, "Fatal error: Port sharing failed");
}
@ -601,6 +596,27 @@ init_static (void)
return false;
#endif
#ifdef TEST_GET_DEFAULT_GATEWAY
{
struct gc_arena gc = gc_new ();
in_addr_t addr;
char macaddr[6];
if (get_default_gateway(&addr, NULL))
msg (M_INFO, "GW %s", print_in_addr_t(addr, 0, &gc));
else
msg (M_INFO, "GDG ERROR");
if (get_default_gateway_mac_addr(macaddr))
msg (M_INFO, "MAC %s", format_hex_ex (macaddr, 6, 0, 1, ":", &gc));
else
msg (M_INFO, "GDGMA ERROR");
gc_free (&gc);
return false;
}
#endif
#ifdef GEN_PATH_TEST
{
struct gc_arena gc = gc_new ();
@ -1223,7 +1239,14 @@ do_route (const struct options *options,
struct env_set *es)
{
if (!options->route_noexec && ( route_list || route_ipv6_list ) )
add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
{
add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
setenv_int (es, "redirect_gateway", route_list->did_redirect_default_gateway);
}
#ifdef ENABLE_MANAGEMENT
if (management)
management_up_down (management, "UP", es);
#endif
if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
{
@ -1441,7 +1464,10 @@ do_close_tun (struct context *c, bool force)
#ifdef ENABLE_MANAGEMENT
/* tell management layer we are about to close the TUN/TAP device */
if (management)
management_pre_tunnel_close (management);
{
management_pre_tunnel_close (management);
management_up_down (management, "DOWN", c->c2.es);
}
#endif
/* delete any routes we added */
@ -1586,7 +1612,6 @@ pull_permission_mask (const struct context *c)
unsigned int flags =
OPT_P_UP
| OPT_P_ROUTE_EXTRAS
| OPT_P_IPWIN32
| OPT_P_SOCKBUF
| OPT_P_SOCKFLAGS
| OPT_P_SETENV
@ -1600,7 +1625,7 @@ pull_permission_mask (const struct context *c)
| OPT_P_PULL_MODE;
if (!c->options.route_nopull)
flags |= OPT_P_ROUTE;
flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
return flags;
}
@ -1749,8 +1774,10 @@ socket_restart_pause (struct context *c)
if (auth_retry_get () == AR_NOINTERACT)
sec = 10;
#if 0 /* not really needed because of c->persist.restart_sleep_seconds */
if (c->options.server_poll_timeout && sec > 1)
sec = 1;
#endif
#endif
if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec)
@ -1868,8 +1895,11 @@ do_init_crypto_static (struct context *c, const unsigned int flags)
/* Initialize packet ID tracking */
if (options->replay)
{
packet_id_init (&c->c2.packet_id, options->replay_window,
options->replay_time);
packet_id_init (&c->c2.packet_id,
link_socket_proto_connection_oriented (options->ce.proto),
options->replay_window,
options->replay_time,
"STATIC", 0);
c->c2.crypto_options.packet_id = &c->c2.packet_id;
c->c2.crypto_options.pid_persist = &c->c1.pid_persist;
c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM;
@ -1965,7 +1995,7 @@ do_init_crypto_tls_c1 (struct context *c)
msg (M_FATAL, "Error: private key password verification failed");
break;
case AR_INTERACT:
ssl_purge_auth ();
ssl_purge_auth (false);
case AR_NOINTERACT:
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Password failure error */
break;
@ -2017,7 +2047,7 @@ do_init_crypto_tls_c1 (struct context *c)
}
else
{
msg (M_INFO, "Re-using SSL/TLS context");
msg (D_INIT_MEDIUM, "Re-using SSL/TLS context");
}
}
@ -2070,6 +2100,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.replay = options->replay;
to.replay_window = options->replay_window;
to.replay_time = options->replay_time;
to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto);
to.transition_window = options->transition_window;
to.handshake_window = options->handshake_window;
to.packet_timeout = options->tls_timeout;
@ -2094,9 +2125,11 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.verify_export_cert = options->tls_export_cert;
to.verify_x509name = options->tls_remote;
to.crl_file = options->crl_file;
to.ssl_flags = options->ssl_flags;
to.ns_cert_type = options->ns_cert_type;
memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku));
to.remote_cert_eku = options->remote_cert_eku;
to.verify_hash = options->verify_hash;
to.es = c->c2.es;
#ifdef ENABLE_DEBUG
@ -2113,11 +2146,14 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.auth_user_pass_verify_script = options->auth_user_pass_verify_script;
to.auth_user_pass_verify_script_via_file = options->auth_user_pass_verify_script_via_file;
to.tmp_dir = options->tmp_dir;
to.ssl_flags = options->ssl_flags;
if (options->ccd_exclusive)
to.client_config_dir_exclusive = options->client_config_dir;
#endif
#ifdef ENABLE_X509_TRACK
to.x509_track = options->x509_track;
#endif
/* TLS handshake authentication (--tls-auth) */
if (options->tls_auth_file)
{

32
lzo.c
View file

@ -32,6 +32,8 @@
#include "memdbg.h"
#ifndef LZO_STUB
static bool
lzo_adaptive_compress_test (struct lzo_adaptive_compress *ac)
{
@ -79,6 +81,8 @@ lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n
ac->n_comp += n_comp;
}
#endif /* LZO_STUB */
void lzo_adjust_frame_parameters (struct frame *frame)
{
/* Leave room for our one-byte compressed/didn't-compress prefix byte. */
@ -94,14 +98,18 @@ lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags)
{
CLEAR (*lzowork);
lzowork->wmem_size = LZO_WORKSPACE;
lzowork->flags = flags;
#ifndef LZO_STUB
lzowork->wmem_size = LZO_WORKSPACE;
if (lzo_init () != LZO_E_OK)
msg (M_FATAL, "Cannot initialize LZO compression library");
lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size);
check_malloc_return (lzowork->wmem);
msg (M_INFO, "LZO compression initialized");
msg (D_INIT_MEDIUM, "LZO compression initialized");
#else
msg (D_INIT_MEDIUM, "LZO stub compression initialized");
#endif
lzowork->defined = true;
}
@ -111,8 +119,10 @@ lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
if (lzowork)
{
ASSERT (lzowork->defined);
#ifndef LZO_STUB
lzo_free (lzowork->wmem);
lzowork->wmem = NULL;
#endif
lzowork->defined = false;
}
}
@ -120,6 +130,7 @@ lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
static inline bool
lzo_compression_enabled (struct lzo_compress_workspace *lzowork)
{
#ifndef LZO_STUB
if ((lzowork->flags & (LZO_SELECTED|LZO_ON)) == (LZO_SELECTED|LZO_ON))
{
if (lzowork->flags & LZO_ADAPTIVE)
@ -127,6 +138,7 @@ lzo_compression_enabled (struct lzo_compress_workspace *lzowork)
else
return true;
}
#endif
return false;
}
@ -139,15 +151,18 @@ lzo_compress (struct buffer *buf, struct buffer work,
struct lzo_compress_workspace *lzowork,
const struct frame* frame)
{
#ifndef LZO_STUB
lzo_uint zlen = 0;
int err;
bool compressed = false;
#endif
ASSERT (lzowork->defined);
if (buf->len <= 0)
return;
#ifndef LZO_STUB
/*
* In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
* and our adaptive level must give the OK.
@ -193,6 +208,7 @@ lzo_compress (struct buffer *buf, struct buffer work,
*buf = work;
}
else
#endif
{
uint8_t *header = buf_prepend (buf, 1);
*header = NO_COMPRESS;
@ -204,9 +220,11 @@ lzo_decompress (struct buffer *buf, struct buffer work,
struct lzo_compress_workspace *lzowork,
const struct frame* frame)
{
#ifndef LZO_STUB
lzo_uint zlen = EXPANDED_SIZE (frame);
uint8_t c; /* flag indicating whether or not our peer compressed */
int err;
#endif
uint8_t c; /* flag indicating whether or not our peer compressed */
ASSERT (lzowork->defined);
@ -220,6 +238,7 @@ lzo_decompress (struct buffer *buf, struct buffer work,
if (c == YES_COMPRESS) /* packet was compressed */
{
#ifndef LZO_STUB
ASSERT (buf_safe (&work, zlen));
err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen,
lzowork->wmem);
@ -238,6 +257,11 @@ lzo_decompress (struct buffer *buf, struct buffer work,
lzowork->post_decompress += work.len;
*buf = work;
#else
dmsg (D_COMP_ERRORS, "LZO decompression error: LZO capability not compiled");
buf->len = 0;
return;
#endif
}
else if (c == NO_COMPRESS) /* packet was not compressed */
{
@ -264,10 +288,12 @@ void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct
{
ASSERT (lzo_compwork->defined);
#ifndef LZO_STUB
status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress);
status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress);
status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress);
status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress);
#endif
}
#else

29
lzo.h
View file

@ -27,6 +27,7 @@
#ifdef USE_LZO
#ifndef LZO_STUB
#ifdef LZO_HEADER_DIR
#include "lzo/lzoutil.h"
#include "lzo/lzo1x.h"
@ -34,6 +35,7 @@
#include "lzoutil.h"
#include "lzo1x.h"
#endif
#endif
#include "buffer.h"
#include "mtu.h"
@ -45,6 +47,18 @@
#define LZO_ON (1<<1)
#define LZO_ADAPTIVE (1<<2)
/*
* Length of prepended prefix on LZO packets
*/
#define LZO_PREFIX_LEN 1
/*
* LZO 2.0 worst case size expansion
*/
#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3)
#ifndef LZO_STUB
/*
* Use LZO compress routine lzo1x_1_15_compress which is described
* as faster but needs a bit more memory than the standard routine.
@ -58,18 +72,11 @@
#define LZO_WORKSPACE LZO1X_1_15_MEM_COMPRESS
#define LZO_DECOMPRESS lzo1x_decompress_safe
#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3) /* LZO 2.0 worst case size expansion. */
/*
* Don't try to compress any packet smaller than this.
*/
#define COMPRESS_THRESHOLD 100
/*
* Length of prepended prefix on LZO packets
*/
#define LZO_PREFIX_LEN 1
/*
* Adaptive compress parameters
*/
@ -88,23 +95,27 @@ struct lzo_adaptive_compress {
int n_comp;
};
#endif /* LZO_STUB */
/*
* Compress and Uncompress routines.
*/
struct lzo_compress_workspace
{
bool defined;
unsigned int flags;
#ifndef LZO_STUB
lzo_voidp wmem;
int wmem_size;
struct lzo_adaptive_compress ac;
unsigned int flags;
bool defined;
/* statistics */
counter_type pre_decompress;
counter_type post_decompress;
counter_type pre_compress;
counter_type post_compress;
#endif
};
void lzo_adjust_frame_parameters(struct frame *frame);

View file

@ -96,7 +96,7 @@ man_help ()
msg (M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID");
msg (M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason");
msg (M_CLIENT, " text R and optional client reason text CR");
msg (M_CLIENT, "client-kill CID : Kill client instance CID");
msg (M_CLIENT, "client-kill CID [M] : Kill client instance CID with message M (def=RESTART)");
msg (M_CLIENT, "env-filter [level] : Set env-var filter level");
#ifdef MANAGEMENT_PF
msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)");
@ -698,7 +698,7 @@ static void
man_forget_passwords (struct management *man)
{
#if defined(USE_CRYPTO) && defined(USE_SSL)
ssl_purge_auth ();
ssl_purge_auth (false);
msg (M_CLIENT, "SUCCESS: Passwords were forgotten");
#endif
}
@ -947,14 +947,14 @@ man_client_deny (struct management *man, const char *cid_str, const char *kid_st
}
static void
man_client_kill (struct management *man, const char *cid_str)
man_client_kill (struct management *man, const char *cid_str, const char *kill_msg)
{
unsigned long cid = 0;
if (parse_cid (cid_str, &cid))
{
if (man->persist.callback.kill_by_cid)
{
const bool status = (*man->persist.callback.kill_by_cid) (man->persist.callback.arg, cid);
const bool status = (*man->persist.callback.kill_by_cid) (man->persist.callback.arg, cid, kill_msg);
if (status)
{
msg (M_CLIENT, "SUCCESS: client-kill command succeeded");
@ -1265,8 +1265,8 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
#ifdef MANAGEMENT_DEF_AUTH
else if (streq (p[0], "client-kill"))
{
if (man_need (man, p, 1, 0))
man_client_kill (man, p[1]);
if (man_need (man, p, 1, MN_AT_LEAST))
man_client_kill (man, p[1], p[2]);
}
else if (streq (p[0], "client-deny"))
{
@ -1682,7 +1682,7 @@ man_reset_client_socket (struct management *man, const bool exiting)
{
#if defined(USE_CRYPTO) && defined(USE_SSL)
if (man->settings.flags & MF_FORGET_DISCONNECT)
ssl_purge_auth ();
ssl_purge_auth (false);
#endif
if (man->settings.flags & MF_SIGNAL) {
int mysig = man_mod_signal (man, SIGUSR1);
@ -2190,6 +2190,7 @@ management_open (struct management *man,
void
management_close (struct management *man)
{
man_output_list_push_finalize (man); /* flush output queue */
man_connection_close (man);
man_settings_close (&man->settings);
man_persist_close (&man->persist);
@ -2252,8 +2253,6 @@ management_set_state (struct management *man,
}
}
#ifdef MANAGEMENT_DEF_AUTH
static bool
env_filter_match (const char *env_str, const int env_filter_level)
{
@ -2261,7 +2260,7 @@ env_filter_match (const char *env_str, const int env_filter_level)
"username=",
"password=",
"X509_0_CN=",
"tls_serial_0=",
"tls_serial_",
"untrusted_ip=",
"ifconfig_local=",
"ifconfig_netmask=",
@ -2274,24 +2273,28 @@ env_filter_match (const char *env_str, const int env_filter_level)
"bytes_sent=",
"bytes_received="
};
if (env_filter_level >= 1)
if (env_filter_level == 0)
return true;
else if (env_filter_level <= 1 && !strncmp(env_str, "X509_", 5))
return true;
else if (env_filter_level <= 2)
{
size_t i;
for (i = 0; i < SIZE(env_names); ++i)
{
const char *en = env_names[i];
const size_t len = strlen(en);
if (strncmp(env_str, en, len) == 0)
if (!strncmp(env_str, en, len))
return true;
}
return false;
}
else
return true;
return false;
}
static void
man_output_env (const struct env_set *es, const bool tail, const int env_filter_level)
man_output_env (const struct env_set *es, const bool tail, const int env_filter_level, const char *prefix)
{
if (es)
{
@ -2299,15 +2302,15 @@ man_output_env (const struct env_set *es, const bool tail, const int env_filter_
for (e = es->list; e != NULL; e = e->next)
{
if (e->string && (!env_filter_level || env_filter_match(e->string, env_filter_level)))
msg (M_CLIENT, ">CLIENT:ENV,%s", e->string);
msg (M_CLIENT, ">%s:ENV,%s", prefix, e->string);
}
}
if (tail)
msg (M_CLIENT, ">CLIENT:ENV,END");
msg (M_CLIENT, ">%s:ENV,END", prefix);
}
static void
man_output_extra_env (struct management *man)
man_output_extra_env (struct management *man, const char *prefix)
{
struct gc_arena gc = gc_new ();
struct env_set *es = env_set_create (&gc);
@ -2316,10 +2319,28 @@ man_output_extra_env (struct management *man)
const int nclients = (*man->persist.callback.n_clients) (man->persist.callback.arg);
setenv_int (es, "n_clients", nclients);
}
man_output_env (es, false, man->connection.env_filter_level);
man_output_env (es, false, man->connection.env_filter_level, prefix);
gc_free (&gc);
}
void
management_up_down(struct management *man, const char *updown, const struct env_set *es)
{
if (man->settings.flags & MF_UP_DOWN)
{
msg (M_CLIENT, ">UPDOWN:%s", updown);
man_output_env (es, true, 0, "UPDOWN");
}
}
void
management_notify(struct management *man, const char *severity, const char *type, const char *text)
{
msg (M_CLIENT, ">NOTIFY:%s,%s,%s", severity, type, text);
}
#ifdef MANAGEMENT_DEF_AUTH
static bool
validate_peer_info_line(const char *line)
{
@ -2384,9 +2405,9 @@ management_notify_client_needing_auth (struct management *management,
if (mdac->flags & DAF_CONNECTION_ESTABLISHED)
mode = "REAUTH";
msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id);
man_output_extra_env (management);
man_output_extra_env (management, "CLIENT");
man_output_peer_info_env(management, mdac);
man_output_env (es, true, management->connection.env_filter_level);
man_output_env (es, true, management->connection.env_filter_level, "CLIENT");
mdac->flags |= DAF_INITIAL_AUTH;
}
}
@ -2398,8 +2419,8 @@ management_connection_established (struct management *management,
{
mdac->flags |= DAF_CONNECTION_ESTABLISHED;
msg (M_CLIENT, ">CLIENT:ESTABLISHED,%lu", mdac->cid);
man_output_extra_env (management);
man_output_env (es, true, management->connection.env_filter_level);
man_output_extra_env (management, "CLIENT");
man_output_env (es, true, management->connection.env_filter_level, "CLIENT");
}
void
@ -2410,7 +2431,7 @@ management_notify_client_close (struct management *management,
if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED))
{
msg (M_CLIENT, ">CLIENT:DISCONNECT,%lu", mdac->cid);
man_output_env (es, true, management->connection.env_filter_level);
man_output_env (es, true, management->connection.env_filter_level, "CLIENT");
mdac->flags |= DAF_CONNECTION_CLOSED;
}
}
@ -2494,6 +2515,12 @@ management_auth_failure (struct management *man, const char *type, const char *r
msg (M_CLIENT, ">PASSWORD:Verification Failed: '%s'", type);
}
void
management_auth_token (struct management *man, const char *token)
{
msg (M_CLIENT, ">PASSWORD:Auth-Token:%s", token);
}
static inline bool
man_persist_state (unsigned int *persistent, const int n)
{

View file

@ -156,7 +156,7 @@ struct management_callback
void (*delete_event) (void *arg, event_t event);
int (*n_clients) (void *arg);
#ifdef MANAGEMENT_DEF_AUTH
bool (*kill_by_cid) (void *arg, const unsigned long cid);
bool (*kill_by_cid) (void *arg, const unsigned long cid, const char *kill_msg);
bool (*client_auth) (void *arg,
const unsigned long cid,
const unsigned int mda_key_id,
@ -274,7 +274,6 @@ struct man_connection {
#ifdef MANAGEMENT_DEF_AUTH
unsigned long in_extra_cid;
unsigned int in_extra_kid;
int env_filter_level;
#endif
#ifdef MANAGMENT_EXTERNAL_KEY
# define EKS_UNDEF 0
@ -286,6 +285,7 @@ struct man_connection {
#endif
#endif
struct event_set *es;
int env_filter_level;
bool state_realtime;
bool log_realtime;
@ -332,6 +332,7 @@ struct management *management_init (void);
#ifdef MANAGMENT_EXTERNAL_KEY
# define MF_EXTERNAL_KEY (1<<9)
#endif
#define MF_UP_DOWN (1<<10)
bool management_open (struct management *man,
const char *addr,
@ -372,6 +373,10 @@ bool management_hold (struct management *man);
void management_event_loop_n_seconds (struct management *man, int sec);
void management_up_down(struct management *man, const char *updown, const struct env_set *es);
void management_notify(struct management *man, const char *severity, const char *type, const char *text);
#ifdef MANAGEMENT_DEF_AUTH
void management_notify_client_needing_auth (struct management *management,
const unsigned int auth_id,
@ -466,6 +471,11 @@ void management_echo (struct management *man, const char *string, const bool pul
void management_auth_failure (struct management *man, const char *type, const char *reason);
/*
* Echo an authentication token to management interface
*/
void management_auth_token (struct management *man, const char *token);
/*
* These functions drive the bytecount in/out counters.
*/

44
misc.c
View file

@ -1713,6 +1713,16 @@ purge_user_pass (struct user_pass *up, const bool force)
}
}
void
set_auth_token (struct user_pass *up, const char *token)
{
if (token && strlen(token) && up && up->defined && !up->nocache)
{
CLEAR (up->password);
strncpynt (up->password, token, USER_PASS_LEN);
}
}
/*
* Process string received by untrusted peer before
* printing to console or log file.
@ -2381,3 +2391,37 @@ openvpn_basename (const char *path)
}
return NULL;
}
/*
* Remove SESS_ID_x strings (i.e. auth tokens) from control message
* strings so that they will not be output to log file.
*/
const char *
sanitize_control_message(const char *str, struct gc_arena *gc)
{
char *ret = gc_malloc (strlen(str)+1, false, gc);
char *cp = ret;
bool redact = false;
strcpy(ret, str);
for (;;)
{
const char c = *cp;
if (c == '\0')
break;
if (c == 'S' && !strncmp(cp, "SESS_ID_", 8))
{
cp += 7;
redact = true;
}
else
{
if (c == ',') /* end of session id? */
redact = false;
if (redact)
*cp = '_';
}
++cp;
}
return ret;
}

4
misc.h
View file

@ -316,6 +316,8 @@ void fail_user_pass (const char *prefix,
void purge_user_pass (struct user_pass *up, const bool force);
void set_auth_token (struct user_pass *up, const char *token);
/*
* Process string received by untrusted peer before
* printing to console or log file.
@ -337,6 +339,8 @@ void openvpn_sleep (const int n);
void configure_path (void);
const char *sanitize_control_message(const char *str, struct gc_arena *gc);
#if AUTO_USERID
void get_user_pass_auto_userid (struct user_pass *up, const char *tag);
#endif

10
multi.c
View file

@ -626,7 +626,7 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
perf_push (PERF_MULTI_CREATE_INSTANCE);
msg (D_MULTI_LOW, "MULTI: multi_create_instance called");
msg (D_MULTI_MEDIUM, "MULTI: multi_create_instance called");
ALLOC_OBJ_CLEAR (mi, struct multi_instance);
@ -1237,6 +1237,9 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
mi->context.c2.push_ifconfig_defined = true;
mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
#ifdef ENABLE_CLIENT_NAT
mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias;
#endif
/* the current implementation does not allow "static IPv4, pool IPv6",
* (see below) so issue a warning if that happens - don't break the
@ -2650,13 +2653,14 @@ lookup_by_cid (struct multi_context *m, const unsigned long cid)
}
static bool
management_kill_by_cid (void *arg, const unsigned long cid)
management_kill_by_cid (void *arg, const unsigned long cid, const char *kill_msg)
{
struct multi_context *m = (struct multi_context *) arg;
struct multi_instance *mi = lookup_by_cid (m, cid);
if (mi)
{
send_restart (&mi->context); /* was: multi_signal_instance (m, mi, SIGTERM); */
send_restart (&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */
multi_schedule_context_wakeup(m, mi);
return true;
}
else

106
openvpn.8
View file

@ -1083,6 +1083,31 @@ and
.B \-\-route-gateway.
.\"*********************************************************
.TP
.B \-\-client-nat snat|dnat network netmask alias
This pushable client option sets up a stateless one-to-one NAT
rule on packet addresses (not ports), and is useful in cases
where routes or ifconfig settings pushed to the client would
create an IP numbering conflict.
.B network/netmask
(for example 192.168.0.0/255.255.0.0)
defines the local view of a resource from the client perspective, while
.B alias/netmask
(for example 10.64.0.0/255.255.0.0)
defines the remote view from the server perspective.
Use
.B snat
(source NAT) for resources owned by the client and
.B dnat
(destination NAT) for remote resources.
Set
.B \-\-verb 6
for debugging info showing the transformation of src/dest
addresses in packets.
.\"*********************************************************
.TP
.B \-\-redirect-gateway flags...
(Experimental) Automatically execute routing commands to cause all outgoing IP traffic
to be redirected over the VPN.
@ -2406,6 +2431,11 @@ lines of log file history for usage
by the management channel.
.\"*********************************************************
.TP
.B \-\-management-up-down
Report tunnel up/down events to management interface.
.B
.\"*********************************************************
.TP
.B \-\-management-client-auth
Gives management interface client the responsibility
to authenticate clients after their client certificate
@ -2740,7 +2770,7 @@ This option is deprecated, and should be replaced with
which is functionally equivalent.
.\"*********************************************************
.TP
.B \-\-ifconfig-push local remote-netmask
.B \-\-ifconfig-push local remote-netmask [alias]
Push virtual IP endpoints for client tunnel,
overriding the \-\-ifconfig-pool dynamic allocation.
@ -2759,6 +2789,15 @@ are from the perspective of the client, not the server. They may be
DNS names rather than IP addresses, in which case they will be resolved
on the server at the time of client connection.
The optional
.B alias
parameter may be used in cases where NAT causes the client view
of its local endpoint to differ from the server view. In this case
.B local/remote-netmask
will refer to the server view while
.B alias/remote-netmask
will refer to the client view.
This option must be associated with a specific client instance,
which means that it must be specified either in a client
instance config file using
@ -3259,7 +3298,7 @@ disable the remapping feature. Don't use this option unless you
know what you are doing!
.\"*********************************************************
.TP
.B \-\-port-share host port
.B \-\-port-share host port [dir]
When run in TCP server mode, share the OpenVPN port with
another application, such as an HTTPS server. If OpenVPN
senses a connection to its port which is using a non-OpenVPN
@ -3269,6 +3308,16 @@ Currently only designed to work with HTTP/HTTPS,
though it would be theoretically possible to extend to
other protocols such as ssh.
.B dir
specifies an optional directory where a temporary file with name N
containing content C will be dynamically generated for each proxy
connection, where N is the source IP:port of the client connection
and C is the source IP:port of the connection to the proxy
receiver. This directory can be used as a dictionary by
the proxy receiver to determine the origin of the connection.
Each generated file will be automatically deleted when the proxied
connection is torn down.
Not implemented on Windows.
.\"*********************************************************
.SS Client Mode
@ -3902,6 +3951,22 @@ that for certificate authority functions, you must set up the files
).
.\"*********************************************************
.TP
.B \-\-extra-certs file
Specify a
.B file
containing one or more PEM certs (concatenated together)
that complete the
local certificate chain.
This option is useful for "split" CAs, where the CA for server
certs is different than the CA for client certs. Putting certs
in this file allows them to be used to complete the local
certificate chain without trusting them to verify the peer-submitted
certificate, as would be the case if the certs were placed in the
.B ca
file.
.\"*********************************************************
.TP
.B \-\-key file
Local peer's private key in .pem format. Use the private key which was generated
when you built your peer's certificate (see
@ -3918,6 +3983,17 @@ and
.B \-\-key.
.\"*********************************************************
.TP
.B \-\-verify-hash hash
Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the
CA (or intermediate cert) that signs the leaf certificate, and is
one removed from the leaf certificate in the direction of the root.
When accepting a connection from a peer, the level-1 cert
fingerprint must match
.B hash
or certificate verification will fail. Hash is specified
as XX:XX:... For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
.\"*********************************************************
.TP
.B \-\-pkcs11-cert-private [0|1]...
Set if access to certificate object should be performed after login.
Every provider has its own setting.
@ -4347,7 +4423,7 @@ additional parameters passed as environmental variables.
.TP
.B \-\-tls-export-cert directory
Store the certificates the clients uses upon connection to this
directory. This will be done before --tls-verify is called. The
directory. This will be done before \-\-tls-verify is called. The
certificates will use a temporary name and will be deleted when
the tls-verify script returns. The file name used for the certificate
is available via the peer_cert environment variable.
@ -4387,6 +4463,18 @@ works in a
environment too.
.\"*********************************************************
.TP
.B \-\-x509-track attribute
Save peer X509
.B attribute
value in environment for use by plugins and management interface.
Prepend a '+' to
.B attribute
to save values from full cert chain. Values will be encoded
as X509_<depth>_<attribute>=<value>. Multiple
.B \-\-x509-track
options can be defined to track multiple attributes.
.\"*********************************************************
.TP
.B \-\-ns-cert-type client|server
Require that peer certificate was signed with an explicit
.B nsCertType
@ -4472,7 +4560,7 @@ or
.B \-\-tls-verify.
.\"*********************************************************
.TP
.B \-\-crl-verify crl
.B \-\-crl-verify crl ['dir']
Check peer certificate against the file
.B crl
in PEM format.
@ -4488,6 +4576,16 @@ overall integrity of the PKI.
The only time when it would be necessary to rebuild the entire PKI from scratch would be
if the root certificate key itself was compromised.
If the optional
.B dir
flag is specified, enable a different mode where
.B crl
is a directory containing files named as revoked serial numbers
(the files may be empty, the contents are never read). If a client
requests a connection, where the client certificate serial number
(decimal string) is the name of a file present in the directory,
it will be rejected.
.\"*********************************************************
.SS SSL Library information:
.\"*********************************************************

View file

@ -417,8 +417,12 @@ struct context_2
/* --ifconfig endpoints to be pushed to client */
bool push_reply_deferred;
bool push_ifconfig_defined;
bool sent_push_reply;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
#ifdef ENABLE_CLIENT_NAT
in_addr_t push_ifconfig_local_alias;
#endif
bool push_ifconfig_ipv6_defined;
struct in6_addr push_ifconfig_ipv6_local;
@ -435,6 +439,7 @@ struct context_2
#endif
struct event_timeout push_request_interval;
int n_sent_push_requests;
bool did_pre_pull_restore;
/* hash of pulled options, so we can compare when options change */

143
options.c
View file

@ -223,6 +223,9 @@ static const char usage_message[] =
" Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
"--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
" the default gateway. Useful when pushing private subnets.\n"
#ifdef ENABLE_CLIENT_NAT
"--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n"
#endif
#ifdef ENABLE_PUSH_PEER_INFO
"--push-peer-info : (client only) push client info to server.\n"
#endif
@ -359,6 +362,7 @@ static const char usage_message[] =
"--management-signal : Issue SIGUSR1 when management disconnect event occurs.\n"
"--management-forget-disconnect : Forget passwords when management disconnect\n"
" event occurs.\n"
"--management-up-down : Report tunnel up/down events to management interface.\n"
"--management-log-cache n : Cache n lines of log file history for usage\n"
" by the management channel.\n"
#if UNIX_SOCK_SUPPORT
@ -448,8 +452,9 @@ static const char usage_message[] =
"--max-clients n : Allow a maximum of n simultaneously connected clients.\n"
"--max-routes-per-client n : Allow a maximum of n internal routes per client.\n"
#if PORT_SHARE
"--port-share host port : When run in TCP mode, proxy incoming HTTPS sessions\n"
" to a web server at host:port.\n"
"--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n"
" sessions to a web server at host:port. dir specifies an\n"
" optional directory to write origin IP:port data.\n"
#endif
#endif
"\n"
@ -527,6 +532,7 @@ static const char usage_message[] =
" Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n"
"--cert file : Local certificate in .pem format -- must be signed\n"
" by a Certificate Authority in --ca file.\n"
"--extra-certs file : one or more PEM certs that complete the cert chain.\n"
"--key file : Local private key in .pem format.\n"
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
@ -534,6 +540,7 @@ static const char usage_message[] =
"--x509-username-field : Field used in x509 certificat to be username.\n"
" Default is CN.\n"
#endif
"--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n"
#ifdef WIN32
"--cryptoapicert select-string : Load the certificate and private key from the\n"
" Windows Certificate System Store.\n"
@ -558,7 +565,7 @@ static const char usage_message[] =
" see --secret option for more info.\n"
"--askpass [file]: Get PEM password from controlling tty before we daemonize.\n"
"--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n"
"--crl-verify crl: Check peer certificate against a CRL.\n"
"--crl-verify crl ['dir']: Check peer certificate against a CRL.\n"
"--tls-verify cmd: Execute shell command cmd to verify the X509 name of a\n"
" pending TLS connection that has otherwise passed all other\n"
" tests of certification. cmd should return 0 to allow\n"
@ -572,6 +579,8 @@ static const char usage_message[] =
" of verification.\n"
"--ns-cert-type t: Require that peer certificate was signed with an explicit\n"
" nsCertType designation t = 'client' | 'server'.\n"
"--x509-track x : Save peer X509 attribute x in environment for use by\n"
" plugins and management interface.\n"
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
"--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
" explicit key usage, you can specify more than one value.\n"
@ -1000,6 +1009,40 @@ is_stateful_restart (const struct options *o)
return is_persist_option (o) || connection_list_defined (o);
}
#ifdef USE_SSL
static uint8_t *
parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_arena *gc)
{
int i;
const char *cp = str;
uint8_t *ret = (uint8_t *) gc_malloc (nbytes, true, gc);
char term = 1;
int byte;
char bs[3];
for (i = 0; i < nbytes; ++i)
{
if (strlen(cp) < 2)
msg (msglevel, "format error in hash fingerprint: %s", str);
bs[0] = *cp++;
bs[1] = *cp++;
bs[2] = 0;
byte = 0;
if (sscanf(bs, "%x", &byte) != 1)
msg (msglevel, "format error in hash fingerprint hex byte: %s", str);
ret[i] = (uint8_t)byte;
term = *cp++;
if (term != ':' && term != 0)
msg (msglevel, "format error in hash fingerprint delimiter: %s", str);
if (term == 0)
break;
}
if (term != 0 || i != nbytes-1)
msg (msglevel, "hash fingerprint is different length than expected (%d bytes): %s", nbytes, str);
return ret;
}
#endif
#ifdef WIN32
#ifdef ENABLE_DEBUG
@ -1133,7 +1176,6 @@ show_p2mp_parms (const struct options *o)
SHOW_INT (max_routes_per_client);
SHOW_STR (auth_user_pass_verify_script);
SHOW_BOOL (auth_user_pass_verify_script_via_file);
SHOW_INT (ssl_flags);
#if PORT_SHARE
SHOW_STR (port_share_host);
SHOW_INT (port_share_port);
@ -1223,6 +1265,9 @@ options_detach (struct options *o)
{
gc_detach (&o->gc);
o->routes = NULL;
#ifdef ENABLE_CLIENT_NAT
o->client_nat = NULL;
#endif
#if P2MP_SERVER
clone_push_list(o);
#endif
@ -1242,6 +1287,15 @@ rol6_check_alloc (struct options *options)
options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
}
#ifdef ENABLE_CLIENT_NAT
static void
cnol_check_alloc (struct options *options)
{
if (!options->client_nat)
options->client_nat = new_client_nat_list (&options->gc);
}
#endif
#ifdef ENABLE_DEBUG
static void
show_connection_entry (const struct connection_entry *o)
@ -1435,6 +1489,11 @@ show_settings (const struct options *o)
SHOW_BOOL (allow_pull_fqdn);
if (o->routes)
print_route_options (o->routes, D_SHOW_PARMS);
#ifdef ENABLE_CLIENT_NAT
if (o->client_nat)
print_client_nat_list(o->client_nat, D_SHOW_PARMS);
#endif
#ifdef ENABLE_MANAGEMENT
SHOW_STR (management_addr);
@ -1496,6 +1555,7 @@ show_settings (const struct options *o)
SHOW_INT (remote_cert_ku[i]);
}
SHOW_STR (remote_cert_eku);
SHOW_INT (ssl_flags);
SHOW_INT (tls_timeout);
@ -2548,6 +2608,13 @@ pre_pull_save (struct options *o)
o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc);
o->pre_pull->routes_defined = true;
}
#ifdef ENABLE_CLIENT_NAT
if (o->client_nat)
{
o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc);
o->pre_pull->client_nat_defined = true;
}
#endif
}
}
@ -2569,6 +2636,16 @@ pre_pull_restore (struct options *o)
else
o->routes = NULL;
#ifdef ENABLE_CLIENT_NAT
if (pp->client_nat_defined)
{
cnol_check_alloc (o);
copy_client_nat_option_list (o->client_nat, pp->client_nat);
}
else
o->client_nat = NULL;
#endif
o->foreign_option_index = pp->foreign_option_index;
}
@ -3865,6 +3942,11 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_FORGET_DISCONNECT;
}
else if (streq (p[0], "management-up-down"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_UP_DOWN;
}
else if (streq (p[0], "management-client"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@ -3886,6 +3968,13 @@ add_option (struct options *options,
options->management_flags |= MF_CLIENT_AUTH;
}
#endif
#ifdef ENABLE_X509_TRACK
else if (streq (p[0], "x509-track") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
x509_track_add (&options->x509_track, p[1], msglevel, &options->gc);
}
#endif
#ifdef MANAGEMENT_PF
else if (streq (p[0], "management-client-pf"))
{
@ -4792,6 +4881,14 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_PERSIST_IP);
options->persist_remote_ip = true;
}
#ifdef ENABLE_CLIENT_NAT
else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
cnol_check_alloc (options);
add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel);
}
#endif
else if (streq (p[0], "route") && p[1])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
@ -4958,6 +5055,12 @@ add_option (struct options *options,
msg (msglevel, "this is a generic configuration and cannot directly be used");
goto err;
}
#ifdef ENABLE_PUSH_PEER_INFO
else if (streq (p[1], "PUSH_PEER_INFO"))
{
options->push_peer_info = true;
}
#endif
#if P2MP
else if (streq (p[1], "SERVER_POLL_TIMEOUT") && p[2])
{
@ -5352,6 +5455,7 @@ add_option (struct options *options,
options->port_share_host = p[1];
options->port_share_port = port;
options->port_share_journal_dir = p[3];
}
#endif
else if (streq (p[0], "client-to-client"))
@ -5392,6 +5496,10 @@ add_option (struct options *options,
options->push_ifconfig_defined = true;
options->push_ifconfig_local = local;
options->push_ifconfig_remote_netmask = remote_netmask;
#ifdef ENABLE_CLIENT_NAT
if (p[3])
options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL);
#endif
}
else
{
@ -6051,6 +6159,22 @@ add_option (struct options *options,
}
#endif
}
else if (streq (p[0], "extra-certs") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->extra_certs_file = p[1];
#if ENABLE_INLINE_FILES
if (streq (p[1], INLINE_FILE_TAG) && p[2])
{
options->extra_certs_file_inline = p[2];
}
#endif
}
else if (streq (p[0], "verify-hash") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc);
}
#ifdef WIN32
else if (streq (p[0], "cryptoapicert") && p[1])
{
@ -6095,6 +6219,15 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
ssl_set_auth_nocache ();
}
else if (streq (p[0], "auth-token") && p[1])
{
VERIFY_PERMISSION (OPT_P_ECHO);
ssl_set_auth_token(p[1]);
#ifdef ENABLE_MANAGEMENT
if (management)
management_auth_token (management, p[1]);
#endif
}
else if (streq (p[0], "single-session"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@ -6120,6 +6253,8 @@ add_option (struct options *options,
else if (streq (p[0], "crl-verify") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[2] && streq(p[2], "dir"))
options->ssl_flags |= SSLF_CRL_VERIFY_DIR;
options->crl_file = p[1];
}
else if (streq (p[0], "tls-verify") && p[1])

View file

@ -41,6 +41,7 @@
#include "proxy.h"
#include "lzo.h"
#include "pushlist.h"
#include "clinat.h"
/*
* Maximum number of parameters associated with an option,
@ -67,6 +68,11 @@ struct options_pre_pull
bool routes_defined;
struct route_option_list *routes;
#ifdef ENABLE_CLIENT_NAT
bool client_nat_defined;
struct client_nat_option_list *client_nat;
#endif
int foreign_option_index;
};
@ -334,6 +340,10 @@ struct options
bool route_gateway_via_dhcp;
bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
#ifdef ENABLE_CLIENT_NAT
struct client_nat_option_list *client_nat;
#endif
#ifdef ENABLE_OCC
/* Enable options consistency check between peers */
bool occ;
@ -410,6 +420,9 @@ struct options
bool push_ifconfig_defined;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
#ifdef ENABLE_CLIENT_NAT
in_addr_t push_ifconfig_local_alias;
#endif
bool push_ifconfig_constraint_defined;
in_addr_t push_ifconfig_constraint_network;
in_addr_t push_ifconfig_constraint_netmask;
@ -426,10 +439,10 @@ struct options
const char *auth_user_pass_verify_script;
bool auth_user_pass_verify_script_via_file;
unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */
#if PORT_SHARE
char *port_share_host;
int port_share_port;
const char *port_share_journal_dir;
#endif
#endif
@ -476,6 +489,7 @@ struct options
const char *ca_path;
const char *dh_file;
const char *cert_file;
const char *extra_certs_file;
const char *priv_key_file;
const char *pkcs12_file;
const char *cipher_list;
@ -487,6 +501,7 @@ struct options
#if ENABLE_INLINE_FILES
const char *ca_file_inline;
const char *cert_file_inline;
const char *extra_certs_file_inline;
char *priv_key_file_inline;
const char *dh_file_inline;
const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */
@ -495,6 +510,8 @@ struct options
int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
uint8_t *verify_hash;
unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */
#ifdef ENABLE_PKCS11
const char *pkcs11_providers[MAX_PARMS];
@ -551,6 +568,10 @@ struct options
#endif /* USE_SSL */
#endif /* USE_CRYPTO */
#ifdef ENABLE_X509_TRACK
const struct x509_track *x509_track;
#endif
/* special state parms */
int foreign_option_index;

View file

@ -41,6 +41,8 @@
#include "memdbg.h"
/* #define PID_SIMULATE_BACKTRACK */
/*
* Special time_t value that indicates that
* sequence number has expired.
@ -48,17 +50,39 @@
#define SEQ_UNSEEN ((time_t)0)
#define SEQ_EXPIRED ((time_t)1)
void
packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack)
static void packet_id_debug_print (int msglevel,
const struct packet_id_rec *p,
const struct packet_id_net *pin,
const char *message,
int value);
static inline void
packet_id_debug (int msglevel,
const struct packet_id_rec *p,
const struct packet_id_net *pin,
const char *message,
int value)
{
dmsg (D_PID_DEBUG_LOW, "PID packet_id_init seq_backtrack=%d time_backtrack=%d",
seq_backtrack,
time_backtrack);
#ifdef ENABLE_DEBUG
if (unlikely(check_debug_level(msglevel)))
packet_id_debug_print (msglevel, p, pin, message, value);
#endif
}
void
packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit)
{
dmsg (D_PID_DEBUG, "PID packet_id_init tcp_mode=%d seq_backtrack=%d time_backtrack=%d",
tcp_mode,
seq_backtrack,
time_backtrack);
ASSERT (p);
CLEAR (*p);
if (seq_backtrack)
p->rec.name = name;
p->rec.unit = unit;
if (seq_backtrack && !tcp_mode)
{
ASSERT (MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK);
ASSERT (MIN_TIME_BACKTRACK <= time_backtrack && time_backtrack <= MAX_TIME_BACKTRACK);
@ -74,7 +98,7 @@ packet_id_free (struct packet_id *p)
{
if (p)
{
dmsg (D_PID_DEBUG_LOW, "PID packet_id_free");
dmsg (D_PID_DEBUG, "PID packet_id_free");
if (p->rec.seq_list)
free (p->rec.seq_list);
CLEAR (*p);
@ -105,7 +129,11 @@ packet_id_add (struct packet_id_rec *p, const struct packet_id_net *pin)
CIRC_LIST_RESET (p->seq_list);
}
while (p->id < pin->id)
while (p->id < pin->id
#ifdef PID_SIMULATE_BACKTRACK
|| (get_random() % 64) < 31
#endif
)
{
CIRC_LIST_PUSH (p->seq_list, SEQ_UNSEEN);
++p->id;
@ -155,17 +183,13 @@ packet_id_reap (struct packet_id_rec *p)
* it is a replay.
*/
bool
packet_id_test (const struct packet_id_rec *p,
packet_id_test (struct packet_id_rec *p,
const struct packet_id_net *pin)
{
static int max_backtrack_stat;
packet_id_type diff;
dmsg (D_PID_DEBUG,
"PID TEST " time_format ":" packet_id_format " " time_format ":" packet_id_format "",
(time_type)p->time, (packet_id_print_type)p->id, (time_type)pin->time,
(packet_id_print_type)pin->id);
packet_id_debug (D_PID_DEBUG, p, pin, "PID_TEST", 0);
ASSERT (p->initialized);
if (!pin->id)
@ -189,19 +213,35 @@ packet_id_test (const struct packet_id_rec *p,
diff = p->id - pin->id;
/* keep track of maximum backtrack seen for debugging purposes */
if ((int)diff > max_backtrack_stat)
if ((int)diff > p->max_backtrack_stat)
{
max_backtrack_stat = (int)diff;
msg (D_BACKTRACK, "Replay-window backtrack occurred [%d]", max_backtrack_stat);
p->max_backtrack_stat = (int)diff;
packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR replay-window backtrack occurred", p->max_backtrack_stat);
}
if (diff >= (packet_id_type) CIRC_LIST_SIZE (p->seq_list))
return false;
{
packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR large diff", diff);
return false;
}
return CIRC_LIST_ITEM (p->seq_list, diff) == 0;
{
const time_t v = CIRC_LIST_ITEM (p->seq_list, diff);
if (v == 0)
return true;
else
{
/* might want to increase this to D_PID_DEBUG_MEDIUM (or even D_PID_DEBUG) in the future */
packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR replay", diff);
return false;
}
}
}
else if (pin->time < p->time) /* if time goes back, reject */
return false;
{
packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR time backtrack", 0);
return false;
}
else /* time moved forward */
return true;
}
@ -434,6 +474,76 @@ packet_id_persist_print (const struct packet_id_persist *p, struct gc_arena *gc)
return (char *)out.data;
}
#ifdef ENABLE_DEBUG
static void
packet_id_debug_print (int msglevel,
const struct packet_id_rec *p,
const struct packet_id_net *pin,
const char *message,
int value)
{
struct gc_arena gc = gc_new ();
struct buffer out = alloc_buf_gc (256, &gc);
struct timeval tv;
const time_t prev_now = now;
const struct seq_list *sl = p->seq_list;
int i;
CLEAR (tv);
gettimeofday (&tv, NULL);
buf_printf (&out, "%s [%d]", message, value);
buf_printf (&out, " [%s-%d] [", p->name, p->unit);
for (i = 0; i < sl->x_size; ++i)
{
char c;
time_t v;
int diff;
v = CIRC_LIST_ITEM(sl, i);
if (v == SEQ_UNSEEN)
c = '_';
else if (v == SEQ_EXPIRED)
c = 'E';
else
{
diff = (int) prev_now - v;
if (diff < 0)
c = 'N';
else if (diff < 10)
c = '0' + diff;
else
c = '>';
}
buf_printf(&out, "%c", c);
}
buf_printf (&out, "] " time_format ":" packet_id_format, (time_type)p->time, (packet_id_print_type)p->id);
if (pin)
buf_printf (&out, " " time_format ":" packet_id_format, (time_type)pin->time, (packet_id_print_type)pin->id);
buf_printf (&out, " t=" time_format "[%d]",
(time_type)prev_now,
(int)(prev_now - tv.tv_sec));
buf_printf (&out, " r=[%d,%d,%d,%d,%d]",
(int)(p->last_reap - tv.tv_sec),
p->seq_backtrack,
p->time_backtrack,
p->max_backtrack_stat,
(int)p->initialized);
buf_printf (&out, " sl=[%d,%d,%d,%d]",
sl->x_head,
sl->x_size,
sl->x_cap,
sl->x_sizeof);
msg (msglevel, "%s", BSTR(&out));
gc_free (&gc);
}
#endif
#ifdef PID_TEST
void

View file

@ -138,8 +138,11 @@ struct packet_id_rec
packet_id_type id; /* highest sequence number received */
int seq_backtrack; /* set from --replay-window */
int time_backtrack; /* set from --replay-window */
int max_backtrack_stat; /* maximum backtrack seen so far */
bool initialized; /* true if packet_id_init was called */
struct seq_list *seq_list; /* packet-id "memory" */
const char *name;
int unit;
};
/*
@ -207,11 +210,11 @@ struct packet_id
struct packet_id_rec rec;
};
void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack);
void packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit);
void packet_id_free (struct packet_id *p);
/* should we accept an incoming packet id ? */
bool packet_id_test (const struct packet_id_rec *p,
bool packet_id_test (struct packet_id_rec *p,
const struct packet_id_net *pin);
/* change our current state to reflect an accepted packet id */

37
proto.h
View file

@ -164,6 +164,14 @@ struct openvpn_tcphdr {
#define OPENVPN_TCPOPT_MAXSEG 2
#define OPENVPN_TCPOLEN_MAXSEG 4
struct ip_tcp_udp_hdr {
struct openvpn_iphdr ip;
union {
struct openvpn_tcphdr tcp;
struct openvpn_udphdr udp;
} u;
};
#pragma pack()
/*
@ -175,19 +183,30 @@ struct openvpn_tcphdr {
* is the checksum value to be updated.
*/
#define ADJUST_CHECKSUM(acc, cksum) { \
(acc) += (cksum); \
if ((acc) < 0) { \
(acc) = -(acc); \
(acc) = ((acc) >> 16) + ((acc) & 0xffff); \
(acc) += (acc) >> 16; \
(cksum) = (uint16_t) ~(acc); \
int _acc = acc; \
_acc += (cksum); \
if (_acc < 0) { \
_acc = -_acc; \
_acc = (_acc >> 16) + (_acc & 0xffff); \
_acc += _acc >> 16; \
(cksum) = (uint16_t) ~_acc; \
} else { \
(acc) = ((acc) >> 16) + ((acc) & 0xffff); \
(acc) += (acc) >> 16; \
(cksum) = (uint16_t) (acc); \
_acc = (_acc >> 16) + (_acc & 0xffff); \
_acc += _acc >> 16; \
(cksum) = (uint16_t) _acc; \
} \
}
#define ADD_CHECKSUM_32(acc, u32) { \
acc += (u32) & 0xffff; \
acc += (u32) >> 16; \
}
#define SUB_CHECKSUM_32(acc, u32) { \
acc -= (u32) & 0xffff; \
acc -= (u32) >> 16; \
}
/*
* We are in a "liberal" position with respect to MSS,
* i.e. we assume that MSS can be calculated from MTU

116
ps.c
View file

@ -69,6 +69,7 @@ struct proxy_connection {
bool buffer_initial;
int rwflags;
int sd;
char *jfn;
};
#if 0
@ -226,7 +227,9 @@ port_share_sendmsg (const socket_descriptor_t sd,
status = sendmsg (sd, &mesg, MSG_NOSIGNAL);
if (status == -1)
msg (M_WARN, "PORT SHARE: sendmsg failed (unable to communicate with background process)");
msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE: sendmsg failed -- unable to communicate with background process (%d,%d,%d,%d)",
sd, sd_send, sd_null[0], sd_null[1]
);
close_socket_if_defined (sd_null[0]);
close_socket_if_defined (sd_null[1]);
@ -261,6 +264,12 @@ proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es)
pc->buffer_initial = false;
pc->rwflags = 0;
pc->defined = false;
if (pc->jfn)
{
unlink (pc->jfn);
free (pc->jfn);
pc->jfn = NULL;
}
if (cp && cp->defined && cp->counterpart == pc)
proxy_entry_mark_for_close (cp, es);
}
@ -296,6 +305,48 @@ proxy_list_housekeeping (struct proxy_connection **list)
}
}
/*
* Record IP/port of client in filesystem, so that server receiving
* the proxy can determine true client origin.
*/
static void
journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp)
{
struct gc_arena gc = gc_new ();
struct openvpn_sockaddr from, to;
socklen_t slen, dlen;
int fnlen;
char *jfn;
int fd;
slen = sizeof(from.sa);
dlen = sizeof(to.sa);
if (!getpeername (pc->sd, (struct sockaddr *) &from.sa, &slen)
&& !getsockname (cp->sd, (struct sockaddr *) &to.sa, &dlen))
{
const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc);
const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc);
fnlen = strlen(journal_dir) + strlen(t) + 2;
jfn = (char *) malloc(fnlen);
check_malloc_return (jfn);
openvpn_snprintf (jfn, fnlen, "%s/%s", journal_dir, t);
dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f);
fd = open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd != -1)
{
write(fd, f, strlen(f));
close (fd);
cp->jfn = jfn;
}
else
{
msg (M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn);
free (jfn);
}
}
gc_free (&gc);
}
/*
* Cleanup function, on proxy process exit.
*/
@ -349,7 +400,8 @@ proxy_entry_new (struct proxy_connection **list,
const in_addr_t server_addr,
const int server_port,
const socket_descriptor_t sd_client,
struct buffer *initial_data)
struct buffer *initial_data,
const char *journal_dir)
{
struct openvpn_sockaddr osaddr;
socket_descriptor_t sd_server;
@ -359,7 +411,11 @@ proxy_entry_new (struct proxy_connection **list,
/* connect to port share server */
sock_addr_set (&osaddr, server_addr, server_port);
sd_server = create_socket_tcp ();
if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE PROXY: cannot create socket");
return false;
}
status = openvpn_connect (sd_server, &osaddr, 5, NULL);
if (status)
{
@ -396,6 +452,10 @@ proxy_entry_new (struct proxy_connection **list,
/* add to list */
*list = pc;
/* add journal entry */
if (journal_dir)
journal_add (journal_dir, pc, cp);
dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: NEW CONNECTION [c=%d s=%d]", (int)sd_client, (int)sd_server);
@ -417,9 +477,14 @@ control_message_from_parent (const socket_descriptor_t sd_control,
struct proxy_connection **list,
struct event_set *es,
const in_addr_t server_addr,
const int server_port)
const int server_port,
const int max_initial_buf,
const char *journal_dir)
{
struct buffer buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
/* this buffer needs to be large enough to handle the largest buffer
that might be returned by the link_socket_read call in read_incoming_link. */
struct buffer buf = alloc_buf (max_initial_buf);
struct msghdr mesg;
struct cmsghdr* h;
struct iovec iov[2];
@ -455,7 +520,7 @@ control_message_from_parent (const socket_descriptor_t sd_control,
|| h->cmsg_level != SOL_SOCKET
|| h->cmsg_type != SCM_RIGHTS )
{
ret = false;
msg (M_WARN, "PORT SHARE PROXY: received unknown message");
}
else
{
@ -470,7 +535,8 @@ control_message_from_parent (const socket_descriptor_t sd_control,
server_addr,
server_port,
received_fd,
&buf))
&buf,
journal_dir))
{
CLEAR (buf); /* we gave the buffer to proxy_entry_new */
}
@ -505,6 +571,7 @@ proxy_connection_io_recv (struct proxy_connection *pc)
{
if (!status)
return IOSTAT_READ_ERROR;
dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: read[%d] %d", (int)pc->sd, status);
pc->buf.len = status;
}
return IOSTAT_GOOD;
@ -532,7 +599,7 @@ proxy_connection_io_send (struct proxy_connection *pc, int *bytes_sent)
}
else
{
/*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status);*/
dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status);
pc->buf.len = 0;
pc->buf.offset = 0;
}
@ -615,6 +682,8 @@ proxy_connection_io_dispatch (struct proxy_connection *pc,
int rwflags_pc = pc->rwflags;
int rwflags_cp = cp->rwflags;
ASSERT(pc->defined && cp->defined && cp->counterpart == pc);
if (rwflags & EVENT_READ)
{
const int status = proxy_connection_io_xfer (pc, max_transfer_per_iteration);
@ -641,7 +710,11 @@ proxy_connection_io_dispatch (struct proxy_connection *pc,
* This is the main function for the port share proxy background process.
*/
static void
port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descriptor_t sd_control)
port_share_proxy (const in_addr_t hostaddr,
const int port,
const socket_descriptor_t sd_control,
const int max_initial_buf,
const char *journal_dir)
{
if (send_control (sd_control, RESPONSE_INIT_SUCCEEDED) >= 0)
{
@ -675,7 +748,7 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip
const struct event_set_return *e = &esr[i];
if (e->arg == sd_control_marker)
{
if (!control_message_from_parent (sd_control, &list, es, hostaddr, port))
if (!control_message_from_parent (sd_control, &list, es, hostaddr, port, max_initial_buf, journal_dir))
goto done;
}
else
@ -701,7 +774,7 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip
proxy_list_close (&list);
event_free (es);
}
msg (D_PS_PROXY, "PORT SHARE PROXY: proxy exiting");
msg (M_INFO, "PORT SHARE PROXY: proxy exiting");
}
/*
@ -709,7 +782,10 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip
* share proxy.
*/
struct port_share *
port_share_open (const char *host, const int port)
port_share_open (const char *host,
const int port,
const int max_initial_buf,
const char *journal_dir)
{
pid_t pid;
socket_descriptor_t fd[2];
@ -717,6 +793,8 @@ port_share_open (const char *host, const int port)
struct port_share *ps;
ALLOC_OBJ_CLEAR (ps, struct port_share);
ps->foreground_fd = -1;
ps->background_pid = -1;
/*
* Get host's IP address
@ -758,9 +836,17 @@ port_share_open (const char *host, const int port)
status = recv_control (fd[0]);
if (status == RESPONSE_INIT_SUCCEEDED)
{
/* note that this will cause possible EAGAIN when writing to
control socket if proxy process is backlogged */
set_nonblock (fd[0]);
ps->foreground_fd = fd[0];
return ps;
}
else
{
msg (M_SOCKERR, "PORT SHARE: unexpected init recv_control status=%d", status);
}
}
else
{
@ -787,7 +873,7 @@ port_share_open (const char *host, const int port)
prng_init (NULL, 0);
/* execute the event loop */
port_share_proxy (hostaddr, port, fd[1]);
port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir);
openvpn_close_socket (fd[1]);
@ -872,7 +958,9 @@ void
port_share_redirect (struct port_share *ps, const struct buffer *head, socket_descriptor_t sd)
{
if (ps)
port_share_sendmsg (ps->foreground_fd, COMMAND_REDIRECT, head, sd);
{
port_share_sendmsg (ps->foreground_fd, COMMAND_REDIRECT, head, sd);
}
}
#endif

4
ps.h
View file

@ -44,7 +44,9 @@ struct port_share {
extern struct port_share *port_share;
struct port_share *port_share_open (const char *host,
const int port);
const int port,
const int max_initial_buf,
const char *journal_dir);
void port_share_close (struct port_share *ps);
void port_share_abort (struct port_share *ps);

97
push.c
View file

@ -42,7 +42,7 @@
void
receive_auth_failed (struct context *c, const struct buffer *buffer)
{
msg (M_VERB0, "AUTH: Received AUTH_FAILED control message");
msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer));
connection_list_set_no_advance(&c->options);
if (c->options.pull)
{
@ -52,7 +52,7 @@ receive_auth_failed (struct context *c, const struct buffer *buffer)
c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */
break;
case AR_INTERACT:
ssl_purge_auth ();
ssl_purge_auth (false);
case AR_NOINTERACT:
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */
break;
@ -87,13 +87,48 @@ receive_auth_failed (struct context *c, const struct buffer *buffer)
* Act on received restart message from server
*/
void
server_pushed_restart (struct context *c, const struct buffer *buffer)
server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv)
{
if (c->options.pull)
{
msg (D_STREAM_ERRORS, "Connection reset command was pushed by server");
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */
c->sig->signal_text = "server-pushed-connection-reset";
struct buffer buf = *buffer;
const char *m = "";
if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf))
m = BSTR (&buf);
/* preserve cached passwords? */
{
bool purge = true;
if (m[0] == '[')
{
int i;
for (i = 1; m[i] != '\0' && m[i] != ']'; ++i)
{
if (m[i] == 'P')
purge = false;
}
}
if (purge)
ssl_purge_auth (true);
}
if (restart)
{
msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m);
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */
c->sig->signal_text = "server-pushed-connection-reset";
}
else
{
msg (D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m);
c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */
c->sig->signal_text = "server-pushed-halt";
}
#ifdef ENABLE_MANAGEMENT
if (management)
management_notify (management, "info", c->sig->signal_text, m);
#endif
}
}
@ -130,10 +165,10 @@ send_auth_failed (struct context *c, const char *client_reason)
* Send restart message from server to client.
*/
void
send_restart (struct context *c)
send_restart (struct context *c, const char *kill_msg)
{
schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM);
send_control_channel_string (c, "RESTART", D_PUSH);
send_control_channel_string (c, kill_msg ? kill_msg : "RESTART", D_PUSH);
}
#endif
@ -149,7 +184,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
unsigned int option_types_found = 0;
int status;
msg (D_PUSH, "PUSH: Received control message: '%s'", BSTR (buffer));
msg (D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc));
status = process_incoming_push_msg (c,
buffer,
@ -158,7 +193,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
&option_types_found);
if (status == PUSH_MSG_ERROR)
msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (buffer));
msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc));
else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION)
{
if (status == PUSH_MSG_REPLY)
@ -172,7 +207,18 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
bool
send_push_request (struct context *c)
{
return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH);
const int max_push_requests = c->options.handshake_window / PUSH_REQUEST_INTERVAL;
if (++c->c2.n_sent_push_requests <= max_push_requests)
{
return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH);
}
else
{
msg (D_STREAM_ERRORS, "No reply from server after sending %d push requests", max_push_requests);
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */
c->sig->signal_text = "no-push-reply";
return false;
}
}
#if P2MP_SERVER
@ -185,7 +231,7 @@ send_push_reply (struct context *c)
struct push_entry *e = c->options.push_list.head;
bool multi_push = false;
static char cmd[] = "PUSH_REPLY";
const int extra = 64; /* extra space for possible trailing ifconfig and push-continuation */
const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */
const int safe_cap = BCAP (&buf) - extra;
bool push_sent = false;
@ -238,9 +284,16 @@ send_push_reply (struct context *c)
}
if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask)
buf_printf (&buf, ",ifconfig %s %s",
print_in_addr_t (c->c2.push_ifconfig_local, 0, &gc),
print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc));
{
in_addr_t ifconfig_local = c->c2.push_ifconfig_local;
#ifdef ENABLE_CLIENT_NAT
if (c->c2.push_ifconfig_local_alias)
ifconfig_local = c->c2.push_ifconfig_local_alias;
#endif
buf_printf (&buf, ",ifconfig %s %s",
print_in_addr_t (ifconfig_local, 0, &gc),
print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc));
}
if (multi_push)
buf_printf (&buf, ",push-continuation 1");
@ -359,8 +412,18 @@ process_incoming_push_msg (struct context *c,
}
else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED)
{
if (send_push_reply (c))
ret = PUSH_MSG_REQUEST;
if (c->c2.sent_push_reply)
{
ret = PUSH_MSG_ALREADY_REPLIED;
}
else
{
if (send_push_reply (c))
{
ret = PUSH_MSG_REQUEST;
c->c2.sent_push_reply = true;
}
}
}
else
{

5
push.h
View file

@ -35,6 +35,7 @@
#define PUSH_MSG_REQUEST_DEFERRED 3
#define PUSH_MSG_AUTH_FAILURE 4
#define PUSH_MSG_CONTINUATION 5
#define PUSH_MSG_ALREADY_REPLIED 6
void incoming_push_message (struct context *c,
const struct buffer *buffer);
@ -49,7 +50,7 @@ bool send_push_request (struct context *c);
void receive_auth_failed (struct context *c, const struct buffer *buffer);
void server_pushed_restart (struct context *c, const struct buffer *buffer);
void server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv);
#if P2MP_SERVER
@ -66,7 +67,7 @@ void remove_iroutes_from_push_route_list (struct options *o);
void send_auth_failed (struct context *c, const char *client_reason);
void send_restart (struct context *c);
void send_restart (struct context *c, const char *kill_msg);
#endif
#endif

163
route.c
View file

@ -2324,70 +2324,26 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/route.h>
#include <net/if_dl.h>
/* all of this is taken from <net/route.h> in Darwin */
#define RTA_DST 0x1
#define RTA_GATEWAY 0x2
#define RTA_NETMASK 0x4
#define RTM_GET 0x4
#define RTM_VERSION 5
#define RTF_UP 0x1
#define RTF_GATEWAY 0x2
/*
* These numbers are used by reliable protocols for determining
* retransmission behavior and are included in the routing structure.
*/
struct rt_metrics {
u_long rmx_locks; /* Kernel must leave these values alone */
u_long rmx_mtu; /* MTU for this path */
u_long rmx_hopcount; /* max hops expected */
u_long rmx_expire; /* lifetime for route, e.g. redirect */
u_long rmx_recvpipe; /* inbound delay-bandwidth product */
u_long rmx_sendpipe; /* outbound delay-bandwidth product */
u_long rmx_ssthresh; /* outbound gateway buffer limit */
u_long rmx_rtt; /* estimated round trip time */
u_long rmx_rttvar; /* estimated rtt variance */
u_long rmx_pksent; /* packets sent using this route */
u_long rmx_filler[4]; /* will be used for T/TCP later */
};
/*
* Structures for routing messages.
*/
struct rt_msghdr {
u_short rtm_msglen; /* to skip over non-understood messages */
u_char rtm_version; /* future binary compatibility */
u_char rtm_type; /* message type */
u_short rtm_index; /* index for associated ifp */
int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
int rtm_addrs; /* bitmask identifying sockaddrs in msg */
pid_t rtm_pid; /* identify sender */
int rtm_seq; /* for sender to identify action */
int rtm_errno; /* why failed */
int rtm_use; /* from rtentry */
u_long rtm_inits; /* which metrics we are initializing */
struct rt_metrics rtm_rmx; /* metrics themselves */
};
struct {
struct rtmsg {
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
};
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
bool
get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
static bool
get_default_gateway_ex (in_addr_t *ret, in_addr_t *netmask, char **ifname)
{
struct gc_arena gc = gc_new ();
struct rtmsg m_rtmsg;
int s, seq, l, pid, rtm_addrs, i;
struct sockaddr so_dst, so_mask;
char *cp = m_rtmsg.m_space;
struct sockaddr *gate = NULL, *sa;
struct sockaddr *gate = NULL, *ifp = NULL, *sa;
struct rt_msghdr *rtm_aux;
#define NEXTADDR(w, u) \
@ -2401,8 +2357,9 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
pid = getpid();
seq = 0;
rtm_addrs = RTA_DST | RTA_NETMASK;
rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP;
bzero(&m_rtmsg, sizeof(m_rtmsg));
bzero(&so_dst, sizeof(so_dst));
bzero(&so_mask, sizeof(so_mask));
bzero(&rtm, sizeof(struct rt_msghdr));
@ -2444,11 +2401,16 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
cp = ((char *)(rtm_aux + 1));
if (rtm_aux->rtm_addrs) {
for (i = 1; i; i <<= 1)
if (i & rtm_aux->rtm_addrs) {
sa = (struct sockaddr *)cp;
if (i == RTA_GATEWAY )
gate = sa;
ADVANCE(cp, sa);
{
if (i & rtm_aux->rtm_addrs)
{
sa = (struct sockaddr *)cp;
if (i == RTA_GATEWAY )
gate = sa;
else if (i == RTA_IFP)
ifp = sa;
ADVANCE(cp, sa);
}
}
}
else
@ -2471,6 +2433,16 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
*netmask = 0xFFFFFF00; // FIXME -- get the real netmask of the adapter containing the default gateway
}
if (ifp && ifname)
{
struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp;
char *name = malloc(adl->sdl_nlen+1);
check_malloc_return(name);
memcpy(name, adl->sdl_data, adl->sdl_nlen);
name[adl->sdl_nlen] = '\0';
*ifname = name;
}
gc_free (&gc);
return true;
}
@ -2481,6 +2453,12 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
}
}
bool
get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
{
return get_default_gateway_ex(ret, netmask, NULL);
}
#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
#include <sys/types.h>
@ -2896,6 +2874,73 @@ get_default_gateway_mac_addr (unsigned char *macaddr)
return false;
}
#elif defined(TARGET_DARWIN)
bool
get_default_gateway_mac_addr (unsigned char *macaddr)
{
# define max(a,b) ((a) > (b) ? (a) : (b))
struct gc_arena gc = gc_new ();
struct ifconf ifc;
struct ifreq *ifr;
char *buffer, *cp;
bool status = false;
in_addr_t gw = 0;
char *ifname = NULL;
int sockfd = -1;
const int bufsize = 4096;
if (!get_default_gateway_ex (&gw, NULL, &ifname)) /* get interface name of default gateway */
{
msg (M_WARN, "GDGMA: get_default_gateway_ex failed");
goto done;
}
if (!ifname)
{
msg (M_WARN, "GDGMA: cannot get default gateway ifname");
goto done;
}
buffer = (char *) gc_malloc (bufsize, true, &gc);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
msg (M_WARN, "GDGMA: socket failed");
goto done;
}
ifc.ifc_len = bufsize;
ifc.ifc_buf = buffer;
if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) < 0)
{
msg (M_WARN, "GDGMA: ioctl failed");
goto done;
}
for (cp = buffer; cp <= buffer + bufsize - sizeof(struct ifreq); )
{
ifr = (struct ifreq *)cp;
if (ifr->ifr_addr.sa_family == AF_LINK && !strncmp(ifr->ifr_name, ifname, IFNAMSIZ))
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
memcpy(macaddr, LLADDR(sdl), 6);
status = true;
}
cp += sizeof(ifr->ifr_name) + max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len);
}
done:
if (sockfd >= 0)
close (sockfd);
free (ifname);
gc_free (&gc);
return status;
# undef max
}
#else
bool

View file

@ -133,15 +133,15 @@ static HANDLE exit_event = NULL;
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
{
va_list arglist;
int ret = 0;
int len = -1;
if (size > 0)
{
va_start (arglist, format);
ret = vsnprintf (str, size, format, arglist);
len = vsnprintf (str, size, format, arglist);
va_end (arglist);
str[size - 1] = 0;
}
return ret;
return (len >= 0 && len < size);
}

View file

@ -2014,21 +2014,25 @@ link_socket_init_phase2 (struct link_socket *sock,
#endif
/* print local address */
if (sock->inetd)
msg (M_INFO, "%s link local: [inetd]", proto2ascii (sock->info.proto, true));
else
msg (M_INFO, "%s link local%s: %s",
proto2ascii (sock->info.proto, true),
(sock->bind_local ? " (bound)" : ""),
print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc));
{
const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
/* print active remote address */
msg (M_INFO, "%s link remote: %s",
proto2ascii (sock->info.proto, true),
print_link_socket_actual_ex (&sock->info.lsa->actual,
":",
PS_SHOW_PORT_IF_DEFINED,
&gc));
if (sock->inetd)
msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, true));
else
msg (msglevel, "%s link local%s: %s",
proto2ascii (sock->info.proto, true),
(sock->bind_local ? " (bound)" : ""),
print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc));
/* print active remote address */
msg (msglevel, "%s link remote: %s",
proto2ascii (sock->info.proto, true),
print_link_socket_actual_ex (&sock->info.lsa->actual,
":",
PS_SHOW_PORT_IF_DEFINED,
&gc));
}
done:
if (sig_save && signal_received)
@ -2057,7 +2061,7 @@ link_socket_close (struct link_socket *sock)
#endif
if (!gremlin)
{
msg (D_CLOSE, "TCP/UDP: Closing socket");
msg (D_LOW, "TCP/UDP: Closing socket");
if (openvpn_close_socket (sock->sd))
msg (M_WARN | M_ERRNO_SOCK, "TCP/UDP: Close Socket failed");
}

358
ssl.c
View file

@ -320,16 +320,28 @@ ssl_set_auth_nocache (void)
auth_user_pass.nocache = true;
}
/*
* Set an authentication token
*/
void
ssl_set_auth_token (const char *token)
{
set_auth_token (&auth_user_pass, token);
}
/*
* Forget private key password AND auth-user-pass username/password.
*/
void
ssl_purge_auth (void)
ssl_purge_auth (const bool auth_user_pass_only)
{
if (!auth_user_pass_only)
{
#ifdef USE_PKCS11
pkcs11_logout ();
pkcs11_logout ();
#endif
purge_user_pass (&passbuf, true);
purge_user_pass (&passbuf, true);
}
purge_user_pass (&auth_user_pass, true);
#ifdef ENABLE_CLIENT_CR
ssl_purge_auth_challenge();
@ -573,6 +585,96 @@ bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
sk_GENERAL_NAME_free (extensions);
}
return retval;
#ifdef ENABLE_X509_TRACK
/*
* setenv_x509_track function -- save X509 fields to environment,
* using the naming convention:
*
* X509_{cert_depth}_{name}={value}
*
* This function differs from setenv_x509 below in the following ways:
*
* (1) Only explicitly named attributes in xt are saved, per usage
* of --x509-track program options.
* (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN
* flag is set in xt->flags (corresponds with prepending a '+'
* to the name when specified by --x509-track program option).
* (3) This function supports both X509 subject name fields as
* well as X509 V3 extensions.
*/
/* worker method for setenv_x509_track */
static void
do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
{
char *name_expand;
size_t name_expand_size;
string_mod (value, CC_ANY, CC_CRLF, '?');
msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
name_expand_size = 64 + strlen (name);
name_expand = (char *) malloc (name_expand_size);
check_malloc_return (name_expand);
openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
setenv_str (es, name_expand, value);
free (name_expand);
}
static void
setenv_x509_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509)
{
X509_NAME *x509_name = X509_get_subject_name (x509);
const char nullc = '\0';
int i;
while (xt)
{
if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
{
i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1);
if (i >= 0)
{
X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
if (ent)
{
ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent);
unsigned char *buf;
buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
if (ASN1_STRING_to_UTF8 (&buf, val) > 0)
{
do_setenv_x509(es, xt->name, (char *)buf, depth);
OPENSSL_free (buf);
}
}
}
else
{
i = X509_get_ext_by_NID(x509, xt->nid, -1);
if (i >= 0)
{
X509_EXTENSION *ext = X509_get_ext(x509, i);
if (ext)
{
BIO *bio = BIO_new(BIO_s_mem());
if (bio)
{
if (X509V3_EXT_print(bio, ext, 0, 0))
{
if (BIO_write(bio, &nullc, 1) == 1)
{
char *str;
BIO_get_mem_data(bio, &str);
do_setenv_x509(es, xt->name, str, depth);
}
}
BIO_free(bio);
}
}
}
}
}
xt = xt->next;
}
}
#endif
@ -834,6 +936,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
const struct tls_options *opt;
const int max_depth = MAX_CERT_DEPTH;
struct argv argv = argv_new ();
char *serial = NULL;
/* get the tls_session pointer */
ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
@ -854,7 +957,12 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
}
/* Save X509 fields in environment */
setenv_x509 (opt->es, ctx->error_depth, X509_get_subject_name (ctx->current_cert));
#ifdef ENABLE_X509_TRACK
if (opt->x509_track)
setenv_x509_track (opt->x509_track, opt->es, ctx->error_depth, ctx->current_cert);
else
#endif
setenv_x509 (opt->es, ctx->error_depth, X509_get_subject_name (ctx->current_cert));
/* enforce character class restrictions in X509 name */
string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags);
@ -918,6 +1026,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
goto err; /* Reject connection */
}
/* verify level 1 cert, i.e. the CA that signed our leaf cert */
if (ctx->error_depth == 1 && opt->verify_hash)
{
if (memcmp (ctx->current_cert->sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH))
{
msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed");
goto err;
}
}
/* save common name in session object */
if (ctx->error_depth == 0)
set_common_name (session, common_name);
@ -943,32 +1061,17 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
setenv_str (opt->es, envname, common_name);
#endif
/* export serial number as environmental variable */
/* export serial number as environmental variable,
use bignum in case serial number is large */
{
BIO *bio = NULL;
char serial[100];
int n1, n2;
CLEAR (serial);
if ((bio = BIO_new (BIO_s_mem ())) == NULL)
{
msg (M_WARN, "CALLBACK: Cannot create BIO (for tls_serial_%d)", ctx->error_depth);
}
else
{
/* "prints" the serial number onto the BIO and read it back */
if ( ! ( ( (n1 = i2a_ASN1_INTEGER(bio, X509_get_serialNumber (ctx->current_cert))) >= 0 ) &&
( (n2 = BIO_read (bio, serial, sizeof (serial)-1)) >= 0 ) &&
( n1 == n2 ) ) )
{
msg (M_WARN, "CALLBACK: Error reading/writing BIO (for tls_serial_%d)", ctx->error_depth);
CLEAR (serial); /* empty string */
}
openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth);
setenv_str (opt->es, envname, serial);
BIO_free(bio);
}
ASN1_INTEGER *asn1_i;
BIGNUM *bignum;
asn1_i = X509_get_serialNumber(ctx->current_cert);
bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
serial = BN_bn2dec(bignum);
openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth);
setenv_str (opt->es, envname, serial);
BN_free(bignum);
}
/* export current untrusted IP */
@ -1108,67 +1211,89 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
/* check peer cert against CRL */
if (opt->crl_file)
{
X509_CRL *crl=NULL;
X509_REVOKED *revoked;
BIO *in=NULL;
int n,i,retval = 0;
in=BIO_new(BIO_s_file());
if (in == NULL) {
msg (M_ERR, "CRL: BIO err");
goto end;
}
if (BIO_read_filename(in, opt->crl_file) <= 0) {
msg (M_ERR, "CRL: cannot read: %s", opt->crl_file);
goto end;
}
crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
if (crl == NULL) {
msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file);
goto end;
}
if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject);
retval = 1;
goto end;
}
n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
for (i = 0; i < n; i++) {
revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
goto end;
if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
{
char fn[256];
int fd;
if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", opt->crl_file, OS_SPECIFIC_DIRSEP, serial))
{
msg (D_HANDSHAKE, "VERIFY CRL: filename overflow");
goto err;
}
fd = open (fn, O_RDONLY);
if (fd >= 0)
{
msg (D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial);
close(fd);
goto err;
}
}
}
else
{
X509_CRL *crl=NULL;
X509_REVOKED *revoked;
BIO *in=NULL;
int n,i,retval = 0;
retval = 1;
msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
in=BIO_new(BIO_s_file());
end:
if (in == NULL) {
msg (M_ERR, "CRL: BIO err");
goto end;
}
if (BIO_read_filename(in, opt->crl_file) <= 0) {
msg (M_ERR, "CRL: cannot read: %s", opt->crl_file);
goto end;
}
crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
if (crl == NULL) {
msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file);
goto end;
}
BIO_free(in);
if (crl)
X509_CRL_free (crl);
if (!retval)
goto err;
if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject);
retval = 1;
goto end;
}
n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
for (i = 0; i < n; i++) {
revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
goto end;
}
}
retval = 1;
msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
end:
BIO_free(in);
if (crl)
X509_CRL_free (crl);
if (!retval)
goto err;
}
}
msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", ctx->error_depth, subject);
session->verified = true;
done:
OPENSSL_free (subject);
if (serial)
OPENSSL_free(serial);
argv_reset (&argv);
return 1; /* Accept connection */
return (session->verified == true) ? 1 : 0;
err:
ERR_clear_error ();
OPENSSL_free (subject);
argv_reset (&argv);
return 0; /* Reject connection */
session->verified = false;
goto done;
}
void
@ -1232,6 +1357,31 @@ tls_lock_username (struct tls_multi *multi, const char *username)
return true;
}
#ifdef ENABLE_X509_TRACK
void
x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
{
struct x509_track *xt;
ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc);
if (*name == '+')
{
xt->flags |= XT_FULL_CHAIN;
++name;
}
xt->name = name;
xt->nid = OBJ_txt2nid(name);
if (xt->nid != NID_undef)
{
xt->next = *ll_head;
*ll_head = xt;
}
else
msg(msglevel, "x509_track: no such attribute '%s'", name);
}
#endif
#ifdef ENABLE_DEF_AUTH
/* key_state_test_auth_control_file return values,
NOTE: acf_merge indexing depends on these values */
@ -1978,7 +2128,7 @@ init_ssl (const struct options *options)
{
if (!X509_STORE_add_cert(ctx->cert_store,sk_X509_value(ca, i)))
msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)");
if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i)))
if (options->tls_server && !SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i)))
msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)");
}
}
@ -2090,11 +2240,11 @@ init_ssl (const struct options *options)
#endif
{
/* Load CA file for verifying peer supplied certificate */
status = SSL_CTX_load_verify_locations (ctx, options->ca_file, options->ca_path);
status = SSL_CTX_load_verify_locations (ctx, options->ca_file, NULL);
}
if (!status)
msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", options->ca_file, options->ca_path);
msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", np(options->ca_file), np(options->ca_path));
/* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */
if (options->ca_path) {
@ -2118,7 +2268,7 @@ init_ssl (const struct options *options)
}
/* Load names of CAs from file and use it as a client CA list */
if (options->ca_file) {
if (options->ca_file && options->tls_server) {
STACK_OF(X509_NAME) *cert_names = NULL;
#if ENABLE_INLINE_FILES
if (!strcmp (options->ca_file, INLINE_FILE_TAG) && options->ca_file_inline)
@ -2132,7 +2282,7 @@ init_ssl (const struct options *options)
}
if (!cert_names)
msg (M_SSLERR, "Cannot load CA certificate file %s (SSL_load_client_CA_file)", options->ca_file);
SSL_CTX_set_client_CA_list (ctx, cert_names);
SSL_CTX_set_client_CA_list (ctx, cert_names);
}
}
@ -2143,6 +2293,37 @@ init_ssl (const struct options *options)
msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", options->cert_file);
}
/* Load extra certificates that are part of our own certificate
chain but shouldn't be included in the verify chain */
if (options->extra_certs_file || options->extra_certs_file_inline)
{
BIO *bio;
X509 *cert;
#if ENABLE_INLINE_FILES
if (!strcmp (options->extra_certs_file, INLINE_FILE_TAG) && options->extra_certs_file_inline)
{
bio = BIO_new_mem_buf ((char *)options->extra_certs_file_inline, -1);
}
else
#endif
{
bio = BIO_new(BIO_s_file());
if (BIO_read_filename(bio, options->extra_certs_file) <= 0)
msg (M_SSLERR, "Cannot load extra-certs file: %s", options->extra_certs_file);
}
for (;;)
{
cert = NULL;
if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */
break;
if (!cert)
msg (M_SSLERR, "Error reading extra-certs certificate");
if (SSL_CTX_add_extra_chain_cert(ctx, cert) != 1)
msg (M_SSLERR, "Error adding extra-certs certificate");
}
BIO_free (bio);
}
/* Require peer certificate verification */
#if P2MP_SERVER
if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
@ -2674,8 +2855,10 @@ key_state_init (struct tls_session *session, struct key_state *ks)
/* init packet ID tracker */
packet_id_init (&ks->packet_id,
session->opt->tcp_mode,
session->opt->replay_window,
session->opt->replay_time);
session->opt->replay_time,
"SSL", ks->key_id);
#ifdef MANAGEMENT_DEF_AUTH
ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++;
@ -2779,8 +2962,10 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session)
/* initialize packet ID replay window for --tls-auth */
packet_id_init (session->tls_auth.packet_id,
session->opt->tcp_mode,
session->opt->replay_window,
session->opt->replay_time);
session->opt->replay_time,
"TLS_AUTH", session->key_id);
/* load most recent packet-id to replay protect on --tls-auth */
packet_id_persist_load_obj (session->tls_auth.pid_persist, session->tls_auth.packet_id);
@ -3851,6 +4036,11 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (macaddr, 6, 0, 1, ":", &gc));
}
/* push LZO status */
#ifdef LZO_STUB
buf_printf (&out, "IV_LZO_STUB=1\n");
#endif
/* push env vars that begin with UV_ */
for (e=es->list; e != NULL; e=e->next)
{

25
ssl.h
View file

@ -404,6 +404,21 @@ struct key_state
#endif
};
#ifdef ENABLE_X509_TRACK
struct x509_track
{
const struct x509_track *next;
const char *name;
# define XT_FULL_CHAIN (1<<0)
unsigned int flags;
int nid;
};
void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc);
#endif
/*
* Our const options, obtained directly or derived from
* command line options.
@ -454,6 +469,7 @@ struct tls_options
int ns_cert_type;
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
uint8_t *verify_hash;
/* allow openvpn config info to be
passed over control channel */
@ -465,6 +481,7 @@ struct tls_options
int replay_window; /* --replay-window parm */
int replay_time; /* --replay-window parm */
bool tcp_mode;
/* packet authentication for TLS handshake */
struct crypto_options tls_auth;
@ -491,12 +508,17 @@ struct tls_options
# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2)
# define SSLF_NO_NAME_REMAPPING (1<<3)
# define SSLF_OPT_VERIFY (1<<4)
# define SSLF_CRL_VERIFY_DIR (1<<5)
unsigned int ssl_flags;
#ifdef MANAGEMENT_DEF_AUTH
struct man_def_auth_context *mda_context;
#endif
#ifdef ENABLE_X509_TRACK
const struct x509_track *x509_track;
#endif
/* --gremlin bits */
int gremlin;
};
@ -703,7 +725,8 @@ void pem_password_setup (const char *auth_file);
int pem_password_callback (char *buf, int size, int rwflag, void *u);
void auth_user_pass_setup (const char *auth_file);
void ssl_set_auth_nocache (void);
void ssl_purge_auth (void);
void ssl_set_auth_token (const char *token);
void ssl_purge_auth (const bool auth_user_pass_only);
#ifdef ENABLE_CLIENT_CR

View file

@ -598,6 +598,13 @@ socket_defined (const socket_descriptor_t sd)
#define ENABLE_PKCS11
#endif
/*
* Enable x509-track feature?
*/
#if defined(USE_CRYPTO) && defined(USE_SSL)
#define ENABLE_X509_TRACK
#endif
/*
* Is poll available on this platform?
*/
@ -676,4 +683,21 @@ socket_defined (const socket_descriptor_t sd)
*/
#define ENABLE_PUSH_PEER_INFO
/*
* Do we support internal client-side NAT?
*/
#define ENABLE_CLIENT_NAT
/*
* Support LZO as a stub in client? (LZO lib not included, but we
* we still support LZO protocol changes that allow us to
* communicate with an LZO-enabled server)
*/
#ifdef LZO_STUB
#undef USE_LZO
#undef LZO_VERSION_NUM
#define USE_LZO 1
#define LZO_VERSION_NUM "STUB"
#endif
#endif

2
tun.c
View file

@ -991,7 +991,6 @@ do_ifconfig (struct tuntap *tt,
tt->did_ifconfig = true;
#elif defined(TARGET_DARWIN)
/*
* Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD...
*/
@ -1037,6 +1036,7 @@ do_ifconfig (struct tuntap *tt,
tun_mtu
);
}
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed");
tt->did_ifconfig = true;

View file

@ -4,16 +4,20 @@ from wb import config, choose_arch, home_fn
if 'SIGNTOOL' in config:
sys.path.append(home_fn(config['SIGNTOOL']))
def main(conf, arch):
def main(conf, arch, tap_dir):
from signtool import SignTool
st = SignTool(conf)
st = SignTool(conf, tap_dir)
for x64 in choose_arch(arch):
st.sign_verify(x64=x64)
# if we are run directly, and not loaded as a module
if __name__ == "__main__":
if len(sys.argv) >= 2:
main(config, sys.argv[1])
if len(sys.argv) >= 3:
tap_dir = home_fn(sys.argv[2])
else:
tap_dir = None
main(config, sys.argv[1], tap_dir)
else:
print "usage: sign <x64|x86|all>"
print "usage: sign <x64|x86|all> [tap-dir]"
sys.exit(2)