Added session resumption to TLS server.

This commit is contained in:
Nikos Mavrogiannopoulos
2013-02-03 21:23:29 +01:00
parent 7d962401a1
commit 1fb76ce890
25 changed files with 1304 additions and 162 deletions

View File

@@ -446,6 +446,9 @@
/* The size of `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* The size of `unsigned long', as computed by sizeof. */
#undef SIZEOF_UNSIGNED_LONG
/* Define to l, ll, u, ul, ull, etc., as suitable for constants of type
'size_t'. */
#undef SIZE_T_SUFFIX

View File

@@ -15,6 +15,8 @@ if [ test "$GCC" = "yes" ];then
CFLAGS="$CFLAGS -Wall"
fi
AC_CHECK_SIZEOF([unsigned long])
PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.0.0])
LIBS="$oldlibs -lgdbm"

View File

@@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl gettime memmem
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl gettime hash-pjw-bare memmem
AUTOMAKE_OPTIONS = 1.5 gnits
@@ -64,6 +64,12 @@ EXTRA_libgnu_a_SOURCES += gettimeofday.c
## end gnulib module gettimeofday
## begin gnulib module hash-pjw-bare
libgnu_a_SOURCES += hash-pjw-bare.h hash-pjw-bare.c
## end gnulib module hash-pjw-bare
## begin gnulib module memchr

42
gl/hash-pjw-bare.c Normal file
View File

@@ -0,0 +1,42 @@
/* hash-pjw-bare.c -- compute a hash value from a provided buffer.
Copyright (C) 2012-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include "hash-pjw-bare.h"
#include <limits.h>
#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
/* Return a hash of the N bytes of X using the method described by
Bruno Haible in http://www.haible.de/bruno/hashfunc.html.
Note that while many hash functions reduce their result via modulo
to a 0..table_size-1 range, this function does not do that. */
size_t
hash_pjw_bare (const void *x, size_t n)
{
const unsigned char *s = x;
size_t h = 0;
unsigned i;
for (i = 0; i < n; i++)
h = s[i] + ((h << 9) | (h >> (SIZE_BITS - 9)));
return h;
}

24
gl/hash-pjw-bare.h Normal file
View File

@@ -0,0 +1,24 @@
/* hash-pjw-bare.h -- declaration for a simple hash function
Copyright (C) 2012-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>. */
#include <stddef.h>
/* Compute a hash code for a buffer starting at X and of size N,
and return the hash code. Note that unlike hash_pjw(), it does not
return it modulo a table size.
The result is platform dependent: it depends on the size of the 'size_t'
type and on the signedness of the 'char' type. */
extern size_t hash_pjw_bare (const void *x, size_t n) _GL_ATTRIBUTE_PURE;

View File

@@ -27,12 +27,13 @@
# Specification in the form of a command-line invocation:
# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl gettime memmem
# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gl/tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl gettime hash-pjw-bare memmem
# Specification in the form of a few gnulib-tool.m4 macro invocations:
gl_LOCAL_DIR([])
gl_MODULES([
gettime
hash-pjw-bare
memmem
])
gl_AVOID([])

View File

