2 Commits

Author SHA1 Message Date
lns
9f2bf9fdc3 Removed TLS proxy capabilities as it complicates the code and makes no sense.
* nDPIsrvd-cached will do the same job in the future

Signed-off-by: lns <matzeton@googlemail.com>
2023-01-17 22:03:03 +01:00
Toni Uhlig
ac4c7390a3 Added TLS proxy support.
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
2023-01-17 22:03:00 +01:00
8 changed files with 900 additions and 121 deletions

View File

@@ -51,6 +51,7 @@ jobs:
sudo apt-get update
sudo apt-get install autoconf automake cmake libtool pkg-config gettext libjson-c-dev flex bison libpcap-dev zlib1g-dev
sudo apt-get install ${{ matrix.compiler }} lcov iproute2
sudo apt-get install rpm alien
- name: Install Ubuntu Prerequisites (libgcrypt)
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.ndpid_gcrypt, '-DNDPI_WITH_GCRYPT=ON')
run: |
@@ -93,6 +94,9 @@ jobs:
- name: CPack DEB
run: |
cd ./build && cpack -G DEB && sudo dpkg -i nDPId-*.deb && cd ..
- name: CPack RPM
run: |
cd ./build && cpack -G RPM
- name: systemd test
if: startsWith(matrix.os, 'ubuntu-latest') && startsWith(matrix.compiler, 'default-cc')
run: |

View File

