mirror of
https://github.com/OpenVPN/openvpn.git
synced 2025-05-08 21:25:53 +08:00
Updated version to 2.1_rc7e.
Added client authentication and packet filtering capability to management interface. Extended packet filtering capability to work on both --dev tun and --dev tap tunnels. Updated valgrind-suppress file. Made "Linux ip addr del failed" error nonfatal. Amplified --client-cert-not-required warning. Added #pragma pack to proto.h. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2991 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
parent
4d84de11b1
commit
90efcacba6
@ -112,7 +112,7 @@ openvpn_SOURCES = \
|
||||
otime.c otime.h \
|
||||
packet_id.c packet_id.h \
|
||||
perf.c perf.h \
|
||||
pf.c pf.h \
|
||||
pf.c pf.h pf-inline.h \
|
||||
ping.c ping.h ping-inline.h \
|
||||
plugin.c plugin.h \
|
||||
pool.c pool.h \
|
||||
|
127
buffer.c
127
buffer.c
@ -819,3 +819,130 @@ valign4 (const struct buffer *buf, const char *file, const int line)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* struct buffer_list
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_BUFFER_LIST
|
||||
|
||||
struct buffer_list *
|
||||
buffer_list_new (const int max_size)
|
||||
{
|
||||
struct buffer_list *ret;
|
||||
ALLOC_OBJ_CLEAR (ret, struct buffer_list);
|
||||
ret->max_size = max_size;
|
||||
ret->size = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_list_free (struct buffer_list *ol)
|
||||
{
|
||||
buffer_list_reset (ol);
|
||||
free (ol);
|
||||
}
|
||||
|
||||
bool
|
||||
buffer_list_defined (const struct buffer_list *ol)
|
||||
{
|
||||
return ol->head != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_list_reset (struct buffer_list *ol)
|
||||
{
|
||||
struct buffer_entry *e = ol->head;
|
||||
while (e)
|
||||
{
|
||||
struct buffer_entry *next = e->next;
|
||||
free_buf (&e->buf);
|
||||
free (e);
|
||||
e = next;
|
||||
}
|
||||
ol->head = ol->tail = NULL;
|
||||
ol->size = 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_list_push (struct buffer_list *ol, const unsigned char *str)
|
||||
{
|
||||
if (!ol->max_size || ol->size < ol->max_size)
|
||||
{
|
||||
struct buffer_entry *e;
|
||||
ALLOC_OBJ_CLEAR (e, struct buffer_entry);
|
||||
|
||||
++ol->size;
|
||||
if (ol->tail)
|
||||
{
|
||||
ASSERT (ol->head);
|
||||
ol->tail->next = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT (!ol->head);
|
||||
ol->head = e;
|
||||
}
|
||||
e->buf = string_alloc_buf ((const char *) str, NULL);
|
||||
ol->tail = e;
|
||||
}
|
||||
}
|
||||
|
||||
const struct buffer *
|
||||
buffer_list_peek (struct buffer_list *ol)
|
||||
{
|
||||
if (ol->head)
|
||||
return &ol->head->buf;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_list_pop (struct buffer_list *ol)
|
||||
{
|
||||
if (ol->head)
|
||||
{
|
||||
struct buffer_entry *e = ol->head->next;
|
||||
free_buf (&ol->head->buf);
|
||||
free (ol->head);
|
||||
ol->head = e;
|
||||
--ol->size;
|
||||
if (!e)
|
||||
ol->tail = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
buffer_list_advance (struct buffer_list *ol, int n)
|
||||
{
|
||||
if (ol->head)
|
||||
{
|
||||
struct buffer *buf = &ol->head->buf;
|
||||
ASSERT (buf_advance (buf, n));
|
||||
if (!BLEN (buf))
|
||||
buffer_list_pop (ol);
|
||||
}
|
||||
}
|
||||
|
||||
struct buffer_list *
|
||||
buffer_list_file (const char *fn, int max_line_len)
|
||||
{
|
||||
FILE *fp = fopen (fn, "r");
|
||||
struct buffer_list *bl = NULL;
|
||||
|
||||
if (fp)
|
||||
{
|
||||
char *line = (char *) malloc (max_line_len);
|
||||
if (line)
|
||||
{
|
||||
bl = buffer_list_new (0);
|
||||
while (fgets (line, max_line_len, fp) != NULL)
|
||||
buffer_list_push (bl, (unsigned char *)line);
|
||||
free (line);
|
||||
}
|
||||
fclose (fp);
|
||||
}
|
||||
return bl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
34
buffer.h
34
buffer.h
@ -723,4 +723,38 @@ check_malloc_return (void *p)
|
||||
out_of_memory ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Manage lists of buffers
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_BUFFER_LIST
|
||||
|
||||
struct buffer_entry
|
||||
{
|
||||
struct buffer buf;
|
||||
struct buffer_entry *next;
|
||||
};
|
||||
|
||||
struct buffer_list
|
||||
{
|
||||
struct buffer_entry *head; /* next item to pop/peek */
|
||||
struct buffer_entry *tail; /* last item pushed */
|
||||
int size; /* current number of entries */
|
||||
int max_size; /* maximum size list should grow to */
|
||||
};
|
||||
|
||||
struct buffer_list *buffer_list_new (const int max_size);
|
||||
void buffer_list_free (struct buffer_list *ol);
|
||||
|
||||
bool buffer_list_defined (const struct buffer_list *ol);
|
||||
void buffer_list_reset (struct buffer_list *ol);
|
||||
|
||||
void buffer_list_push (struct buffer_list *ol, const unsigned char *str);
|
||||
const struct buffer *buffer_list_peek (struct buffer_list *ol);
|
||||
void buffer_list_advance (struct buffer_list *ol, int n);
|
||||
|
||||
struct buffer_list *buffer_list_file (const char *fn, int max_line_len);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* BUFFER_H */
|
||||
|
@ -1,118 +1,411 @@
|
||||
# Valgrind suppressions file for OpenVPN.
|
||||
#
|
||||
# Mostly deal with uninitialized data warnings
|
||||
# in OpenSSL.
|
||||
|
||||
{
|
||||
cond_BN
|
||||
Memcheck:Cond
|
||||
fun:BN_*
|
||||
}
|
||||
|
||||
{
|
||||
value4_BN
|
||||
Memcheck:Value4
|
||||
fun:BN_*
|
||||
}
|
||||
|
||||
{
|
||||
cond_bn
|
||||
Memcheck:Cond
|
||||
fun:bn_*
|
||||
}
|
||||
|
||||
{
|
||||
value4_bn
|
||||
Memcheck:Value4
|
||||
fun:bn_*
|
||||
}
|
||||
|
||||
{
|
||||
cond_SHA1_Update
|
||||
Memcheck:Cond
|
||||
fun:SHA1_Update
|
||||
}
|
||||
|
||||
{
|
||||
value4_SHA1_Update
|
||||
Memcheck:Value4
|
||||
fun:SHA1_Update
|
||||
}
|
||||
|
||||
{
|
||||
cond_ssl3_read_bytes
|
||||
Memcheck:Cond
|
||||
fun:ssl3_read_bytes
|
||||
}
|
||||
|
||||
{
|
||||
cond_crypto
|
||||
Memcheck:Cond
|
||||
obj:/lib/libcrypto.so.*
|
||||
}
|
||||
|
||||
{
|
||||
value4_crypto
|
||||
Memcheck:Value4
|
||||
obj:/lib/libcrypto.so.*
|
||||
}
|
||||
|
||||
{
|
||||
cond_ssl
|
||||
Memcheck:Cond
|
||||
obj:/lib/libssl.so.*
|
||||
}
|
||||
|
||||
{
|
||||
value4_ssl
|
||||
Memcheck:Value4
|
||||
obj:/lib/libssl.so.*
|
||||
}
|
||||
|
||||
{
|
||||
addr4_AES_cbc_encrypt
|
||||
Memcheck:Addr4
|
||||
fun:AES_cbc_encrypt
|
||||
}
|
||||
|
||||
{
|
||||
cond_memcpy_ssl3_read_bytes
|
||||
Memcheck:Cond
|
||||
fun:memcpy
|
||||
fun:ssl3_read_bytes
|
||||
}
|
||||
|
||||
{
|
||||
value4_memcpy_ssl3_read_bytes
|
||||
Memcheck:Value4
|
||||
fun:memcpy
|
||||
fun:ssl3_read_bytes
|
||||
}
|
||||
|
||||
{
|
||||
cond_memset_BUF_MEM_grow_clean
|
||||
Memcheck:Cond
|
||||
fun:memset
|
||||
fun:BUF_MEM_grow_clean
|
||||
}
|
||||
|
||||
{
|
||||
value4_memset_BUF_MEM_grow_clean
|
||||
Memcheck:Value4
|
||||
fun:memset
|
||||
fun:BUF_MEM_grow_clean
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
fun:__nss_next
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
fun:dlopen
|
||||
fun:plugin_list_init
|
||||
fun:init_plugins
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
fun:dlopen
|
||||
fun:plugin_list_init
|
||||
fun:init_plugins
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
fun:dlsym
|
||||
fun:libdl_resolve_symbol
|
||||
fun:plugin_list_init
|
||||
fun:init_plugins
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
fun:dlopen
|
||||
fun:plugin_list_init
|
||||
fun:init_plugins
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
fun:__nss_next
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
fun:__nss_next
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
fun:__nss_next
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_udp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libc-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
fun:__libc_dlopen_mode
|
||||
fun:__nss_lookup_function
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:gethostbyname_r
|
||||
fun:gethostbyname
|
||||
fun:getaddr
|
||||
fun:resolve_remote
|
||||
fun:link_socket_init_phase1
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
obj:/lib/ld-2.5.so
|
||||
obj:/lib/libdl-2.5.so
|
||||
fun:dlopen
|
||||
fun:plugin_list_init
|
||||
fun:init_plugins
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
@ -128,3 +421,172 @@
|
||||
fun:init_static
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:__nss_lookup_function
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:__nss_lookup_function
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:__nss_lookup_function
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_udp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:getdelim
|
||||
fun:getpass
|
||||
fun:get_console_input
|
||||
fun:get_user_pass
|
||||
fun:context_init_1
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:tsearch
|
||||
fun:__nss_lookup_function
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:tsearch
|
||||
fun:__nss_lookup_function
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:tsearch
|
||||
fun:__nss_lookup_function
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_udp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:__nss_database_lookup
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:__nss_database_lookup
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_tcp
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
obj:/lib/libc-2.5.so
|
||||
fun:__nss_database_lookup
|
||||
obj:*
|
||||
obj:*
|
||||
fun:getgrnam_r
|
||||
fun:getgrnam
|
||||
fun:get_group
|
||||
fun:do_init_first_time
|
||||
fun:init_instance
|
||||
fun:init_instance_handle_signals
|
||||
fun:tunnel_server_udp
|
||||
fun:main
|
||||
}
|
||||
|
||||
|
2
dovalns
Executable file
2
dovalns
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
valgrind --tool=memcheck --error-limit=no --gen-suppressions=all --leak-check=full --show-reachable=yes --num-callers=32 $*
|
@ -94,7 +94,7 @@
|
||||
#define D_ROUTE_QUOTA LOGLEV(3, 43, 0) /* show route quota exceeded messages */
|
||||
#define D_OSBUF LOGLEV(3, 44, 0) /* show socket/tun/tap buffer sizes */
|
||||
#define D_PS_PROXY LOGLEV(3, 45, 0) /* messages related to --port-share option */
|
||||
#define D_PF LOGLEV(3, 46, 0) /* messages related to packet filter */
|
||||
#define D_PF_INFO LOGLEV(3, 46, 0) /* packet filter informational messages */
|
||||
|
||||
#define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */
|
||||
#define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */
|
||||
@ -102,6 +102,7 @@
|
||||
#define D_DHCP_OPT LOGLEV(4, 53, 0) /* show DHCP options binary string */
|
||||
#define D_MBUF LOGLEV(4, 54, 0) /* mbuf.[ch] routines */
|
||||
#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_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */
|
||||
|
||||
@ -136,6 +137,8 @@
|
||||
#define D_PING LOGLEV(7, 70, M_DEBUG) /* PING send/receive messages */
|
||||
#define D_PS_PROXY_DEBUG LOGLEV(7, 70, M_DEBUG) /* port share proxy debug */
|
||||
#define D_AUTO_USERID LOGLEV(7, 70, M_DEBUG) /* AUTO_USERID debugging */
|
||||
#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 */
|
||||
|
||||
#define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */
|
||||
#define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */
|
||||
|
5
error.c
5
error.c
@ -268,7 +268,10 @@ void x_msg (const unsigned int flags, const char *format, ...)
|
||||
#endif
|
||||
|
||||
/* set up client prefix */
|
||||
prefix = msg_get_prefix ();
|
||||
if (flags & M_NOIPREFIX)
|
||||
prefix = NULL;
|
||||
else
|
||||
prefix = msg_get_prefix ();
|
||||
prefix_sep = " ";
|
||||
if (!prefix)
|
||||
prefix_sep = prefix = "";
|
||||
|
8
error.h
8
error.h
@ -102,13 +102,14 @@ extern int x_msg_line_num;
|
||||
#define M_MSG_VIRT_OUT (1<<14) /* output message through msg_status_output callback */
|
||||
#define M_OPTERR (1<<15) /* print "Options error:" prefix */
|
||||
#define M_NOLF (1<<16) /* don't print new line */
|
||||
#define M_NOIPREFIX (1<<17) /* don't print instance prefix */
|
||||
|
||||
/* flag combinations which are frequently used */
|
||||
#define M_ERR (M_FATAL | M_ERRNO)
|
||||
#define M_SOCKERR (M_FATAL | M_ERRNO_SOCK)
|
||||
#define M_SSLERR (M_FATAL | M_SSL)
|
||||
#define M_USAGE (M_USAGE_SMALL | M_NOPREFIX | M_OPTERR)
|
||||
#define M_CLIENT (M_MSG_VIRT_OUT|M_NOMUTE)
|
||||
#define M_CLIENT (M_MSG_VIRT_OUT | M_NOMUTE | M_NOIPREFIX)
|
||||
|
||||
/*
|
||||
* Mute levels are designed to avoid large numbers of
|
||||
@ -126,6 +127,11 @@ extern int x_msg_line_num;
|
||||
* log_level: verbosity level n (--verb n) must be >= log_level to print.
|
||||
* mute_level: don't print more than n (--mute n) consecutive messages at
|
||||
* a given mute level, or if 0 disable muting and print everything.
|
||||
*
|
||||
* Mask map:
|
||||
* Bits 0-3: log level
|
||||
* Bits 4-23: M_x flags
|
||||
* Bits 24-31: mute level
|
||||
*/
|
||||
#define LOGLEV(log_level, mute_level, other) ((log_level) | ENCODE_MUTE_LEVEL(mute_level) | other)
|
||||
|
||||
|
@ -492,7 +492,7 @@ process_coarse_timers (struct context *c)
|
||||
check_push_request (c);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
#ifdef PLUGIN_PF
|
||||
pf_check_reload (c);
|
||||
#endif
|
||||
|
||||
|
23
init.c
23
init.c
@ -1558,6 +1558,10 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
|
||||
|
||||
to.plugins = c->plugins;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
to.mda_context = &c->c2.mda_context;
|
||||
#endif
|
||||
|
||||
#if P2MP_SERVER
|
||||
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;
|
||||
@ -2356,7 +2360,7 @@ open_plugins (struct context *c, const bool import_options, int init_point)
|
||||
{
|
||||
unsigned int option_types_found = 0;
|
||||
if (config.list[i] && config.list[i]->value)
|
||||
options_plugin_import (&c->options,
|
||||
options_string_import (&c->options,
|
||||
config.list[i]->value,
|
||||
D_IMPORT_ERRORS|M_OPTERR,
|
||||
OPT_P_DEFAULT & ~OPT_P_PLUGIN,
|
||||
@ -2452,21 +2456,19 @@ open_management (struct context *c)
|
||||
{
|
||||
if (c->options.management_addr)
|
||||
{
|
||||
unsigned int flags = c->options.management_flags;
|
||||
if (c->options.mode == MODE_SERVER)
|
||||
flags |= MF_SERVER;
|
||||
if (management_open (management,
|
||||
c->options.management_addr,
|
||||
c->options.management_port,
|
||||
c->options.management_user_pass,
|
||||
c->options.mode == MODE_SERVER,
|
||||
c->options.management_query_passwords,
|
||||
c->options.management_log_history_cache,
|
||||
c->options.management_echo_buffer_size,
|
||||
c->options.management_state_buffer_size,
|
||||
c->options.management_hold,
|
||||
c->options.management_signal,
|
||||
c->options.management_forget_disconnect,
|
||||
c->options.management_client,
|
||||
c->options.management_write_peer_info_file,
|
||||
c->options.remap_sigusr1))
|
||||
c->options.remap_sigusr1,
|
||||
flags))
|
||||
{
|
||||
management_set_state (management,
|
||||
OPENVPN_STATE_CONNECTING,
|
||||
@ -2792,6 +2794,11 @@ close_instance (struct context *c)
|
||||
/* close TUN/TAP device */
|
||||
do_close_tun (c, false);
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management)
|
||||
management_notify_client_close (management, &c->c2.mda_context, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
pf_destroy_context (&c->c2.pf);
|
||||
#endif
|
||||
|
536
manage.c
536
manage.c
@ -87,6 +87,15 @@ man_help ()
|
||||
#ifdef ENABLE_PKCS11
|
||||
msg (M_CLIENT, "pkcs11-id-count : Get number of available PKCS#11 identities.");
|
||||
msg (M_CLIENT, "pkcs11-id-get index : Get PKCS#11 identity at index.");
|
||||
#endif
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
msg (M_CLIENT, "client-auth CID KID : Authenticate client-id/key-id CID/KID (MULTILINE)");
|
||||
msg (M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID");
|
||||
msg (M_CLIENT, "client-deny CID KID R : Deny auth client-id/key-id CID/KID with reason text R");
|
||||
msg (M_CLIENT, "client-kill CID : Kill client instance CID");
|
||||
#ifdef MANAGEMENT_PF
|
||||
msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)");
|
||||
#endif
|
||||
#endif
|
||||
msg (M_CLIENT, "signal s : Send signal s to daemon,");
|
||||
msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
|
||||
@ -178,7 +187,7 @@ man_update_io_state (struct management *man)
|
||||
{
|
||||
if (socket_defined (man->connection.sd_cli))
|
||||
{
|
||||
if (output_list_defined (man->connection.out))
|
||||
if (buffer_list_defined (man->connection.out))
|
||||
{
|
||||
man->connection.state = MS_CC_WAIT_WRITE;
|
||||
}
|
||||
@ -195,7 +204,7 @@ man_output_list_push (struct management *man, const char *str)
|
||||
if (management_connected (man))
|
||||
{
|
||||
if (str)
|
||||
output_list_push (man->connection.out, (const unsigned char *) str);
|
||||
buffer_list_push (man->connection.out, (const unsigned char *) str);
|
||||
man_update_io_state (man);
|
||||
if (!man->persist.standalone_disabled)
|
||||
{
|
||||
@ -672,12 +681,12 @@ man_hold (struct management *man, const char *cmd)
|
||||
{
|
||||
if (streq (cmd, "on"))
|
||||
{
|
||||
man->settings.hold = true;
|
||||
man->settings.flags |= MF_HOLD;
|
||||
msg (M_CLIENT, "SUCCESS: hold flag set to ON");
|
||||
}
|
||||
else if (streq (cmd, "off"))
|
||||
{
|
||||
man->settings.hold = false;
|
||||
man->settings.flags &= ~MF_HOLD;
|
||||
msg (M_CLIENT, "SUCCESS: hold flag set to OFF");
|
||||
}
|
||||
else if (streq (cmd, "release"))
|
||||
@ -691,9 +700,205 @@ man_hold (struct management *man, const char *cmd)
|
||||
}
|
||||
}
|
||||
else
|
||||
msg (M_CLIENT, "SUCCESS: hold=%d", (int) man->settings.hold);
|
||||
msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD));
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
|
||||
static bool
|
||||
parse_cid (const char *str, unsigned long *cid)
|
||||
{
|
||||
if (sscanf (str, "%lu", cid) == 1)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: cannot parse CID");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_kid (const char *str, unsigned int *kid)
|
||||
{
|
||||
if (sscanf (str, "%u", kid) == 1)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: cannot parse KID");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
in_extra_reset (struct man_connection *mc, const bool new)
|
||||
{
|
||||
if (mc)
|
||||
{
|
||||
if (!new)
|
||||
{
|
||||
mc->in_extra_cmd = IEC_UNDEF;
|
||||
mc->in_extra_cid = 0;
|
||||
mc->in_extra_kid = 0;
|
||||
}
|
||||
if (mc->in_extra)
|
||||
{
|
||||
buffer_list_free (mc->in_extra);
|
||||
mc->in_extra = NULL;
|
||||
}
|
||||
if (new)
|
||||
mc->in_extra = buffer_list_new (0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
in_extra_dispatch (struct management *man)
|
||||
{
|
||||
switch (man->connection.in_extra_cmd)
|
||||
{
|
||||
case IEC_CLIENT_AUTH:
|
||||
if (man->persist.callback.client_auth)
|
||||
{
|
||||
const bool status = (*man->persist.callback.client_auth)
|
||||
(man->persist.callback.arg,
|
||||
man->connection.in_extra_cid,
|
||||
man->connection.in_extra_kid,
|
||||
true,
|
||||
NULL,
|
||||
man->connection.in_extra);
|
||||
man->connection.in_extra = NULL;
|
||||
if (status)
|
||||
{
|
||||
msg (M_CLIENT, "SUCCESS: client-auth command succeeded");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: client-auth command failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode");
|
||||
}
|
||||
break;
|
||||
#ifdef MANAGEMENT_PF
|
||||
case IEC_CLIENT_PF:
|
||||
if (man->persist.callback.client_pf)
|
||||
{
|
||||
const bool status = (*man->persist.callback.client_pf)
|
||||
(man->persist.callback.arg,
|
||||
man->connection.in_extra_cid,
|
||||
man->connection.in_extra);
|
||||
man->connection.in_extra = NULL;
|
||||
if (status)
|
||||
{
|
||||
msg (M_CLIENT, "SUCCESS: client-pf command succeeded");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: client-pf command failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: The client-pf command is not supported by the current daemon mode");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
in_extra_reset (&man->connection, false);
|
||||
}
|
||||
|
||||
static void
|
||||
man_client_auth (struct management *man, const char *cid_str, const char *kid_str, const bool extra)
|
||||
{
|
||||
struct man_connection *mc = &man->connection;
|
||||
mc->in_extra_cid = 0;
|
||||
mc->in_extra_kid = 0;
|
||||
if (parse_cid (cid_str, &mc->in_extra_cid)
|
||||
&& parse_kid (kid_str, &mc->in_extra_kid))
|
||||
{
|
||||
mc->in_extra_cmd = IEC_CLIENT_AUTH;
|
||||
in_extra_reset (mc, true);
|
||||
if (!extra)
|
||||
in_extra_dispatch (man);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
man_client_deny (struct management *man, const char *cid_str, const char *kid_str, const char *reason)
|
||||
{
|
||||
unsigned long cid = 0;
|
||||
unsigned int kid = 0;
|
||||
if (parse_cid (cid_str, &cid) && parse_kid (kid_str, &kid))
|
||||
{
|
||||
if (man->persist.callback.client_auth)
|
||||
{
|
||||
const bool status = (*man->persist.callback.client_auth)
|
||||
(man->persist.callback.arg,
|
||||
cid,
|
||||
kid,
|
||||
false,
|
||||
reason,
|
||||
NULL);
|
||||
if (status)
|
||||
{
|
||||
msg (M_CLIENT, "SUCCESS: client-deny command succeeded");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: client-deny command failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: The client-deny command is not supported by the current daemon mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
man_client_kill (struct management *man, const char *cid_str)
|
||||
{
|
||||
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);
|
||||
if (status)
|
||||
{
|
||||
msg (M_CLIENT, "SUCCESS: client-kill command succeeded");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: client-kill command failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_CLIENT, "ERROR: The client-kill command is not supported by the current daemon mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_PF
|
||||
|
||||
static void
|
||||
man_client_pf (struct management *man, const char *cid_str)
|
||||
{
|
||||
struct man_connection *mc = &man->connection;
|
||||
mc->in_extra_cid = 0;
|
||||
mc->in_extra_kid = 0;
|
||||
if (parse_cid (cid_str, &mc->in_extra_cid))
|
||||
{
|
||||
mc->in_extra_cmd = IEC_CLIENT_PF;
|
||||
in_extra_reset (mc, true);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MN_AT_LEAST (1<<0)
|
||||
|
||||
static bool
|
||||
@ -867,6 +1072,35 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
|
||||
if (man_need (man, p, 1, 0))
|
||||
man_bytecount (man, atoi(p[1]));
|
||||
}
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
else if (streq (p[0], "client-kill"))
|
||||
{
|
||||
if (man_need (man, p, 1, 0))
|
||||
man_client_kill (man, p[1]);
|
||||
}
|
||||
else if (streq (p[0], "client-deny"))
|
||||
{
|
||||
if (man_need (man, p, 3, 0))
|
||||
man_client_deny (man, p[1], p[2], p[3]);
|
||||
}
|
||||
else if (streq (p[0], "client-auth-nt"))
|
||||
{
|
||||
if (man_need (man, p, 2, 0))
|
||||
man_client_auth (man, p[1], p[2], false);
|
||||
}
|
||||
else if (streq (p[0], "client-auth"))
|
||||
{
|
||||
if (man_need (man, p, 2, 0))
|
||||
man_client_auth (man, p[1], p[2], true);
|
||||
}
|
||||
#ifdef MANAGEMENT_PF
|
||||
else if (streq (p[0], "client-pf"))
|
||||
{
|
||||
if (man_need (man, p, 1, 0))
|
||||
man_client_pf (man, p[1]);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENABLE_PKCS11
|
||||
else if (streq (p[0], "pkcs11-id-count"))
|
||||
{
|
||||
@ -999,7 +1233,7 @@ man_new_connection_post (struct management *man, const char *description)
|
||||
description,
|
||||
print_sockaddr (&man->settings.local, &gc));
|
||||
|
||||
output_list_reset (man->connection.out);
|
||||
buffer_list_reset (man->connection.out);
|
||||
|
||||
if (!man_password_needed (man))
|
||||
man_welcome (man);
|
||||
@ -1134,14 +1368,17 @@ man_reset_client_socket (struct management *man, const bool exiting)
|
||||
man_close_socket (man, man->connection.sd_cli);
|
||||
man->connection.sd_cli = SOCKET_UNDEFINED;
|
||||
command_line_reset (man->connection.in);
|
||||
output_list_reset (man->connection.out);
|
||||
buffer_list_reset (man->connection.out);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
in_extra_reset (&man->connection, false);
|
||||
#endif
|
||||
}
|
||||
if (!exiting)
|
||||
{
|
||||
if (man->settings.management_forget_disconnect)
|
||||
if (man->settings.flags & MF_FORGET_DISCONNECT)
|
||||
ssl_purge_auth ();
|
||||
|
||||
if (man->settings.signal_on_disconnect) {
|
||||
if (man->settings.flags & MF_SIGNAL) {
|
||||
int mysig = man_mod_signal (man, SIGUSR1);
|
||||
if (mysig >= 0)
|
||||
{
|
||||
@ -1150,7 +1387,7 @@ man_reset_client_socket (struct management *man, const bool exiting)
|
||||
}
|
||||
}
|
||||
|
||||
if (man->settings.connect_as_client)
|
||||
if (man->settings.flags & MF_CONNECT_AS_CLIENT)
|
||||
{
|
||||
msg (D_MANAGEMENT, "MANAGEMENT: Triggering management exit");
|
||||
throw_signal_soft (SIGTERM, "management-exit");
|
||||
@ -1170,6 +1407,9 @@ man_process_command (struct management *man, const char *line)
|
||||
|
||||
CLEAR (parms);
|
||||
so = status_open (NULL, 0, -1, &man->persist.vout, 0);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
in_extra_reset (&man->connection, false);
|
||||
#endif
|
||||
|
||||
if (man_password_needed (man))
|
||||
{
|
||||
@ -1243,7 +1483,7 @@ man_read (struct management *man)
|
||||
/*
|
||||
* Reset output object
|
||||
*/
|
||||
output_list_reset (man->connection.out);
|
||||
buffer_list_reset (man->connection.out);
|
||||
|
||||
/*
|
||||
* process command line if complete
|
||||
@ -1252,7 +1492,22 @@ man_read (struct management *man)
|
||||
const unsigned char *line;
|
||||
while ((line = command_line_get (man->connection.in)))
|
||||
{
|
||||
man_process_command (man, (char *) line);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (man->connection.in_extra)
|
||||
{
|
||||
if (!strcmp ((char *)line, "END"))
|
||||
{
|
||||
in_extra_dispatch (man);
|
||||
in_extra_reset (&man->connection, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_list_push (man->connection.in_extra, line);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
man_process_command (man, (char *) line);
|
||||
if (man->connection.halt)
|
||||
break;
|
||||
command_line_next (man->connection.in);
|
||||
@ -1289,14 +1544,14 @@ man_write (struct management *man)
|
||||
const int max_send = 256;
|
||||
int sent = 0;
|
||||
|
||||
const struct buffer *buf = output_list_peek (man->connection.out);
|
||||
const struct buffer *buf = buffer_list_peek (man->connection.out);
|
||||
if (buf && BLEN (buf))
|
||||
{
|
||||
const int len = min_int (max_send, BLEN (buf));
|
||||
sent = send (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL);
|
||||
if (sent >= 0)
|
||||
{
|
||||
output_list_advance (man->connection.out, sent);
|
||||
buffer_list_advance (man->connection.out, sent);
|
||||
}
|
||||
else if (sent < 0)
|
||||
{
|
||||
@ -1387,27 +1642,18 @@ man_settings_init (struct man_settings *ms,
|
||||
const char *addr,
|
||||
const int port,
|
||||
const char *pass_file,
|
||||
const bool server,
|
||||
const bool query_passwords,
|
||||
const int log_history_cache,
|
||||
const int echo_buffer_size,
|
||||
const int state_buffer_size,
|
||||
const bool hold,
|
||||
const bool signal_on_disconnect,
|
||||
const bool management_forget_disconnect,
|
||||
const bool connect_as_client,
|
||||
const char *write_peer_info_file,
|
||||
const int remap_sigusr1)
|
||||
const int remap_sigusr1,
|
||||
const unsigned int flags)
|
||||
{
|
||||
if (!ms->defined)
|
||||
{
|
||||
CLEAR (*ms);
|
||||
|
||||
/*
|
||||
* Are we a server? If so, it will influence
|
||||
* the way we handle state transitions.
|
||||
*/
|
||||
ms->server = server;
|
||||
ms->flags = flags;
|
||||
|
||||
/*
|
||||
* Get username/password
|
||||
@ -1415,34 +1661,6 @@ man_settings_init (struct man_settings *ms,
|
||||
if (pass_file)
|
||||
get_user_pass (&ms->up, pass_file, "Management", GET_USER_PASS_PASSWORD_ONLY);
|
||||
|
||||
/*
|
||||
* Should OpenVPN query the management layer for
|
||||
* passwords?
|
||||
*/
|
||||
ms->up_query_passwords = query_passwords;
|
||||
|
||||
/*
|
||||
* Should OpenVPN hibernate on startup?
|
||||
*/
|
||||
ms->hold = hold;
|
||||
|
||||
/*
|
||||
* Should OpenVPN be signaled if management
|
||||
* disconnects?
|
||||
*/
|
||||
ms->signal_on_disconnect = signal_on_disconnect;
|
||||
|
||||
/*
|
||||
* Should OpenVPN forget passwords when managmenet
|
||||
* session disconnects?
|
||||
*/
|
||||
ms->management_forget_disconnect = management_forget_disconnect;
|
||||
|
||||
/*
|
||||
* Should OpenVPN connect to management interface as a client
|
||||
* rather than a server?
|
||||
*/
|
||||
ms->connect_as_client = connect_as_client;
|
||||
ms->write_peer_info_file = string_alloc (write_peer_info_file, NULL);
|
||||
|
||||
/*
|
||||
@ -1456,7 +1674,7 @@ man_settings_init (struct man_settings *ms,
|
||||
* Run management over tunnel, or
|
||||
* separate channel?
|
||||
*/
|
||||
if (streq (addr, "tunnel") && !connect_as_client)
|
||||
if (streq (addr, "tunnel") && !(flags & MF_CONNECT_AS_CLIENT))
|
||||
{
|
||||
ms->management_over_tunnel = true;
|
||||
}
|
||||
@ -1511,7 +1729,7 @@ man_connection_init (struct management *man)
|
||||
* command output from/to the socket.
|
||||
*/
|
||||
man->connection.in = command_line_new (256);
|
||||
man->connection.out = output_list_new (0);
|
||||
man->connection.out = buffer_list_new (0);
|
||||
|
||||
/*
|
||||
* Initialize event set for standalone usage, when we are
|
||||
@ -1525,7 +1743,7 @@ man_connection_init (struct management *man)
|
||||
/*
|
||||
* Listen/connect socket
|
||||
*/
|
||||
if (man->settings.connect_as_client)
|
||||
if (man->settings.flags & MF_CONNECT_AS_CLIENT)
|
||||
man_connect (man);
|
||||
else
|
||||
man_listen (man);
|
||||
@ -1549,7 +1767,10 @@ man_connection_close (struct management *man)
|
||||
if (mc->in)
|
||||
command_line_free (mc->in);
|
||||
if (mc->out)
|
||||
output_list_free (mc->out);
|
||||
buffer_list_free (mc->out);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
in_extra_reset (&man->connection, false);
|
||||
#endif
|
||||
man_connection_clear (mc);
|
||||
}
|
||||
|
||||
@ -1574,17 +1795,12 @@ management_open (struct management *man,
|
||||
const char *addr,
|
||||
const int port,
|
||||
const char *pass_file,
|
||||
const bool server,
|
||||
const bool query_passwords,
|
||||
const int log_history_cache,
|
||||
const int echo_buffer_size,
|
||||
const int state_buffer_size,
|
||||
const bool hold,
|
||||
const bool signal_on_disconnect,
|
||||
const bool management_forget_disconnect,
|
||||
const bool connect_as_client,
|
||||
const char *write_peer_info_file,
|
||||
const int remap_sigusr1)
|
||||
const int remap_sigusr1,
|
||||
const unsigned int flags)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
@ -1596,17 +1812,12 @@ management_open (struct management *man,
|
||||
addr,
|
||||
port,
|
||||
pass_file,
|
||||
server,
|
||||
query_passwords,
|
||||
log_history_cache,
|
||||
echo_buffer_size,
|
||||
state_buffer_size,
|
||||
hold,
|
||||
signal_on_disconnect,
|
||||
management_forget_disconnect,
|
||||
connect_as_client,
|
||||
write_peer_info_file,
|
||||
remap_sigusr1);
|
||||
remap_sigusr1,
|
||||
flags);
|
||||
|
||||
/*
|
||||
* The log is initially sized to MANAGEMENT_LOG_HISTORY_INITIAL_SIZE,
|
||||
@ -1665,7 +1876,7 @@ management_set_state (struct management *man,
|
||||
const in_addr_t tun_local_ip,
|
||||
const in_addr_t tun_remote_ip)
|
||||
{
|
||||
if (man->persist.state && (!man->settings.server || state < OPENVPN_STATE_CLIENT_BASE))
|
||||
if (man->persist.state && (!(man->settings.flags & MF_SERVER) || state < OPENVPN_STATE_CLIENT_BASE))
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct log_entry e;
|
||||
@ -1697,6 +1908,79 @@ management_set_state (struct management *man,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
|
||||
static void
|
||||
man_output_env (const struct env_set *es)
|
||||
{
|
||||
if (es)
|
||||
{
|
||||
struct env_item *e;
|
||||
for (e = es->list; e != NULL; e = e->next)
|
||||
{
|
||||
if (e->string)
|
||||
msg (M_CLIENT, ">CLIENT:ENV,%s", e->string);
|
||||
}
|
||||
}
|
||||
msg (M_CLIENT, ">CLIENT:ENV,END");
|
||||
}
|
||||
|
||||
void
|
||||
management_notify_client_needing_auth (struct management *management,
|
||||
const unsigned int mda_key_id,
|
||||
struct man_def_auth_context *mdac,
|
||||
const struct env_set *es)
|
||||
{
|
||||
if (!(mdac->flags & DAF_CONNECTION_CLOSED))
|
||||
{
|
||||
const char *mode = "CONNECT";
|
||||
if (mdac->flags & DAF_CONNECTION_ESTABLISHED)
|
||||
mode = "REAUTH";
|
||||
msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id);
|
||||
man_output_env (es);
|
||||
mdac->flags |= DAF_INITIAL_AUTH;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
management_connection_established (struct management *management,
|
||||
struct man_def_auth_context *mdac)
|
||||
{
|
||||
mdac->flags |= DAF_CONNECTION_ESTABLISHED;
|
||||
}
|
||||
|
||||
void
|
||||
management_notify_client_close (struct management *management,
|
||||
struct man_def_auth_context *mdac,
|
||||
const struct env_set *es)
|
||||
{
|
||||
if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED))
|
||||
{
|
||||
msg (M_CLIENT, ">CLIENT:DISCONNECT,%lu", mdac->cid);
|
||||
man_output_env (es);
|
||||
mdac->flags |= DAF_CONNECTION_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
management_learn_addr (struct management *management,
|
||||
struct man_def_auth_context *mdac,
|
||||
const struct mroute_addr *addr,
|
||||
const bool primary)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED))
|
||||
{
|
||||
msg (M_CLIENT, ">CLIENT:ADDRESS,%lu,%s,%d",
|
||||
mdac->cid,
|
||||
mroute_addr_print_ex (addr, MAPF_SUBNET, &gc),
|
||||
BOOL_CAST (primary));
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
management_echo (struct management *man, const char *string, const bool pull)
|
||||
{
|
||||
@ -2178,7 +2462,7 @@ management_query_user_pass (struct management *man,
|
||||
bool
|
||||
management_would_hold (struct management *man)
|
||||
{
|
||||
return man->settings.hold && !man->persist.hold_release && man_standalone_ok (man);
|
||||
return (man->settings.flags & MF_HOLD) && !man->persist.hold_release && man_standalone_ok (man);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2188,7 +2472,7 @@ management_would_hold (struct management *man)
|
||||
bool
|
||||
management_should_daemonize (struct management *man)
|
||||
{
|
||||
return management_would_hold (man) || man->settings.up_query_passwords;
|
||||
return management_would_hold (man) || (man->settings.flags & MF_QUERY_PASSWORDS);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2301,108 +2585,6 @@ command_line_next (struct command_line *cl)
|
||||
buf_clear (&cl->residual);
|
||||
}
|
||||
|
||||
/*
|
||||
* struct output_list
|
||||
*/
|
||||
|
||||
struct output_list *
|
||||
output_list_new (const int max_size)
|
||||
{
|
||||
struct output_list *ret;
|
||||
ALLOC_OBJ_CLEAR (ret, struct output_list);
|
||||
ret->max_size = max_size;
|
||||
ret->size = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
output_list_free (struct output_list *ol)
|
||||
{
|
||||
output_list_reset (ol);
|
||||
free (ol);
|
||||
}
|
||||
|
||||
bool
|
||||
output_list_defined (const struct output_list *ol)
|
||||
{
|
||||
return ol->head != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
output_list_reset (struct output_list *ol)
|
||||
{
|
||||
struct output_entry *e = ol->head;
|
||||
while (e)
|
||||
{
|
||||
struct output_entry *next = e->next;
|
||||
free_buf (&e->buf);
|
||||
free (e);
|
||||
e = next;
|
||||
}
|
||||
ol->head = ol->tail = NULL;
|
||||
ol->size = 0;
|
||||
}
|
||||
|
||||
void
|
||||
output_list_push (struct output_list *ol, const unsigned char *str)
|
||||
{
|
||||
if (!ol->max_size || ol->size < ol->max_size)
|
||||
{
|
||||
struct output_entry *e;
|
||||
ALLOC_OBJ_CLEAR (e, struct output_entry);
|
||||
|
||||
++ol->size;
|
||||
if (ol->tail)
|
||||
{
|
||||
ASSERT (ol->head);
|
||||
ol->tail->next = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT (!ol->head);
|
||||
ol->head = e;
|
||||
}
|
||||
e->buf = string_alloc_buf ((const char *) str, NULL);
|
||||
ol->tail = e;
|
||||
}
|
||||
}
|
||||
|
||||
const struct buffer *
|
||||
output_list_peek (struct output_list *ol)
|
||||
{
|
||||
if (ol->head)
|
||||
return &ol->head->buf;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
output_list_pop (struct output_list *ol)
|
||||
{
|
||||
if (ol->head)
|
||||
{
|
||||
struct output_entry *e = ol->head->next;
|
||||
free_buf (&ol->head->buf);
|
||||
free (ol->head);
|
||||
ol->head = e;
|
||||
--ol->size;
|
||||
if (!e)
|
||||
ol->tail = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
output_list_advance (struct output_list *ol, int n)
|
||||
{
|
||||
if (ol->head)
|
||||
{
|
||||
struct buffer *buf = &ol->head->buf;
|
||||
ASSERT (buf_advance (buf, n));
|
||||
if (!BLEN (buf))
|
||||
output_list_pop (ol);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* struct log_entry
|
||||
*/
|
||||
|
139
manage.h
139
manage.h
@ -30,6 +30,7 @@
|
||||
#include "misc.h"
|
||||
#include "event.h"
|
||||
#include "socket.h"
|
||||
#include "mroute.h"
|
||||
|
||||
#define MANAGEMENT_VERSION 1
|
||||
#define MANAGEMENT_N_PASSWORD_RETRIES 3
|
||||
@ -37,6 +38,22 @@
|
||||
#define MANAGEMENT_ECHO_BUFFER_SIZE 100
|
||||
#define MANAGEMENT_STATE_BUFFER_SIZE 100
|
||||
|
||||
/*
|
||||
* Management-interface-based deferred authentication
|
||||
*/
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
struct man_def_auth_context {
|
||||
unsigned long cid;
|
||||
|
||||
#define DAF_CONNECTION_ESTABLISHED (1<<0)
|
||||
#define DAF_CONNECTION_CLOSED (1<<1)
|
||||
#define DAF_INITIAL_AUTH (1<<2)
|
||||
unsigned int flags;
|
||||
|
||||
unsigned int mda_key_id_counter;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Manage build-up of command line
|
||||
*/
|
||||
@ -54,34 +71,6 @@ const unsigned char *command_line_get (struct command_line *cl);
|
||||
void command_line_reset (struct command_line *cl);
|
||||
void command_line_next (struct command_line *cl);
|
||||
|
||||
/*
|
||||
* Manage lists of output strings
|
||||
*/
|
||||
|
||||
struct output_entry
|
||||
{
|
||||
struct buffer buf;
|
||||
struct output_entry *next;
|
||||
};
|
||||
|
||||
struct output_list
|
||||
{
|
||||
struct output_entry *head; /* next item to pop/peek */
|
||||
struct output_entry *tail; /* last item pushed */
|
||||
int size; /* current number of entries */
|
||||
int max_size; /* maximum size list should grow to */
|
||||
};
|
||||
|
||||
struct output_list *output_list_new (const int max_size);
|
||||
void output_list_free (struct output_list *ol);
|
||||
|
||||
bool output_list_defined (const struct output_list *ol);
|
||||
void output_list_reset (struct output_list *ol);
|
||||
|
||||
void output_list_push (struct output_list *ol, const unsigned char *str);
|
||||
const struct buffer *output_list_peek (struct output_list *ol);
|
||||
void output_list_advance (struct output_list *ol, int n);
|
||||
|
||||
/*
|
||||
* Manage log file history
|
||||
*/
|
||||
@ -148,7 +137,8 @@ log_history_capacity (const struct log_history *h)
|
||||
}
|
||||
|
||||
/*
|
||||
* Callbacks for 'status' and 'kill' commands
|
||||
* Callbacks for 'status' and 'kill' commands.
|
||||
* Also for management-based deferred authentication and packet filter.
|
||||
*/
|
||||
struct management_callback
|
||||
{
|
||||
@ -158,6 +148,20 @@ struct management_callback
|
||||
int (*kill_by_cn) (void *arg, const char *common_name);
|
||||
int (*kill_by_addr) (void *arg, const in_addr_t addr, const int port);
|
||||
void (*delete_event) (void *arg, event_t event);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
bool (*kill_by_cid) (void *arg, const unsigned long cid);
|
||||
bool (*client_auth) (void *arg,
|
||||
const unsigned long cid,
|
||||
const unsigned int mda_key_id,
|
||||
const bool auth,
|
||||
const char *reason,
|
||||
struct buffer_list *cc_config); /* ownership transferred */
|
||||
#endif
|
||||
#ifdef MANAGEMENT_PF
|
||||
bool (*client_pf) (void *arg,
|
||||
const unsigned long cid,
|
||||
struct buffer_list *pf_config); /* ownership transferred */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@ -196,18 +200,13 @@ struct man_persist {
|
||||
|
||||
struct man_settings {
|
||||
bool defined;
|
||||
unsigned int flags; /* MF_x flags */
|
||||
struct openvpn_sockaddr local;
|
||||
bool up_query_passwords;
|
||||
bool management_over_tunnel;
|
||||
struct user_pass up;
|
||||
int log_history_cache;
|
||||
int echo_buffer_size;
|
||||
int state_buffer_size;
|
||||
bool server;
|
||||
bool hold;
|
||||
bool signal_on_disconnect;
|
||||
bool management_forget_disconnect;
|
||||
bool connect_as_client;
|
||||
char *write_peer_info_file;
|
||||
|
||||
/* flags for handling the management interface "signal" command */
|
||||
@ -246,8 +245,17 @@ struct man_connection {
|
||||
int password_tries;
|
||||
|
||||
struct command_line *in;
|
||||
struct output_list *out;
|
||||
struct buffer_list *out;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
# define IEC_UNDEF 0
|
||||
# define IEC_CLIENT_AUTH 1
|
||||
# define IEC_CLIENT_PF 2
|
||||
int in_extra_cmd;
|
||||
unsigned long in_extra_cid;
|
||||
unsigned int in_extra_kid;
|
||||
struct buffer_list *in_extra;
|
||||
#endif
|
||||
struct event_set *es;
|
||||
|
||||
bool state_realtime;
|
||||
@ -274,21 +282,29 @@ struct user_pass;
|
||||
|
||||
struct management *management_init (void);
|
||||
|
||||
/* management_open flags */
|
||||
# define MF_SERVER (1<<0)
|
||||
# define MF_QUERY_PASSWORDS (1<<1)
|
||||
# define MF_HOLD (1<<2)
|
||||
# define MF_SIGNAL (1<<3)
|
||||
# define MF_FORGET_DISCONNECT (1<<4)
|
||||
# define MF_CONNECT_AS_CLIENT (1<<5)
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
# define MF_CLIENT_AUTH (1<<6)
|
||||
#endif
|
||||
#ifdef MANAGEMENT_PF
|
||||
# define MF_CLIENT_PF (1<<7)
|
||||
#endif
|
||||
bool management_open (struct management *man,
|
||||
const char *addr,
|
||||
const int port,
|
||||
const char *pass_file,
|
||||
const bool server,
|
||||
const bool query_passwords,
|
||||
const int log_history_cache,
|
||||
const int echo_buffer_size,
|
||||
const int state_buffer_size,
|
||||
const bool hold,
|
||||
const bool signal_on_disconnect,
|
||||
const bool management_forget_disconnect,
|
||||
const bool connect_as_client,
|
||||
const char *write_peer_info_file,
|
||||
const int remap_sigusr1);
|
||||
const int remap_sigusr1,
|
||||
const unsigned int flags);
|
||||
|
||||
void management_close (struct management *man);
|
||||
|
||||
@ -316,6 +332,25 @@ bool management_hold (struct management *man);
|
||||
|
||||
void management_event_loop_n_seconds (struct management *man, int sec);
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
void management_notify_client_needing_auth (struct management *management,
|
||||
const unsigned int auth_id,
|
||||
struct man_def_auth_context *mdac,
|
||||
const struct env_set *es);
|
||||
|
||||
void management_connection_established (struct management *management,
|
||||
struct man_def_auth_context *mdac);
|
||||
|
||||
void management_notify_client_close (struct management *management,
|
||||
struct man_def_auth_context *mdac,
|
||||
const struct env_set *es);
|
||||
|
||||
void management_learn_addr (struct management *management,
|
||||
struct man_def_auth_context *mdac,
|
||||
const struct mroute_addr *addr,
|
||||
const bool primary);
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
management_connected (const struct management *man)
|
||||
{
|
||||
@ -325,9 +360,25 @@ management_connected (const struct management *man)
|
||||
static inline bool
|
||||
management_query_user_pass_enabled (const struct management *man)
|
||||
{
|
||||
return man->settings.up_query_passwords;
|
||||
return BOOL_CAST(man->settings.flags & MF_QUERY_PASSWORDS);
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_PF
|
||||
static inline bool
|
||||
management_enable_pf (const struct management *man)
|
||||
{
|
||||
return man && BOOL_CAST(man->settings.flags & MF_CLIENT_PF);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
static inline bool
|
||||
management_enable_def_auth (const struct management *man)
|
||||
{
|
||||
return man && BOOL_CAST(man->settings.flags & MF_CLIENT_AUTH);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OpenVPN tells the management layer what state it's in
|
||||
*/
|
||||
|
@ -25,13 +25,12 @@ Future versions of the management interface may allow out-of-band
|
||||
connections (i.e. not over the VPN) and secured with SSL/TLS.
|
||||
|
||||
The management interface is enabled in the OpenVPN
|
||||
configuration file using the following directives:
|
||||
configuration file using the following directive:
|
||||
|
||||
--management
|
||||
--management-query-passwords
|
||||
--management-log-cache
|
||||
|
||||
See the man page for documentation on these directives.
|
||||
See the man page for documentation on this and related
|
||||
directives.
|
||||
|
||||
Once OpenVPN has started with the management layer enabled,
|
||||
you can telnet to the management port (make sure to use
|
||||
@ -444,6 +443,199 @@ Example:
|
||||
pkcs11-id-get 1
|
||||
PKCS11ID-ENTRY:'1', ID:'<snip>', BLOB:'<snip>'
|
||||
|
||||
COMMAND -- client-auth (OpenVPN 2.1 or higher)
|
||||
-----------------------------------------------
|
||||
|
||||
Authorize a ">CLIENT:CONNECT" or ">CLIENT:REAUTH" request and specify
|
||||
"client-connect" configuration directives in a subsequent text block.
|
||||
|
||||
The OpenVPN server should have been started with the
|
||||
--management-client-auth directive so that it will ask the management
|
||||
interface to approve client connections.
|
||||
|
||||
|
||||
client-auth {CID} {KID}
|
||||
line_1
|
||||
line_2
|
||||
...
|
||||
line_n
|
||||
END
|
||||
|
||||
CID,KID -- client ID and Key ID. See documentation for ">CLIENT:"
|
||||
notification for more info.
|
||||
|
||||
line_1 to line_n -- client-connect configuration text block, as would be
|
||||
returned by a --client-connect script. The text block may be null, with
|
||||
"END" immediately following the "client-auth" line (using a null text
|
||||
block is equivalent to using the client-auth-nt command).
|
||||
|
||||
A client-connect configuration text block contains OpenVPN directives
|
||||
that will be applied to the client instance object representing a newly
|
||||
connected client.
|
||||
|
||||
COMMAND -- client-auth-nt (OpenVPN 2.1 or higher)
|
||||
--------------------------------------------------
|
||||
|
||||
Authorize a ">CLIENT:CONNECT" or ">CLIENT:REAUTH" request without specifying
|
||||
client-connect configuration text.
|
||||
|
||||
The OpenVPN server should have been started with the
|
||||
--management-client-auth directive so that it will ask the management
|
||||
interface to approve client connections.
|
||||
|
||||
client-auth-nt {CID} {KID}
|
||||
|
||||
CID,KID -- client ID and Key ID. See documentation for ">CLIENT:"
|
||||
notification for more info.
|
||||
|
||||
COMMAND -- client-deny (OpenVPN 2.1 or higher)
|
||||
-----------------------------------------------
|
||||
|
||||
Deny a ">CLIENT:CONNECT" or ">CLIENT:REAUTH" request.
|
||||
|
||||
client-deny {CID} {KID} "reason-text"
|
||||
|
||||
CID,KID -- client ID and Key ID. See documentation for ">CLIENT:"
|
||||
notification for more info.
|
||||
|
||||
reason-text: a human-readable message explaining why the authentication
|
||||
request was denied. This message will be output to the OpenVPN log
|
||||
file or syslog.
|
||||
|
||||
Note that client-deny denies a specific Key ID (pertaining to a
|
||||
TLS renegotiation). A client-deny command issued in response to
|
||||
an initial TLS key negotiation (notified by ">CLIENT:CONNECT") will
|
||||
terminate the client session after returning "AUTH-FAILED" to the client.
|
||||
On the other hand, a client-deny command issued in response to
|
||||
a TLS renegotiation (">CLIENT:REAUTH") will invalidate the renegotiated
|
||||
key, however the TLS session associated with the currently active
|
||||
key will continue to live for up to --tran-window seconds before
|
||||
expiration.
|
||||
|
||||
To immediately kill a client session, use "client-kill".
|
||||
|
||||
COMMAND -- client-kill (OpenVPN 2.1 or higher)
|
||||
-----------------------------------------------
|
||||
|
||||
Immediately kill a client instance by CID.
|
||||
|
||||
client-kill {CID}
|
||||
|
||||
CID -- client ID. See documentation for ">CLIENT:" notification for more
|
||||
info.
|
||||
|
||||
COMMAND -- client-pf (OpenVPN 2.1 or higher)
|
||||
---------------------------------------------
|
||||
|
||||
Push a packet filter file to a specific client.
|
||||
|
||||
The OpenVPN server should have been started with the
|
||||
--management-client-pf directive so that it will require that
|
||||
VPN tunnel packets sent or received by client instances must
|
||||
conform to that client's packet filter configuration.
|
||||
|
||||
client-pf {CID}
|
||||
line_1
|
||||
line_2
|
||||
...
|
||||
line_n
|
||||
END
|
||||
|
||||
CID -- client ID. See documentation for ">CLIENT:" notification for
|
||||
more info.
|
||||
|
||||
line_1 to line_n -- the packet filter configuration file for this
|
||||
client.
|
||||
|
||||
Packet filter file grammar:
|
||||
|
||||
[CLIENTS DROP|ACCEPT]
|
||||
{+|-}common_name1
|
||||
{+|-}common_name2
|
||||
. . .
|
||||
[SUBNETS DROP|ACCEPT]
|
||||
{+|-}subnet1
|
||||
{+|-}subnet2
|
||||
. . .
|
||||
[END]
|
||||
|
||||
Subnet: IP-ADDRESS | IP-ADDRESS/NUM_NETWORK_BITS | "unknown"
|
||||
|
||||
CLIENTS refers to the set of clients (by their common-name) which
|
||||
this instance is allowed ('+') to connect to, or is excluded ('-')
|
||||
from connecting to. Note that in the case of client-to-client
|
||||
connections, such communication must be allowed by the packet filter
|
||||
configuration files of both clients AND the --client-to-client
|
||||
directive must have been specified in the OpenVPN server config.
|
||||
|
||||
SUBNETS refers to IP addresses or IP address subnets which this
|
||||
client instance may connect to ('+') or is excluded ('-') from
|
||||
connecting to, and applies to IPv4 and ARP packets. The special
|
||||
"unknown" tag refers to packets of unknown type, i.e. a packet that
|
||||
is not IPv4 or ARP.
|
||||
|
||||
DROP or ACCEPT defines default policy when there is no explicit match
|
||||
for a common-name or subnet. The [END] tag must exist.
|
||||
|
||||
Notes:
|
||||
|
||||
* The SUBNETS section currently only supports IPv4 addresses and
|
||||
subnets.
|
||||
|
||||
* A given client or subnet rule applies to both incoming and
|
||||
outgoing packets.
|
||||
|
||||
* The CLIENTS list is order-invariant. Because the list is stored
|
||||
as a hash-table, the order of the list does not affect its function.
|
||||
|
||||
* The SUBNETS table is scanned sequentially, and the first item to
|
||||
match is chosen. Therefore the SUBNETS table is NOT order-invariant.
|
||||
|
||||
* No client-to-client communication is allowed unless the
|
||||
--client-to-client configuration directive is enabled AND
|
||||
the CLIENTS list of BOTH clients allows the communication.
|
||||
|
||||
Example packet filter spec, as transmitted to the management interface:
|
||||
|
||||
client-pf 42
|
||||
[CLIENTS ACCEPT]
|
||||
-accounting
|
||||
-enigma
|
||||
[SUBNETS DROP]
|
||||
-10.46.79.9
|
||||
+10.0.0.0/8
|
||||
[END]
|
||||
END
|
||||
|
||||
The above example sets the packet filter policy for the client
|
||||
identified by CID=42. This client may connect to all other clients
|
||||
except those having a common name of "accounting" or "enigma".
|
||||
The client may only interact with external IP addresses in the
|
||||
10.0.0.0/8 subnet, however access to 10.46.79.9 is specifically
|
||||
excluded.
|
||||
|
||||
Another example packet filter spec, as transmitted to the
|
||||
management interface:
|
||||
|
||||
client-pf 99
|
||||
[CLIENTS DENY]
|
||||
+public
|
||||
[SUBNETS ACCEPT]
|
||||
+10.10.0.1
|
||||
-10.0.0.0/8
|
||||
-unknown
|
||||
[END]
|
||||
END
|
||||
|
||||
The above example sets the packet filter policy for the client
|
||||
identified by CID=99. This client may not connect to any other
|
||||
clients except those having a common name of "public". It may
|
||||
interact with any external IP address except those in the
|
||||
10.0.0.0/8 netblock. However interaction with one address in
|
||||
the 10.0.0.0/8 netblock is allowed: 10.10.0.1. Also, the client
|
||||
may not interact with external IP addresses using an "unknown"
|
||||
protocol (i.e. one that is not IPv4 or ARP).
|
||||
|
||||
OUTPUT FORMAT
|
||||
-------------
|
||||
|
||||
@ -454,7 +646,7 @@ OUTPUT FORMAT
|
||||
the last line will be "END".
|
||||
|
||||
(3) Real-time messages will be in the form ">[source]:[text]",
|
||||
where source is "ECHO", "FATAL", "HOLD", "INFO", "LOG",
|
||||
where source is "CLIENT", "ECHO", "FATAL", "HOLD", "INFO", "LOG",
|
||||
"NEED-OK", "PASSWORD", or "STATE".
|
||||
|
||||
REAL-TIME MESSAGE FORMAT
|
||||
@ -469,6 +661,12 @@ column and are immediately followed by a type keyword
|
||||
indicating the type of real-time message. The following
|
||||
types are currently defined:
|
||||
|
||||
CLIENT -- Notification of client connections and disconnections
|
||||
on an OpenVPN server. Enabled when OpenVPN is started
|
||||
with the --management-client-auth option. CLIENT
|
||||
notifications may be multi-line. See "The CLIENT
|
||||
notification" section below for detailed info.
|
||||
|
||||
ECHO -- Echo messages as controlled by the "echo" command.
|
||||
|
||||
FATAL -- A fatal error which is output to the log file just
|
||||
@ -497,6 +695,60 @@ PASSWORD -- Used to tell the management client that OpenVPN
|
||||
STATE -- Shows the current OpenVPN state, as controlled
|
||||
by the "state" command.
|
||||
|
||||
The CLIENT notification
|
||||
-----------------------
|
||||
|
||||
The ">CLIENT:" notification is enabled by the --management-client-auth
|
||||
OpenVPN configuration directive that gives the management interface client
|
||||
the responsibility to authenticate OpenVPN clients after their client
|
||||
certificate has been verified. CLIENT notifications may be multi-line, and
|
||||
the sequentiality of a given CLIENT notification, its associated environmental
|
||||
variables, and the terminating ">CLIENT:ENV,END" line are guaranteed to be
|
||||
atomic.
|
||||
|
||||
CLIENT notification types:
|
||||
|
||||
(1) Notify new client connection ("CONNECT") or existing client TLS session
|
||||
renegotiation ("REAUTH"). Information about the client is provided
|
||||
by a list of environmental variables which are documented in the OpenVPN
|
||||
man page. The environmental variables passed are equivalent to those
|
||||
that would be passed to an --auth-user-pass-verify script.
|
||||
|
||||
>CLIENT:CONNECT|REAUTH,{CID},{KID}
|
||||
>CLIENT:ENV,name1=val1
|
||||
>CLIENT:ENV,name2=val2
|
||||
>CLIENT:ENV,...
|
||||
>CLIENT:ENV,END
|
||||
|
||||
(2) Notify existing client disconnection. The environmental variables passed
|
||||
are equivalent to those that would be passed to a --client-disconnect
|
||||
script.
|
||||
|
||||
>CLIENT:DISCONNECT,{CID}
|
||||
>CLIENT:ENV,name1=val1
|
||||
>CLIENT:ENV,name2=val2
|
||||
>CLIENT:ENV,...
|
||||
>CLIENT:ENV,END
|
||||
|
||||
(3) Notify that a particular virtual address or subnet
|
||||
is now associated with a specific client.
|
||||
|
||||
>CLIENT:ADDRESS,{CID},{ADDR},{PRI}
|
||||
|
||||
Variables:
|
||||
|
||||
CID -- Client ID, numerical ID for each connecting client, sequence = 0,1,2,...
|
||||
KID -- Key ID, numerical ID for the key associated with a given client TLS session,
|
||||
sequence = 0,1,2,...
|
||||
PRI -- Primary (1) or Secondary (0) VPN address/subnet. All clients have at least
|
||||
one primary IP address. Secondary address/subnets are associated with
|
||||
client-specific "iroute" directives.
|
||||
ADDR -- IPv4 address/subnet in the form 1.2.3.4 or 1.2.3.0/255.255.255.0
|
||||
|
||||
In the unlikely scenario of an extremely long-running OpenVPN server,
|
||||
CID and KID should be assumed to recycle to 0 after (2^32)-1, however this
|
||||
recycling behavior is guaranteed to be collision-free.
|
||||
|
||||
Command Parsing
|
||||
---------------
|
||||
|
||||
|
225
mroute.c
225
mroute.c
@ -76,91 +76,148 @@ mroute_learnable_address (const struct mroute_addr *addr)
|
||||
return not_all_zeros && not_all_ones && !is_mac_mcast_maddr (addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a raw packet in buf, return the src and dest
|
||||
* addresses of the packet.
|
||||
*/
|
||||
unsigned int
|
||||
mroute_extract_addr_from_packet (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
struct buffer *buf,
|
||||
int tunnel_type)
|
||||
static inline void
|
||||
mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
|
||||
{
|
||||
if (ma)
|
||||
{
|
||||
ma->type = MR_ADDR_IPV4 | mask;
|
||||
ma->netbits = 0;
|
||||
ma->len = 4;
|
||||
*(in_addr_t*)ma->addr = src;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
mroute_is_mcast (const in_addr_t addr)
|
||||
{
|
||||
return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
|
||||
static unsigned int
|
||||
mroute_extract_addr_arp (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
const struct buffer *buf)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
verify_align_4 (buf);
|
||||
if (tunnel_type == DEV_TYPE_TUN)
|
||||
if (BLEN (buf) >= (int) sizeof (struct openvpn_arp))
|
||||
{
|
||||
if (BLEN (buf) >= 1)
|
||||
const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR (buf);
|
||||
if (arp->mac_addr_type == htons(0x0001)
|
||||
&& arp->proto_addr_type == htons(0x0800)
|
||||
&& arp->mac_addr_size == 0x06
|
||||
&& arp->proto_addr_size == 0x04)
|
||||
{
|
||||
switch (OPENVPN_IPH_GET_VER (*BPTR(buf)))
|
||||
{
|
||||
case 4:
|
||||
if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))
|
||||
{
|
||||
const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf);
|
||||
if (src)
|
||||
{
|
||||
src->type = MR_ADDR_IPV4;
|
||||
src->netbits = 0;
|
||||
src->len = 4;
|
||||
memcpy (src->addr, &ip->saddr, 4);
|
||||
}
|
||||
if (dest)
|
||||
{
|
||||
dest->type = MR_ADDR_IPV4;
|
||||
dest->netbits = 0;
|
||||
dest->len = 4;
|
||||
memcpy (dest->addr, &ip->daddr, 4);
|
||||
mroute_get_in_addr_t (src, arp->ip_src, MR_ARP);
|
||||
mroute_get_in_addr_t (dest, arp->ip_dest, MR_ARP);
|
||||
|
||||
/* mcast address? */
|
||||
if ((ip->daddr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK))
|
||||
ret |= MROUTE_EXTRACT_MCAST;
|
||||
/* multicast packet? */
|
||||
if (mroute_is_mcast (arp->ip_dest))
|
||||
ret |= MROUTE_EXTRACT_MCAST;
|
||||
|
||||
/* IGMP message? */
|
||||
if (ip->protocol == OPENVPN_IPPROTO_IGMP)
|
||||
ret |= MROUTE_EXTRACT_IGMP;
|
||||
}
|
||||
ret |= MROUTE_EXTRACT_SUCCEEDED;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
msg (M_WARN, "Need IPv6 code in mroute_extract_addr_from_packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tunnel_type == DEV_TYPE_TAP)
|
||||
{
|
||||
if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr))
|
||||
{
|
||||
const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR (buf);
|
||||
if (src)
|
||||
{
|
||||
src->type = MR_ADDR_ETHER;
|
||||
src->netbits = 0;
|
||||
src->len = 6;
|
||||
memcpy (src->addr, eth->source, 6);
|
||||
}
|
||||
if (dest)
|
||||
{
|
||||
dest->type = MR_ADDR_ETHER;
|
||||
dest->netbits = 0;
|
||||
dest->len = 6;
|
||||
memcpy (dest->addr, eth->dest, 6);
|
||||
|
||||
/* ethernet broadcast/multicast packet? */
|
||||
if (is_mac_mcast_addr (eth->dest))
|
||||
ret |= MROUTE_EXTRACT_BCAST;
|
||||
}
|
||||
|
||||
ret |= MROUTE_EXTRACT_SUCCEEDED;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned int
|
||||
mroute_extract_addr_ipv4 (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
const struct buffer *buf)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
if (BLEN (buf) >= 1)
|
||||
{
|
||||
switch (OPENVPN_IPH_GET_VER (*BPTR(buf)))
|
||||
{
|
||||
case 4:
|
||||
if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))
|
||||
{
|
||||
const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf);
|
||||
|
||||
mroute_get_in_addr_t (src, ip->saddr, 0);
|
||||
mroute_get_in_addr_t (dest, ip->daddr, 0);
|
||||
|
||||
/* multicast packet? */
|
||||
if (mroute_is_mcast (ip->daddr))
|
||||
ret |= MROUTE_EXTRACT_MCAST;
|
||||
|
||||
/* IGMP message? */
|
||||
if (ip->protocol == OPENVPN_IPPROTO_IGMP)
|
||||
ret |= MROUTE_EXTRACT_IGMP;
|
||||
|
||||
ret |= MROUTE_EXTRACT_SUCCEEDED;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
msg (M_WARN, "Need IPv6 code in mroute_extract_addr_from_packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
mroute_extract_addr_ether (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
struct mroute_addr *esrc,
|
||||
struct mroute_addr *edest,
|
||||
const struct buffer *buf)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr))
|
||||
{
|
||||
const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR (buf);
|
||||
if (src)
|
||||
{
|
||||
src->type = MR_ADDR_ETHER;
|
||||
src->netbits = 0;
|
||||
src->len = 6;
|
||||
memcpy (src->addr, eth->source, 6);
|
||||
}
|
||||
if (dest)
|
||||
{
|
||||
dest->type = MR_ADDR_ETHER;
|
||||
dest->netbits = 0;
|
||||
dest->len = 6;
|
||||
memcpy (dest->addr, eth->dest, 6);
|
||||
|
||||
/* ethernet broadcast/multicast packet? */
|
||||
if (is_mac_mcast_addr (eth->dest))
|
||||
ret |= MROUTE_EXTRACT_BCAST;
|
||||
}
|
||||
|
||||
ret |= MROUTE_EXTRACT_SUCCEEDED;
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
if (esrc || edest)
|
||||
{
|
||||
struct buffer b = *buf;
|
||||
if (buf_advance (&b, sizeof (struct openvpn_ethhdr)))
|
||||
{
|
||||
switch (ntohs (eth->proto))
|
||||
{
|
||||
case OPENVPN_ETH_P_IPV4:
|
||||
ret |= (mroute_extract_addr_ipv4 (esrc, edest, &b) << MROUTE_SEC_SHIFT);
|
||||
break;
|
||||
case OPENVPN_ETH_P_ARP:
|
||||
ret |= (mroute_extract_addr_arp (esrc, edest, &b) << MROUTE_SEC_SHIFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a struct openvpn_sockaddr (osaddr)
|
||||
* to a struct mroute_addr (addr).
|
||||
@ -228,6 +285,14 @@ mroute_addr_compare_function (const void *key1, const void *key2)
|
||||
const char *
|
||||
mroute_addr_print (const struct mroute_addr *ma,
|
||||
struct gc_arena *gc)
|
||||
{
|
||||
return mroute_addr_print_ex (ma, MAPF_IA_EMPTY_IF_UNDEF, gc);
|
||||
}
|
||||
|
||||
const char *
|
||||
mroute_addr_print_ex (const struct mroute_addr *ma,
|
||||
const unsigned int flags,
|
||||
struct gc_arena *gc)
|
||||
{
|
||||
struct buffer out = alloc_buf_gc (64, gc);
|
||||
if (ma)
|
||||
@ -249,9 +314,19 @@ mroute_addr_print (const struct mroute_addr *ma,
|
||||
addr = buf_read_u32 (&buf, &status);
|
||||
if (status)
|
||||
{
|
||||
buf_printf (&out, "%s", print_in_addr_t (addr, IA_EMPTY_IF_UNDEF, gc));
|
||||
if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
|
||||
buf_printf (&out, "ARP/");
|
||||
buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
|
||||
if (maddr.type & MR_WITH_NETBITS)
|
||||
buf_printf (&out, "/%d", maddr.netbits);
|
||||
{
|
||||
if (flags & MAPF_SUBNET)
|
||||
{
|
||||
const in_addr_t netmask = netbits_to_netmask (maddr.netbits);
|
||||
buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc));
|
||||
}
|
||||
else
|
||||
buf_printf (&out, "/%d", maddr.netbits);
|
||||
}
|
||||
}
|
||||
if (maddr.type & MR_WITH_PORT)
|
||||
{
|
||||
|
73
mroute.h
73
mroute.h
@ -35,10 +35,18 @@
|
||||
#define IP_MCAST_NETWORK ((in_addr_t)224<<24)
|
||||
|
||||
/* Return status values for mroute_extract_addr_from_packet */
|
||||
#define MROUTE_EXTRACT_SUCCEEDED (1<<1)
|
||||
#define MROUTE_EXTRACT_BCAST (1<<2)
|
||||
#define MROUTE_EXTRACT_MCAST (1<<3)
|
||||
#define MROUTE_EXTRACT_IGMP (1<<4)
|
||||
|
||||
#define MROUTE_EXTRACT_SUCCEEDED (1<<0)
|
||||
#define MROUTE_EXTRACT_BCAST (1<<1)
|
||||
#define MROUTE_EXTRACT_MCAST (1<<2)
|
||||
#define MROUTE_EXTRACT_IGMP (1<<3)
|
||||
|
||||
#define MROUTE_SEC_EXTRACT_SUCCEEDED (1<<(0+MROUTE_SEC_SHIFT))
|
||||
#define MROUTE_SEC_EXTRACT_BCAST (1<<(1+MROUTE_SEC_SHIFT))
|
||||
#define MROUTE_SEC_EXTRACT_MCAST (1<<(2+MROUTE_SEC_SHIFT))
|
||||
#define MROUTE_SEC_EXTRACT_IGMP (1<<(3+MROUTE_SEC_SHIFT))
|
||||
|
||||
#define MROUTE_SEC_SHIFT 4
|
||||
|
||||
/*
|
||||
* Choose the largest address possible with
|
||||
@ -62,6 +70,9 @@
|
||||
/* Address type mask indicating that netbits is part of address */
|
||||
#define MR_WITH_NETBITS 8
|
||||
|
||||
/* Indicates than IPv4 addr was extracted from ARP packet */
|
||||
#define MR_ARP 16
|
||||
|
||||
struct mroute_addr {
|
||||
uint8_t len; /* length of address */
|
||||
uint8_t unused;
|
||||
@ -72,8 +83,7 @@ struct mroute_addr {
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of bits in an address. Should be raised for
|
||||
* IPv6.
|
||||
* Number of bits in an address. Should be raised for IPv6.
|
||||
*/
|
||||
#define MR_HELPER_NET_LEN 32
|
||||
|
||||
@ -89,11 +99,6 @@ struct mroute_helper {
|
||||
int net_len_refcount[MR_HELPER_NET_LEN]; /* refcount of each netlength */
|
||||
};
|
||||
|
||||
unsigned int mroute_extract_addr_from_packet (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
struct buffer *buf,
|
||||
int tunnel_type);
|
||||
|
||||
struct openvpn_sockaddr;
|
||||
|
||||
bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
|
||||
@ -110,6 +115,13 @@ void mroute_addr_init (struct mroute_addr *addr);
|
||||
const char *mroute_addr_print (const struct mroute_addr *ma,
|
||||
struct gc_arena *gc);
|
||||
|
||||
#define MAPF_SUBNET (1<<0)
|
||||
#define MAPF_IA_EMPTY_IF_UNDEF (1<<1)
|
||||
#define MAPF_SHOW_ARP (1<<2)
|
||||
const char *mroute_addr_print_ex (const struct mroute_addr *ma,
|
||||
const unsigned int flags,
|
||||
struct gc_arena *gc);
|
||||
|
||||
void mroute_addr_mask_host_bits (struct mroute_addr *ma);
|
||||
|
||||
struct mroute_helper *mroute_helper_init (int ageable_ttl_secs);
|
||||
@ -117,6 +129,36 @@ void mroute_helper_free (struct mroute_helper *mh);
|
||||
void mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir);
|
||||
void mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir);
|
||||
|
||||
/*
|
||||
* Given a raw packet in buf, return the src and dest
|
||||
* addresses of the packet.
|
||||
*/
|
||||
static inline unsigned int
|
||||
mroute_extract_addr_from_packet (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
struct mroute_addr *esrc,
|
||||
struct mroute_addr *edest,
|
||||
const struct buffer *buf,
|
||||
int tunnel_type)
|
||||
{
|
||||
unsigned int mroute_extract_addr_ipv4 (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
const struct buffer *buf);
|
||||
|
||||
unsigned int mroute_extract_addr_ether (struct mroute_addr *src,
|
||||
struct mroute_addr *dest,
|
||||
struct mroute_addr *esrc,
|
||||
struct mroute_addr *edest,
|
||||
const struct buffer *buf);
|
||||
unsigned int ret = 0;
|
||||
verify_align_4 (buf);
|
||||
if (tunnel_type == DEV_TYPE_TUN)
|
||||
ret = mroute_extract_addr_ipv4 (src, dest, buf);
|
||||
else if (tunnel_type == DEV_TYPE_TAP)
|
||||
ret = mroute_extract_addr_ether (src, dest, esrc, edest, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void
|
||||
mroute_helper_lock (struct mroute_helper *mh)
|
||||
{
|
||||
@ -166,11 +208,18 @@ mroute_extract_in_addr_t (struct mroute_addr *dest, const in_addr_t src)
|
||||
static inline in_addr_t
|
||||
in_addr_t_from_mroute_addr (const struct mroute_addr *addr)
|
||||
{
|
||||
if (addr->type == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4)
|
||||
if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4)
|
||||
return ntohl(*(in_addr_t*)addr->addr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
mroute_addr_reset (struct mroute_addr *ma)
|
||||
{
|
||||
ma->len = 0;
|
||||
ma->type = MR_ADDR_NONE;
|
||||
}
|
||||
|
||||
#endif /* P2MP_SERVER */
|
||||
#endif /* MROUTE_H */
|
||||
|
353
multi.c
353
multi.c
@ -35,6 +35,7 @@
|
||||
#include "memdbg.h"
|
||||
|
||||
#include "forward-inline.h"
|
||||
#include "pf-inline.h"
|
||||
|
||||
/*#define MULTI_DEBUG_EVENT_LOOP*/
|
||||
|
||||
@ -49,6 +50,16 @@ id (struct multi_instance *mi)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
static void
|
||||
set_cc_config (struct multi_instance *mi, struct buffer_list *cc_config)
|
||||
{
|
||||
if (mi->cc_config)
|
||||
buffer_list_free (mi->cc_config);
|
||||
mi->cc_config = cc_config;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
learn_address_script (const struct multi_context *m,
|
||||
const struct multi_instance *mi,
|
||||
@ -198,6 +209,25 @@ reap_buckets_per_pass (int n_buckets)
|
||||
return constrain_int (n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX);
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
|
||||
static uint32_t
|
||||
cid_hash_function (const void *key, uint32_t iv)
|
||||
{
|
||||
const unsigned long *k = (const unsigned long *)key;
|
||||
return (uint32_t) *k;
|
||||
}
|
||||
|
||||
static bool
|
||||
cid_compare_function (const void *key1, const void *key2)
|
||||
{
|
||||
const unsigned long *k1 = (const unsigned long *)key1;
|
||||
const unsigned long *k2 = (const unsigned long *)key2;
|
||||
return *k1 == *k2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main initialization function, init multi_context object.
|
||||
*/
|
||||
@ -252,6 +282,13 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
|
||||
mroute_addr_hash_function,
|
||||
mroute_addr_compare_function);
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
m->cid_hash = hash_init (t->options.real_hash_size,
|
||||
0,
|
||||
cid_hash_function,
|
||||
cid_compare_function);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is our scheduler, for time-based wakeup
|
||||
* events.
|
||||
@ -376,6 +413,15 @@ ungenerate_prefix (struct multi_instance *mi)
|
||||
set_prefix (mi);
|
||||
}
|
||||
|
||||
static const char *
|
||||
mi_prefix (const struct multi_instance *mi)
|
||||
{
|
||||
if (mi && mi->msg_prefix)
|
||||
return mi->msg_prefix;
|
||||
else
|
||||
return "UNDEF_I";
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the route helper about deleted iroutes so
|
||||
* that it can update its mask of currently used
|
||||
@ -439,6 +485,11 @@ multi_client_disconnect_script (struct multi_context *m,
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management)
|
||||
management_notify_client_close (management, &mi->context.c2.mda_context, mi->context.c2.es);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,6 +521,12 @@ multi_close_instance (struct multi_context *m,
|
||||
{
|
||||
ASSERT (hash_remove (m->iter, &mi->real));
|
||||
}
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (mi->did_cid_hash)
|
||||
{
|
||||
ASSERT (hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid));
|
||||
}
|
||||
#endif
|
||||
|
||||
schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
|
||||
|
||||
@ -487,6 +544,10 @@ multi_close_instance (struct multi_context *m,
|
||||
mbuf_dereference_instance (m->mbuf, mi);
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
set_cc_config (mi, NULL);
|
||||
#endif
|
||||
|
||||
multi_client_disconnect_script (m, mi);
|
||||
|
||||
if (mi->did_open_context)
|
||||
@ -538,6 +599,9 @@ multi_uninit (struct multi_context *m)
|
||||
hash_free (m->hash);
|
||||
hash_free (m->vhash);
|
||||
hash_free (m->iter);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
hash_free (m->cid_hash);
|
||||
#endif
|
||||
m->hash = NULL;
|
||||
|
||||
schedule_free (m->schedule);
|
||||
@ -608,6 +672,13 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
|
||||
}
|
||||
mi->did_iter = true;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
do {
|
||||
mi->context.c2.mda_context.cid = m->cid_counter++;
|
||||
} while (!hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false));
|
||||
mi->did_cid_hash = true;
|
||||
#endif
|
||||
|
||||
mi->context.c2.push_reply_deferred = true;
|
||||
|
||||
if (!multi_process_post (m, mi, MPP_PRE_SELECT))
|
||||
@ -983,7 +1054,8 @@ static struct multi_instance *
|
||||
multi_learn_in_addr_t (struct multi_context *m,
|
||||
struct multi_instance *mi,
|
||||
in_addr_t a,
|
||||
int netbits) /* -1 if host route, otherwise # of network bits in address */
|
||||
int netbits, /* -1 if host route, otherwise # of network bits in address */
|
||||
bool primary)
|
||||
{
|
||||
struct openvpn_sockaddr remote_si;
|
||||
struct mroute_addr addr;
|
||||
@ -998,7 +1070,15 @@ multi_learn_in_addr_t (struct multi_context *m,
|
||||
addr.type |= MR_WITH_NETBITS;
|
||||
addr.netbits = (uint8_t) netbits;
|
||||
}
|
||||
return multi_learn_addr (m, mi, &addr, 0);
|
||||
|
||||
{
|
||||
struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management && owner)
|
||||
management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary);
|
||||
#endif
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1028,7 +1108,7 @@ multi_add_iroutes (struct multi_context *m,
|
||||
|
||||
mroute_helper_add_iroute (m->route_helper, ir);
|
||||
|
||||
multi_learn_in_addr_t (m, mi, ir->network, ir->netbits);
|
||||
multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false);
|
||||
}
|
||||
}
|
||||
gc_free (&gc);
|
||||
@ -1255,7 +1335,7 @@ multi_client_connect_post_plugin (struct multi_context *m,
|
||||
for (i = 0; i < config.n; ++i)
|
||||
{
|
||||
if (config.list[i] && config.list[i]->value)
|
||||
options_plugin_import (&mi->context.options,
|
||||
options_string_import (&mi->context.options,
|
||||
config.list[i]->value,
|
||||
D_IMPORT_ERRORS|M_OPTERR,
|
||||
option_permissions_mask,
|
||||
@ -1276,6 +1356,46 @@ multi_client_connect_post_plugin (struct multi_context *m,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
|
||||
/*
|
||||
* Called to load management-derived client-connect config
|
||||
*/
|
||||
static void
|
||||
multi_client_connect_mda (struct multi_context *m,
|
||||
struct multi_instance *mi,
|
||||
const struct buffer_list *config,
|
||||
unsigned int option_permissions_mask,
|
||||
unsigned int *option_types_found)
|
||||
{
|
||||
if (config)
|
||||
{
|
||||
struct buffer_entry *be;
|
||||
|
||||
for (be = config->head; be != NULL; be = be->next)
|
||||
{
|
||||
const char *opt = BSTR(&be->buf);
|
||||
options_string_import (&mi->context.options,
|
||||
opt,
|
||||
D_IMPORT_ERRORS|M_OPTERR,
|
||||
option_permissions_mask,
|
||||
option_types_found,
|
||||
mi->context.c2.es);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the --client-connect script generates a config file
|
||||
* with an --ifconfig-push directive, it will override any
|
||||
* --ifconfig-push directive from the --client-config-dir
|
||||
* directory or any --ifconfig-pool dynamic address.
|
||||
*/
|
||||
multi_select_virtual_addr (m, mi);
|
||||
multi_set_virtual_addr_env (m, mi);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
multi_client_connect_setenv (struct multi_context *m,
|
||||
struct multi_instance *mi)
|
||||
@ -1468,6 +1588,17 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
cc_succeeded = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for client-connect script left by management interface client
|
||||
*/
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (cc_succeeded && mi->cc_config)
|
||||
{
|
||||
multi_client_connect_mda (m, mi, mi->cc_config, option_permissions_mask, &option_types_found);
|
||||
++cc_succeeded_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check for "disable" directive in client-config-dir file
|
||||
* or config file generated by --client-connect script.
|
||||
@ -1515,7 +1646,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
{
|
||||
if (mi->context.c2.push_ifconfig_defined)
|
||||
{
|
||||
multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1);
|
||||
multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1, true);
|
||||
msg (D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s",
|
||||
multi_instance_string (mi, false, &gc),
|
||||
print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc));
|
||||
@ -1553,6 +1684,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
||||
/* set flag so we don't get called again */
|
||||
mi->connection_established_flag = true;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management)
|
||||
management_connection_established (management, &mi->context.c2.mda_context);
|
||||
#endif
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
@ -1606,10 +1742,11 @@ multi_unicast (struct multi_context *m,
|
||||
/*
|
||||
* Broadcast a packet to all clients.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
multi_bcast (struct multi_context *m,
|
||||
const struct buffer *buf,
|
||||
struct multi_instance *omit)
|
||||
const struct multi_instance *sender_instance,
|
||||
const struct mroute_addr *sender_addr)
|
||||
{
|
||||
struct hash_iterator hi;
|
||||
struct hash_element *he;
|
||||
@ -1628,8 +1765,34 @@ multi_bcast (struct multi_context *m,
|
||||
while ((he = hash_iterator_next (&hi)))
|
||||
{
|
||||
mi = (struct multi_instance *) he->value;
|
||||
if (mi != omit && !mi->halt)
|
||||
multi_add_mbuf (m, mi, mb);
|
||||
if (mi != sender_instance && !mi->halt)
|
||||
{
|
||||
#ifdef ENABLE_PF
|
||||
if (sender_instance)
|
||||
{
|
||||
if (!pf_c2c_test (&sender_instance->context, &mi->context, "bcast_c2c"))
|
||||
{
|
||||
msg (D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter",
|
||||
mi_prefix (sender_instance),
|
||||
mi_prefix (mi));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sender_addr)
|
||||
{
|
||||
if (!pf_addr_test (&mi->context, sender_addr, "bcast_src_addr"))
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
msg (D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter",
|
||||
mroute_addr_print_ex (sender_addr, MAPF_SHOW_ARP, &gc),
|
||||
mi_prefix (mi));
|
||||
gc_free (&gc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
multi_add_mbuf (m, mi, mb);
|
||||
}
|
||||
}
|
||||
|
||||
hash_iterator_free (&hi);
|
||||
@ -1789,6 +1952,8 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
||||
/* extract packet source and dest addresses */
|
||||
mroute_flags = mroute_extract_addr_from_packet (&src,
|
||||
&dest,
|
||||
NULL,
|
||||
NULL,
|
||||
&c->c2.to_tun,
|
||||
DEV_TYPE_TUN);
|
||||
|
||||
@ -1811,7 +1976,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
||||
if (mroute_flags & MROUTE_EXTRACT_MCAST)
|
||||
{
|
||||
/* for now, treat multicast as broadcast */
|
||||
multi_bcast (m, &c->c2.to_tun, m->pending);
|
||||
multi_bcast (m, &c->c2.to_tun, m->pending, NULL);
|
||||
}
|
||||
else /* possible client to client routing */
|
||||
{
|
||||
@ -1822,10 +1987,10 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
||||
if (mi)
|
||||
{
|
||||
#ifdef ENABLE_PF
|
||||
if (!pf_c2c_test (c, &mi->context))
|
||||
if (!pf_c2c_test (c, &mi->context, "tun_c2c"))
|
||||
{
|
||||
msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
|
||||
np (mi->msg_prefix));
|
||||
msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter",
|
||||
mi_prefix (mi));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1838,18 +2003,29 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PF
|
||||
else if (!pf_addr_test (c, &dest))
|
||||
if (c->c2.to_tun.len && !pf_addr_test (c, &dest, "tun_dest_addr"))
|
||||
{
|
||||
msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
|
||||
mroute_addr_print (&dest, &gc));
|
||||
msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter",
|
||||
mroute_addr_print_ex (&dest, MAPF_SHOW_ARP, &gc));
|
||||
c->c2.to_tun.len = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP)
|
||||
{
|
||||
#ifdef ENABLE_PF
|
||||
struct mroute_addr edest;
|
||||
mroute_addr_reset (&edest);
|
||||
#endif
|
||||
/* extract packet source and dest addresses */
|
||||
mroute_flags = mroute_extract_addr_from_packet (&src,
|
||||
&dest,
|
||||
NULL,
|
||||
#ifdef ENABLE_PF
|
||||
&edest,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
&c->c2.to_tun,
|
||||
DEV_TYPE_TAP);
|
||||
|
||||
@ -1862,7 +2038,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
||||
{
|
||||
if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST))
|
||||
{
|
||||
multi_bcast (m, &c->c2.to_tun, m->pending);
|
||||
multi_bcast (m, &c->c2.to_tun, m->pending, NULL);
|
||||
}
|
||||
else /* try client-to-client routing */
|
||||
{
|
||||
@ -1871,12 +2047,30 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
||||
/* if dest addr is a known client, route to it */
|
||||
if (mi)
|
||||
{
|
||||
multi_unicast (m, &c->c2.to_tun, mi);
|
||||
register_activity (c, BLEN(&c->c2.to_tun));
|
||||
#ifdef ENABLE_PF
|
||||
if (!pf_c2c_test (c, &mi->context, "tap_c2c"))
|
||||
{
|
||||
msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter",
|
||||
mi_prefix (mi));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
multi_unicast (m, &c->c2.to_tun, mi);
|
||||
register_activity (c, BLEN(&c->c2.to_tun));
|
||||
}
|
||||
c->c2.to_tun.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PF
|
||||
if (c->c2.to_tun.len && !pf_addr_test (c, &edest, "tap_dest_addr"))
|
||||
{
|
||||
msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter",
|
||||
mroute_addr_print_ex (&edest, MAPF_SHOW_ARP, &gc));
|
||||
c->c2.to_tun.len = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1918,6 +2112,20 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
|
||||
struct mroute_addr src, dest;
|
||||
const int dev_type = TUNNEL_TYPE (m->top.c1.tuntap);
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
struct mroute_addr esrc, *e1, *e2;
|
||||
if (dev_type == DEV_TYPE_TUN)
|
||||
{
|
||||
e1 = NULL;
|
||||
e2 = &src;
|
||||
}
|
||||
else
|
||||
{
|
||||
e1 = e2 = &esrc;
|
||||
mroute_addr_reset (&esrc);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MULTI_DEBUG_EVENT_LOOP
|
||||
printf ("TUN -> TCP/UDP [%d]\n", BLEN (&m->top.c2.buf));
|
||||
#endif
|
||||
@ -1932,6 +2140,12 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
|
||||
|
||||
mroute_flags = mroute_extract_addr_from_packet (&src,
|
||||
&dest,
|
||||
#ifdef ENABLE_PF
|
||||
e1,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
NULL,
|
||||
&m->top.c2.buf,
|
||||
dev_type);
|
||||
|
||||
@ -1943,7 +2157,11 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
|
||||
if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST))
|
||||
{
|
||||
/* for now, treat multicast as broadcast */
|
||||
multi_bcast (m, &m->top.c2.buf, NULL);
|
||||
#ifdef ENABLE_PF
|
||||
multi_bcast (m, &m->top.c2.buf, NULL, e2);
|
||||
#else
|
||||
multi_bcast (m, &m->top.c2.buf, NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1957,10 +2175,10 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
|
||||
set_prefix (m->pending);
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
if (!pf_addr_test (c, &src))
|
||||
if (!pf_addr_test (c, e2, "tun_tap_src_addr"))
|
||||
{
|
||||
msg (D_PF, "PF: [%s] -> client packet dropped by packet filter",
|
||||
mroute_addr_print (&src, &gc));
|
||||
msg (D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter",
|
||||
mroute_addr_print_ex (&src, MAPF_SHOW_ARP, &gc));
|
||||
buf_reset_len (&c->c2.buf);
|
||||
}
|
||||
else
|
||||
@ -2111,7 +2329,7 @@ gremlin_flood_clients (struct multi_context *m)
|
||||
ASSERT (buf_write_u8 (&buf, get_random () & 0xFF));
|
||||
|
||||
for (i = 0; i < parm.n_packets; ++i)
|
||||
multi_bcast (m, &buf, NULL);
|
||||
multi_bcast (m, &buf, NULL, NULL);
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
@ -2281,6 +2499,86 @@ management_delete_event (void *arg, event_t event)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
|
||||
static struct multi_instance *
|
||||
lookup_by_cid (struct multi_context *m, const unsigned long cid)
|
||||
{
|
||||
if (m)
|
||||
{
|
||||
struct multi_instance *mi = (struct multi_instance *) hash_lookup (m->cid_hash, &cid);
|
||||
if (mi && !mi->halt)
|
||||
return mi;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
management_kill_by_cid (void *arg, const unsigned long cid)
|
||||
{
|
||||
struct multi_context *m = (struct multi_context *) arg;
|
||||
struct multi_instance *mi = lookup_by_cid (m, cid);
|
||||
if (mi)
|
||||
{
|
||||
multi_signal_instance (m, mi, SIGTERM);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
management_client_auth (void *arg,
|
||||
const unsigned long cid,
|
||||
const unsigned int mda_key_id,
|
||||
const bool auth,
|
||||
const char *reason,
|
||||
struct buffer_list *cc_config) /* ownership transferred */
|
||||
{
|
||||
struct multi_context *m = (struct multi_context *) arg;
|
||||
struct multi_instance *mi = lookup_by_cid (m, cid);
|
||||
bool cc_config_owned = true;
|
||||
bool ret = false;
|
||||
|
||||
if (mi)
|
||||
{
|
||||
ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth);
|
||||
if (ret)
|
||||
{
|
||||
if (auth && !mi->connection_established_flag)
|
||||
{
|
||||
set_cc_config (mi, cc_config);
|
||||
cc_config_owned = false;
|
||||
}
|
||||
if (!auth && reason)
|
||||
msg (D_MULTI_LOW, "MULTI: connection rejected: %s", reason);
|
||||
}
|
||||
}
|
||||
if (cc_config_owned && cc_config)
|
||||
buffer_list_free (cc_config);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_PF
|
||||
static bool
|
||||
management_client_pf (void *arg,
|
||||
const unsigned long cid,
|
||||
struct buffer_list *pf_config) /* ownership transferred */
|
||||
{
|
||||
struct multi_context *m = (struct multi_context *) arg;
|
||||
struct multi_instance *mi = lookup_by_cid (m, cid);
|
||||
bool ret = false;
|
||||
|
||||
if (mi && pf_config)
|
||||
ret = pf_load_from_buffer_list (&mi->context, pf_config);
|
||||
|
||||
if (pf_config)
|
||||
buffer_list_free (pf_config);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
init_management_callback_multi (struct multi_context *m)
|
||||
{
|
||||
@ -2295,6 +2593,13 @@ init_management_callback_multi (struct multi_context *m)
|
||||
cb.kill_by_cn = management_callback_kill_by_cn;
|
||||
cb.kill_by_addr = management_callback_kill_by_addr;
|
||||
cb.delete_event = management_delete_event;
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
cb.kill_by_cid = management_kill_by_cid;
|
||||
cb.client_auth = management_client_auth;
|
||||
#endif
|
||||
#ifdef MANAGEMENT_PF
|
||||
cb.client_pf = management_client_pf;
|
||||
#endif
|
||||
management_set_callback (management, &cb);
|
||||
}
|
||||
#endif
|
||||
|
13
multi.h
13
multi.h
@ -77,6 +77,10 @@ struct multi_instance {
|
||||
bool did_open_context;
|
||||
bool did_real_hash;
|
||||
bool did_iter;
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
bool did_cid_hash;
|
||||
struct buffer_list *cc_config;
|
||||
#endif
|
||||
bool connection_established_flag;
|
||||
bool did_iroutes;
|
||||
|
||||
@ -111,6 +115,11 @@ struct multi_context {
|
||||
int tcp_queue_limit;
|
||||
int status_file_version;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
struct hash *cid_hash;
|
||||
unsigned long cid_counter;
|
||||
#endif
|
||||
|
||||
struct multi_instance *pending;
|
||||
struct multi_instance *earliest_wakeup;
|
||||
struct multi_instance **mpp_touched;
|
||||
@ -143,10 +152,6 @@ void tunnel_server (struct context *top);
|
||||
|
||||
const char *multi_instance_string (const struct multi_instance *mi, bool null, struct gc_arena *gc);
|
||||
|
||||
void multi_bcast (struct multi_context *m,
|
||||
const struct buffer *buf,
|
||||
struct multi_instance *omit);
|
||||
|
||||
/*
|
||||
* Called by mtcp.c, mudp.c, or other (to be written) protocol drivers
|
||||
*/
|
||||
|
15
openvpn.8
15
openvpn.8
@ -179,6 +179,8 @@ openvpn \- secure IP tunnel daemon.
|
||||
[\ \fB\-\-log\fR\ \fIfile\fR\ ]
|
||||
[\ \fB\-\-suppress-timestamps\fR\ ]
|
||||
[\ \fB\-\-lport\fR\ \fIport\fR\ ]
|
||||
[\ \fB\-\-management\-client\-auth\fR\ ]
|
||||
[\ \fB\-\-management\-client\-pf\fR\ ]
|
||||
[\ \fB\-\-management\-forget\-disconnect\fR\ ]
|
||||
[\ \fB\-\-management\-hold\fR\ ]
|
||||
[\ \fB\-\-management\-log\-cache\fR\ \fIn\fR\ ]
|
||||
@ -2357,6 +2359,19 @@ lines of log file history for usage
|
||||
by the management channel.
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --management-client-auth
|
||||
Gives management interface client the responsibility
|
||||
to authenticate clients after their client certificate
|
||||
has been verified. See management-notes.txt in OpenVPN
|
||||
distribution for detailed notes.
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --management-client-pf
|
||||
Management interface clients must specify a packet
|
||||
filter file for each connecting client. See management-notes.txt
|
||||
in OpenVPN distribution for detailed notes.
|
||||
.\"*********************************************************
|
||||
.TP
|
||||
.B --plugin module-pathname [init-string]
|
||||
Load plug-in module from the file
|
||||
.B module-pathname,
|
||||
|
@ -437,6 +437,10 @@ struct context_2
|
||||
#ifdef ENABLE_PF
|
||||
struct pf_context pf;
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
struct man_def_auth_context mda_context;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
61
options.c
61
options.c
@ -316,6 +316,15 @@ static const char usage_message[] =
|
||||
" event occurs.\n"
|
||||
"--management-log-cache n : Cache n lines of log file history for usage\n"
|
||||
" by the management channel.\n"
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
"--management-client-auth : gives management interface client the responsibility\n"
|
||||
" to authenticate clients after their client certificate\n"
|
||||
" has been verified.\n"
|
||||
#endif
|
||||
#ifdef MANAGEMENT_PF
|
||||
"--management-client-pf : management interface clients must specify a packet\n"
|
||||
" filter file for each connecting client.\n"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN
|
||||
"--plugin m [str]: Load plug-in module m passing str as an argument\n"
|
||||
@ -1195,12 +1204,8 @@ show_settings (const struct options *o)
|
||||
SHOW_STR (management_user_pass);
|
||||
SHOW_INT (management_log_history_cache);
|
||||
SHOW_INT (management_echo_buffer_size);
|
||||
SHOW_BOOL (management_query_passwords);
|
||||
SHOW_BOOL (management_hold);
|
||||
SHOW_BOOL (management_client);
|
||||
SHOW_BOOL (management_signal);
|
||||
SHOW_BOOL (management_forget_disconnect);
|
||||
SHOW_STR (management_write_peer_info_file);
|
||||
SHOW_INT (management_flags);
|
||||
#endif
|
||||
#ifdef ENABLE_PLUGIN
|
||||
if (o->plugin_list)
|
||||
@ -1525,8 +1530,7 @@ options_postprocess (struct options *options, bool first_time)
|
||||
*/
|
||||
#ifdef ENABLE_MANAGEMENT
|
||||
if (!options->management_addr &&
|
||||
(options->management_query_passwords || options->management_hold || options->management_signal
|
||||
|| options->management_forget_disconnect || options->management_client
|
||||
(options->management_flags
|
||||
|| options->management_write_peer_info_file
|
||||
|| options->management_log_history_cache != defaults.management_log_history_cache))
|
||||
msg (M_USAGE, "--management is not specified, however one or more options which modify the behavior of --management were specified");
|
||||
@ -1672,12 +1676,15 @@ options_postprocess (struct options *options, bool first_time)
|
||||
if (options->key_method != 2)
|
||||
msg (M_USAGE, "--mode server requires --key-method 2");
|
||||
|
||||
if (PLUGIN_OPTION_LIST (options) == NULL)
|
||||
{
|
||||
if (options->client_cert_not_required && !options->auth_user_pass_verify_script)
|
||||
msg (M_USAGE, "--client-cert-not-required must be used with an --auth-user-pass-verify script");
|
||||
if (options->username_as_common_name && !options->auth_user_pass_verify_script)
|
||||
msg (M_USAGE, "--username-as-common-name must be used with an --auth-user-pass-verify script");
|
||||
const bool ccnr = (options->auth_user_pass_verify_script
|
||||
|| PLUGIN_OPTION_LIST (options)
|
||||
|| MAN_CLIENT_AUTH_ENABLED (options));
|
||||
const char *postfix = "must be used with --management-client-auth, an --auth-user-pass-verify script, or plugin";
|
||||
if (options->client_cert_not_required && !ccnr)
|
||||
msg (M_USAGE, "--client-cert-not-required %s", postfix);
|
||||
if (options->username_as_common_name && !ccnr)
|
||||
msg (M_USAGE, "--username-as-common-name %s", postfix);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2983,9 +2990,7 @@ options_server_import (struct options *o,
|
||||
es);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PLUGIN
|
||||
|
||||
void options_plugin_import (struct options *options,
|
||||
void options_string_import (struct options *options,
|
||||
const char *config,
|
||||
const int msglevel,
|
||||
const unsigned int permission_mask,
|
||||
@ -2995,8 +3000,6 @@ void options_plugin_import (struct options *options,
|
||||
read_config_string (options, config, msglevel, permission_mask, option_types_found, es);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if P2MP
|
||||
|
||||
#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], (mask), permission_mask, option_types_found, msglevel)) goto err; }
|
||||
@ -3144,29 +3147,43 @@ add_option (struct options *options,
|
||||
else if (streq (p[0], "management-query-passwords"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_query_passwords = true;
|
||||
options->management_flags |= MF_QUERY_PASSWORDS;
|
||||
}
|
||||
else if (streq (p[0], "management-hold"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_hold = true;
|
||||
options->management_flags |= MF_HOLD;
|
||||
}
|
||||
else if (streq (p[0], "management-signal"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_signal = true;
|
||||
options->management_flags |= MF_SIGNAL;
|
||||
}
|
||||
else if (streq (p[0], "management-forget-disconnect"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_forget_disconnect = true;
|
||||
options->management_flags |= MF_FORGET_DISCONNECT;
|
||||
}
|
||||
else if (streq (p[0], "management-client"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_client = true;
|
||||
options->management_flags |= MF_CONNECT_AS_CLIENT;
|
||||
options->management_write_peer_info_file = p[1];
|
||||
}
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
else if (streq (p[0], "management-client-auth"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_flags |= MF_CLIENT_AUTH;
|
||||
}
|
||||
#endif
|
||||
#ifdef MANAGEMENT_PF
|
||||
else if (streq (p[0], "management-client-pf"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->management_flags |= (MF_CLIENT_PF | MF_CLIENT_AUTH);
|
||||
}
|
||||
#endif
|
||||
else if (streq (p[0], "management-log-cache") && p[1])
|
||||
{
|
||||
int cache;
|
||||
|
20
options.h
20
options.h
@ -281,12 +281,10 @@ struct options
|
||||
int management_log_history_cache;
|
||||
int management_echo_buffer_size;
|
||||
int management_state_buffer_size;
|
||||
bool management_query_passwords;
|
||||
bool management_hold;
|
||||
bool management_signal;
|
||||
bool management_forget_disconnect;
|
||||
bool management_client;
|
||||
const char *management_write_peer_info_file;
|
||||
|
||||
/* Mask of MF_ values of manage.h */
|
||||
unsigned int management_flags;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PLUGIN
|
||||
@ -537,6 +535,12 @@ struct options
|
||||
#define PLUGIN_OPTION_LIST(opt) (NULL)
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
#define MAN_CLIENT_AUTH_ENABLED(opt) ((opt)->management_flags & MF_CLIENT_AUTH)
|
||||
#else
|
||||
#define MAN_CLIENT_AUTH_ENABLED(opt) (false)
|
||||
#endif
|
||||
|
||||
void parse_argv (struct options *options,
|
||||
const int argc,
|
||||
char *argv[],
|
||||
@ -632,9 +636,7 @@ const char *auth_retry_print (void);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PLUGIN
|
||||
|
||||
void options_plugin_import (struct options *options,
|
||||
void options_string_import (struct options *options,
|
||||
const char *config,
|
||||
const int msglevel,
|
||||
const unsigned int permission_mask,
|
||||
@ -642,5 +644,3 @@ void options_plugin_import (struct options *options,
|
||||
struct env_set *es);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
59
pf-inline.h
Normal file
59
pf-inline.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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-2005 OpenVPN Solutions LLC <info@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(ENABLE_PF) && !defined(PF_INLINE_H)
|
||||
#define PF_INLINE_H
|
||||
|
||||
/*
|
||||
* Inline functions
|
||||
*/
|
||||
|
||||
#define PCT_SRC 1
|
||||
#define PCT_DEST 2
|
||||
static inline bool
|
||||
pf_c2c_test (const struct context *src, const struct context *dest, const char *prefix)
|
||||
{
|
||||
bool pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix);
|
||||
return (!src->c2.pf.enabled || pf_cn_test (src->c2.pf.pfs, dest->c2.tls_multi, PCT_DEST, prefix))
|
||||
&& (!dest->c2.pf.enabled || pf_cn_test (dest->c2.pf.pfs, src->c2.tls_multi, PCT_SRC, prefix));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pf_addr_test (const struct context *src, const struct mroute_addr *dest, const char *prefix)
|
||||
{
|
||||
bool pf_addr_test_dowork (const struct context *src, const struct mroute_addr *dest, const char *prefix);
|
||||
|
||||
if (src->c2.pf.enabled)
|
||||
return pf_addr_test_dowork (src, dest, prefix);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pf_kill_test (const struct pf_set *pfs)
|
||||
{
|
||||
return pfs->kill;
|
||||
}
|
||||
|
||||
#endif
|
276
pf.c
276
pf.c
@ -32,6 +32,8 @@
|
||||
|
||||
#include "memdbg.h"
|
||||
|
||||
#include "pf-inline.h"
|
||||
|
||||
static void
|
||||
pf_destroy (struct pf_set *pfs)
|
||||
{
|
||||
@ -64,7 +66,7 @@ pf_destroy (struct pf_set *pfs)
|
||||
}
|
||||
|
||||
static bool
|
||||
add_client (const char *line, const char *fn, const int line_num, struct pf_cn_elem ***next, const bool exclude)
|
||||
add_client (const char *line, const char *prefix, const int line_num, struct pf_cn_elem ***next, const bool exclude)
|
||||
{
|
||||
struct pf_cn_elem *e;
|
||||
ALLOC_OBJ_CLEAR (e, struct pf_cn_elem);
|
||||
@ -76,34 +78,44 @@ add_client (const char *line, const char *fn, const int line_num, struct pf_cn_e
|
||||
}
|
||||
|
||||
static bool
|
||||
add_subnet (const char *line, const char *fn, const int line_num, struct pf_subnet ***next, const bool exclude)
|
||||
add_subnet (const char *line, const char *prefix, const int line_num, struct pf_subnet ***next, const bool exclude)
|
||||
{
|
||||
struct in_addr network;
|
||||
in_addr_t netmask = 0;
|
||||
int netbits = 32;
|
||||
char *div = strchr (line, '/');
|
||||
|
||||
if (div)
|
||||
if (strcmp (line, "unknown"))
|
||||
{
|
||||
*div++ = '\0';
|
||||
if (sscanf (div, "%d", &netbits) != 1)
|
||||
int netbits = 32;
|
||||
char *div = strchr (line, '/');
|
||||
|
||||
if (div)
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: '%s'", fn, line_num, div);
|
||||
return false;
|
||||
}
|
||||
if (netbits < 0 || netbits > 32)
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", fn, line_num, div);
|
||||
*div++ = '\0';
|
||||
if (sscanf (div, "%d", &netbits) != 1)
|
||||
{
|
||||
msg (D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: '%s'", prefix, line_num, div);
|
||||
return false;
|
||||
}
|
||||
if (netbits < 0 || netbits > 32)
|
||||
{
|
||||
msg (D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", prefix, line_num, div);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (openvpn_inet_aton (line, &network) != OIA_IP)
|
||||
{
|
||||
msg (D_PF_INFO, "PF: %s/%d: bad network address: '%s'", prefix, line_num, line);
|
||||
return false;
|
||||
}
|
||||
netmask = netbits_to_netmask (netbits);
|
||||
}
|
||||
|
||||
if (openvpn_inet_aton (line, &network) != OIA_IP)
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: bad network address: '%s'", fn, line_num, line);
|
||||
return false;
|
||||
/* match special "unknown" tag for addresses unrecognized by mroute */
|
||||
network.s_addr = htonl(0);
|
||||
netmask = ~0;
|
||||
}
|
||||
netmask = netbits_to_netmask (netbits);
|
||||
|
||||
{
|
||||
struct pf_subnet *e;
|
||||
@ -130,7 +142,7 @@ cn_compare_function (const void *key1, const void *key2)
|
||||
}
|
||||
|
||||
static bool
|
||||
genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
|
||||
genhash (struct pf_cn_set *cns, const char *prefix, const int n_clients)
|
||||
{
|
||||
struct pf_cn_elem *e;
|
||||
bool status = true;
|
||||
@ -143,7 +155,7 @@ genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
|
||||
{
|
||||
if (!hash_add (cns->hash_table, e->rule.cn, &e->rule, false))
|
||||
{
|
||||
msg (D_PF, "PF: %s: duplicate common name in [clients] section: '%s'", fn, e->rule.cn);
|
||||
msg (D_PF_INFO, "PF: %s: duplicate common name in [clients] section: '%s'", prefix, e->rule.cn);
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
@ -152,7 +164,7 @@ genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
|
||||
}
|
||||
|
||||
static struct pf_set *
|
||||
pf_init (const char *fn)
|
||||
pf_init (const struct buffer_list *bl, const char *prefix, const bool allow_kill)
|
||||
{
|
||||
# define MODE_UNDEF 0
|
||||
# define MODE_CLIENTS 1
|
||||
@ -163,18 +175,19 @@ pf_init (const char *fn)
|
||||
int n_subnets = 0;
|
||||
int n_errors = 0;
|
||||
struct pf_set *pfs = NULL;
|
||||
char line[256];
|
||||
char line[PF_MAX_LINE_LEN];
|
||||
|
||||
ALLOC_OBJ_CLEAR (pfs, struct pf_set);
|
||||
FILE *fp = fopen (fn, "r");
|
||||
if (fp)
|
||||
if (bl)
|
||||
{
|
||||
struct pf_cn_elem **cl = &pfs->cns.list;
|
||||
struct pf_subnet **sl = &pfs->sns.list;
|
||||
struct buffer_entry *be;
|
||||
|
||||
while (fgets (line, sizeof (line), fp) != NULL)
|
||||
for (be = bl->head; be != NULL; be = be->next)
|
||||
{
|
||||
++line_num;
|
||||
strncpynt (line, BSTR(&be->buf), sizeof(line));
|
||||
rm_trailing_chars (line, "\r\n\t ");
|
||||
if (line[0] == '\0' || line[0] == '#')
|
||||
;
|
||||
@ -184,19 +197,19 @@ pf_init (const char *fn)
|
||||
|
||||
if (line[1] =='\0')
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: no data after +/-: '%s'", fn, line_num, line);
|
||||
msg (D_PF_INFO, "PF: %s/%d: no data after +/-: '%s'", prefix, line_num, line);
|
||||
++n_errors;
|
||||
}
|
||||
else if (mode == MODE_CLIENTS)
|
||||
{
|
||||
if (add_client (&line[1], fn, line_num, &cl, exclude))
|
||||
if (add_client (&line[1], prefix, line_num, &cl, exclude))
|
||||
++n_clients;
|
||||
else
|
||||
++n_errors;
|
||||
}
|
||||
else if (mode == MODE_SUBNETS)
|
||||
{
|
||||
if (add_subnet (&line[1], fn, line_num, &sl, exclude))
|
||||
if (add_subnet (&line[1], prefix, line_num, &sl, exclude))
|
||||
++n_subnets;
|
||||
else
|
||||
++n_errors;
|
||||
@ -232,41 +245,40 @@ pf_init (const char *fn)
|
||||
}
|
||||
else if (!strcasecmp (line, "[end]"))
|
||||
goto done;
|
||||
else if (!strcasecmp (line, "[kill]"))
|
||||
else if (allow_kill && !strcasecmp (line, "[kill]"))
|
||||
goto kill;
|
||||
else
|
||||
{
|
||||
mode = MODE_UNDEF;
|
||||
msg (D_PF, "PF: %s/%d unknown tag: '%s'", fn, line_num, line);
|
||||
msg (D_PF_INFO, "PF: %s/%d unknown tag: '%s'", prefix, line_num, line);
|
||||
++n_errors;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", fn, line_num, line);
|
||||
msg (D_PF_INFO, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", prefix, line_num, line);
|
||||
++n_errors;
|
||||
}
|
||||
}
|
||||
++n_errors;
|
||||
msg (D_PF, "PF: %s: missing [end]", fn);
|
||||
msg (D_PF_INFO, "PF: %s: missing [end]", prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF|M_ERRNO, "PF: %s: cannot open", fn);
|
||||
msg (D_PF_INFO, "PF: %s: cannot open", prefix);
|
||||
++n_errors;
|
||||
}
|
||||
|
||||
done:
|
||||
if (fp)
|
||||
if (bl)
|
||||
{
|
||||
fclose (fp);
|
||||
if (!n_errors)
|
||||
{
|
||||
if (!genhash (&pfs->cns, fn, n_clients))
|
||||
if (!genhash (&pfs->cns, prefix, n_clients))
|
||||
++n_errors;
|
||||
}
|
||||
if (n_errors)
|
||||
msg (D_PF, "PF: %s rejected due to %d error(s)", fn, n_errors);
|
||||
msg (D_PF_INFO, "PF: %s rejected due to %d error(s)", prefix, n_errors);
|
||||
}
|
||||
if (n_errors)
|
||||
{
|
||||
@ -276,15 +288,32 @@ pf_init (const char *fn)
|
||||
return pfs;
|
||||
|
||||
kill:
|
||||
if (fp)
|
||||
fclose (fp);
|
||||
pf_destroy (pfs);
|
||||
ALLOC_OBJ_CLEAR (pfs, struct pf_set);
|
||||
pfs->kill = true;
|
||||
return pfs;
|
||||
}
|
||||
|
||||
#if PF_DEBUG >= 1
|
||||
#ifdef PLUGIN_PF
|
||||
static struct pf_set *
|
||||
pf_init_from_file (const char *fn)
|
||||
{
|
||||
struct buffer_list *bl = buffer_list_file (fn, PF_MAX_LINE_LEN);
|
||||
if (bl)
|
||||
{
|
||||
struct pf_set *pfs = pf_init (bl, fn, true);
|
||||
buffer_list_free (bl);
|
||||
return pfs;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF_INFO|M_ERRNO, "PF: %s: cannot open", fn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
|
||||
static const char *
|
||||
drop_accept (const bool accept)
|
||||
@ -292,31 +321,46 @@ drop_accept (const bool accept)
|
||||
return accept ? "ACCEPT" : "DROP";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if PF_DEBUG >= 2
|
||||
static const char *
|
||||
pct_name (const int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PCT_SRC:
|
||||
return "SRC";
|
||||
case PCT_DEST:
|
||||
return "DEST";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pf_cn_test_print (const char *prefix,
|
||||
const int type,
|
||||
const char *prefix2,
|
||||
const char *cn,
|
||||
const bool allow,
|
||||
const struct pf_cn *rule)
|
||||
{
|
||||
if (rule)
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s rule=[%s %s]",
|
||||
prefix, cn, drop_accept (allow),
|
||||
dmsg (D_PF_DEBUG, "PF: %s/%s/%s %s %s rule=[%s %s]",
|
||||
prefix, prefix2, pct_name (type),
|
||||
cn, drop_accept (allow),
|
||||
rule->cn, drop_accept (!rule->exclude));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s",
|
||||
prefix, cn, drop_accept (allow));
|
||||
dmsg (D_PF_DEBUG, "PF: %s/%s/%s %s %s",
|
||||
prefix, prefix2, pct_name (type),
|
||||
cn, drop_accept (allow));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pf_addr_test_print (const char *prefix,
|
||||
const char *prefix2,
|
||||
const struct context *src,
|
||||
const struct mroute_addr *dest,
|
||||
const bool allow,
|
||||
@ -325,10 +369,11 @@ pf_addr_test_print (const char *prefix,
|
||||
struct gc_arena gc = gc_new ();
|
||||
if (rule)
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s %s rule=[%s/%s %s]",
|
||||
dmsg (D_PF_DEBUG, "PF: %s/%s %s %s %s rule=[%s/%s %s]",
|
||||
prefix,
|
||||
prefix2,
|
||||
tls_common_name (src->c2.tls_multi, false),
|
||||
mroute_addr_print (dest, &gc),
|
||||
mroute_addr_print_ex (dest, MAPF_SHOW_ARP, &gc),
|
||||
drop_accept (allow),
|
||||
print_in_addr_t (rule->network, 0, &gc),
|
||||
print_in_addr_t (rule->netmask, 0, &gc),
|
||||
@ -336,10 +381,11 @@ pf_addr_test_print (const char *prefix,
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s %s",
|
||||
dmsg (D_PF_DEBUG, "PF: %s/%s %s %s %s",
|
||||
prefix,
|
||||
prefix2,
|
||||
tls_common_name (src->c2.tls_multi, false),
|
||||
mroute_addr_print (dest, &gc),
|
||||
mroute_addr_print_ex (dest, MAPF_SHOW_ARP, &gc),
|
||||
drop_accept (allow));
|
||||
}
|
||||
gc_free (&gc);
|
||||
@ -357,8 +403,8 @@ lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
cn_test (struct pf_set *pfs, const struct tls_multi *tm)
|
||||
bool
|
||||
pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix)
|
||||
{
|
||||
if (!pfs->kill)
|
||||
{
|
||||
@ -369,8 +415,9 @@ cn_test (struct pf_set *pfs, const struct tls_multi *tm)
|
||||
const struct pf_cn *rule = lookup_cn_rule (pfs->cns.hash_table, cn, cn_hash);
|
||||
if (rule)
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_cn_test_print ("PF_CN_MATCH", cn, !rule->exclude, rule);
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_cn_test_print ("PF_CN_MATCH", type, prefix, cn, !rule->exclude, rule);
|
||||
#endif
|
||||
if (!rule->exclude)
|
||||
return true;
|
||||
@ -379,8 +426,9 @@ cn_test (struct pf_set *pfs, const struct tls_multi *tm)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_cn_test_print ("PF_CN_DEFAULT", cn, pfs->cns.default_allow, NULL);
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_cn_test_print ("PF_CN_DEFAULT", type, prefix, cn, pfs->cns.default_allow, NULL);
|
||||
#endif
|
||||
if (pfs->cns.default_allow)
|
||||
return true;
|
||||
@ -389,59 +437,50 @@ cn_test (struct pf_set *pfs, const struct tls_multi *tm)
|
||||
}
|
||||
}
|
||||
}
|
||||
#if PF_DEBUG >= 2
|
||||
pf_cn_test_print ("PF_CN_FAULT", tls_common_name (tm, false), false, NULL);
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_cn_test_print ("PF_CN_FAULT", type, prefix, tls_common_name (tm, false), false, NULL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
pf_c2c_test (const struct context *src, const struct context *dest)
|
||||
pf_addr_test_dowork (const struct context *src, const struct mroute_addr *dest, const char *prefix)
|
||||
{
|
||||
return (!src->c2.pf.filename || cn_test (src->c2.pf.pfs, dest->c2.tls_multi))
|
||||
&& (!dest->c2.pf.filename || cn_test (dest->c2.pf.pfs, src->c2.tls_multi));
|
||||
}
|
||||
|
||||
bool
|
||||
pf_addr_test (const struct context *src, const struct mroute_addr *dest)
|
||||
{
|
||||
if (src->c2.pf.filename)
|
||||
struct pf_set *pfs = src->c2.pf.pfs;
|
||||
if (pfs && !pfs->kill)
|
||||
{
|
||||
struct pf_set *pfs = src->c2.pf.pfs;
|
||||
if (pfs && !pfs->kill)
|
||||
const in_addr_t addr = in_addr_t_from_mroute_addr (dest);
|
||||
const struct pf_subnet *se = pfs->sns.list;
|
||||
while (se)
|
||||
{
|
||||
const in_addr_t addr = in_addr_t_from_mroute_addr (dest);
|
||||
const struct pf_subnet *se = pfs->sns.list;
|
||||
while (se)
|
||||
if ((addr & se->rule.netmask) == se->rule.network)
|
||||
{
|
||||
if ((addr & se->rule.netmask) == se->rule.network)
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_addr_test_print ("PF_ADDR_MATCH", src, dest, !se->rule.exclude, &se->rule);
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_addr_test_print ("PF_ADDR_MATCH", prefix, src, dest, !se->rule.exclude, &se->rule);
|
||||
#endif
|
||||
return !se->rule.exclude;
|
||||
}
|
||||
se = se->next;
|
||||
return !se->rule.exclude;
|
||||
}
|
||||
#if PF_DEBUG >= 2
|
||||
pf_addr_test_print ("PF_ADDR_DEFAULT", src, dest, pfs->sns.default_allow, NULL);
|
||||
#endif
|
||||
return pfs->sns.default_allow;
|
||||
se = se->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_addr_test_print ("PF_ADDR_FAULT", src, dest, false, NULL);
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_addr_test_print ("PF_ADDR_DEFAULT", prefix, src, dest, pfs->sns.default_allow, NULL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return pfs->sns.default_allow;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_addr_test_print ("PF_ADDR_FAULT", prefix, src, dest, false, NULL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PLUGIN_PF
|
||||
void
|
||||
pf_check_reload (struct context *c)
|
||||
{
|
||||
@ -450,14 +489,16 @@ pf_check_reload (struct context *c)
|
||||
const int wakeup_transition = 60;
|
||||
bool reloaded = false;
|
||||
|
||||
if (c->c2.pf.filename && event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
|
||||
if (c->c2.pf.enabled
|
||||
&& c->c2.pf.filename
|
||||
&& event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (c->c2.pf.filename, &s))
|
||||
{
|
||||
if (s.st_mtime > c->c2.pf.file_last_mod)
|
||||
{
|
||||
struct pf_set *pfs = pf_init (c->c2.pf.filename);
|
||||
struct pf_set *pfs = pf_init_from_file (c->c2.pf.filename);
|
||||
if (pfs)
|
||||
{
|
||||
if (c->c2.pf.pfs)
|
||||
@ -482,16 +523,35 @@ pf_check_reload (struct context *c)
|
||||
c->c2.pf.n_check_reload++;
|
||||
}
|
||||
}
|
||||
#if PF_DEBUG >= 1
|
||||
if (reloaded)
|
||||
pf_context_print (&c->c2.pf, "pf_check_reload", M_INFO);
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (reloaded && check_debug_level (D_PF_DEBUG))
|
||||
pf_context_print (&c->c2.pf, "pf_check_reload", D_PF_DEBUG);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_PF
|
||||
bool
|
||||
pf_load_from_buffer_list (struct context *c, const struct buffer_list *config)
|
||||
{
|
||||
struct pf_set *pfs = pf_init (config, "[SERVER-PF]", false);
|
||||
if (pfs)
|
||||
{
|
||||
if (c->c2.pf.pfs)
|
||||
pf_destroy (c->c2.pf.pfs);
|
||||
c->c2.pf.pfs = pfs;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
pf_init_context (struct context *c)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
#ifdef PLUGIN_PF
|
||||
if (plugin_defined (c->plugins, OPENVPN_PLUGIN_ENABLE_PF))
|
||||
{
|
||||
const char *pf_file = create_temp_filename (c->options.tmp_dir, "pf", &gc);
|
||||
@ -502,8 +562,10 @@ pf_init_context (struct context *c)
|
||||
{
|
||||
event_timeout_init (&c->c2.pf.reload, 1, now);
|
||||
c->c2.pf.filename = string_alloc (pf_file, NULL);
|
||||
#if PF_DEBUG >= 1
|
||||
pf_context_print (&c->c2.pf, "pf_init_context", M_INFO);
|
||||
c->c2.pf.enabled = true;
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_context_print (&c->c2.pf, "pf_init_context#1", D_PF_DEBUG);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -511,22 +573,35 @@ pf_init_context (struct context *c)
|
||||
msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MANAGEMENT_PF
|
||||
if (!c->c2.pf.enabled && management_enable_pf (management))
|
||||
{
|
||||
c->c2.pf.enabled = true;
|
||||
#ifdef ENABLE_DEBUG
|
||||
if (check_debug_level (D_PF_DEBUG))
|
||||
pf_context_print (&c->c2.pf, "pf_init_context#2", D_PF_DEBUG);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void
|
||||
pf_destroy_context (struct pf_context *pfc)
|
||||
{
|
||||
#ifdef PLUGIN_PF
|
||||
if (pfc->filename)
|
||||
{
|
||||
delete_file (pfc->filename);
|
||||
free (pfc->filename);
|
||||
}
|
||||
#endif
|
||||
if (pfc->pfs)
|
||||
pf_destroy (pfc->pfs);
|
||||
}
|
||||
|
||||
#if PF_DEBUG >= 1
|
||||
#ifdef ENABLE_DEBUG
|
||||
|
||||
static void
|
||||
pf_subnet_set_print (const struct pf_subnet_set *s, const int lev)
|
||||
@ -613,10 +688,13 @@ pf_context_print (const struct pf_context *pfc, const char *prefix, const int le
|
||||
msg (lev, "----- %s : struct pf_context -----", prefix);
|
||||
if (pfc)
|
||||
{
|
||||
msg (lev, "enabled=%d", pfc->enabled);
|
||||
#ifdef PLUGIN_PF
|
||||
msg (lev, "filename='%s'", np(pfc->filename));
|
||||
msg (lev, "file_last_mod=%u", (unsigned int)pfc->file_last_mod);
|
||||
msg (lev, "n_check_reload=%u", pfc->n_check_reload);
|
||||
msg (lev, "reload=[%d,%u,%u]", pfc->reload.defined, pfc->reload.n, (unsigned int)pfc->reload.last);
|
||||
#endif
|
||||
pf_set_print (pfc->pfs, lev);
|
||||
}
|
||||
msg (lev, "--------------------");
|
||||
|
23
pf.h
23
pf.h
@ -30,7 +30,7 @@
|
||||
#include "list.h"
|
||||
#include "mroute.h"
|
||||
|
||||
#define PF_DEBUG 0
|
||||
#define PF_MAX_LINE_LEN 256
|
||||
|
||||
struct context;
|
||||
|
||||
@ -73,30 +73,29 @@ struct pf_set {
|
||||
};
|
||||
|
||||
struct pf_context {
|
||||
bool enabled;
|
||||
struct pf_set *pfs;
|
||||
#ifdef PLUGIN_PF
|
||||
char *filename;
|
||||
time_t file_last_mod;
|
||||
unsigned int n_check_reload;
|
||||
struct event_timeout reload;
|
||||
struct pf_set *pfs;
|
||||
#endif
|
||||
};
|
||||
|
||||
void pf_init_context (struct context *c);
|
||||
|
||||
void pf_destroy_context (struct pf_context *pfc);
|
||||
|
||||
#ifdef PLUGIN_PF
|
||||
void pf_check_reload (struct context *c);
|
||||
#endif
|
||||
|
||||
bool pf_c2c_test (const struct context *src, const struct context *dest);
|
||||
#ifdef MANAGEMENT_PF
|
||||
bool pf_load_from_buffer_list (struct context *c, const struct buffer_list *config);
|
||||
#endif
|
||||
|
||||
bool pf_addr_test (const struct context *src, const struct mroute_addr *dest);
|
||||
|
||||
static inline bool
|
||||
pf_kill_test (const struct pf_set *pfs)
|
||||
{
|
||||
return pfs->kill;
|
||||
}
|
||||
|
||||
#if PF_DEBUG >= 1
|
||||
#ifdef ENABLE_DEBUG
|
||||
void pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev);
|
||||
#endif
|
||||
|
||||
|
22
proto.h
22
proto.h
@ -28,6 +28,8 @@
|
||||
#include "common.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/*
|
||||
* Tunnel types
|
||||
*/
|
||||
@ -62,6 +64,24 @@ struct openvpn_ethhdr
|
||||
uint16_t proto; /* packet type ID field */
|
||||
};
|
||||
|
||||
struct openvpn_arp {
|
||||
# define ARP_MAC_ADDR_TYPE 0x0001
|
||||
uint16_t mac_addr_type; // 0x0001
|
||||
|
||||
uint16_t proto_addr_type; // 0x0800
|
||||
uint8_t mac_addr_size; // 0x06
|
||||
uint8_t proto_addr_size; // 0x04
|
||||
|
||||
# define ARP_REQUEST 0x0001
|
||||
# define ARP_REPLY 0x0002
|
||||
uint16_t arp_command; // 0x0001 for ARP request, 0x0002 for ARP reply
|
||||
|
||||
uint8_t mac_src[OPENVPN_ETH_ALEN];
|
||||
in_addr_t ip_src;
|
||||
uint8_t mac_dest[OPENVPN_ETH_ALEN];
|
||||
in_addr_t ip_dest;
|
||||
};
|
||||
|
||||
struct openvpn_iphdr {
|
||||
# define OPENVPN_IPH_GET_VER(v) (((v) >> 4) & 0x0F)
|
||||
# define OPENVPN_IPH_GET_LEN(v) (((v) & 0x0F) << 2)
|
||||
@ -129,6 +149,8 @@ struct openvpn_tcphdr {
|
||||
#define OPENVPN_TCPOPT_MAXSEG 2
|
||||
#define OPENVPN_TCPOLEN_MAXSEG 4
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/*
|
||||
* The following macro is used to update an
|
||||
* internet checksum. "acc" is a 32-bit
|
||||
|
174
ssl.c
174
ssl.c
@ -860,6 +860,26 @@ tls_lock_common_name (struct tls_multi *multi)
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
/* key_state_test_auth_control_file return values,
|
||||
NOTE: acf_merge indexing depends on these values */
|
||||
#define ACF_UNDEFINED 0
|
||||
#define ACF_SUCCEEDED 1
|
||||
#define ACF_DISABLED 2
|
||||
#define ACF_FAILED 3
|
||||
#endif
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
static inline unsigned int
|
||||
man_def_auth_test (const struct key_state *ks)
|
||||
{
|
||||
if (management_enable_def_auth (management))
|
||||
return ks->mda_status;
|
||||
else
|
||||
return ACF_DISABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
|
||||
/*
|
||||
* auth_control_file functions
|
||||
@ -890,17 +910,12 @@ key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
/* key_state_test_auth_control_file return values */
|
||||
#define ACF_UNDEFINED 0
|
||||
#define ACF_SUCCEEDED 1
|
||||
#define ACF_DISABLED 2
|
||||
#define ACF_FAILED 3
|
||||
static int
|
||||
static unsigned int
|
||||
key_state_test_auth_control_file (struct key_state *ks)
|
||||
{
|
||||
if (ks && ks->auth_control_file)
|
||||
{
|
||||
int ret = ks->auth_control_status;
|
||||
unsigned int ret = ks->auth_control_status;
|
||||
if (ret == ACF_UNDEFINED)
|
||||
{
|
||||
FILE *fp = fopen (ks->auth_control_file, "r");
|
||||
@ -935,14 +950,37 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
|
||||
bool active = false;
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
if (latency && multi->tas_last && multi->tas_last + latency >= now)
|
||||
return TLS_AUTHENTICATION_UNDEFINED;
|
||||
multi->tas_last = now;
|
||||
static const unsigned char acf_merge[] =
|
||||
{
|
||||
ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */
|
||||
ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */
|
||||
ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */
|
||||
ACF_FAILED, /* s1=ACF_UNDEFINED s2=ACF_FAILED */
|
||||
ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */
|
||||
ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */
|
||||
ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */
|
||||
ACF_FAILED, /* s1=ACF_SUCCEEDED s2=ACF_FAILED */
|
||||
ACF_UNDEFINED, /* s1=ACF_DISABLED s2=ACF_UNDEFINED */
|
||||
ACF_SUCCEEDED, /* s1=ACF_DISABLED s2=ACF_SUCCEEDED */
|
||||
ACF_DISABLED, /* s1=ACF_DISABLED s2=ACF_DISABLED */
|
||||
ACF_FAILED, /* s1=ACF_DISABLED s2=ACF_FAILED */
|
||||
ACF_FAILED, /* s1=ACF_FAILED s2=ACF_UNDEFINED */
|
||||
ACF_FAILED, /* s1=ACF_FAILED s2=ACF_SUCCEEDED */
|
||||
ACF_FAILED, /* s1=ACF_FAILED s2=ACF_DISABLED */
|
||||
ACF_FAILED /* s1=ACF_FAILED s2=ACF_FAILED */
|
||||
};
|
||||
#endif
|
||||
|
||||
if (multi)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
if (latency && multi->tas_last && multi->tas_last + latency >= now)
|
||||
return TLS_AUTHENTICATION_UNDEFINED;
|
||||
multi->tas_last = now;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < KEY_SCAN_SIZE; ++i)
|
||||
{
|
||||
struct key_state *ks = multi->key_scan[i];
|
||||
@ -952,7 +990,16 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
|
||||
if (ks->authenticated)
|
||||
{
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
switch (key_state_test_auth_control_file (ks))
|
||||
unsigned int s1 = ACF_DISABLED;
|
||||
unsigned int s2 = ACF_DISABLED;
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
s1 = key_state_test_auth_control_file (ks);
|
||||
#endif
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
s2 = man_def_auth_test (ks);
|
||||
#endif
|
||||
ASSERT (s1 < 4 && s2 < 4);
|
||||
switch (acf_merge[(s1<<2) + s2])
|
||||
{
|
||||
case ACF_SUCCEEDED:
|
||||
case ACF_DISABLED:
|
||||
@ -989,6 +1036,28 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
|
||||
return TLS_AUTHENTICATION_FAILED;
|
||||
}
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
bool
|
||||
tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth)
|
||||
{
|
||||
bool ret = false;
|
||||
if (multi)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < KEY_SCAN_SIZE; ++i)
|
||||
{
|
||||
struct key_state *ks = multi->key_scan[i];
|
||||
if (ks->mda_key_id == mda_key_id)
|
||||
{
|
||||
ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
tls_deauthenticate (struct tls_multi *multi)
|
||||
{
|
||||
@ -1458,7 +1527,7 @@ init_ssl (const struct options *options)
|
||||
#if P2MP_SERVER
|
||||
if (options->client_cert_not_required)
|
||||
{
|
||||
msg (M_WARN, "WARNING: This configuration may accept clients which do not present a certificate");
|
||||
msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION --client-cert-not-required may accept clients which do not present a certificate");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1976,6 +2045,10 @@ key_state_init (struct tls_session *session, struct key_state *ks)
|
||||
packet_id_init (&ks->packet_id,
|
||||
session->opt->replay_window,
|
||||
session->opt->replay_time);
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2018,7 +2091,7 @@ key_state_free (struct key_state *ks, bool clear)
|
||||
|
||||
packet_id_free (&ks->packet_id);
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
key_state_rm_auth_control_file (ks);
|
||||
#endif
|
||||
|
||||
@ -2933,7 +3006,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
|
||||
/* setenv client real IP address */
|
||||
setenv_untrusted (session);
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
/* generate filename for deferred auth control file */
|
||||
key_state_gen_auth_control_file (ks, session->opt);
|
||||
#endif
|
||||
@ -2941,7 +3014,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
|
||||
/* call command */
|
||||
retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es);
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
/* purge auth control filename (and file itself) for non-deferred returns */
|
||||
if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
key_state_rm_auth_control_file (ks);
|
||||
@ -2952,12 +3025,56 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
|
||||
msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* MANAGEMENT_DEF_AUTH internal ssl.c status codes
|
||||
*/
|
||||
#define KMDA_ERROR 0
|
||||
#define KMDA_SUCCESS 1
|
||||
#define KMDA_UNDEF 2
|
||||
#define KMDA_DEF 3
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
static int
|
||||
verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username)
|
||||
{
|
||||
int retval = KMDA_ERROR;
|
||||
|
||||
/* Is username defined? */
|
||||
if (strlen (up->username))
|
||||
{
|
||||
/* set username/password in private env space */
|
||||
setenv_str (session->opt->es, "username", raw_username);
|
||||
setenv_str (session->opt->es, "password", up->password);
|
||||
|
||||
/* setenv incoming cert common name for script */
|
||||
setenv_str (session->opt->es, "common_name", session->common_name);
|
||||
|
||||
/* setenv client real IP address */
|
||||
setenv_untrusted (session);
|
||||
|
||||
if (management)
|
||||
management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es);
|
||||
|
||||
setenv_del (session->opt->es, "password");
|
||||
setenv_str (session->opt->es, "username", up->username);
|
||||
|
||||
retval = KMDA_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle the reading and writing of key data to and from
|
||||
* the TLS control channel (cleartext).
|
||||
@ -3134,6 +3251,13 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
||||
char *options;
|
||||
struct user_pass *up;
|
||||
|
||||
bool man_def_auth = KMDA_UNDEF;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management_enable_def_auth (management))
|
||||
man_def_auth = KMDA_DEF;
|
||||
#endif
|
||||
|
||||
ASSERT (session->opt->key_method == 2);
|
||||
|
||||
/* allocate temporary objects */
|
||||
@ -3169,7 +3293,8 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
||||
/* should we check username/password? */
|
||||
ks->authenticated = false;
|
||||
if (session->opt->auth_user_pass_verify_script
|
||||
|| plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
|
||||
|| plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
|
||||
|| man_def_auth == KMDA_DEF)
|
||||
{
|
||||
int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
bool s2 = true;
|
||||
@ -3195,6 +3320,10 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
||||
string_mod (up->password, CC_PRINT, CC_CRLF, '_');
|
||||
|
||||
/* call plugin(s) and/or script */
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (man_def_auth == KMDA_DEF)
|
||||
man_def_auth = verify_user_pass_management (session, up, raw_username);
|
||||
#endif
|
||||
if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
|
||||
s1 = verify_user_pass_plugin (session, up, raw_username);
|
||||
if (session->opt->auth_user_pass_verify_script)
|
||||
@ -3202,16 +3331,21 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
||||
|
||||
/* auth succeeded? */
|
||||
if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
|| s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
|
||||
#endif
|
||||
) && s2)
|
||||
) && s2 && man_def_auth != KMDA_ERROR)
|
||||
{
|
||||
ks->authenticated = true;
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
ks->auth_deferred = true;
|
||||
#endif
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (man_def_auth != KMDA_UNDEF)
|
||||
ks->auth_deferred = true;
|
||||
#endif
|
||||
|
||||
if (session->opt->username_as_common_name)
|
||||
set_common_name (session, up->username);
|
||||
msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
|
||||
|
16
ssl.h
16
ssl.h
@ -375,9 +375,15 @@ struct key_state
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
/* If auth_deferred is true, authentication is being deferred */
|
||||
bool auth_deferred;
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
unsigned int mda_key_id;
|
||||
unsigned int mda_status;
|
||||
#endif
|
||||
#ifdef PLUGIN_DEF_AUTH
|
||||
unsigned int auth_control_status;
|
||||
time_t acf_last_mod;
|
||||
char *auth_control_file;
|
||||
int auth_control_status;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -459,6 +465,10 @@ struct tls_options
|
||||
struct env_set *es;
|
||||
const struct plugin_list *plugins;
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
struct man_def_auth_context *mda_context;
|
||||
#endif
|
||||
|
||||
/* --gremlin bits */
|
||||
int gremlin;
|
||||
};
|
||||
@ -679,6 +689,10 @@ void tls_lock_common_name (struct tls_multi *multi);
|
||||
int tls_authentication_status (struct tls_multi *multi, const int latency);
|
||||
void tls_deauthenticate (struct tls_multi *multi);
|
||||
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* inline functions
|
||||
*/
|
||||
|
29
syshead.h
29
syshead.h
@ -471,19 +471,40 @@ socket_defined (const socket_descriptor_t sd)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable deferred authentication
|
||||
* Enable deferred authentication?
|
||||
*/
|
||||
#if defined(ENABLE_PLUGIN) && P2MP_SERVER
|
||||
#define CONFIGURE_DEF_AUTH /* this should be set by autoconf and config.h */
|
||||
#if defined(CONFIGURE_DEF_AUTH) && defined(P2MP_SERVER) && defined(ENABLE_PLUGIN)
|
||||
#define PLUGIN_DEF_AUTH
|
||||
#endif
|
||||
#if defined(CONFIGURE_DEF_AUTH) && defined(P2MP_SERVER) && defined(ENABLE_MANAGEMENT)
|
||||
#define MANAGEMENT_DEF_AUTH
|
||||
#endif
|
||||
#if defined(PLUGIN_DEF_AUTH) || defined(MANAGEMENT_DEF_AUTH)
|
||||
#define ENABLE_DEF_AUTH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable packet filter
|
||||
* Enable packet filter?
|
||||
*/
|
||||
#if defined(ENABLE_PLUGIN) && P2MP_SERVER && defined(HAVE_STAT)
|
||||
#define CONFIGURE_PF /* this should be set by autoconf and config.h */
|
||||
#if defined(CONFIGURE_PF) && defined(P2MP_SERVER) && defined(ENABLE_PLUGIN) && defined(HAVE_STAT)
|
||||
#define PLUGIN_PF
|
||||
#endif
|
||||
#if defined(CONFIGURE_PF) && defined(P2MP_SERVER) && defined(MANAGEMENT_DEF_AUTH)
|
||||
#define MANAGEMENT_PF
|
||||
#endif
|
||||
#if defined(PLUGIN_PF) || defined(MANAGEMENT_PF)
|
||||
#define ENABLE_PF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't compile the struct buffer_list code unless something needs it
|
||||
*/
|
||||
#if defined(ENABLE_MANAGEMENT) || defined(ENABLE_PF)
|
||||
#define ENABLE_BUFFER_LIST
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do we have pthread capability?
|
||||
*/
|
||||
|
2
tun.c
2
tun.c
@ -1248,7 +1248,7 @@ close_tun (struct tuntap *tt)
|
||||
#endif
|
||||
|
||||
msg (M_INFO, "%s", command_line);
|
||||
system_check (command_line, NULL, S_FATAL, "Linux ip addr del failed");
|
||||
system_check (command_line, NULL, 0, "Linux ip addr del failed");
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
dnl define the OpenVPN version
|
||||
define(PRODUCT_VERSION,[2.1_rc7d])
|
||||
define(PRODUCT_VERSION,[2.1_rc7e])
|
||||
dnl define the TAP version
|
||||
define(PRODUCT_TAP_ID,[tap0901])
|
||||
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])
|
||||
|
Loading…
x
Reference in New Issue
Block a user