@@ -44,6 +44,7 @@ AC_DEFUN([gl_EARLY],
# Code from module extern-inline:
# Code from module gettime:
# Code from module gettimeofday:
# Code from module hash-pjw-bare:
# Code from module include_next:
# Code from module memchr:
# Code from module memmem:
@@ -253,6 +254,8 @@ AC_DEFUN([gl_FILE_LIST], [
build-aux/snippet/warn-on-use.h
lib/gettime.c
lib/gettimeofday.c
lib/hash-pjw-bare.c
lib/hash-pjw-bare.h
lib/memchr.c
lib/memchr.valgrind
lib/memmem.c

View File

@@ -39,7 +39,7 @@
Ideally we should test __BIONIC__ here, but it is only defined after
<sys/cdefs.h> has been included; hence test __ANDROID__ instead. */
#if defined __ANDROID__ \
&& defined _SYS_TYPES_H_ && !defined _SSIZE_T_DEFINED_
&& defined _SYS_TYPES_H_ && !defined __need_size_t
# @INCLUDE_NEXT@ @NEXT_STDINT_H@
#else

View File

@@ -17,37 +17,34 @@
/* Written by Paul Eggert. */
#ifndef _@GUARD_PREFIX@_SYS_TIME_H
#if __GNUC__ >= 3
@PRAGMA_SYSTEM_HEADER@
#endif
@PRAGMA_COLUMNS@
#if defined _@GUARD_PREFIX@_SYS_TIME_H
/* Simply delegate to the system's header, without adding anything. */
# if @HAVE_SYS_TIME_H@
/* The include_next requires a split double-inclusion guard. */
#if @HAVE_SYS_TIME_H@
# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
# endif
#endif
#else
#ifndef _@GUARD_PREFIX@_SYS_TIME_H
#define _@GUARD_PREFIX@_SYS_TIME_H
# define _@GUARD_PREFIX@_SYS_TIME_H
# if @HAVE_SYS_TIME_H@
# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
# else
#if ! @HAVE_SYS_TIME_H@
# include <time.h>
# endif
#endif
/* On native Windows with MSVC, get the 'struct timeval' type.
Also, on native Windows with a 64-bit time_t, where we are overriding the
'struct timeval' type, get all declarations of system functions whose
signature contains 'struct timeval'. */
# if (defined _MSC_VER || @REPLACE_STRUCT_TIMEVAL@) && @HAVE_WINSOCK2_H@ && !defined _GL_INCLUDING_WINSOCK2_H
#if (defined _MSC_VER || @REPLACE_STRUCT_TIMEVAL@) && @HAVE_WINSOCK2_H@ && !defined _GL_INCLUDING_WINSOCK2_H
# define _GL_INCLUDING_WINSOCK2_H
# include <winsock2.h>
# undef _GL_INCLUDING_WINSOCK2_H
# endif
#endif
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
@@ -55,11 +52,11 @@
/* The definition of _GL_WARN_ON_USE is copied here. */
# ifdef __cplusplus
#ifdef __cplusplus
extern "C" {
# endif
#endif
# if !@HAVE_STRUCT_TIMEVAL@ || @REPLACE_STRUCT_TIMEVAL@
#if !@HAVE_STRUCT_TIMEVAL@ || @REPLACE_STRUCT_TIMEVAL@
# if @REPLACE_STRUCT_TIMEVAL@
# define timeval rpl_timeval
@@ -74,13 +71,13 @@ struct timeval
# define GNULIB_defined_struct_timeval 1
# endif
# endif
#endif
# ifdef __cplusplus
#ifdef __cplusplus
}
# endif
#endif
# if @GNULIB_GETTIMEOFDAY@
#if @GNULIB_GETTIMEOFDAY@
# if @REPLACE_GETTIMEOFDAY@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# undef gettimeofday
@@ -103,17 +100,17 @@ _GL_CXXALIAS_SYS_CAST (gettimeofday, int,
(struct timeval *restrict, void *restrict));
# endif
_GL_CXXALIASWARN (gettimeofday);
# elif defined GNULIB_POSIXCHECK
#elif defined GNULIB_POSIXCHECK
# undef gettimeofday
# if HAVE_RAW_DECL_GETTIMEOFDAY
_GL_WARN_ON_USE (gettimeofday, "gettimeofday is unportable - "
"use gnulib module gettimeofday for portability");
# endif
# endif
#endif
/* Hide some function declarations from <winsock2.h>. */
# if defined _MSC_VER && @HAVE_WINSOCK2_H@
#if defined _MSC_VER && @HAVE_WINSOCK2_H@
# if !defined _@GUARD_PREFIX@_UNISTD_H
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# undef close
@@ -200,6 +197,7 @@ _GL_WARN_ON_USE (gettimeofday, "gettimeofday is unportable - "
"select() used without including <sys/select.h>");
# endif
# endif
# endif
#endif
#endif /* _@GUARD_PREFIX@_SYS_TIME_H */
#endif /* _@GUARD_PREFIX@_SYS_TIME_H */

View File

@@ -1,4 +1,4 @@
AM_CPPFLAGS = -I$(srcdir)../gl/ -I$(builddir)../gl/ \
AM_CPPFLAGS = -I$(srcdir)/../gl/ -I$(builddir)/../gl/ \
-I$(srcdir)/ -I$(builddir)/../ -I$(srcdir)/../libopts
EXTRA_DIST = ocserv.1 sample.config
@@ -8,7 +8,8 @@ bin_PROGRAMS = ocserv
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c http-parser/http_parser.c \
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
config.c worker-auth.h pam.c pam.h
config.c worker-auth.h pam.c pam.h worker-resume.c worker.h hash.h \
hashtable.h main-resume.c
ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h

80
src/hash.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef _LINUX_HASH_H
#define _LINUX_HASH_H
/* Fast hashing routine for ints, longs and pointers.
(C) 2002 Nadia Yvette Chambers, IBM */
/*
* Knuth recommends primes in approximately golden ratio to the maximum
* integer representable by a machine word for multiplicative hashing.
* Chuck Lever verified the effectiveness of this technique:
* http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
*
* These primes are chosen to be bit-sparse, that is operations on
* them can use shifts and additions instead of multiplications for
* machines where multiplications are slow.
*/
#include <stdint.h>
/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
#if SIZEOF_UNSIGNED_LONG == 4
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32
#define hash_long(val, bits) hash_32(val, bits)
#elif SIZEOF_UNSIGNED_LONG == 8
#define hash_long(val, bits) hash_64(val, bits)
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64
#else
#error Wordsize not 32 or 64
#endif
static inline uint64_t hash_64(uint64_t val, unsigned int bits)
{
uint64_t hash = val;
/* Sigh, gcc can't optimise this alone like it does for 32 bits. */
uint64_t n = hash;
n <<= 18;
hash -= n;
n <<= 33;
hash -= n;
n <<= 3;
hash += n;
n <<= 3;
hash -= n;
n <<= 4;
hash += n;
n <<= 2;
hash += n;
/* High bits are more random, so use them. */
return hash >> (64 - bits);
}
static inline uint32_t hash_32(uint32_t val, unsigned int bits)
{
/* On some cpus multiply is faster, on others gcc will do shifts */
uint32_t hash = val * GOLDEN_RATIO_PRIME_32;
/* High bits are more random, so use them. */
return hash >> (32 - bits);
}
static inline unsigned long hash_ptr(const void *ptr, unsigned int bits)
{
return hash_long((unsigned long)ptr, bits);
}
static inline uint32_t hash32_ptr(const void *ptr)
{
unsigned long val = (unsigned long)ptr;
#if SIZEOF_UNSIGNED_LONG == 8
val ^= (val >> 32);
#endif
return (uint32_t)val;
}
#endif /* _LINUX_HASH_H */

231
src/hashtable.h Normal file
View File

@@ -0,0 +1,231 @@
/*
* Statically sized hash table implementation
* (C) 2012 Sasha Levin <levinsasha928@gmail.com>
*/
#ifndef _LINUX_HASHTABLE_H
#define _LINUX_HASHTABLE_H
#include <list.h>
#include <stdint.h>
/**
* ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
* @n - parameter
*
* constant-capable log of base 2 calculation
* - this can be used to initialise global variables from constant data, hence
* the massive ternary operator construction
*
* selects the appropriately-sized optimised version depending on sizeof(n)
*/
#define hash_ilog2(n) \
( \
__builtin_constant_p(n) ? ( \
(n) < 1 ? -1 : \
(n) & (1ULL << 63) ? 63 : \
(n) & (1ULL << 62) ? 62 : \
(n) & (1ULL << 61) ? 61 : \
(n) & (1ULL << 60) ? 60 : \
(n) & (1ULL << 59) ? 59 : \
(n) & (1ULL << 58) ? 58 : \
(n) & (1ULL << 57) ? 57 : \
(n) & (1ULL << 56) ? 56 : \
(n) & (1ULL << 55) ? 55 : \
(n) & (1ULL << 54) ? 54 : \
(n) & (1ULL << 53) ? 53 : \
(n) & (1ULL << 52) ? 52 : \
(n) & (1ULL << 51) ? 51 : \
(n) & (1ULL << 50) ? 50 : \
(n) & (1ULL << 49) ? 49 : \
(n) & (1ULL << 48) ? 48 : \
(n) & (1ULL << 47) ? 47 : \
(n) & (1ULL << 46) ? 46 : \
(n) & (1ULL << 45) ? 45 : \
(n) & (1ULL << 44) ? 44 : \
(n) & (1ULL << 43) ? 43 : \
(n) & (1ULL << 42) ? 42 : \
(n) & (1ULL << 41) ? 41 : \
(n) & (1ULL << 40) ? 40 : \
(n) & (1ULL << 39) ? 39 : \
(n) & (1ULL << 38) ? 38 : \
(n) & (1ULL << 37) ? 37 : \
(n) & (1ULL << 36) ? 36 : \
(n) & (1ULL << 35) ? 35 : \
(n) & (1ULL << 34) ? 34 : \
(n) & (1ULL << 33) ? 33 : \
(n) & (1ULL << 32) ? 32 : \
(n) & (1ULL << 31) ? 31 : \
(n) & (1ULL << 30) ? 30 : \
(n) & (1ULL << 29) ? 29 : \
(n) & (1ULL << 28) ? 28 : \
(n) & (1ULL << 27) ? 27 : \
(n) & (1ULL << 26) ? 26 : \
(n) & (1ULL << 25) ? 25 : \
(n) & (1ULL << 24) ? 24 : \
(n) & (1ULL << 23) ? 23 : \
(n) & (1ULL << 22) ? 22 : \
(n) & (1ULL << 21) ? 21 : \
(n) & (1ULL << 20) ? 20 : \
(n) & (1ULL << 19) ? 19 : \
(n) & (1ULL << 18) ? 18 : \
(n) & (1ULL << 17) ? 17 : \
(n) & (1ULL << 16) ? 16 : \
(n) & (1ULL << 15) ? 15 : \
(n) & (1ULL << 14) ? 14 : \
(n) & (1ULL << 13) ? 13 : \
(n) & (1ULL << 12) ? 12 : \
(n) & (1ULL << 11) ? 11 : \
(n) & (1ULL << 10) ? 10 : \
(n) & (1ULL << 9) ? 9 : \
(n) & (1ULL << 8) ? 8 : \
(n) & (1ULL << 7) ? 7 : \
(n) & (1ULL << 6) ? 6 : \
(n) & (1ULL << 5) ? 5 : \
(n) & (1ULL << 4) ? 4 : \
(n) & (1ULL << 3) ? 3 : \
(n) & (1ULL << 2) ? 2 : \
(n) & (1ULL << 1) ? 1 : \
(n) & (1ULL << 0) ? 0 : \
-1 \
) : \
-1 \
)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define DEFINE_HASHTABLE(name, bits) \
struct hlist_head name[1 << (bits)] = \
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
#define DECLARE_HASHTABLE(name, bits) \
struct hlist_head name[1 << (bits)]
#define HASH_SIZE(name) (ARRAY_SIZE(name))
#define HASH_BITS(name) hash_ilog2(HASH_SIZE(name))
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
#define hash_min(val, bits) \
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
{
unsigned int i;
for (i = 0; i < sz; i++)
INIT_HLIST_HEAD(&ht[i]);
}
/**
* hash_init - initialize a hash table
* @hashtable: hashtable to be initialized
*
* Calculates the size of the hashtable from the given parameter, otherwise
* same as hash_init_size.
*
* This has to be a macro since HASH_BITS() will not work on pointers since
* it calculates the size during preprocessing.
*/
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
/**
* hash_add - add an object to a hashtable
* @hashtable: hashtable to add to
* @node: the &struct hlist_node of the object to be added
* @key: the key of the object to be added
*/
#define hash_add(hashtable, node, key) \
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
/**
* hash_hashed - check whether an object is in any hashtable
* @node: the &struct hlist_node of the object to be checked
*/
static inline unsigned hash_hashed(struct hlist_node *node)
{
return !hlist_unhashed(node);
}
static inline unsigned __hash_empty(struct hlist_head *ht, unsigned int sz)
{
unsigned int i;
for (i = 0; i < sz; i++)
if (!hlist_empty(&ht[i]))
return 0;
return 1;
}
/**
* hash_empty - check whether a hashtable is empty
* @hashtable: hashtable to check
*
* This has to be a macro since HASH_BITS() will not work on pointers since
* it calculates the size during preprocessing.
*/
#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
/**
* hash_del - remove an object from a hashtable
* @node: &struct hlist_node of the object to remove
*/
static inline void hash_del(struct hlist_node *node)
{
hlist_del_init(node);
}
/**
* hash_for_each - iterate over a hashtable
* @name: hashtable to iterate
* @bkt: integer to use as bucket loop cursor
* @node: the &struct list_head to use as a loop cursor for each entry
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
*/
#define hash_for_each(name, bkt, node, obj, member) \
for ((bkt) = 0, node = NULL; node == NULL && (bkt) < HASH_SIZE(name); (bkt)++)\
hlist_for_each_entry(obj, node, &name[bkt], member)
/**
* hash_for_each_safe - iterate over a hashtable safe against removal of
* hash entry
* @name: hashtable to iterate
* @bkt: integer to use as bucket loop cursor
* @node: the &struct list_head to use as a loop cursor for each entry
* @tmp: a &struct used for temporary storage
* @obj: the type * to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
*/
#define hash_for_each_safe(name, bkt, node, tmp, obj, member) \
for ((bkt) = 0, node = NULL; node == NULL && (bkt) < HASH_SIZE(name); (bkt)++)\
hlist_for_each_entry_safe(obj, node, tmp, &name[bkt], member)
/**
* hash_for_each_possible - iterate over all possible objects hashing to the
* same bucket
* @name: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @node: the &struct list_head to use as a loop cursor for each entry
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*/
#define hash_for_each_possible(name, obj, node, member, key) \
hlist_for_each_entry(obj, node, &name[hash_min(key, HASH_BITS(name))], member)
/**
* hash_for_each_possible_safe - iterate over all possible objects hashing to the
* same bucket safe against removals
* @name: hashtable to iterate
* @obj: the type * to use as a loop cursor for each entry
* @node: the &struct list_head to use as a loop cursor for each entry
* @tmp: a &struct used for temporary storage
* @member: the name of the hlist_node within the struct
* @key: the key of the objects to iterate over
*/
#define hash_for_each_possible_safe(name, obj, node, tmp, member, key) \
hlist_for_each_entry_safe(obj, node, tmp, \
&name[hash_min(key, HASH_BITS(name))], member)
#endif

View File

@@ -1,5 +1,5 @@
#ifndef WORKER_AUTH_H
#define WORKER_AUTH_H
#ifndef IPC_H
#define IPC_H
#include <config.h>
#include <syslog.h>
@@ -9,11 +9,16 @@
#include <net/if.h>
#include <vpn.h>
#include <cookies.h>
#include <tlslib.h>
typedef enum {
AUTH_REQ = 1,
AUTH_COOKIE_REQ,
AUTH_REP,
RESUME_STORE_REQ,
RESUME_DELETE_REQ,
RESUME_FETCH_REQ,
RESUME_FETCH_REP,
CMD_TERMINATE,
} cmd_request_t;
@@ -22,6 +27,11 @@ typedef enum {
REP_AUTH_FAILED = 1,
} cmd_auth_reply_t;
typedef enum {
REP_RESUME_OK = 0,
REP_RESUME_FAILED = 1,
} cmd_resume_reply_t;
/* AUTH_COOKIE_REQ */
struct __attribute__ ((__packed__)) cmd_auth_cookie_req_st {
uint8_t cookie[COOKIE_SIZE];
@@ -47,10 +57,25 @@ struct __attribute__ ((__packed__)) cmd_auth_reply_st {
char user[MAX_USERNAME_SIZE];
};
int auth_cookie(worker_st *ws, void* cookie, size_t cookie_size);
/* RESUME_FETCH_REQ + RESUME_DELETE_REQ */
struct __attribute__ ((__packed__)) cmd_resume_fetch_req_st {
uint8_t session_id_size;
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
};
int get_auth_handler(worker_st *server);
int post_old_auth_handler(worker_st *server);
int post_new_auth_handler(worker_st *server);
/* RESUME_STORE_REQ */
struct __attribute__ ((__packed__)) cmd_resume_store_req_st {
uint8_t session_id_size;
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
uint16_t session_data_size;
uint8_t session_data[MAX_SESSION_DATA_SIZE];
};
/* RESUME_FETCH_REP */
struct __attribute__ ((__packed__)) cmd_resume_fetch_reply_st {
uint8_t reply;
uint16_t session_data_size;
uint8_t session_data[MAX_SESSION_DATA_SIZE];
};
#endif

View File

@@ -575,4 +575,175 @@ static inline void list_splice_tail_init(struct list_head *list,
n = list_entry(pos->member.next, typeof(*pos), member)
/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next = NULL;
h->pprev = NULL;
}
static inline int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
#define LIST_POISON1 NULL
#define LIST_POISON2 NULL
static inline void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
}
static inline void hlist_del_init(struct hlist_node *n)
{
if (!hlist_unhashed(n)) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if(next->next)
next->next->pprev = &next->next;
}
/* after that we'll appear to be on some hlist and hlist_del will work */
static inline void hlist_add_fake(struct hlist_node *n)
{
n->pprev = &n->next;
}
/*
* Move a list from one list head to another. Fixup the pprev
* reference of the first entry if it exists.
*/
static inline void hlist_move_list(struct hlist_head *old,
struct hlist_head *new)
{
new->first = old->first;
if (new->first)
new->first->pprev = &new->first;
old->first = NULL;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos ; pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct hlist_node to use as a loop cursor.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
#endif

View File

@@ -34,15 +34,17 @@
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <tlslib.h>
#include <worker-auth.h>
#include "ipc.h"
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <list.h>
#include "pam.h"
static int send_auth_reply(cmd_auth_reply_t r, struct proc_list_st* proc, struct lease_st* lease)
static int send_auth_reply(main_server_st* s, struct proc_list_st* proc,
cmd_auth_reply_t r, struct lease_st* lease)
{
struct iovec iov[6];
uint8_t cmd[2];
@@ -96,14 +98,13 @@ static int send_auth_reply(cmd_auth_reply_t r, struct proc_list_st* proc, struct
return(sendmsg(proc->fd, &hdr, 0));
}
static int handle_auth_cookie_req(const struct cfg_st *config, struct tun_st *tun,
const struct cmd_auth_cookie_req_st * req, struct lease_st **lease,
struct proc_list_st* proc)
static int handle_auth_cookie_req(main_server_st* s, struct proc_list_st* proc,
const struct cmd_auth_cookie_req_st * req, struct lease_st **lease)
{
int ret;
struct stored_cookie_st sc;
ret = retrieve_cookie(config, req->cookie, sizeof(req->cookie), &sc);
ret = retrieve_cookie(s->config, req->cookie, sizeof(req->cookie), &sc);
if (ret < 0) {
return -1;
}
@@ -114,7 +115,7 @@ struct stored_cookie_st sc;
memcpy(proc->username, sc.username, sizeof(proc->username));
memcpy(proc->session_id, sc.session_id, sizeof(proc->session_id));
ret = open_tun(config, tun, lease);
ret = open_tun(s->config, s->tun, lease);
if (ret < 0)
ret = -1; /* sorry */
@@ -122,7 +123,7 @@ struct stored_cookie_st sc;
}
static
int generate_and_store_vals(const struct cfg_st* config, struct proc_list_st* proc)
int generate_and_store_vals(main_server_st *s, struct proc_list_st* proc)
{
int ret;
struct stored_cookie_st sc;
@@ -135,51 +136,50 @@ struct stored_cookie_st sc;
return -2;
memset(&sc, 0, sizeof(sc));
sc.expiration = time(0) + config->cookie_validity;
sc.expiration = time(0) + s->config->cookie_validity;
memcpy(sc.username, proc->username, sizeof(sc.username));
memcpy(sc.session_id, proc->session_id, sizeof(sc.session_id));
ret = store_cookie(config, proc->cookie, sizeof(proc->cookie), &sc);
ret = store_cookie(s->config, proc->cookie, sizeof(proc->cookie), &sc);
if (ret < 0)
return -1;
return 0;
}
static int handle_auth_req(const struct cfg_st *config, struct tun_st *tun,
const struct cmd_auth_req_st * req, struct lease_st **lease,
char username[MAX_USERNAME_SIZE])
static int handle_auth_req(main_server_st *s, struct proc_list_st* proc,
const struct cmd_auth_req_st * req, struct lease_st **lease)
{
int ret = -1;
unsigned username_set = 0;
if (config->auth_types & AUTH_TYPE_PAM) {
if (req->user_pass_present != 0 && s->config->auth_types & AUTH_TYPE_PAM) {
ret = pam_auth_user(req->user, req->pass);
if (ret != 0)
ret = -1;
memcpy(username, req->user, MAX_USERNAME_SIZE);
memcpy(proc->username, req->user, MAX_USERNAME_SIZE);
username_set = 1;
}
if (config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (s->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (req->tls_auth_ok != 0) {
ret = 0;
}
if (username_set == 0)
memcpy(username, req->cert_user, MAX_USERNAME_SIZE);
memcpy(proc->username, req->cert_user, MAX_USERNAME_SIZE);
else {
if (strcmp(username, req->cert_user) != 0) {
syslog(LOG_INFO, "User '%s' presented a certificate from user '%s'", username, req->cert_user);
if (strcmp(proc->username, req->cert_user) != 0) {
syslog(LOG_INFO, "User '%s' presented a certificate from user '%s'", proc->username, req->cert_user);
ret = -1;
}
}
}
if (ret == 0) { /* open tun */
ret = open_tun(config, tun, lease);
ret = open_tun(s->config, s->tun, lease);
if (ret < 0)
ret = -1; /* sorry */
}
@@ -187,17 +187,19 @@ unsigned username_set = 0;
return ret;
}
int handle_commands(const struct cfg_st *config, struct tun_st *tun,
struct proc_list_st* proc)
int handle_commands(main_server_st *s, struct proc_list_st* proc)
{
struct iovec iov[2];
char buf[128];
int e;
uint8_t cmd;
struct msghdr hdr;
struct lease_st *lease;
union {
struct cmd_auth_req_st auth;
struct cmd_auth_cookie_req_st cauth;
struct cmd_resume_store_req_st sresume;
struct cmd_resume_fetch_req_st fresume;
} cmd_data;
int ret, cmd_data_len;
const char* peer_ip;
@@ -218,7 +220,8 @@ int handle_commands(const struct cfg_st *config, struct tun_st *tun,
ret = recvmsg( proc->fd, &hdr, 0);
if (ret == -1) {
syslog(LOG_ERR, "Cannot obtain data from command socket (pid: %d, peer: %s).", proc->pid, peer_ip);
e = errno;
syslog(LOG_ERR, "Cannot obtain data from command socket (pid: %d, peer: %s): %s", proc->pid, peer_ip, strerror(e));
return -1;
}
@@ -229,6 +232,51 @@ int handle_commands(const struct cfg_st *config, struct tun_st *tun,
cmd_data_len = ret - 1;
switch(cmd) {
case RESUME_STORE_REQ:
if (cmd_data_len != sizeof(cmd_data.sresume)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_resume_store_req(s, proc, &cmd_data.sresume);
if (ret < 0) {
syslog(LOG_DEBUG, "Could not store resumption data (pid: %d, peer: %s).", proc->pid, peer_ip);
}
break;
case RESUME_DELETE_REQ:
if (cmd_data_len != sizeof(cmd_data.fresume)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_resume_delete_req(s, proc, &cmd_data.fresume);
if (ret < 0) {
syslog(LOG_DEBUG, "Could not delete resumption data (pid: %d, peer: %s).", proc->pid, peer_ip);
}
break;
case RESUME_FETCH_REQ: {
struct cmd_resume_fetch_reply_st reply;
if (cmd_data_len != sizeof(cmd_data.fresume)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_resume_fetch_req(s, proc, &cmd_data.fresume, &reply);
if (ret < 0) {
syslog(LOG_DEBUG, "Could not fetch resumption data (pid: %d, peer: %s).", proc->pid, peer_ip);
ret = send_resume_fetch_reply(s, proc, REP_RESUME_FAILED, NULL);
} else
ret = send_resume_fetch_reply(s, proc, REP_RESUME_OK, &reply);
}
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
break;
case AUTH_REQ:
case AUTH_COOKIE_REQ:
@@ -238,26 +286,26 @@ int handle_commands(const struct cfg_st *config, struct tun_st *tun,
return -2;
}
ret = handle_auth_req(config, tun, &cmd_data.auth, &lease, proc->username);
ret = handle_auth_req(s, proc, &cmd_data.auth, &lease);
} else {
if (cmd_data_len != sizeof(cmd_data.cauth)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_auth_cookie_req(config, tun, &cmd_data.cauth, &lease, proc);
ret = handle_auth_cookie_req(s, proc, &cmd_data.cauth, &lease);
}
if (ret == 0) {
if (cmd == AUTH_REQ) {
/* generate and store cookie */
ret = generate_and_store_vals(config, proc);
ret = generate_and_store_vals(s, proc);
if (ret < 0)
return -2;
}
syslog(LOG_INFO, "User '%s' authenticated", proc->username);
ret = send_auth_reply(REP_AUTH_OK, proc, lease);
ret = send_auth_reply(s, proc, REP_AUTH_OK, lease);
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
@@ -270,7 +318,7 @@ int handle_commands(const struct cfg_st *config, struct tun_st *tun,
lease->fd = -1;
} else {
syslog(LOG_INFO, "Failed authentication attempt for user '%s'", proc->username);
ret = send_auth_reply( REP_AUTH_FAILED, proc, NULL);
ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL);
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;

165
src/main-resume.c Normal file
View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <tlslib.h>
#include "ipc.h"
#include <hash.h>
#include <hash-pjw-bare.h>
#include <vpn.h>
#include <main.h>
#include <tlslib.h>
int send_resume_fetch_reply(main_server_st* s, struct proc_list_st * proc,
cmd_resume_reply_t r, struct cmd_resume_fetch_reply_st * reply)
{
struct iovec iov[3];
uint8_t cmd = RESUME_FETCH_REP;
struct msghdr hdr;
memset(&hdr, 0, sizeof(hdr));
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
hdr.msg_iovlen++;
iov[1].iov_base = reply;
iov[1].iov_len = sizeof(*reply);
hdr.msg_iovlen++;
iov[2].iov_base = reply;
iov[2].iov_len = sizeof(*reply);
hdr.msg_iovlen++;
hdr.msg_iov = iov;
return(sendmsg(proc->fd, &hdr, 0));
}
int handle_resume_delete_req(main_server_st* s, struct proc_list_st * proc,
const struct cmd_resume_fetch_req_st * req)
{
size_t key;
tls_cache_st* cache;
struct hlist_node *pos, *tmp;
key = hash_pjw_bare(req->session_id, req->session_id_size);
hash_for_each_possible_safe(s->tls_db->entry, cache, pos, tmp, list, key) {
if (req->session_id_size == cache->session_id_size &&
memcmp (req->session_id, cache->session_id, req->session_id_size) == 0) {
cache->session_data_size = 0;
cache->session_id_size = 0;
hash_del(&cache->list);
free(cache);
return 0;
}
}
return 0;
}
static int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n)
{
if (((struct sockaddr*)s1)->sa_family == AF_INET) {
return memcmp(SA_IN_P(s1), SA_IN_P(s2), sizeof(struct in_addr));
} else { /* inet6 */
return memcmp(SA_IN6_P(s1), SA_IN6_P(s2), sizeof(struct in6_addr));
}
}
int handle_resume_fetch_req(main_server_st* s, struct proc_list_st * proc,
const struct cmd_resume_fetch_req_st * req,
struct cmd_resume_fetch_reply_st * rep)
{
size_t key;
tls_cache_st* cache;
struct hlist_node *pos;
key = hash_pjw_bare(req->session_id, req->session_id_size);
rep->reply = REP_RESUME_FAILED;
hash_for_each_possible(s->tls_db->entry, cache, pos, list, key) {
if (req->session_id_size == cache->session_id_size &&
memcmp (req->session_id, cache->session_id, req->session_id_size) == 0) {
if (proc->remote_addr_len == cache->remote_addr_len &&
ip_cmp(&proc->remote_addr, &cache->remote_addr, proc->remote_addr_len) == 0) {
rep->reply = REP_RESUME_OK;
memcpy(rep->session_data, cache->session_data, cache->session_data_size);
rep->session_data_size = cache->session_data_size;
return 0;
}
}
}
return 0;
}
int handle_resume_store_req(main_server_st* s, struct proc_list_st * proc,
const struct cmd_resume_store_req_st * req)
{
tls_cache_st* cache;
size_t key;
if (req->session_id_size > GNUTLS_MAX_SESSION_ID)
return -1;
if (req->session_data_size > MAX_SESSION_DATA_SIZE)
return -1;
key = hash_pjw_bare(req->session_id, req->session_id_size);
cache = malloc(sizeof(*cache));
if (cache == NULL)
return -1;
cache->session_id_size = req->session_id_size;
cache->session_data_size = req->session_data_size;
cache->remote_addr_len = proc->remote_addr_len;
memcpy(cache->session_id, req->session_id, req->session_id_size);
memcpy(cache->session_data, req->session_data, req->session_data_size);
memcpy(&cache->remote_addr, &proc->remote_addr, proc->remote_addr_len);
hash_add(s->tls_db->entry, &cache->list, key);
return 0;
}

View File

@@ -34,8 +34,9 @@
#include <gnutls/x509.h>
#include <tlslib.h>
#include <worker-auth.h>
#include "ipc.h"
#include <main.h>
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
@@ -352,9 +353,12 @@ int main(int argc, char** argv)
struct worker_st ws;
struct cfg_st config;
unsigned active_clients = 0;
main_server_st s;
tls_cache_db_st* tls_db;
INIT_LIST_HEAD(&clist.list);
tun_st_init(&tun);
tls_cache_init(&config, &tls_db);
signal(SIGINT, handle_term);
signal(SIGTERM, handle_term);
@@ -374,6 +378,11 @@ int main(int argc, char** argv)
fprintf(stderr, "Error in arguments\n");
exit(1);
}
s.config = &config;
s.tun = &tun;
s.tls_db = tls_db;
/* Listen to network ports */
ret = listen_ports(&config, &llist, config.name, config.port, SOCK_STREAM);
if (ret < 0) {
@@ -562,7 +571,7 @@ fork_failed:
ctmp = list_entry(pos, struct proc_list_st, list);
if (FD_ISSET(ctmp->fd, &rd)) {
ret = handle_commands(&config, &tun, ctmp);
ret = handle_commands(&s, ctmp);
if (ret < 0) {
if (ret == -2) {
/* received a bad command from worker */

49
src/main.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef MAIN_H
# define MAIN_H
#include <vpn.h>
#include <tlslib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
int cmd_parser (int argc, char **argv, struct cfg_st* config);
struct proc_list_st {
struct list_head list;
int fd;
pid_t pid;
struct sockaddr_storage remote_addr; /* peer address */
socklen_t remote_addr_len;
char username[MAX_USERNAME_SIZE]; /* the owner */
uint8_t cookie[COOKIE_SIZE]; /* the cookie associate with the session */
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
/* the tun lease this process has */
struct lease_st* lease;
};
typedef struct main_server_st {
struct cfg_st *config;
struct tun_st *tun;
tls_cache_db_st *tls_db;
} main_server_st;
int handle_commands(main_server_st *s, struct proc_list_st* cur);
int send_resume_fetch_reply(main_server_st* s, struct proc_list_st* proc,
cmd_resume_reply_t r, struct cmd_resume_fetch_reply_st * reply);
int handle_resume_delete_req(main_server_st* s, struct proc_list_st* proc,
const struct cmd_resume_fetch_req_st * req);
int handle_resume_fetch_req(main_server_st* s, struct proc_list_st* proc,
const struct cmd_resume_fetch_req_st * req,
struct cmd_resume_fetch_reply_st * rep);
int handle_resume_store_req(main_server_st* s, struct proc_list_st *proc,
const struct cmd_resume_store_req_st * req);
#endif

View File

@@ -115,3 +115,16 @@ void tls_fatal_close(gnutls_session_t session,
gnutls_alert_send(session, GNUTLS_AL_FATAL, a);
gnutls_deinit(session);
}
void tls_cache_init(struct cfg_st* config, tls_cache_db_st** _db)
{
tls_cache_db_st * db;
db = malloc(sizeof(*db));
if (db == NULL)
exit(1);
hash_init(db->entry);
*_db = db;
}

View File

@@ -2,6 +2,10 @@
#define TLS_H
#include <gnutls/gnutls.h>
#include <vpn.h>
#include <hashtable.h>
#define MAX_SESSION_DATA_SIZE (4*1024)
#define tls_puts(s, str) tls_send(s, str, sizeof(str)-1)
@@ -28,4 +32,29 @@ void tls_close(gnutls_session_t session);
void tls_fatal_close(gnutls_session_t session,
gnutls_alert_description_t a);
#define MAX_SESSION_DATA_SIZE (4*1024)
typedef struct
{
/* does not allow resumption from different address
* than the original */
struct sockaddr_storage remote_addr;
socklen_t remote_addr_len;
char session_id[GNUTLS_MAX_SESSION_ID];
unsigned int session_id_size;
char session_data[MAX_SESSION_DATA_SIZE];
unsigned int session_data_size;
struct hlist_node list;
} tls_cache_st;
typedef struct
{
DECLARE_HASHTABLE(entry, 7);
} tls_cache_db_st;
void tls_cache_init(struct cfg_st* config, tls_cache_db_st** db);
#endif

View File

@@ -143,25 +143,6 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
void __attribute__ ((format(printf, 3, 4)))
oclog(const worker_st * server, int priority, const char *fmt, ...);
int cmd_parser (int argc, char **argv, struct cfg_st* config);
struct proc_list_st {
struct list_head list;
int fd;
pid_t pid;
struct sockaddr_storage remote_addr; /* peer address */
socklen_t remote_addr_len;
char username[MAX_USERNAME_SIZE]; /* the owner */
uint8_t cookie[COOKIE_SIZE]; /* the cookie associate with the session */
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
/* the tun lease this process has */
struct lease_st* lease;
};
int handle_commands(const struct cfg_st *config, struct tun_st *tun,
struct proc_list_st* proc);
/* Helper casts */
#define SA_IN_P(p) (&((struct sockaddr_in *)(p))->sin_addr)
#define SA_IN_U8_P(p) ((uint8_t*)(&((struct sockaddr_in *)(p))->sin_addr))

View File

@@ -34,7 +34,8 @@
#include <limits.h>
#include <vpn.h>
#include <worker-auth.h>
#include "ipc.h"
#include <worker.h>
#include <cookies.h>
#include <tlslib.h>

236
src/worker-resume.c Normal file
View File

@@ -0,0 +1,236 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <gnutls/x509.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <vpn.h>
#include "ipc.h"
#include <cookies.h>
#include <tlslib.h>
static int send_resume_fetch_req(worker_st * ws, const struct cmd_resume_fetch_req_st* r,
int delete)
{
struct iovec iov[2];
uint8_t cmd;
struct msghdr hdr;
memset(&hdr, 0, sizeof(hdr));
if (delete != 0)
cmd = RESUME_DELETE_REQ;
else
cmd = RESUME_FETCH_REQ;
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = (void*)r;
iov[1].iov_len = sizeof(*r);
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
return(sendmsg(ws->cmd_fd, &hdr, 0));
}
static int send_resume_store_req(worker_st * ws, const struct cmd_resume_store_req_st* r)
{
struct iovec iov[2];
uint8_t cmd;
struct msghdr hdr;
memset(&hdr, 0, sizeof(hdr));
cmd = RESUME_STORE_REQ;
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = (void*)r;
iov[1].iov_len = sizeof(*r);
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
return(sendmsg(ws->cmd_fd, &hdr, 0));
}
static int recv_resume_fetch_reply(worker_st *ws, struct cmd_resume_fetch_reply_st* resp)
{
struct iovec iov[2];
uint8_t cmd = 0;
struct msghdr hdr;
int ret;
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = resp;
iov[1].iov_len = sizeof(*resp);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
ret = recvmsg( ws->cmd_fd, &hdr, 0);
if (ret < sizeof(*resp)+1) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", ret, (int)sizeof(*resp)+1);
return -1;
}
if (cmd != RESUME_FETCH_REP) {
oclog(ws, LOG_ERR, "Received unexpected response (%d, expected %d) from main", (int)cmd, (int)RESUME_FETCH_REP);
return -1;
}
switch(resp->reply) {
case REP_RESUME_OK:
return 0;
default:
return -1;
}
}
/* sends an authentication request to main thread and waits for
* a reply.
* Returns 0 on success.
*/
static gnutls_datum_t resume_db_fetch(void *dbf, gnutls_datum_t key)
{
worker_st *ws = dbf;
struct cmd_resume_fetch_req_st areq;
struct cmd_resume_fetch_reply_st *arep;
gnutls_datum_t r = { NULL, 0 };
int ret;
if (key.size > GNUTLS_MAX_SESSION_ID) {
oclog(ws, LOG_DEBUG, "Session ID size exceeds the maximum %u", key.size);
return r;
}
areq.session_id_size = key.size;
memcpy(areq.session_id, key.data, key.size);
oclog(ws, LOG_DEBUG, "Sending resumption request");
ret = send_resume_fetch_req(ws, &areq, 0);
if (ret < 0)
return r;
arep = malloc(sizeof(*arep));
if (arep == NULL)
return r;
ret = recv_resume_fetch_reply(ws, arep);
if (ret < 0) {
goto cleanup;
}
r.data = gnutls_malloc(arep->session_data_size);
if (r.data == NULL)
goto cleanup;
r.size = arep->session_data_size;
memcpy(r.data, arep->session_data, r.size);
cleanup:
free(arep);
return r;
}
static int
resume_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
{
worker_st *ws = dbf;
struct cmd_resume_store_req_st areq;
int ret;
if (data.size > MAX_SESSION_DATA_SIZE) {
oclog(ws, LOG_DEBUG, "Session data size exceeds the maximum %u", data.size);
return GNUTLS_E_DB_ERROR;
}
if (key.size > GNUTLS_MAX_SESSION_ID) {
oclog(ws, LOG_DEBUG, "Session ID size exceeds the maximum %u", key.size);
return GNUTLS_E_DB_ERROR;
}
areq.session_id_size = key.size;
areq.session_data_size = data.size;
memcpy(areq.session_id, key.data, key.size);
memcpy(areq.session_data, data.data, data.size);
ret = send_resume_store_req(ws, &areq);
if (ret < 0) {
return GNUTLS_E_DB_ERROR;
}
return 0;
}
/* sends an authentication request to main thread and waits for
* a reply.
* Returns 0 on success.
*/
static int resume_db_delete(void *dbf, gnutls_datum_t key)
{
worker_st *ws = dbf;
struct cmd_resume_fetch_req_st areq;
int ret;
if (key.size > GNUTLS_MAX_SESSION_ID) {
oclog(ws, LOG_DEBUG, "Session ID size exceeds the maximum %u", key.size);
return GNUTLS_E_DB_ERROR;
}
areq.session_id_size = key.size;
memcpy(areq.session_id, key.data, key.size);
oclog(ws, LOG_DEBUG, "Sending resumption request");
ret = send_resume_fetch_req(ws, &areq, 1);
if (ret < 0)
return GNUTLS_E_DB_ERROR;
return 0;
}
void set_resume_db_funcs(gnutls_session_t session)
{
gnutls_db_set_retrieve_function (session, resume_db_fetch);
gnutls_db_set_remove_function (session, resume_db_delete);
gnutls_db_set_store_function (session, resume_db_store);
}

View File

@@ -42,8 +42,9 @@
#include <time.h>
#include <vpn.h>
#include <worker-auth.h>
#include "ipc.h"
#include <cookies.h>
#include <worker.h>
#include <tlslib.h>
#include <http-parser/http_parser.h>
@@ -283,7 +284,6 @@ gnutls_datum_t sid = { ws->session_id, sizeof(ws->session_id) };
goto fail;
}
ret =
gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
ws->creds->xcred);
@@ -342,7 +342,9 @@ void vpn_server(struct worker_st* ws)
gnutls_certificate_server_set_request(session, ws->config->cert_req);
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) (long)ws->conn_fd);
set_resume_db_funcs(session);
gnutls_session_set_ptr(session, ws);
gnutls_db_set_ptr (session, ws);
do {
ret = gnutls_handshake(session);

22
src/worker.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef WORKER_H
#define WORKER_H
#include <config.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
#include <vpn.h>
#include <cookies.h>
#include <tlslib.h>
int auth_cookie(worker_st *ws, void* cookie, size_t cookie_size);
int get_auth_handler(worker_st *server);
int post_old_auth_handler(worker_st *server);
int post_new_auth_handler(worker_st *server);
void set_resume_db_funcs(gnutls_session_t);
#endif