@@ -10,13 +10,20 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
find_package(PkgConfig REQUIRED)
set(CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/utoni/nDPId")
set(CPACK_PACKAGE_NAME "nDPId")
set(CPACK_PACKAGE_CONTACT "toni@impl.cc")
set(CPACK_DEBIAN_PACKAGE_NAME "nDPId")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Tiny nDPI based deep packet inspection daemons / toolkit.")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
set(CPACK_PACKAGE_VERSION_MAJOR 1)
set(CPACK_PACKAGE_VERSION_MINOR 5)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3.0")
include(CPack)
include(CheckFunctionExists)
@@ -46,6 +53,7 @@ option(ENABLE_SANITIZER_THREAD "Enable TSAN (does not work together with ASAN)."
option(ENABLE_MEMORY_PROFILING "Enable dynamic memory tracking." OFF)
option(ENABLE_ZLIB "Enable zlib support for nDPId (experimental)." OFF)
option(ENABLE_SYSTEMD "Install systemd components." OFF)
option(ENABLE_GNUTLS "Enable GnuTLS support for nDPIsrvd TCP connections." ON)
option(BUILD_EXAMPLES "Build C examples." ON)
option(BUILD_NDPI "Clone and build nDPI from github." OFF)
if(BUILD_NDPI)
@@ -134,9 +142,13 @@ if(ENABLE_SANITIZER_THREAD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize=alignment -fsanitize=enum -fsanitize=thread")
endif()
if(ENABLE_ZLIB)
set(ZLIB_DEFS "-DENABLE_ZLIB=1")
set(NDPID_DEFS ${NDPID_DEFS} -DENABLE_ZLIB=1)
pkg_check_modules(ZLIB REQUIRED zlib)
endif()
if(ENABLE_GNUTLS)
set(NDPID_DEFS ${NDPID_DEFS} -DENABLE_GNUTLS=1)
pkg_check_modules(GNUTLS REQUIRED gnutls)
endif()
if(NDPI_WITH_GCRYPT)
message(STATUS "nDPI: Enable GCRYPT")
set(NDPI_ADDITIONAL_ARGS "${NDPI_ADDITIONAL_ARGS} --with-local-libgcrypt")
@@ -276,15 +288,17 @@ target_link_libraries(nDPId "${STATIC_LIBNDPI_LIB}" "${pkgcfg_lib_NDPI_ndpi}"
target_compile_definitions(nDPIsrvd PRIVATE -D_GNU_SOURCE=1 -DGIT_VERSION=\"${GIT_VERSION}\" ${NDPID_DEFS})
target_include_directories(nDPIsrvd PRIVATE ${NDPID_DEPS_INC})
target_link_libraries(nDPIsrvd "${pkgcfg_lib_GNUTLS_gnutls}")
target_include_directories(nDPId-test PRIVATE ${NDPID_DEPS_INC})
target_compile_options(nDPId-test PRIVATE "-Wno-unused-function" "-pthread")
target_compile_definitions(nDPId-test PRIVATE -D_GNU_SOURCE=1 -DNO_MAIN=1 -DGIT_VERSION=\"${GIT_VERSION}\"
${NDPID_DEFS} ${ZLIB_DEFS} ${NDPID_TEST_MPROF_DEFS})
${NDPID_DEFS} ${NDPID_TEST_MPROF_DEFS})
target_include_directories(nDPId-test PRIVATE
"${STATIC_LIBNDPI_INC}" "${DEFAULT_NDPI_INCLUDE}" ${NDPID_DEPS_INC})
target_link_libraries(nDPId-test "${STATIC_LIBNDPI_LIB}" "${pkgcfg_lib_NDPI_ndpi}"
"${pkgcfg_lib_PCRE_pcre}" "${pkgcfg_lib_MAXMINDDB_maxminddb}" "${pkgcfg_lib_ZLIB_z}"
"${pkgcfg_lib_GNUTLS_gnutls}"
"${GCRYPT_LIBRARY}" "${GCRYPT_ERROR_LIBRARY}" "${PCAP_LIBRARY}" "${LIBM_LIB}"
"-pthread")
@@ -364,14 +378,19 @@ install(FILES schema/error_event_schema.json schema/daemon_event_schema.json
message(STATUS "--------------------------")
message(STATUS "nDPId GIT_VERSION........: ${GIT_VERSION}")
message(STATUS "Cross Compilation........: ${CMAKE_CROSSCOMPILING}")
message(STATUS "CMAKE_SYSTEM_NAME........: ${CMAKE_SYSTEM_NAME}")
message(STATUS "CMAKE_SYSTEM_PROCESSOR...: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_BUILD_TYPE.........: ${CMAKE_BUILD_TYPE}")
message(STATUS "CMAKE_C_FLAGS............: ${CMAKE_C_FLAGS}")
message(STATUS "NDPID_DEFS...............: ${NDPID_DEFS}")
string(REPLACE ";" " " PRETTY_NDPID_DEFS "${NDPID_DEFS}")
message(STATUS "NDPID_DEFS...............: ${PRETTY_NDPID_DEFS}")
message(STATUS "ENABLE_COVERAGE..........: ${ENABLE_COVERAGE}")
message(STATUS "ENABLE_SANITIZER.........: ${ENABLE_SANITIZER}")
message(STATUS "ENABLE_SANITIZER_THREAD..: ${ENABLE_SANITIZER_THREAD}")
message(STATUS "ENABLE_MEMORY_PROFILING..: ${ENABLE_MEMORY_PROFILING}")
message(STATUS "ENABLE_ZLIB..............: ${ENABLE_ZLIB}")
message(STATUS "ENABLE_SYSTEMD...........: ${ENABLE_SYSTEMD}")
message(STATUS "ENABLE_GNUTLS............: ${ENABLE_GNUTLS}")
if(STATIC_LIBNDPI_INSTALLDIR)
message(STATUS "STATIC_LIBNDPI_INSTALLDIR: ${STATIC_LIBNDPI_INSTALLDIR}")
endif()

View File

@@ -1293,9 +1293,12 @@ int main(int argc, char ** argv)
}
/* We do not have any sockets, any socket operation must fail! */
collector_un_sockfd = -1;
distributor_un_sockfd = -1;
distributor_in_sockfd = -1;
sockfds[COLLECTOR_UN] = -1;
sockfds[DISTRIBUTOR_UN] = -1;
sockfds[DISTRIBUTOR_IN] = -1;
#ifdef ENABLE_GNUTLS
sockfds[DISTRIBUTOR_IN_TLS] = -1;
#endif
if (setup_remote_descriptors(MAX_REMOTE_DESCRIPTORS) != 0)
{

View File

@@ -1,6 +1,9 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#ifdef ENABLE_GNUTLS
#include <gnutls/gnutls.h>
#endif
#include <netdb.h>
#include <netinet/tcp.h>
#include <pwd.h>
@@ -21,9 +24,12 @@
enum sock_type
{
COLLECTOR_UN,
COLLECTOR_UN = 0,
DISTRIBUTOR_UN,
DISTRIBUTOR_IN,
#ifdef ENABLE_GNUTLS
DISTRIBUTOR_IN_TLS,
#endif
};
struct nDPIsrvd_write_buffer
@@ -64,6 +70,18 @@ struct remote_desc
struct nDPIsrvd_write_buffer main_write_buffer;
UT_array * additional_write_buffers;
} event_distributor_in; /* TCP/IP socket */
#ifdef ENABLE_GNUTLS
struct
{
struct sockaddr_in peer;
char peer_addr[INET_ADDRSTRLEN];
struct nDPIsrvd_write_buffer main_write_buffer;
UT_array * additional_write_buffers;
gnutls_session_t session;
} event_distributor_in_tls;
#endif
};
};
@@ -75,12 +93,38 @@ static struct
} remotes = {NULL, 0, 0};
static int nDPIsrvd_main_thread_shutdown = 0;
static int collector_un_sockfd = -1;
static int distributor_un_sockfd = -1;
static int distributor_in_sockfd = -1;
static struct nDPIsrvd_address distributor_in_address = {
.raw.sa_family = 0xFFFF,
static int sockfds[] = {[COLLECTOR_UN] = -1,
[DISTRIBUTOR_UN] = -1,
[DISTRIBUTOR_IN] = -1,
#ifdef ENABLE_GNUTLS
[DISTRIBUTOR_IN_TLS] = -1
#endif
};
static struct nDPIsrvd_address addrs[] = {[COLLECTOR_UN] =
{
.raw.sa_family = 0xFFFF,
},
[DISTRIBUTOR_UN] =
{
.raw.sa_family = 0xFFFF,
},
[DISTRIBUTOR_IN] =
{
.raw.sa_family = 0xFFFF,
},
#ifdef ENABLE_GNUTLS
[DISTRIBUTOR_IN_TLS] =
{
.raw.sa_family = 0xFFFF,
}
#endif
};
#ifdef ENABLE_GNUTLS
static int enable_tls;
static gnutls_certificate_credentials_t x509_creds = NULL;
static gnutls_priority_t prio_cache = NULL;
#endif
static struct
{
@@ -93,6 +137,13 @@ static struct
nDPIsrvd_ull max_remote_descriptors;
nDPIsrvd_ull max_write_buffers;
int bufferbloat_fallback_to_blocking;
#ifdef ENABLE_GNUTLS
char * distributor_in_tls_address;
char * x509_certfile;
char * x509_keyfile;
char * x509_crlfile;
char * x509_cafile;
#endif
} nDPIsrvd_options = {.pidfile = CMDARG(nDPIsrvd_PIDFILE),
.collector_un_sockpath = CMDARG(COLLECTOR_UNIX_SOCKET),
.distributor_un_sockpath = CMDARG(DISTRIBUTOR_UNIX_SOCKET),
@@ -100,7 +151,6 @@ static struct
.user = CMDARG(DEFAULT_CHUSER),
.group = CMDARG(NULL),
.max_remote_descriptors = nDPIsrvd_MAX_REMOTE_DESCRIPTORS,
.max_write_buffers = nDPIsrvd_MAX_WRITE_BUFFERS,
.bufferbloat_fallback_to_blocking = 1};
static void logger_nDPIsrvd(struct remote_desc const * const remote,
@@ -169,15 +219,118 @@ void nDPIsrvd_memprof_log(char const * const format, ...)
#endif
#endif
#ifdef ENABLE_GNUTLS
static int gtls_global_init(char const * const certfile,
char const * const keyfile,
char const * const crlfile,
char const * const cafile,
gnutls_certificate_credentials_t * const x509_creds,
gnutls_priority_t * prio_cache)
{
int error;
if (gnutls_check_version("3.4.6") == NULL)
{
logger_early(1, "GnuTLS 3.4.6 or later is required.");
return -1;
}
if ((error = gnutls_global_init()) < 0)
{
logger_early(1, "GnuTLS global init failed %s %s.", gnutls_strerror(error), gnutls_strerror_name(error));
return -1;
}
if ((error = gnutls_certificate_allocate_credentials(x509_creds)) < 0)
{
logger_early(1,
"GnuTLS certificate allocation failed %s %s.",
gnutls_strerror(error),
gnutls_strerror_name(error));
return -1;
}
if ((error = gnutls_certificate_set_x509_crl_file(*x509_creds, crlfile, GNUTLS_X509_FMT_PEM)) < 0)
{
logger_early(1,
"GnuTLS x509 crl file invalid. PEM format required %s %s.",
gnutls_strerror(error),
gnutls_strerror_name(error));
return -1;
}
if ((error = gnutls_certificate_set_x509_key_file(*x509_creds, certfile, keyfile, GNUTLS_X509_FMT_PEM)) < 0)
{
logger_early(1,
"GnuTLS x509 cert/key file invalid. PEM format required %s %s.",
gnutls_strerror(error),
gnutls_strerror_name(error));
return -1;
}
if ((error = gnutls_certificate_set_x509_trust_file(*x509_creds, cafile, GNUTLS_X509_FMT_PEM)) < 0)
{
logger_early(1,
"GnuTLS x509 ca file invalid. PEM format required: %s %s.",
gnutls_strerror(error),
gnutls_strerror_name(error));
return -1;
}
if ((error = gnutls_priority_init(prio_cache, "SECURE256", NULL)) < 0)
{
logger_early(1,
"GnuTLS priority cache init failed: %s %s.",
gnutls_strerror(error),
gnutls_strerror_name(error));
return -1;
}
#if GNUTLS_VERSION_NUMBER >= 0x030506
gnutls_certificate_set_known_dh_params(*x509_creds, GNUTLS_SEC_PARAM_HIGH);
#else
gnutls_certificate_set_dh_params(*x509_creds, GNUTLS_SEC_PARAM_HIGH);
#endif
return 0;
}
static int gtls_init_session_server(struct remote_desc * const remote)
{
if (remote->sock_type != DISTRIBUTOR_IN_TLS)
{
return 1;
}
if (gnutls_init(&remote->event_distributor_in_tls.session, GNUTLS_SERVER) < 0)
{
return 1;
}
if (gnutls_priority_set(remote->event_distributor_in_tls.session, prio_cache) < 0)
{
return 1;
}
if (gnutls_credentials_set(remote->event_distributor_in_tls.session,
GNUTLS_CRD_CERTIFICATE, x509_creds) < 0)
{
return 1;
}
gnutls_session_set_verify_cert(remote->event_distributor_in_tls.session, NULL, 0);
gnutls_certificate_server_set_request(remote->event_distributor_in_tls.session, GNUTLS_CERT_REQUIRE);
gnutls_certificate_send_x509_rdn_sequence(remote->event_distributor_in_tls.session, 1);
gnutls_handshake_set_timeout(remote->event_distributor_in_tls.session,
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_transport_set_int(remote->event_distributor_in_tls.session, remote->fd);
return 0;
}
#endif
static struct nDPIsrvd_json_buffer * get_read_buffer(struct remote_desc * const remote)
{
switch (remote->sock_type)
{
case COLLECTOR_UN:
return &remote->event_collector_un.main_read_buffer;
case DISTRIBUTOR_UN:
case DISTRIBUTOR_IN:
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
#endif
return NULL;
}
@@ -196,6 +349,11 @@ static struct nDPIsrvd_write_buffer * get_write_buffer(struct remote_desc * cons
case DISTRIBUTOR_IN:
return &remote->event_distributor_in.main_write_buffer;
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
return &remote->event_distributor_in_tls.main_write_buffer;
#endif
}
return NULL;
@@ -213,6 +371,10 @@ static UT_array * get_additional_write_buffers(struct remote_desc * const remote
case DISTRIBUTOR_IN:
return remote->event_distributor_in.additional_write_buffers;
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
return remote->event_distributor_in_tls.additional_write_buffers;
#endif
}
return NULL;
@@ -291,6 +453,17 @@ static void logger_nDPIsrvd(struct remote_desc const * const remote,
ntohs(remote->event_distributor_in.peer.sin_port),
logbuf);
break;
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
logger(1,
"%s %.*s:%u %s",
prefix,
(int)sizeof(remote->event_distributor_in_tls.peer_addr),
remote->event_distributor_in_tls.peer_addr,
ntohs(remote->event_distributor_in_tls.peer.sin_port),
logbuf);
break;
#endif
case COLLECTOR_UN:
logger(1, "%s PID %d %s", prefix, remote->event_collector_un.pid, logbuf);
break;
@@ -454,24 +627,39 @@ static int fcntl_del_flags(int fd, int flags)
static int create_listen_sockets(void)
{
collector_un_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
distributor_un_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (collector_un_sockfd < 0 || distributor_un_sockfd < 0)
sockfds[COLLECTOR_UN] = socket(AF_UNIX, SOCK_STREAM, 0);
sockfds[DISTRIBUTOR_UN] = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfds[COLLECTOR_UN] < 0 || sockfds[DISTRIBUTOR_UN] < 0)
{
logger(1, "Error creating UNIX socket: %s", strerror(errno));
return 1;
}
#ifdef ENABLE_GNUTLS
if (enable_tls != 0)
{
if (nDPIsrvd_options.distributor_in_tls_address != NULL)
{
sockfds[DISTRIBUTOR_IN_TLS] = socket(AF_INET, SOCK_STREAM, 0);
if (sockfds[DISTRIBUTOR_IN_TLS] < 0)
{
logger(1, "Error creating distributor TLS proxy (server): %s", strerror(errno));
return 1;
}
}
}
#endif
if (is_cmdarg_set(&nDPIsrvd_options.distributor_in_address) != 0)
{
distributor_in_sockfd = socket(distributor_in_address.raw.sa_family, SOCK_STREAM, 0);
if (distributor_in_sockfd < 0)
sockfds[DISTRIBUTOR_IN] = socket(addrs[DISTRIBUTOR_IN].raw.sa_family, SOCK_STREAM, 0);
if (sockfds[DISTRIBUTOR_IN] < 0)
{
logger(1, "Error creating TCP/IP socket: %s", strerror(errno));
return 1;
}
int opt = 1;
if (setsockopt(distributor_in_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
if (setsockopt(sockfds[DISTRIBUTOR_IN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
{
logger(1, "Setting TCP/IP socket option SO_REUSEADDR failed: %s", strerror(errno));
}
@@ -479,8 +667,8 @@ static int create_listen_sockets(void)
{
int opt = 1;
if (setsockopt(collector_un_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0 ||
setsockopt(distributor_un_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
if (setsockopt(sockfds[COLLECTOR_UN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0 ||
setsockopt(sockfds[DISTRIBUTOR_UN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
{
logger(1, "Setting UNIX socket option SO_REUSEADDR failed: %s", strerror(errno));
}
@@ -507,7 +695,7 @@ static int create_listen_sockets(void)
return 1;
}
if (bind(collector_un_sockfd, (struct sockaddr *)&collector_addr, sizeof(collector_addr)) < 0)
if (bind(sockfds[COLLECTOR_UN], (struct sockaddr *)&collector_addr, sizeof(collector_addr)) < 0)
{
logger(1,
"Error binding Collector UNIX socket to `%s': %s",
@@ -538,7 +726,7 @@ static int create_listen_sockets(void)
return 2;
}
if (bind(distributor_un_sockfd, (struct sockaddr *)&distributor_addr, sizeof(distributor_addr)) < 0)
if (bind(sockfds[DISTRIBUTOR_UN], (struct sockaddr *)&distributor_addr, sizeof(distributor_addr)) < 0)
{
logger(1,
"Error binding Distributor socket to `%s': %s",
@@ -550,7 +738,7 @@ static int create_listen_sockets(void)
if (is_cmdarg_set(&nDPIsrvd_options.distributor_in_address) != 0)
{
if (bind(distributor_in_sockfd, &distributor_in_address.raw, distributor_in_address.size) < 0)
if (bind(sockfds[DISTRIBUTOR_IN], &addrs[DISTRIBUTOR_IN].raw, addrs[DISTRIBUTOR_IN].size) < 0)
{
logger(1,
"Error binding Distributor TCP/IP socket to %s: %s",
@@ -558,7 +746,7 @@ static int create_listen_sockets(void)
strerror(errno));
return 3;
}
if (listen(distributor_in_sockfd, 16) < 0)
if (listen(sockfds[DISTRIBUTOR_IN], 16) < 0)
{
logger(1,
"Error listening Distributor TCP/IP socket to %s: %s",
@@ -566,7 +754,7 @@ static int create_listen_sockets(void)
strerror(errno));
return 3;
}
if (fcntl_add_flags(distributor_in_sockfd, O_NONBLOCK) != 0)
if (fcntl_add_flags(sockfds[DISTRIBUTOR_IN], O_NONBLOCK) != 0)
{
logger(1,
"Error setting Distributor TCP/IP socket %s to non-blocking mode: %s",
@@ -576,13 +764,13 @@ static int create_listen_sockets(void)
}
}
if (listen(collector_un_sockfd, 16) < 0 || listen(distributor_un_sockfd, 16) < 0)
if (listen(sockfds[COLLECTOR_UN], 16) < 0 || listen(sockfds[DISTRIBUTOR_UN], 16) < 0)
{
logger(1, "Error listening UNIX socket: %s", strerror(errno));
return 3;
}
if (fcntl_add_flags(collector_un_sockfd, O_NONBLOCK) != 0)
if (fcntl_add_flags(sockfds[COLLECTOR_UN], O_NONBLOCK) != 0)
{
logger(1,
"Error setting Collector UNIX socket `%s' to non-blocking mode: %s",
@@ -591,7 +779,7 @@ static int create_listen_sockets(void)
return 3;
}
if (fcntl_add_flags(distributor_un_sockfd, O_NONBLOCK) != 0)
if (fcntl_add_flags(sockfds[DISTRIBUTOR_UN], O_NONBLOCK) != 0)
{
logger(1,
"Error setting Distributor UNIX socket `%s' to non-blocking mode: %s",
@@ -638,6 +826,17 @@ static struct remote_desc * get_remote_descriptor(enum sock_type type, int remot
write_buffer = &remotes.desc[i].event_distributor_in.main_write_buffer;
additional_write_buffers = &remotes.desc[i].event_distributor_in.additional_write_buffers;
break;
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
if (gtls_init_session_server(&remotes.desc[i]) != 0)
{
logger(1, "GnuTLS init session (server) failed.");
return NULL;
}
write_buffer = &remotes.desc[i].event_distributor_in_tls.main_write_buffer;
additional_write_buffers = &remotes.desc[i].event_distributor_in_tls.additional_write_buffers;
break;
#endif
}
if (additional_write_buffers != NULL && *additional_write_buffers == NULL)
@@ -710,6 +909,19 @@ static void free_remote(int epollfd, struct remote_desc * remote)
}
nDPIsrvd_buffer_free(&remote->event_distributor_in.main_write_buffer.buf);
break;
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
if (errno != 0)
{
logger_nDPIsrvd(remote, "Error closing distributor(TLS) connection", ": %s", strerror(errno));
}
if (remote->event_distributor_in_tls.additional_write_buffers != NULL)
{
utarray_free(remote->event_distributor_in_tls.additional_write_buffers);
}
nDPIsrvd_buffer_free(&remote->event_distributor_in_tls.main_write_buffer.buf);
break;
#endif
}
memset(remote, 0, sizeof(*remote));
@@ -791,7 +1003,7 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
{
int opt;
while ((opt = getopt(argc, argv, "lL:c:dp:s:S:m:u:g:C:Dvh")) != -1)
while ((opt = getopt(argc, argv, "lL:c:dp:s:S:m:u:g:C:DvX:x:h")) != -1)
{
switch (opt)
{
@@ -845,6 +1057,64 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
case 'v':
fprintf(stderr, "%s", get_nDPId_version());
return 1;
case 'X':
#ifdef ENABLE_GNUTLS
nDPIsrvd_options.distributor_in_tls_address = strdup(optarg);
enable_tls = 1;
break;
#else
logger_early(1, "To use TLS capabilities (`-X'), GnuTLS support required.");
return 1;
#endif
case 'x':
{
#ifdef ENABLE_GNUTLS
static char * const x509_subopt_token[] = {"cert", "key", "crl", "ca", NULL};
int errfnd = 0;
char * subopts = optarg;
char * value;
while (*subopts != '\0' && !errfnd)
{
int subopt = getsubopt(&subopts, x509_subopt_token, &value);
if (value == NULL && subopt != -1)
{
logger_early(1, "Missing value for `%s'", x509_subopt_token[subopt]);
return 1;
}
if (subopt == -1)
{
logger_early(1, "Invalid subopt: %s", value);
return 1;
}
switch (subopt)
{
case 0: /* cert */
nDPIsrvd_options.x509_certfile = strdup(value);
break;
case 1: /* key */
nDPIsrvd_options.x509_keyfile = strdup(value);
break;
case 2: /* crl */
nDPIsrvd_options.x509_crlfile = strdup(value);
break;
case 3: /* ca */
nDPIsrvd_options.x509_cafile = strdup(value);
break;
default:
logger_early(1, "Invalid subopt: %s", value);
return 1;
}
}
enable_tls = 1;
#else
logger_early(1, "To use TLS capabilities (`-x'), GnuTLS support required.");
return 1;
#endif
break;
}
case 'h':
default:
fprintf(stderr, "%s\n", get_nDPId_version());
@@ -870,6 +1140,10 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
"\t-s\tPath to a listening UNIX socket (nDPIsrvd Distributor).\n"
"\t \tDefault: %s\n"
"\t-S\tAddress:Port of the listening TCP/IP socket (nDPIsrvd Distributor).\n"
#ifdef ENABLE_GNUTLS
"\t[-X tls-distributor-host:port]\n"
"\t[-x cert=PEM-file] [-x key=PEM-file] [-x crl=file] [-x ca=PEM-file]\n"
#endif
"\t-v\tversion\n"
"\t-h\tthis\n\n",
argv[0],
@@ -898,7 +1172,7 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
if (is_cmdarg_set(&nDPIsrvd_options.distributor_in_address) != 0)
{
if (nDPIsrvd_setup_address(&distributor_in_address, get_cmdarg(&nDPIsrvd_options.distributor_in_address)) != 0)
if (nDPIsrvd_setup_address(&addrs[DISTRIBUTOR_IN], get_cmdarg(&nDPIsrvd_options.distributor_in_address)) != 0)
{
logger_early(1,
"%s: Could not parse address %s",
@@ -906,7 +1180,7 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
get_cmdarg(&nDPIsrvd_options.distributor_in_address));
return 1;
}
if (distributor_in_address.raw.sa_family == AF_UNIX)
if (addrs[DISTRIBUTOR_IN].raw.sa_family == AF_UNIX)
{
logger_early(1,
"%s: You've requested to setup another UNIX socket `%s', but there is already one at `%s'",
@@ -917,6 +1191,44 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
}
}
#ifdef ENABLE_GNUTLS
if (enable_tls != 0)
{
if (nDPIsrvd_options.x509_certfile == NULL || nDPIsrvd_options.x509_keyfile == NULL ||
nDPIsrvd_options.x509_cafile == NULL)
{
logger_early(1,
"%s: To use nDPIsrvd TLS capabilities, `-x cert', `-x key' and `-x ca' need to be set.",
argv[0]);
return 1;
}
if (nDPIsrvd_options.distributor_in_tls_address == NULL)
{
logger_early(1, "%s: To use nDPIsrvd TLS capabilities, `-X' need to bet set.", argv[0]);
return 1;
}
if (nDPIsrvd_setup_address(&addrs[DISTRIBUTOR_IN_TLS],
nDPIsrvd_options.distributor_in_tls_address) != 0)
{
logger_early(1,
"%s: Could not parse address %s",
argv[0],
nDPIsrvd_options.distributor_in_tls_address);
return 1;
}
if (addrs[DISTRIBUTOR_IN_TLS].raw.sa_family == AF_UNIX)
{
logger_early(1,
"%s: You've requested to setup another UNIX socket `%s' for TLS, which is not supported. Please use `-s'.",
argv[0],
nDPIsrvd_options.distributor_in_tls_address);
return 1;
}
}
#endif
if (optind < argc)
{
logger_early(1, "%s: Unexpected argument after options", argv[0]);
@@ -947,6 +1259,63 @@ static struct remote_desc * accept_remote(int server_fd,
return current;
}
static pid_t get_pid_from_unix_socket(int fd, uid_t * const uid)
{
struct ucred ucred = {};
socklen_t ucred_len = sizeof(ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) == -1)
{
logger(1, "Error getting credentials from UNIX socket: %s", strerror(errno));
return -1;
}
if (uid != NULL)
{
*uid = ucred.uid;
}
return ucred.pid;
}
static char * get_username_from_uid(uid_t const uid)
{
struct passwd pwnam = {};
struct passwd * pwres = NULL;
ssize_t pwsiz = sysconf(_SC_GETPW_R_SIZE_MAX);
if (pwsiz == -1)
{
pwsiz = BUFSIZ;
}
char buf[pwsiz];
if (getpwuid_r(uid, &pwnam, &buf[0], pwsiz, &pwres) != 0)
{
logger(1, "Could not get passwd entry for user id %u", uid);
return NULL;
}
return strdup(pwres->pw_name);
}
int set_snd_opts(int fd)
{
int sockopt = NETWORK_BUFFER_MAX_SIZE;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sockopt, sizeof(sockopt)) < 0)
{
logger(1, "Error setting socket option SO_SNDBUF: %s", strerror(errno));
return 1;
}
{
struct timeval send_timeout = {1, 0};
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&send_timeout, sizeof(send_timeout)) != 0)
{
logger(1, "Error setting socket option send timeout: %s", strerror(errno));
return 1;
}
}
return 0;
}
static int new_connection(int epollfd, int eventfd)
{
union
@@ -954,29 +1323,40 @@ static int new_connection(int epollfd, int eventfd)
struct sockaddr_un saddr_collector_un;
struct sockaddr_un saddr_distributor_un;
struct sockaddr_in saddr_distributor_in;
#ifdef ENABLE_GNUTLS
struct sockaddr_in saddr_distributor_in_tls;
#endif
} sockaddr;
socklen_t peer_addr_len;
enum sock_type stype;
int server_fd;
if (eventfd == collector_un_sockfd)
if (eventfd == sockfds[COLLECTOR_UN])
{
peer_addr_len = sizeof(sockaddr.saddr_collector_un);
stype = COLLECTOR_UN;
server_fd = collector_un_sockfd;
server_fd = sockfds[COLLECTOR_UN];
}
else if (eventfd == distributor_un_sockfd)
else if (eventfd == sockfds[DISTRIBUTOR_UN])
{
peer_addr_len = sizeof(sockaddr.saddr_distributor_un);
stype = DISTRIBUTOR_UN;
server_fd = distributor_un_sockfd;
server_fd = sockfds[DISTRIBUTOR_UN];
}
else if (eventfd == distributor_in_sockfd)
else if (eventfd == sockfds[DISTRIBUTOR_IN])
{
peer_addr_len = sizeof(sockaddr.saddr_distributor_in);
stype = DISTRIBUTOR_IN;
server_fd = distributor_in_sockfd;
server_fd = sockfds[DISTRIBUTOR_IN];
}
#ifdef ENABLE_GNUTLS
else if (eventfd == sockfds[DISTRIBUTOR_IN_TLS])
{
peer_addr_len = sizeof(sockaddr.saddr_distributor_in_tls);
stype = DISTRIBUTOR_IN_TLS;
server_fd = sockfds[DISTRIBUTOR_IN_TLS];
}
#endif
else
{
return 1;
@@ -1002,83 +1382,60 @@ static int new_connection(int epollfd, int eventfd)
return 1;
}
struct ucred ucred = {};
socklen_t ucred_len = sizeof(ucred);
if (getsockopt(current->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) == -1)
current->event_collector_un.pid = get_pid_from_unix_socket(current->fd, NULL);
if (current->event_collector_un.pid == -1)
{
logger(1, "Error getting credentials from UNIX socket: %s", strerror(errno));
return 1;
}
current->event_collector_un.pid = ucred.pid;
logger_nDPIsrvd(current, "New collector connection from", "");
break;
case DISTRIBUTOR_UN:
case DISTRIBUTOR_IN:
if (current->sock_type == DISTRIBUTOR_UN)
current->event_distributor_un.peer = sockaddr.saddr_distributor_un;
uid_t uid;
current->event_distributor_un.pid = get_pid_from_unix_socket(current->fd, &uid);
if (current->event_distributor_un.pid == -1)
{
current->event_distributor_un.peer = sockaddr.saddr_distributor_un;
struct ucred ucred = {};
socklen_t ucred_len = sizeof(ucred);
if (getsockopt(current->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) == -1)
{
logger(1, "Error getting credentials from UNIX socket: %s", strerror(errno));
return 1;
}
struct passwd pwnam = {};
struct passwd * pwres = NULL;
ssize_t pwsiz = sysconf(_SC_GETPW_R_SIZE_MAX);
if (pwsiz == -1)
{
pwsiz = BUFSIZ;
}
char buf[pwsiz];
if (getpwuid_r(ucred.uid, &pwnam, &buf[0], pwsiz, &pwres) != 0)
{
logger(1, "Could not get passwd entry for user id %u", ucred.uid);
return 1;
}
current->event_distributor_un.pid = ucred.pid;
current->event_distributor_un.user_name = strdup(pwres->pw_name);
}
else
{
current->event_distributor_in.peer = sockaddr.saddr_distributor_in;
sockopt = 1;
if (setsockopt(current->fd, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)) < 0)
{
logger(1, "Error setting socket option SO_RCVBUF: %s", strerror(errno));
return 1;
}
if (inet_ntop(current->event_distributor_in.peer.sin_family,
&current->event_distributor_in.peer.sin_addr,
&current->event_distributor_in.peer_addr[0],
sizeof(current->event_distributor_in.peer_addr)) == NULL)
{
logger(1, "Error converting an internet address: %s", strerror(errno));
return 1;
}
}
sockopt = NETWORK_BUFFER_MAX_SIZE;
if (setsockopt(current->fd, SOL_SOCKET, SO_SNDBUF, &sockopt, sizeof(sockopt)) < 0)
{
logger(1, "Error setting socket option SO_SNDBUF: %s", strerror(errno));
return 1;
}
current->event_distributor_un.user_name = get_username_from_uid(uid);
if (current->event_distributor_un.user_name == NULL)
{
struct timeval send_timeout = {1, 0};
if (setsockopt(current->fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&send_timeout, sizeof(send_timeout)) != 0)
{
logger(1, "Error setting socket option send timeout: %s", strerror(errno));
}
return 1;
}
if (set_snd_opts(current->fd) != 0)
{
return 1;
}
break;
case DISTRIBUTOR_IN:
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
#endif
current->event_distributor_in.peer = sockaddr.saddr_distributor_in;
sockopt = 1;
if (setsockopt(current->fd, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)) < 0)
{
logger(1, "Error setting socket option SO_RCVBUF: %s", strerror(errno));
return 1;
}
if (inet_ntop(current->event_distributor_in.peer.sin_family,
&current->event_distributor_in.peer.sin_addr,
&current->event_distributor_in.peer_addr[0],
sizeof(current->event_distributor_in.peer_addr)) == NULL)
{
logger(1, "Error converting an internet address: %s", strerror(errno));
return 1;
}
if (set_snd_opts(current->fd) != 0)
{
return 1;
}
logger_nDPIsrvd(current, "New distributor connection from", "");
@@ -1389,8 +1746,12 @@ static int mainloop(int epollfd)
{
if ((events[i].events & EPOLLERR) != 0 || (events[i].events & EPOLLHUP) != 0)
{
if (events[i].data.fd != collector_un_sockfd && events[i].data.fd != distributor_un_sockfd &&
events[i].data.fd != distributor_in_sockfd)
if (events[i].data.fd != sockfds[COLLECTOR_UN] &&
events[i].data.fd != sockfds[DISTRIBUTOR_UN] && events[i].data.fd != sockfds[DISTRIBUTOR_IN]
#ifdef ENABLE_GNUTLS
&& events[i].data.fd != sockfds[DISTRIBUTOR_IN_TLS]
#endif
)
{
struct remote_desc * const current = (struct remote_desc *)events[i].data.ptr;
switch (current->sock_type)
@@ -1402,18 +1763,28 @@ static int mainloop(int epollfd)
case DISTRIBUTOR_IN:
logger_nDPIsrvd(current, "Distributor connection", "closed");
break;
#ifdef ENABLE_GNUTLS
case DISTRIBUTOR_IN_TLS:
logger_nDPIsrvd(current, "Distributor (TLS) connection", "closed");
break;
#endif
}
disconnect_client(epollfd, current);
}
else
{
logger(1, "Epoll event error: %s", (errno != 0 ? strerror(errno) : "unknown"));
if (errno != 0)
{
logger(1, "Epoll event error: %s", strerror(errno));
} else {
logger(1, "Epoll event error (unknown) for fd %d", events[i].data.fd);
}
}
continue;
}
if (events[i].data.fd == collector_un_sockfd || events[i].data.fd == distributor_un_sockfd ||
events[i].data.fd == distributor_in_sockfd)
if (events[i].data.fd == sockfds[COLLECTOR_UN] || events[i].data.fd == sockfds[DISTRIBUTOR_UN] ||
events[i].data.fd == sockfds[DISTRIBUTOR_IN])
{
/* New connection to collector / distributor. */
if (new_connection(epollfd, events[i].data.fd) != 0)
@@ -1473,21 +1844,21 @@ static int setup_event_queue(void)
return -1;
}
if (add_in_event_fd(epollfd, collector_un_sockfd) != 0)
if (add_in_event_fd(epollfd, sockfds[COLLECTOR_UN]) != 0)
{
logger(1, "Error adding collector UNIX socket fd to epoll: %s", strerror(errno));
return -1;
}
if (add_in_event_fd(epollfd, distributor_un_sockfd) != 0)
if (add_in_event_fd(epollfd, sockfds[DISTRIBUTOR_UN]) != 0)
{
logger(1, "Error adding distributor UNIX socket fd to epoll: %s", strerror(errno));
return -1;
}
if (distributor_in_sockfd >= 0)
if (sockfds[DISTRIBUTOR_IN] >= 0)
{
if (add_in_event_fd(epollfd, distributor_in_sockfd) != 0)
if (add_in_event_fd(epollfd, sockfds[DISTRIBUTOR_IN]) != 0)
{
logger(1, "Error adding distributor TCP/IP socket fd to epoll: %s", strerror(errno));
return -1;
@@ -1597,20 +1968,28 @@ int main(int argc, char ** argv)
logger(0, "collector UNIX socket listen on `%s'", get_cmdarg(&nDPIsrvd_options.collector_un_sockpath));
logger(0, "distributor UNIX listen on `%s'", get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
switch (distributor_in_address.raw.sa_family)
switch (addrs[DISTRIBUTOR_IN].raw.sa_family)
{
default:
goto error_unlink_sockets;
case AF_INET:
case AF_INET6:
logger(0, "distributor TCP listen on `%s'", get_cmdarg(&nDPIsrvd_options.distributor_in_address));
logger(1,
"Please keep in mind that using a TCP Socket may leak sensitive information to "
"everyone with access to the device/network. You've been warned!");
"Please keep in mind that using a TCP Socket (with `-S') may leak sensitive information to "
"everyone with access to the device/network. You've been warned!"
"Please use TLS (with `-x' and `-X' if possible.");
break;
case AF_UNIX:
case 0xFFFF:
break;
}
#ifdef ENABLE_GNUTLS
if (enable_tls)
{
logger(0, "distributor (TLS) TCP listen on `%s'", nDPIsrvd_options.distributor_in_tls_address);
}
#endif
errno = 0;
if (change_user_group(get_cmdarg(&nDPIsrvd_options.user),
@@ -1638,6 +2017,18 @@ int main(int argc, char ** argv)
goto error_unlink_sockets;
}
#ifdef ENABLE_GNUTLS
if (enable_tls != 0 && gtls_global_init(nDPIsrvd_options.x509_certfile,
nDPIsrvd_options.x509_keyfile,
nDPIsrvd_options.x509_crlfile,
nDPIsrvd_options.x509_cafile,
&x509_creds,
&prio_cache) != 0)
{
goto error_unlink_sockets;
}
#endif
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
@@ -1656,9 +2047,9 @@ error_unlink_sockets:
unlink(get_cmdarg(&nDPIsrvd_options.collector_un_sockpath));
unlink(get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
error:
close(collector_un_sockfd);
close(distributor_un_sockfd);
close(distributor_in_sockfd);
close(sockfds[COLLECTOR_UN]);
close(sockfds[DISTRIBUTOR_UN]);
close(sockfds[DISTRIBUTOR_IN]);
daemonize_shutdown(get_cmdarg(&nDPIsrvd_options.pidfile));
logger(0, "Bye.");

32
scripts/generate-tls-ca.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env sh
set -e
OUTDIR="$(dirname ${0})"
printf 'Output directory: %s\n' "${OUTDIR}"
printf 'ca\ncert_signing_key' > template
certtool --generate-privkey > "${OUTDIR}/ca-key.pem"
certtool --generate-self-signed \
--template template \
--load-privkey "${OUTDIR}/ca-key.pem" \
--outfile "${OUTDIR}/ca-cert.pem"
rm template
printf 'expiration_days = 365' > template
certtool --generate-crl --load-ca-privkey "${OUTDIR}/ca-key.pem" \
--template template \
--load-ca-certificate "${OUTDIR}/ca-cert.pem" \
--outfile "${OUTDIR}/crl.pem"
rm template
printf 'encryption_key\nsigning_key' > template
certtool --generate-privkey > "${OUTDIR}/server-key.pem"
certtool --generate-certificate \
--template template \
--load-privkey "${OUTDIR}/server-key.pem" \
--load-ca-certificate "${OUTDIR}/ca-cert.pem" \
--load-ca-privkey "${OUTDIR}/ca-key.pem" \
--outfile "${OUTDIR}/server-cert.pem"
rm template

17
scripts/generate-tls-cert.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env sh
set -e
OUTDIR="$(dirname ${0})"
printf 'Output directory: %s\n' "${OUTDIR}"
printf 'encryption_key\nsigning_key' > template
certtool --generate-privkey > "${OUTDIR}/client-key.pem"
certtool --generate-certificate \
--template template \
--load-privkey "${OUTDIR}/client-key.pem" \
--load-ca-certificate "${OUTDIR}/ca-cert.pem" \
--load-ca-privkey "${OUTDIR}/ca-key.pem" \
--outfile "${OUTDIR}/client-cert.pem"
rm template

167
tls-cli.c Normal file
View File

@@ -0,0 +1,167 @@
/* This example code is placed in the public domain. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#define CHECK(x) assert((x) >= 0)
#define MAX_BUF 1024
#define MSG "Hello TLS"
static int tcp_connect(void)
{
const char * PORT = "5556";
const char * SERVER = "127.0.0.1";
int err, sd;
struct sockaddr_in sa;
/* connects to server
*/
sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sa, '\0', sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(atoi(PORT));
inet_pton(AF_INET, SERVER, &sa.sin_addr);
err = connect(sd, (struct sockaddr *)&sa, sizeof(sa));
if (err < 0)
{
fprintf(stderr, "Connect error\n");
exit(1);
}
return sd;
}
static void tcp_close(int sd)
{
shutdown(sd, SHUT_RDWR); /* no more receptions */
close(sd);
}
int main(void)
{
int ret, sd, ii;
gnutls_session_t session;
char buffer[MAX_BUF + 1], *desc;
gnutls_datum_t out;
int type;
unsigned status;
gnutls_certificate_credentials_t xcred;
if (gnutls_check_version("3.4.6") == NULL)
{
fprintf(stderr, "GnuTLS 3.4.6 or later is required for this example\n");
exit(1);
}
/* for backwards compatibility with gnutls < 3.3.0 */
CHECK(gnutls_global_init());
/* X509 stuff */
CHECK(gnutls_certificate_allocate_credentials(&xcred));
gnutls_certificate_set_x509_key_file(xcred, "client-cert.pem", "client-key.pem", GNUTLS_X509_FMT_PEM);
CHECK(gnutls_certificate_set_x509_trust_file(xcred, "ca-cert.pem", GNUTLS_X509_FMT_PEM));
/* Initialize TLS session */
CHECK(gnutls_init(&session, GNUTLS_CLIENT));
/* It is recommended to use the default priorities */
CHECK(gnutls_set_default_priority(session));
/* put the x509 credentials to the current session */
CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred));
sd = tcp_connect();
gnutls_transport_set_int(session, sd);
gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
/* Perform the TLS handshake */
do
{
ret = gnutls_handshake(session);
} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
if (ret < 0)
{
if (ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR)
{
/* check certificate verification status */
type = gnutls_certificate_type_get(session);
status = gnutls_session_get_verify_cert_status(session);
CHECK(gnutls_certificate_verification_status_print(status, type, &out, 0));
printf("cert verify output: %s\n", out.data);
gnutls_free(out.data);
}
fprintf(stderr, "*** Handshake failed: %s\n", gnutls_strerror(ret));
goto end;
}
else
{
desc = gnutls_session_get_desc(session);
printf("- Session info: %s\n", desc);
gnutls_free(desc);
}
/* send data */
CHECK(gnutls_record_send(session, MSG, strlen(MSG)));
ret = gnutls_record_recv(session, buffer, MAX_BUF);
if (ret == 0)
{
printf("- Peer has closed the TLS connection\n");
goto end;
}
else if (ret < 0 && gnutls_error_is_fatal(ret) == 0)
{
fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
}
else if (ret < 0)
{
fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
goto end;
}
if (ret > 0)
{
printf("- Received %d bytes: ", ret);
for (ii = 0; ii < ret; ii++)
{
fputc(buffer[ii], stdout);
}
fputs("\n", stdout);
}
CHECK(gnutls_bye(session, GNUTLS_SHUT_RDWR));
end:
tcp_close(sd);
gnutls_deinit(session);
gnutls_certificate_free_credentials(xcred);
gnutls_global_deinit();
return 0;
}

146
tls-srv.c Normal file
View File

@@ -0,0 +1,146 @@
/* This example code is placed in the public domain. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <assert.h>
#define CAFILE "ca-cert.pem"
#define KEYFILE "server-key.pem"
#define CERTFILE "server-cert.pem"
#define CRLFILE "crl.pem"
#define CHECK(x) assert((x) >= 0)
#define LOOP_CHECK(rval, cmd) \
do \
{ \
rval = cmd; \
} while (rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
#define MAX_BUF 16
#define PORT 5556 /* listen to 5556 port */
int main(void)
{
int listen_sd;
int sd, ret;
gnutls_certificate_credentials_t x509_cred;
gnutls_priority_t priority_cache;
struct sockaddr_in sa_serv;
struct sockaddr_in sa_cli;
socklen_t client_len;
char topbuf[512];
gnutls_session_t session;
char buffer[MAX_BUF + 1];
int optval = 1;
/* for backwards compatibility with gnutls < 3.3.0 */
CHECK(gnutls_global_init());
CHECK(gnutls_certificate_allocate_credentials(&x509_cred));
CHECK(gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM));
CHECK(gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM));
CHECK(gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, GNUTLS_X509_FMT_PEM));
CHECK(gnutls_priority_init(&priority_cache, NULL, NULL));
#if GNUTLS_VERSION_NUMBER >= 0x030506
/* only available since GnuTLS 3.5.6, on previous versions see
* gnutls_certificate_set_dh_params(). */
gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_HIGH);
#endif
/* Socket operations */
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sa_serv, '\0', sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons(PORT); /* Server Port number */
setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int));
bind(listen_sd, (struct sockaddr *)&sa_serv, sizeof(sa_serv));
listen(listen_sd, 1024);
printf("Server ready. Listening to port '%d'.\n", PORT);
client_len = sizeof(sa_cli);
for (;;)
{
CHECK(gnutls_init(&session, GNUTLS_SERVER));
CHECK(gnutls_priority_set(session, priority_cache));
CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred));
gnutls_session_set_verify_cert(session, NULL, 0);
gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
gnutls_certificate_send_x509_rdn_sequence(session, 1);
gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
sd = accept(listen_sd, (struct sockaddr *)&sa_cli, &client_len);
printf("- connection from %s, port %d\n",
inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)),
ntohs(sa_cli.sin_port));
gnutls_transport_set_int(session, sd);
LOOP_CHECK(ret, gnutls_handshake(session));
if (ret < 0)
{
close(sd);
gnutls_deinit(session);
fprintf(stderr, "*** Handshake has failed (%s)\n", gnutls_strerror(ret));
continue;
}
printf("- Handshake was completed\n");
for (;;)
{
LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF));
if (ret == 0)
{
printf("- Peer has closed the GnuTLS connection\n");
break;
}
else if (ret < 0 && gnutls_error_is_fatal(ret) == 0)
{
fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
}
else if (ret < 0)
{
fprintf(stderr,
"\n*** Received corrupted "
"data(%d). Closing the connection.\n",
ret);
break;
}
else if (ret > 0 && ret < MAX_BUF - 1)
{
buffer[ret] = '$';
CHECK(gnutls_record_send(session, buffer, ret + 1));
}
}
LOOP_CHECK(ret, gnutls_bye(session, GNUTLS_SHUT_WR));
close(sd);
gnutls_deinit(session);
}
close(listen_sd);
gnutls_certificate_free_credentials(x509_cred);
gnutls_priority_deinit(priority_cache);
gnutls_global_deinit();
return 0;
}