diff --git a/Makefile.am b/Makefile.am index 418b4b34..1eaab425 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,205 +1,210 @@ # # Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+ # MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \ config.guess config.sub missing install-sh \ ltmain.sh compile config.h.in config.h.in~ \ autoscan.log configure.scan test-driver \ m4/libtool.m4 m4/lt~obsolete.m4 m4/ltoptions.m4 \ m4/ltsugar.m4 m4/ltversion.m4 include $(top_srcdir)/build-aux/check.mk AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 SPEC = $(PACKAGE_NAME).spec TARGZFILE = $(PACKAGE_NAME)-$(VERSION).tar.gz EXTRA_DIST = autogen.sh .version \ NOTES_TO_PACKAGE_MAINTAINERS \ $(SPEC).in build-aux SUBDIRS = libnozzle libknet if BUILD_MAN SUBDIRS += man endif dist_doc_DATA = \ COPYING.applications \ COPYING.libraries \ COPYRIGHT \ README.licence \ README all-local: $(SPEC) clean-local: rm -rf $(SPEC) cov* distclean-local: rm -f $(PACKAGE_NAME)-*.tar.* $(PACKAGE_NAME)-*.sha256* tag-* ## make rpm/srpm section. $(SPEC): $(SPEC).in .version config.status rm -f $@-t $@ date="`LC_ALL=C $(UTC_DATE_AT)$(SOURCE_EPOCH) "+%a %b %d %Y"`" && \ gvgver="`cd $(abs_srcdir); build-aux/git-version-gen --fallback $(VERSION) .tarball-version .gitarchivever`" && \ if [ "$$gvgver" = "`echo $$gvgver | sed 's/-/./'`" ];then \ rpmver="$$gvgver" && \ alphatag="" && \ dirty="" && \ numcomm="0"; \ else \ gitver="`echo $$gvgver | sed 's/\(.*\)\./\1-/'`" && \ rpmver=`echo $$gitver | sed 's/-.*//g'` && \ alphatag=`echo $$gvgver | sed 's/[^-]*-\([^-]*\).*/\1/'` && \ numcomm=`echo $$gitver | sed 's/[^-]*-\([^-]*\).*/\1/'` && \ dirty="" && \ if [ "`echo $$gitver | sed 's/^.*-dirty$$//g'`" = "" ];then \ dirty="dirty"; \ fi \ fi && \ if [ -n "$$dirty" ]; then dirty="dirty"; else dirty=""; fi && \ if [ "$$numcomm" = "0" ]; then \ sed \ -e "s#@version@#$$rpmver#g" \ -e "s#%glo.*alpha.*##g" \ -e "s#%glo.*numcomm.*##g" \ -e "s#@dirty@#$$dirty#g" \ -e "s#@date@#$$date#g" \ $(abs_srcdir)/$@.in > $@-t; \ else \ sed \ -e "s#@version@#$$rpmver#g" \ -e "s#@alphatag@#$$alphatag#g" \ -e "s#@numcomm@#$$numcomm#g" \ -e "s#@dirty@#$$dirty#g" \ -e "s#@date@#$$date#g" \ $(abs_srcdir)/$@.in > $@-t; \ fi; \ if [ -z "$$dirty" ]; then sed -i -e "s#%glo.*dirty.*##g" $@-t; fi if BUILD_SCTP sed -i -e "s#@sctp@#bcond_without#g" $@-t else sed -i -e "s#@sctp@#bcond_with#g" $@-t endif if BUILD_CRYPTO_NSS sed -i -e "s#@nss@#bcond_without#g" $@-t else sed -i -e "s#@nss@#bcond_with#g" $@-t endif if BUILD_CRYPTO_OPENSSL sed -i -e "s#@openssl@#bcond_without#g" $@-t else sed -i -e "s#@openssl@#bcond_with#g" $@-t endif +if BUILD_CRYPTO_GCRYPT + sed -i -e "s#@gcrypt@#bcond_without#g" $@-t +else + sed -i -e "s#@gcrypt@#bcond_with#g" $@-t +endif if BUILD_COMPRESS_ZLIB sed -i -e "s#@zlib@#bcond_without#g" $@-t else sed -i -e "s#@zlib@#bcond_with#g" $@-t endif if BUILD_COMPRESS_LZ4 sed -i -e "s#@lz4@#bcond_without#g" $@-t else sed -i -e "s#@lz4@#bcond_with#g" $@-t endif if BUILD_COMPRESS_LZO2 sed -i -e "s#@lzo2@#bcond_without#g" $@-t else sed -i -e "s#@lzo2@#bcond_with#g" $@-t endif if BUILD_COMPRESS_LZMA sed -i -e "s#@lzma@#bcond_without#g" $@-t else sed -i -e "s#@lzma@#bcond_with#g" $@-t endif if BUILD_COMPRESS_BZIP2 sed -i -e "s#@bzip2@#bcond_without#g" $@-t else sed -i -e "s#@bzip2@#bcond_with#g" $@-t endif if BUILD_COMPRESS_ZSTD sed -i -e "s#@zstd@#bcond_without#g" $@-t else sed -i -e "s#@zstd@#bcond_with#g" $@-t endif if BUILD_LIBNOZZLE sed -i -e "s#@libnozzle@#bcond_without#g" $@-t else sed -i -e "s#@libnozzle@#bcond_with#g" $@-t endif if BUILD_RUNAUTOGEN sed -i -e "s#@runautogen@#bcond_without#g" $@-t else sed -i -e "s#@runautogen@#bcond_with#g" $@-t endif if OVERRIDE_RPM_DEBUGINFO sed -i -e "s#@overriderpmdebuginfo@#bcond_without#g" $@-t else sed -i -e "s#@overriderpmdebuginfo@#bcond_with#g" $@-t endif if BUILD_RPM_DEBUGINFO sed -i -e "s#@rpmdebuginfo@#bcond_without#g" $@-t else sed -i -e "s#@rpmdebuginfo@#bcond_with#g" $@-t endif if BUILD_MAN sed -i -e "s#@buildman@#bcond_without#g" $@-t else sed -i -e "s#@buildman@#bcond_with#g" $@-t endif if INSTALL_TESTS sed -i -e "s#@installtests@#bcond_without#g" $@-t else sed -i -e "s#@installtests@#bcond_with#g" $@-t endif sed -i -e "s#@defaultadmgroup@#$(DEFAULTADMGROUP)#g" $@-t chmod a-w $@-t mv $@-t $@ rm -f $@-t* $(TARGZFILE): $(MAKE) dist RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \ --define "_specdir $(abs_builddir)" \ --define "_builddir $(abs_builddir)" \ --define "_srcrpmdir $(abs_builddir)" \ --define "_rpmdir $(abs_builddir)" srpm: clean $(MAKE) $(SPEC) $(TARGZFILE) rpmbuild $(RPMBUILDOPTS) --nodeps -bs $(SPEC) rpm: clean $(MAKE) $(SPEC) $(TARGZFILE) rpmbuild $(RPMBUILDOPTS) -ba $(SPEC) # release/versioning BUILT_SOURCES = .version .version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: gen-ChangeLog echo $(VERSION) > $(distdir)/.tarball-version echo $(SOURCE_EPOCH) > $(distdir)/source_epoch gen_start_date = 2000-01-01 .PHONY: gen-ChangeLog gen-ChangeLog: if test -d $(abs_srcdir)/.git; then \ LC_ALL=C $(top_srcdir)/build-aux/gitlog-to-changelog \ --since=$(gen_start_date) > $(distdir)/cl-t; \ rm -f $(distdir)/ChangeLog; \ mv $(distdir)/cl-t $(distdir)/ChangeLog; \ fi diff --git a/build-aux/knet_valgrind_memcheck.supp b/build-aux/knet_valgrind_memcheck.supp index cd09f695..c705e00c 100644 --- a/build-aux/knet_valgrind_memcheck.supp +++ b/build-aux/knet_valgrind_memcheck.supp @@ -1,616 +1,688 @@ { lzma internals (spotted on Debian 9 and Ubuntu 18.04 LTS x86-64) Memcheck:Cond obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 fun:lzma_block_buffer_encode fun:lzma_stream_buffer_encode fun:lzma_easy_buffer_encode fun:lzma_compress fun:compress_lib_test fun:compress_cfg fun:knet_handle_compress fun:test } { lzma internals (spotted on Ubuntu 18.04 LTS i386) Memcheck:Cond obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 fun:lzma_stream_buffer_encode fun:lzma_easy_buffer_encode fun:lzma_compress fun:compress_lib_test fun:compress_cfg fun:knet_handle_compress } { openssl internals (spotted on OpenSUSE 15) Memcheck:Cond fun:__memcmp_sse4_1 obj:/usr/lib64/libcrypto.so.1.1 fun:FIPS_selftest obj:/usr/lib64/libcrypto.so.1.1 fun:FIPS_mode_set obj:/usr/lib64/libcrypto.so.1.1 fun:call_init.part.0 fun:_dl_init fun:dl_open_worker fun:_dl_catch_error fun:_dl_open fun:dlopen_doit } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib64/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib64/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on OpenSUSE 15) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 fun:FIPS_mode_set obj:/usr/lib64/libcrypto.so.1.1 fun:call_init.part.0 fun:_dl_init fun:dl_open_worker fun:_dl_catch_error fun:_dl_open fun:dlopen_doit fun:_dl_catch_error fun:_dlerror_run fun:dlopen@@GLIBC_2.2.5 } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread fun:start_thread fun:clone } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:_handle_check_link_pmtud fun:_handle_check_pmtud fun:_handle_pmtud_link_thread fun:start_thread fun:clone } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed) Memcheck:Param sendmsg(msg.msg_iov[0]) fun:sendmsg fun:_sendmmsg fun:_dispatch_to_links fun:_parse_recv_from_sock fun:_handle_send_to_links fun:_handle_send_to_links_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__libc_sendmsg fun:sendmsg fun:_sendmmsg fun:_dispatch_to_links fun:_parse_recv_from_sock fun:_handle_send_to_links fun:_handle_send_to_links_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { nss internal leak (3.41) non recurring (spotted on f29) Memcheck:Leak match-leak-kinds: definite fun:malloc obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:/usr/lib64/libnss3.so } { nss internal leak (3.41) non recurring Memcheck:Leak match-leak-kinds: definite fun:calloc obj:* obj:* obj:* obj:* obj:* fun:init_nss fun:nsscrypto_init fun:crypto_init fun:knet_handle_crypto_set_config fun:test fun:main } { nss internal leak (3.41) non recurring Memcheck:Leak match-leak-kinds: definite fun:malloc obj:* obj:* obj:* obj:* obj:* fun:init_nss fun:nsscrypto_init fun:crypto_init fun:knet_handle_crypto_set_config fun:test fun:main } { nss internal leak (3.55) non recurring (spotted on f34) Memcheck:Leak match-leak-kinds: definite fun:malloc fun:realpath@@GLIBC_2.3 obj:* obj:* obj:* obj:/usr/lib64/libnss3.so fun:SECMOD_LoadModule fun:SECMOD_LoadModule obj:/usr/lib64/libnss3.so fun:NSS_NoDB_Init fun:init_nss fun:nsscrypto_init fun:crypto_init fun:_knet_handle_crypto_set_config } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:send_pong fun:process_ping fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:send_pmtud_reply fun:process_pmtud fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__libc_sendmsg fun:sendmsg fun:_sendmmsg fun:_dispatch_to_links fun:_prep_and_send_msgs fun:_parse_recv_from_sock fun:_handle_send_to_links fun:_handle_send_to_links_thread fun:start_thread fun:clone } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { nss internal leak (3.59) non recurring (spotted on f34) Memcheck:Leak match-leak-kinds: definite fun:malloc fun:realpath@@GLIBC_2.3 obj:* obj:* obj:* obj:* obj:/usr/lib64/libnss3.so fun:SECMOD_LoadModule fun:SECMOD_LoadModule obj:/usr/lib64/libnss3.so fun:NSS_NoDB_Init fun:init_nss fun:nsscrypto_init } { nss internal leak (3.59) non recurring (spotted on f34) Memcheck:Leak match-leak-kinds: definite fun:malloc fun:realpath@@GLIBC_2.3 obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* fun:init_nss fun:nsscrypto_init } +{ + libgcrypt internal conditinal (debian 10) + Memcheck:Cond + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + fun:encrypt_gcrypt.isra.0 + fun:gcryptcrypto_encrypt_and_signv + fun:gcryptcrypto_encrypt_and_sign + fun:send_ping + fun:_send_pings + fun:_handle_heartbt_thread + fun:start_thread + fun:clone +} +{ + libgcrypt internal conditinal (debian 10 - clang) + Memcheck:Cond + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4 + fun:encrypt_gcrypt + fun:gcryptcrypto_encrypt_and_signv + fun:gcryptcrypto_encrypt_and_sign + fun:send_ping + fun:_send_pings + fun:_handle_heartbt_thread + fun:start_thread + fun:clone +} +{ + libgcrypt internal conditinal (opensuse 15) + Memcheck:Cond + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + fun:encrypt_gcrypt.isra.0 + fun:gcryptcrypto_encrypt_and_signv + fun:gcryptcrypto_encrypt_and_sign + fun:send_ping + fun:_send_pings + fun:_handle_heartbt_thread + fun:start_thread + fun:clone +} +{ + libgcrypt internal conditinal (opensuse 15 - clang) + Memcheck:Cond + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + obj:/usr/lib64/libgcrypt.so.20.2.2 + fun:encrypt_gcrypt + fun:gcryptcrypto_encrypt_and_signv + fun:gcryptcrypto_encrypt_and_sign + fun:send_ping + fun:_send_pings + fun:_handle_heartbt_thread + fun:start_thread + fun:clone +} diff --git a/configure.ac b/configure.ac index 8677a647..e481f63e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,412 +1,421 @@ # # Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved. # # Authors: Fabio M. Di Nitto # Federico Simoncelli # # This software licensed under GPL-2.0+ # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # AC_PREREQ([2.63]) AC_INIT([kronosnet], m4_esyscmd([build-aux/git-version-gen .tarball-version .gitarchivever]), [devel@lists.kronosnet.org]) # Don't let AC_PROC_CC (invoked by AC_USE_SYSTEM_EXTENSIONS) replace # undefined CFLAGS with -g -O2, overriding our special OPT_CFLAGS. : ${CFLAGS=""} AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([1.13 dist-bzip2 dist-xz color-tests -Wno-portability subdir-objects]) LT_PREREQ([2.2.6]) # --enable-new-dtags: Use RUNPATH instead of RPATH. # It is necessary to have this done before libtool does linker detection. # See also: https://github.com/kronosnet/kronosnet/issues/107 # --as-needed: Modern systems have builtin ceil() making -lm superfluous but # AC_SEARCH_LIBS can't detect this because it tests with a false prototype AX_CHECK_LINK_FLAG([-Wl,--enable-new-dtags], [AM_LDFLAGS=-Wl,--enable-new-dtags], [AC_MSG_ERROR(["Linker support for --enable-new-dtags is required"])]) AX_CHECK_LINK_FLAG([-Wl,--as-needed], [AM_LDFLAGS="$AM_LDFLAGS -Wl,--as-needed"]) AC_SUBST([AM_LDFLAGS]) saved_LDFLAGS="$LDFLAGS" LDFLAGS="$AM_LDFLAGS $LDFLAGS" LT_INIT LDFLAGS="$saved_LDFLAGS" AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([libknet/handle.c]) AC_CONFIG_HEADERS([config.h]) AC_CANONICAL_HOST AC_LANG([C]) if test "$prefix" = "NONE"; then prefix="/usr" if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$libdir" = "\${exec_prefix}/lib"; then if test -e /usr/lib64; then libdir="/usr/lib64" else libdir="/usr/lib" fi fi fi AC_PROG_AWK AC_PROG_GREP AC_PROG_SED AC_PROG_CPP AC_PROG_CC AC_PROG_CC_C99 if test "x$ac_cv_prog_cc_c99" = "xno"; then AC_MSG_ERROR(["C99 support is required"]) fi AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_MAKE_SET PKG_PROG_PKG_CONFIG AC_CHECK_PROGS([VALGRIND_EXEC], [valgrind]) AM_CONDITIONAL([HAS_VALGRIND], [test x$VALGRIND_EXEC != "x"]) AC_CHECK_PROGS([COVBUILD_EXEC], [cov-build]) AM_CONDITIONAL([HAS_COVBUILD], [test x$COVBUILD_EXEC != "x"]) AC_CHECK_PROGS([COVANALYZE_EXEC], [cov-analyze]) AM_CONDITIONAL([HAS_COVANALYZE], [test x$COVANALYZE_EXEC != "x"]) AC_CHECK_PROGS([COVFORMATERRORS_EXEC], [cov-format-errors]) AM_CONDITIONAL([HAS_COVFORMATERRORS], [test x$COVFORMATERRORS_EXEC != "x"]) # KNET_OPTION_DEFINES(stem,type,detection code) # stem: enters name of option, Automake conditional and preprocessor define # type: compress or crypto, determines where the default comes from AC_DEFUN([KNET_OPTION_DEFINES],[ AC_ARG_ENABLE([$2-$1],[AS_HELP_STRING([--disable-$2-$1],[disable libknet $1 support])],, [enable_$2_$1="$enable_$2_all"]) AM_CONDITIONAL([BUILD_]m4_toupper([$2_$1]),[test "x$enable_$2_$1" = xyes]) if test "x$enable_$2_$1" = xyes; then $3 fi AC_DEFINE_UNQUOTED([WITH_]m4_toupper([$2_$1]), [`test "x$enable_$2_$1" != xyes; echo $?`], $1 $2 [built in]) ]) AC_ARG_ENABLE([man], [AS_HELP_STRING([--disable-man],[disable man page creation])],, [ enable_man="yes" ]) AM_CONDITIONAL([BUILD_MAN], [test x$enable_man = xyes]) AC_ARG_ENABLE([libknet-sctp], [AS_HELP_STRING([--disable-libknet-sctp],[disable libknet SCTP support])],, [ enable_libknet_sctp="yes" ]) AM_CONDITIONAL([BUILD_SCTP], [test x$enable_libknet_sctp = xyes]) AC_ARG_ENABLE([crypto-all], [AS_HELP_STRING([--disable-crypto-all],[disable libknet all crypto modules support])],, [ enable_crypto_all="yes" ]) KNET_OPTION_DEFINES([nss],[crypto],[PKG_CHECK_MODULES([nss], [nss])]) -KNET_OPTION_DEFINES([openssl],[crypto],[PKG_CHECK_MODULES([openssl],[libcrypto])]) +KNET_OPTION_DEFINES([openssl],[crypto],[PKG_CHECK_MODULES([openssl], [libcrypto])]) + +# use gcry_mac_open to detect if libgcrypt is new enough +KNET_OPTION_DEFINES([gcrypt],[crypto],[ + PKG_CHECK_MODULES([gcrypt], [libgcrypt >= 1.8.0],, + [AC_CHECK_HEADERS([gcrypt.h], + [AC_CHECK_LIB([gcrypt], [gcry_mac_open], + [AC_SUBST([gcrypt_LIBS], ["-lgcrypt -ldl -lgpg-error"])])], + [AC_MSG_ERROR(["missing required gcrypt.h"])])]) +]) AC_ARG_ENABLE([compress-all], [AS_HELP_STRING([--disable-compress-all],[disable libknet all compress modules support])],, [ enable_compress_all="yes" ]) KNET_OPTION_DEFINES([zstd],[compress],[PKG_CHECK_MODULES([libzstd], [libzstd])]) KNET_OPTION_DEFINES([zlib],[compress],[PKG_CHECK_MODULES([zlib], [zlib])]) KNET_OPTION_DEFINES([lz4],[compress],[PKG_CHECK_MODULES([liblz4], [liblz4])]) KNET_OPTION_DEFINES([lzo2],[compress],[ PKG_CHECK_MODULES([lzo2], [lzo2], [# work around broken pkg-config file in v2.10 AC_SUBST([lzo2_CFLAGS],[`echo $lzo2_CFLAGS | sed 's,/lzo *, ,'`])], [AC_CHECK_HEADERS([lzo/lzo1x.h], [AC_CHECK_LIB([lzo2], [lzo1x_decompress_safe], [AC_SUBST([lzo2_LIBS], [-llzo2])])], [AC_MSG_ERROR(["missing required lzo/lzo1x.h header"])])]) ]) KNET_OPTION_DEFINES([lzma],[compress],[PKG_CHECK_MODULES([liblzma], [liblzma])]) KNET_OPTION_DEFINES([bzip2],[compress],[ PKG_CHECK_MODULES([bzip2], [bzip2],, [AC_CHECK_HEADERS([bzlib.h], [AC_CHECK_LIB([bz2], [BZ2_bzBuffToBuffCompress], [AC_SUBST([bzip2_LIBS], [-lbz2])])], [AC_MSG_ERROR(["missing required bzlib.h"])])]) ]) AC_ARG_ENABLE([install-tests], [AS_HELP_STRING([--enable-install-tests],[install tests])],, [ enable_install_tests="no" ]) AM_CONDITIONAL([INSTALL_TESTS], [test x$enable_install_tests = xyes]) AC_ARG_ENABLE([runautogen], [AS_HELP_STRING([--enable-runautogen],[run autogen.sh])],, [ enable_runautogen="no" ]) AM_CONDITIONAL([BUILD_RUNAUTOGEN], [test x$enable_runautogen = xyes]) override_rpm_debuginfo_option="yes" AC_ARG_ENABLE([rpm-debuginfo], [AS_HELP_STRING([--enable-rpm-debuginfo],[build debuginfo packages])],, [ enable_rpm_debuginfo="no", override_rpm_debuginfo_option="no" ]) AM_CONDITIONAL([BUILD_RPM_DEBUGINFO], [test x$enable_rpm_debuginfo = xyes]) AM_CONDITIONAL([OVERRIDE_RPM_DEBUGINFO], [test x$override_rpm_debuginfo_option = xyes]) AC_ARG_ENABLE([libnozzle], [AS_HELP_STRING([--enable-libnozzle],[libnozzle support])],, [ enable_libnozzle="yes" ]) AM_CONDITIONAL([BUILD_LIBNOZZLE], [test x$enable_libnozzle = xyes]) # Checks for libraries. AX_PTHREAD(,[AC_MSG_ERROR([POSIX threads support is required])]) saved_LIBS="$LIBS" LIBS= AC_SEARCH_LIBS([ceil], [m], , [AC_MSG_ERROR([ceil not found])]) AC_SUBST([m_LIBS], [$LIBS]) LIBS= AC_SEARCH_LIBS([clock_gettime], [rt], , [AC_MSG_ERROR([clock_gettime not found])]) AC_SUBST([rt_LIBS], [$LIBS]) LIBS= AC_SEARCH_LIBS([dlopen], [dl dld], , [AC_MSG_ERROR([dlopen not found])]) AC_SUBST([dl_LIBS], [$LIBS]) LIBS="$saved_LIBS" # Check RTLD_DI_ORIGIN (not decalred by musl. glibc has it as an enum so cannot use ifdef) AC_CHECK_DECL([RTLD_DI_ORIGIN], [AC_DEFINE([HAVE_RTLD_DI_ORIGIN], 1, [define when RTLD_DI_ORIGIN is declared])], ,[[#include ]]) # OS detection AC_MSG_CHECKING([for os in ${host_os}]) case "$host_os" in *linux*) AC_DEFINE_UNQUOTED([KNET_LINUX], [1], [Compiling for Linux platform]) AC_MSG_RESULT([Linux]) ;; *bsd*) AC_DEFINE_UNQUOTED([KNET_BSD], [1], [Compiling for BSD platform]) AC_MSG_RESULT([BSD]) ;; *) AC_MSG_ERROR([Unsupported OS? hmmmm]) ;; esac # Checks for header files. AC_CHECK_HEADERS([sys/epoll.h]) AC_CHECK_FUNCS([kevent]) # if neither sys/epoll.h nor kevent are present, we should fail. if test "x$ac_cv_header_sys_epoll_h" = xno && test "x$ac_cv_func_kevent" = xno; then AC_MSG_ERROR([Both epoll and kevent unavailable on this OS]) fi if test "x$ac_cv_header_sys_epoll_h" = xyes && test "x$ac_cv_func_kevent" = xyes; then AC_MSG_ERROR([Both epoll and kevent available on this OS, please contact the maintainers to fix the code]) fi if test "x$enable_libknet_sctp" = xyes; then AC_CHECK_HEADERS([netinet/sctp.h],, [AC_MSG_ERROR(["missing required SCTP headers"])]) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_INT8_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T PKG_CHECK_MODULES([libqb], [libqb]) if test "x$enable_man" = "xyes"; then AC_ARG_VAR([DOXYGEN], [override doxygen executable]) AC_CHECK_PROGS([DOXYGEN], [doxygen], [no]) if test "x$DOXYGEN" = xno; then AC_MSG_ERROR(["Doxygen command not found"]) fi AC_ARG_VAR([DOXYGEN2MAN], [override doxygen2man executable]) # required to detect doxygen2man when libqb is installed # in non standard paths saved_PKG_CONFIG="$PKG_CONFIG" saved_ac_cv_path_PKG_CONFIG="$ac_cv_path_PKG_CONFIG" unset PKG_CONFIG ac_cv_path_PKG_CONFIG AC_PATH_PROG([PKG_CONFIG], [pkg-config]) PKG_CHECK_MODULES([libqb_BUILD], [libqb]) PKG_CHECK_VAR([libqb_BUILD_PREFIX], [libqb], [prefix]) AC_PATH_PROG([DOXYGEN2MAN], [doxygen2man], [no], [$libqb_BUILD_PREFIX/bin$PATH_SEPARATOR$PATH]) PKG_CONFIG="$saved_PKG_CONFIG" ac_cv_path_PKG_CONFIG="$saved_ac_cv_path_PKG_CONFIG" if test "x$DOXYGEN2MAN" = "xno"; then AC_MSG_ERROR(["doxygen2man command not found"]) fi AC_SUBST([DOXYGEN2MAN]) fi # checks for libnozzle if test "x$enable_libnozzle" = xyes; then if `echo $host_os | grep -q linux`; then PKG_CHECK_MODULES([libnl], [libnl-3.0]) PKG_CHECK_MODULES([libnlroute], [libnl-route-3.0 >= 3.3], [], [PKG_CHECK_MODULES([libnlroute], [libnl-route-3.0 < 3.3], [AC_DEFINE_UNQUOTED([LIBNL3_WORKAROUND], [1], [Enable libnl < 3.3 build workaround])], [])]) fi fi # local options AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug],[enable debug build])]) AC_ARG_WITH([sanitizers], [AS_HELP_STRING([--with-sanitizers=...,...], [enable SANitizer build, do *NOT* use for production. Only ASAN/UBSAN/TSAN are currently supported])], [ SANITIZERS="$withval" ], [ SANITIZERS="" ]) AC_ARG_WITH([testdir], [AS_HELP_STRING([--with-testdir=DIR],[path to /usr/lib../kronosnet/tests/ dir where to install the test suite])], [ TESTDIR="$withval" ], [ TESTDIR="$libdir/kronosnet/tests" ]) ## do subst AC_SUBST([TESTDIR]) # debug build stuff if test "x${enable_debug}" = xyes; then AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code]) OPT_CFLAGS="-O0" else OPT_CFLAGS="-O3" fi # gdb flags if test "x${GCC}" = xyes; then GDB_FLAGS="-ggdb3" else GDB_FLAGS="-g" fi # --- ASAN/UBSAN/TSAN (see man gcc) --- # when using SANitizers, we need to pass the -fsanitize.. # to both CFLAGS and LDFLAGS. The CFLAGS/LDFLAGS must be # specified as first in the list or there will be runtime # issues (for example user has to LD_PRELOAD asan for it to work # properly). if test -n "${SANITIZERS}"; then SANITIZERS=$(echo $SANITIZERS | sed -e 's/,/ /g') for SANITIZER in $SANITIZERS; do case $SANITIZER in asan|ASAN) SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=address" SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=address -lasan" AC_CHECK_LIB([asan],[main],,AC_MSG_ERROR([Unable to find libasan])) ;; ubsan|UBSAN) SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=undefined" SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=undefined -lubsan" AC_CHECK_LIB([ubsan],[main],,AC_MSG_ERROR([Unable to find libubsan])) ;; tsan|TSAN) SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=thread" SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=thread -ltsan" AC_CHECK_LIB([tsan],[main],,AC_MSG_ERROR([Unable to find libtsan])) ;; esac done fi DEFAULT_CFLAGS="-Werror -Wall -Wextra" # manual overrides # generates too much noise for stub APIs UNWANTED_CFLAGS="-Wno-unused-parameter" AC_SUBST([AM_CFLAGS],["$SANITIZERS_CFLAGS $OPT_CFLAGS $GDB_FLAGS $DEFAULT_CFLAGS $UNWANTED_CFLAGS"]) LDFLAGS="$SANITIZERS_LDFLAGS $LDFLAGS" AX_PROG_DATE AS_IF([test "$ax_cv_prog_date_gnu_date:$ax_cv_prog_date_gnu_utc" = yes:yes], [UTC_DATE_AT="date -u -d@"], [AS_IF([test "x$ax_cv_prog_date_bsd_date" = xyes], [UTC_DATE_AT="date -u -r"], [AC_MSG_ERROR([date utility unable to convert epoch to UTC])])]) AC_SUBST([UTC_DATE_AT]) AC_ARG_VAR([SOURCE_EPOCH],[last modification date of the source]) AC_MSG_NOTICE([trying to determine source epoch]) AC_MSG_CHECKING([for source epoch in \$SOURCE_EPOCH]) AS_IF([test -n "$SOURCE_EPOCH"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([for source epoch in source_epoch file]) AS_IF([test -e "$srcdir/source_epoch"], [read SOURCE_EPOCH <"$srcdir/source_epoch" AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([for source epoch baked in by gitattributes export-subst]) SOURCE_EPOCH='$Format:%at$' # template for rewriting by git-archive AS_CASE([$SOURCE_EPOCH], [?Format:*], # was not rewritten [AC_MSG_RESULT([no]) AC_MSG_CHECKING([for source epoch in \$SOURCE_DATE_EPOCH]) AS_IF([test "x$SOURCE_DATE_EPOCH" != x], [SOURCE_EPOCH="$SOURCE_DATE_EPOCH" AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([whether git log can provide a source epoch]) SOURCE_EPOCH=f${SOURCE_EPOCH#\$F} # convert into git log --pretty format SOURCE_EPOCH=$(cd "$srcdir" && git log -1 --pretty=${SOURCE_EPOCH%$} 2>/dev/null) AS_IF([test -n "$SOURCE_EPOCH"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no, using current time and breaking reproducibility]) SOURCE_EPOCH=$(date +%s)])])], [AC_MSG_RESULT([yes])] )]) ]) AC_MSG_NOTICE([using source epoch $($UTC_DATE_AT$SOURCE_EPOCH +'%F %T %Z')]) AC_CONFIG_FILES([ Makefile libnozzle/Makefile libnozzle/libnozzle.pc libnozzle/tests/Makefile libknet/Makefile libknet/libknet.pc libknet/tests/Makefile man/Makefile man/Doxyfile-knet man/Doxyfile-nozzle ]) if test "x$VERSION" = "xUNKNOWN"; then AC_MSG_ERROR([m4_text_wrap([ configure was unable to determine the source tree's current version. This generally happens when using git archive (or the github download button) generated tarball/zip file. In order to workaround this issue, either use git clone https://github.com/kronosnet/kronosnet.git or use an official release tarball, available at https://kronosnet.org/releases/. Alternatively you can add a compatible version in a .tarball-version file at the top of the source tree, wipe your autom4te.cache dir and generated configure, and rerun autogen.sh. ], [ ], [ ], [76])]) fi AC_OUTPUT diff --git a/kronosnet.spec.in b/kronosnet.spec.in index 7a3290ce..45544ccf 100644 --- a/kronosnet.spec.in +++ b/kronosnet.spec.in @@ -1,461 +1,483 @@ ############################################################################### ############################################################################### ## ## Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. ## ## This copyrighted material is made available to anyone wishing to use, ## modify, copy, or redistribute it subject to the terms and conditions ## of the GNU General Public License v.2 or higher ## ############################################################################### ############################################################################### # keep around ready for later user %global alphatag @alphatag@ %global numcomm @numcomm@ %global dirty @dirty@ # set defaults from ./configure invokation %@sctp@ sctp %@nss@ nss %@openssl@ openssl +%@gcrypt@ gcrypt %@zlib@ zlib %@lz4@ lz4 %@lzo2@ lzo2 %@lzma@ lzma %@bzip2@ bzip2 %@zstd@ zstd %@libnozzle@ libnozzle %@runautogen@ runautogen %@rpmdebuginfo@ rpmdebuginfo %@overriderpmdebuginfo@ overriderpmdebuginfo %@buildman@ buildman %@installtests@ installtests %if %{with overriderpmdebuginfo} %undefine _enable_debug_packages %endif # main (empty) package # http://www.rpm.org/max-rpm/s1-rpm-subpack-spec-file-changes.html Name: kronosnet Summary: Multipoint-to-Multipoint VPN daemon Version: @version@ Release: 1%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist} License: GPLv2+ and LGPLv2+ URL: https://kronosnet.org Source0: https://kronosnet.org/releases/%{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}.tar.gz # Build dependencies BuildRequires: gcc libqb-devel # required to build man pages %if %{with buildman} BuildRequires: doxygen doxygen2man %endif %if %{with sctp} BuildRequires: lksctp-tools-devel %endif %if %{with nss} %if 0%{?suse_version} BuildRequires: mozilla-nss-devel %else BuildRequires: nss-devel %endif %endif %if %{with openssl} %if 0%{?suse_version} BuildRequires: libopenssl-devel %else BuildRequires: openssl-devel %endif %endif +%if %{with gcrypt} +BuildRequires: libgcrypt-devel >= 1.8.0 +%endif %if %{with zlib} BuildRequires: zlib-devel %endif %if %{with lz4} %if 0%{?suse_version} BuildRequires: liblz4-devel %else BuildRequires: lz4-devel %endif %endif %if %{with lzo2} BuildRequires: lzo-devel %endif %if %{with lzma} BuildRequires: xz-devel %endif %if %{with bzip2} %if 0%{?suse_version} BuildRequires: libbz2-devel %else BuildRequires: bzip2-devel %endif %endif %if %{with zstd} BuildRequires: libzstd-devel %endif %if %{with libnozzle} BuildRequires: libnl3-devel %endif %if %{with runautogen} BuildRequires: autoconf automake libtool %endif %prep %setup -q -n %{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}} %build %if %{with runautogen} ./autogen.sh %endif %{configure} \ %if %{with installtests} --enable-install-tests \ %else --disable-install-tests \ %endif %if %{with buildman} --enable-man \ %else --disable-man \ %endif %if %{with sctp} --enable-libknet-sctp \ %else --disable-libknet-sctp \ %endif %if %{with nss} --enable-crypto-nss \ %else --disable-crypto-nss \ %endif %if %{with openssl} --enable-crypto-openssl \ %else --disable-crypto-openssl \ %endif +%if %{with gcrypt} + --enable-crypto-gcrypt \ +%else + --disable-crypto-gcrypt \ +%endif %if %{with zlib} --enable-compress-zlib \ %else --disable-compress-zlib \ %endif %if %{with lz4} --enable-compress-lz4 \ %else --disable-compress-lz4 \ %endif %if %{with lzo2} --enable-compress-lzo2 \ %else --disable-compress-lzo2 \ %endif %if %{with lzma} --enable-compress-lzma \ %else --disable-compress-lzma \ %endif %if %{with bzip2} --enable-compress-bzip2 \ %else --disable-compress-bzip2 \ %endif %if %{with zstd} --enable-compress-zstd \ %else --disable-compress-zstd \ %endif %if %{with libnozzle} --enable-libnozzle \ %else --disable-libnozzle \ %endif --with-initdefaultdir=%{_sysconfdir}/sysconfig/ \ --with-systemddir=%{_unitdir} make %{_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} # tree cleanup # remove static libraries find %{buildroot} -name "*.a" -exec rm {} \; # remove libtools leftovers find %{buildroot} -name "*.la" -exec rm {} \; -# remove init scripts -rm -rf %{buildroot}/etc/init.d - # remove docs rm -rf %{buildroot}/usr/share/doc/kronosnet # main empty package %description The kronosnet source %if %{with libnozzle} %package -n libnozzle1 Summary: Simple userland wrapper around kernel tap devices License: LGPLv2+ %description -n libnozzle1 This is an over-engineered commodity library to manage a pool of tap devices and provides the basic pre-up.d/up.d/down.d/post-down.d infrastructure. %files -n libnozzle1 %license COPYING.* COPYRIGHT %{_libdir}/libnozzle.so.* %if 0%{?ldconfig_scriptlets} %ldconfig_scriptlets -n libnozzle1 %else %post -n libnozzle1 -p /sbin/ldconfig %postun -n libnozzle1 -p /sbin/ldconfig %endif %package -n libnozzle1-devel Summary: Simple userland wrapper around kernel tap devices (developer files) License: LGPLv2+ Requires: libnozzle1%{_isa} = %{version}-%{release} Requires: pkgconfig %description -n libnozzle1-devel This is an over-engineered commodity library to manage a pool of tap devices and provides the basic pre-up.d/up.d/down.d/post-down.d infrastructure. %files -n libnozzle1-devel %license COPYING.* COPYRIGHT %{_libdir}/libnozzle.so %{_includedir}/libnozzle.h %{_libdir}/pkgconfig/libnozzle.pc %if %{with buildman} %{_mandir}/man3/nozzle*.3.gz %endif %endif %package -n libknet1 Summary: Kronosnet core switching implementation License: LGPLv2+ %description -n libknet1 The whole kronosnet core is implemented in this library. Please refer to the not-yet-existing documentation for further information. %files -n libknet1 %license COPYING.* COPYRIGHT %{_libdir}/libknet.so.* %dir %{_libdir}/kronosnet %if 0%{?ldconfig_scriptlets} %ldconfig_scriptlets -n libknet1 %else %post -n libknet1 -p /sbin/ldconfig %postun -n libknet1 -p /sbin/ldconfig %endif %package -n libknet1-devel Summary: Kronosnet core switching implementation (developer files) License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} Requires: pkgconfig %description -n libknet1-devel The whole kronosnet core is implemented in this library. Please refer to the not-yet-existing documentation for further information. %files -n libknet1-devel %license COPYING.* COPYRIGHT %{_libdir}/libknet.so %{_includedir}/libknet.h %{_libdir}/pkgconfig/libknet.pc %if %{with buildman} %{_mandir}/man3/knet*.3.gz %endif %if %{with nss} %package -n libknet1-crypto-nss-plugin Summary: Provides libknet1 nss support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-crypto-nss-plugin Provides NSS crypto support for libknet1. %files -n libknet1-crypto-nss-plugin %{_libdir}/kronosnet/crypto_nss.so %endif %if %{with openssl} %package -n libknet1-crypto-openssl-plugin Summary: Provides libknet1 openssl support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-crypto-openssl-plugin Provides OpenSSL crypto support for libknet1. %files -n libknet1-crypto-openssl-plugin %{_libdir}/kronosnet/crypto_openssl.so %endif +%if %{with gcrypt} +%package -n libknet1-crypto-gcrypt-plugin +Summary: Provides libknet1 gcrypt support +License: LGPLv2+ +Requires: libknet1%{_isa} = %{version}-%{release} + +%description -n libknet1-crypto-gcrypt-plugin + Provides libgcrypt crypto support for libknet1. + +%files -n libknet1-crypto-gcrypt-plugin +%{_libdir}/kronosnet/crypto_gcrypt.so +%endif + %if %{with zlib} %package -n libknet1-compress-zlib-plugin Summary: Provides libknet1 zlib support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-compress-zlib-plugin Provides zlib compression support for libknet1. %files -n libknet1-compress-zlib-plugin %{_libdir}/kronosnet/compress_zlib.so %endif %if %{with lz4} %package -n libknet1-compress-lz4-plugin Summary: Provides libknet1 lz4 and lz4hc support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-compress-lz4-plugin Provides lz4 and lz4hc compression support for libknet1. %files -n libknet1-compress-lz4-plugin %{_libdir}/kronosnet/compress_lz4.so %{_libdir}/kronosnet/compress_lz4hc.so %endif %if %{with lzo2} %package -n libknet1-compress-lzo2-plugin Summary: Provides libknet1 lzo2 support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-compress-lzo2-plugin Provides lzo2 compression support for libknet1. %files -n libknet1-compress-lzo2-plugin %{_libdir}/kronosnet/compress_lzo2.so %endif %if %{with lzma} %package -n libknet1-compress-lzma-plugin Summary: Provides libknet1 lzma support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-compress-lzma-plugin Provides lzma compression support for libknet1. %files -n libknet1-compress-lzma-plugin %{_libdir}/kronosnet/compress_lzma.so %endif %if %{with bzip2} %package -n libknet1-compress-bzip2-plugin Summary: Provides libknet1 bzip2 support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-compress-bzip2-plugin Provides bzip2 compression support for libknet1. %files -n libknet1-compress-bzip2-plugin %{_libdir}/kronosnet/compress_bzip2.so %endif %if %{with zstd} %package -n libknet1-compress-zstd-plugin Summary: Provides libknet1 zstd support License: LGPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n libknet1-compress-zstd-plugin Provides zstd compression support for libknet1. %files -n libknet1-compress-zstd-plugin %{_libdir}/kronosnet/compress_zstd.so %endif %package -n libknet1-crypto-plugins-all Summary: Provides libknet1 crypto plugins meta package License: LGPLv2+ %if %{with nss} Requires: libknet1-crypto-nss-plugin%{_isa} = %{version}-%{release} %endif %if %{with openssl} Requires: libknet1-crypto-openssl-plugin%{_isa} = %{version}-%{release} %endif +%if %{with gcrypt} +Requires: libknet1-crypto-gcrypt-plugin%{_isa} = %{version}-%{release} +%endif %description -n libknet1-crypto-plugins-all Provides meta package to install all of libknet1 crypto plugins %files -n libknet1-crypto-plugins-all %package -n libknet1-compress-plugins-all Summary: Provides libknet1 compress plugins meta package License: LGPLv2+ %if %{with zlib} Requires: libknet1-compress-zlib-plugin%{_isa} = %{version}-%{release} %endif %if %{with lz4} Requires: libknet1-compress-lz4-plugin%{_isa} = %{version}-%{release} %endif %if %{with lzo2} Requires: libknet1-compress-lzo2-plugin%{_isa} = %{version}-%{release} %endif %if %{with lzma} Requires: libknet1-compress-lzma-plugin%{_isa} = %{version}-%{release} %endif %if %{with bzip2} Requires: libknet1-compress-bzip2-plugin%{_isa} = %{version}-%{release} %endif %if %{with zstd} Requires: libknet1-compress-zstd-plugin%{_isa} = %{version}-%{release} %endif %description -n libknet1-compress-plugins-all Meta package to install all of libknet1 compress plugins %files -n libknet1-compress-plugins-all %package -n libknet1-plugins-all Summary: Provides libknet1 plugins meta package License: LGPLv2+ Requires: libknet1-compress-plugins-all%{_isa} = %{version}-%{release} Requires: libknet1-crypto-plugins-all%{_isa} = %{version}-%{release} %description -n libknet1-plugins-all Meta package to install all of libknet1 plugins %files -n libknet1-plugins-all %if %{with installtests} %package -n kronosnet-tests Summary: Provides kronosnet test suite License: GPLv2+ Requires: libknet1%{_isa} = %{version}-%{release} %description -n kronosnet-tests This package contains all the libknet and libnozzle test suite. %files -n kronosnet-tests %{_libdir}/kronosnet/tests/* %endif %if %{with rpmdebuginfo} %debug_package %endif %changelog * @date@ Autotools generated version - @version@-1-@numcomm@.@alphatag@.@dirty@ - These aren't the droids you're looking for. diff --git a/libknet/Makefile.am b/libknet/Makefile.am index 695bb8a1..9e49b1db 100644 --- a/libknet/Makefile.am +++ b/libknet/Makefile.am @@ -1,169 +1,176 @@ # # Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved. # # Authors: Fabio M. Di Nitto # Federico Simoncelli # # This software licensed under GPL-2.0+ # MAINTAINERCLEANFILES = Makefile.in include $(top_srcdir)/build-aux/check.mk SYMFILE = libknet_exported_syms EXTRA_DIST = $(SYMFILE) SUBDIRS = . tests # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html libversion = 2:0:0 # override global LIBS that pulls in lots of craft we don't need here LIBS = sources = \ common.c \ compat.c \ compress.c \ crypto.c \ handle.c \ handle_api.c \ host.c \ links.c \ links_acl.c \ links_acl_ip.c \ links_acl_loopback.c \ logging.c \ netutils.c \ onwire.c \ onwire_v1.c \ threads_common.c \ threads_dsthandler.c \ threads_heartbeat.c \ threads_pmtud.c \ threads_rx.c \ threads_tx.c \ transports.c \ transport_common.c \ transport_loopback.c \ transport_udp.c \ transport_sctp.c include_HEADERS = libknet.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libknet.pc noinst_HEADERS = \ common.h \ compat.h \ compress.h \ compress_model.h \ crypto.h \ crypto_model.h \ host.h \ internals.h \ links.h \ links_acl.h \ links_acl_ip.h \ links_acl_loopback.h \ logging.h \ netutils.h \ onwire.h \ onwire_v1.h \ threads_common.h \ threads_dsthandler.h \ threads_heartbeat.h \ threads_pmtud.h \ threads_rx.h \ threads_tx.h \ transports.h \ transport_common.h \ transport_loopback.h \ transport_udp.h \ transport_sctp.h lib_LTLIBRARIES = libknet.la libknet_la_SOURCES = $(sources) AM_CFLAGS += $(libqb_CFLAGS) libknet_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) EXTRA_libknet_la_DEPENDENCIES = $(SYMFILE) libknet_la_LDFLAGS = $(AM_LDFLAGS) \ -Wl,--version-script=$(srcdir)/$(SYMFILE) \ -Wl,-rpath=$(pkglibdir) \ -version-info $(libversion) libknet_la_LIBADD = $(PTHREAD_LIBS) $(dl_LIBS) $(rt_LIBS) $(m_LIBS) # Prepare empty value for appending pkglib_LTLIBRARIES = # MODULE_LDFLAGS would mean a target-specific variable for Automake MODULELDFLAGS = $(AM_LDFLAGS) -module -avoid-version -export-dynamic if BUILD_COMPRESS_ZSTD pkglib_LTLIBRARIES += compress_zstd.la compress_zstd_la_LDFLAGS = $(MODULELDFLAGS) compress_zstd_la_CFLAGS = $(AM_CFLAGS) $(libzstd_CFLAGS) compress_zstd_la_LIBADD = $(libzstd_LIBS) endif if BUILD_COMPRESS_ZLIB pkglib_LTLIBRARIES += compress_zlib.la compress_zlib_la_LDFLAGS = $(MODULELDFLAGS) compress_zlib_la_CFLAGS = $(AM_CFLAGS) $(zlib_CFLAGS) compress_zlib_la_LIBADD = $(zlib_LIBS) endif if BUILD_COMPRESS_LZ4 pkglib_LTLIBRARIES += compress_lz4.la compress_lz4hc.la compress_lz4_la_LDFLAGS = $(MODULELDFLAGS) compress_lz4_la_CFLAGS = $(AM_CFLAGS) $(liblz4_CFLAGS) compress_lz4_la_LIBADD = $(liblz4_LIBS) compress_lz4hc_la_LDFLAGS = $(MODULELDFLAGS) compress_lz4hc_la_CFLAGS = $(AM_CFLAGS) $(liblz4_CFLAGS) compress_lz4hc_la_LIBADD = $(liblz4_LIBS) endif if BUILD_COMPRESS_LZO2 pkglib_LTLIBRARIES += compress_lzo2.la compress_lzo2_la_LDFLAGS = $(MODULELDFLAGS) compress_lzo2_la_CFLAGS = $(AM_CFLAGS) $(lzo2_CFLAGS) compress_lzo2_la_LIBADD = $(lzo2_LIBS) endif if BUILD_COMPRESS_LZMA pkglib_LTLIBRARIES += compress_lzma.la compress_lzma_la_LDFLAGS = $(MODULELDFLAGS) compress_lzma_la_CFLAGS = $(AM_CFLAGS) $(liblzma_CFLAGS) compress_lzma_la_LIBADD = $(liblzma_LIBS) endif if BUILD_COMPRESS_BZIP2 pkglib_LTLIBRARIES += compress_bzip2.la compress_bzip2_la_LDFLAGS = $(MODULELDFLAGS) compress_bzip2_la_CFLAGS = $(AM_CFLAGS) $(bzip2_CFLAGS) compress_bzip2_la_LIBADD = $(bzip2_LIBS) endif if BUILD_CRYPTO_NSS pkglib_LTLIBRARIES += crypto_nss.la crypto_nss_la_LDFLAGS = $(MODULELDFLAGS) crypto_nss_la_CFLAGS = $(AM_CFLAGS) $(nss_CFLAGS) crypto_nss_la_LIBADD = $(nss_LIBS) endif if BUILD_CRYPTO_OPENSSL pkglib_LTLIBRARIES += crypto_openssl.la crypto_openssl_la_LDFLAGS = $(MODULELDFLAGS) crypto_openssl_la_CFLAGS = $(AM_CFLAGS) $(openssl_CFLAGS) crypto_openssl_la_LIBADD = $(openssl_LIBS) endif + +if BUILD_CRYPTO_GCRYPT +pkglib_LTLIBRARIES += crypto_gcrypt.la +crypto_gcrypt_la_LDFLAGS = $(MODULELDFLAGS) +crypto_gcrypt_la_CFLAGS = $(AM_CFLAGS) $(gcrypt_CFLAGS) +crypto_gcrypt_la_LIBADD = $(gcrypt_LIBS) +endif diff --git a/libknet/crypto.c b/libknet/crypto.c index 59e1fded..317f03ab 100644 --- a/libknet/crypto.c +++ b/libknet/crypto.c @@ -1,459 +1,460 @@ /* * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under LGPL-2.0+ */ #include "config.h" #include #include #include #include #include #include "crypto.h" #include "crypto_model.h" #include "internals.h" #include "logging.h" #include "common.h" /* * internal module switch data */ static crypto_model_t crypto_modules_cmds[] = { { "nss", WITH_CRYPTO_NSS, 0, NULL }, { "openssl", WITH_CRYPTO_OPENSSL, 0, NULL }, + { "gcrypt", WITH_CRYPTO_GCRYPT, 0, NULL }, { NULL, 0, 0, NULL } }; static int crypto_get_model(const char *model) { int idx = 0; while (crypto_modules_cmds[idx].model_name != NULL) { if (!strcmp(crypto_modules_cmds[idx].model_name, model)) return idx; idx++; } return -1; } /* * exported API */ int crypto_encrypt_and_sign ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { return crypto_modules_cmds[knet_h->crypto_instance[knet_h->crypto_in_use_config]->model].ops->crypt(knet_h, knet_h->crypto_instance[knet_h->crypto_in_use_config], buf_in, buf_in_len, buf_out, buf_out_len); } int crypto_encrypt_and_signv ( knet_handle_t knet_h, const struct iovec *iov_in, int iovcnt_in, unsigned char *buf_out, ssize_t *buf_out_len) { return crypto_modules_cmds[knet_h->crypto_instance[knet_h->crypto_in_use_config]->model].ops->cryptv(knet_h, knet_h->crypto_instance[knet_h->crypto_in_use_config], iov_in, iovcnt_in, buf_out, buf_out_len); } int crypto_authenticate_and_decrypt ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { int i, err = 0; int multiple_configs = 0; uint8_t log_level = KNET_LOG_ERR; for (i = 1; i <= KNET_MAX_CRYPTO_INSTANCES; i++) { if (knet_h->crypto_instance[i]) { multiple_configs++; } } /* * attempt to decrypt first with the in-use config * to avoid excessive performance hit. */ if (multiple_configs > 1) { log_level = KNET_LOG_DEBUG; } if (knet_h->crypto_in_use_config) { err = crypto_modules_cmds[knet_h->crypto_instance[knet_h->crypto_in_use_config]->model].ops->decrypt(knet_h, knet_h->crypto_instance[knet_h->crypto_in_use_config], buf_in, buf_in_len, buf_out, buf_out_len, log_level); } else { err = -1; } /* * if we fail, try to use the other configurations */ if (err) { for (i = 1; i <= KNET_MAX_CRYPTO_INSTANCES; i++) { /* * in-use config was already attempted */ if (i == knet_h->crypto_in_use_config) { continue; } if (knet_h->crypto_instance[i]) { log_debug(knet_h, KNET_SUB_CRYPTO, "Alternative crypto configuration found, attempting to decrypt with config %u", i); err = crypto_modules_cmds[knet_h->crypto_instance[i]->model].ops->decrypt(knet_h, knet_h->crypto_instance[i], buf_in, buf_in_len, buf_out, buf_out_len, KNET_LOG_ERR); if (!err) { errno = 0; /* clear errno from previous failures */ return err; } log_debug(knet_h, KNET_SUB_CRYPTO, "Packet failed to decrypt with crypto config %u", i); } } } return err; } static int crypto_use_config( knet_handle_t knet_h, uint8_t config_num) { if ((config_num) && (!knet_h->crypto_instance[config_num])) { errno = EINVAL; return -1; } knet_h->crypto_in_use_config = config_num; if (config_num) { knet_h->sec_block_size = knet_h->crypto_instance[config_num]->sec_block_size; knet_h->sec_hash_size = knet_h->crypto_instance[config_num]->sec_hash_size; knet_h->sec_salt_size = knet_h->crypto_instance[config_num]->sec_salt_size; } else { knet_h->sec_block_size = 0; knet_h->sec_hash_size = 0; knet_h->sec_salt_size = 0; } force_pmtud_run(knet_h, KNET_SUB_CRYPTO, 1); return 0; } static int crypto_init( knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg, uint8_t config_num) { int err = 0, savederrno = 0; int model = 0; struct crypto_instance *current = NULL, *new = NULL; current = knet_h->crypto_instance[config_num]; model = crypto_get_model(knet_handle_crypto_cfg->crypto_model); if (model < 0) { log_err(knet_h, KNET_SUB_CRYPTO, "model %s not supported", knet_handle_crypto_cfg->crypto_model); return -1; } if (crypto_modules_cmds[model].built_in == 0) { log_err(knet_h, KNET_SUB_CRYPTO, "this version of libknet was built without %s support. Please contact your vendor or fix the build.", knet_handle_crypto_cfg->crypto_model); return -1; } savederrno = pthread_rwlock_wrlock(&shlib_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_CRYPTO, "Unable to get write lock: %s", strerror(savederrno)); return -1; } if (!crypto_modules_cmds[model].loaded) { crypto_modules_cmds[model].ops = load_module (knet_h, "crypto", crypto_modules_cmds[model].model_name); if (!crypto_modules_cmds[model].ops) { savederrno = errno; err = -1; log_err(knet_h, KNET_SUB_CRYPTO, "Unable to load %s lib", crypto_modules_cmds[model].model_name); goto out; } if (crypto_modules_cmds[model].ops->abi_ver != KNET_CRYPTO_MODEL_ABI) { savederrno = EINVAL; err = -1; log_err(knet_h, KNET_SUB_CRYPTO, "ABI mismatch loading module %s. knet ver: %d, module ver: %d", crypto_modules_cmds[model].model_name, KNET_CRYPTO_MODEL_ABI, crypto_modules_cmds[model].ops->abi_ver); goto out; } crypto_modules_cmds[model].loaded = 1; } log_debug(knet_h, KNET_SUB_CRYPTO, "Initizializing crypto module [%s/%s/%s]", knet_handle_crypto_cfg->crypto_model, knet_handle_crypto_cfg->crypto_cipher_type, knet_handle_crypto_cfg->crypto_hash_type); new = malloc(sizeof(struct crypto_instance)); if (!new) { savederrno = ENOMEM; err = -1; log_err(knet_h, KNET_SUB_CRYPTO, "Unable to allocate memory for crypto instance"); goto out; } /* * if crypto_modules_cmds.ops->init fails, it is expected that * it will clean everything by itself. * crypto_modules_cmds.ops->fini is not invoked on error. */ new->model = model; if (crypto_modules_cmds[model].ops->init(knet_h, new, knet_handle_crypto_cfg)) { savederrno = errno; err = -1; goto out; } out: if (!err) { knet_h->crypto_instance[config_num] = new; if (current) { /* * if we are replacing the current config, we need to enable it right away */ if (knet_h->crypto_in_use_config == config_num) { crypto_use_config(knet_h, config_num); } if (crypto_modules_cmds[current->model].ops->fini != NULL) { crypto_modules_cmds[current->model].ops->fini(knet_h, current); } free(current); } } else { if (new) { free(new); } } pthread_rwlock_unlock(&shlib_rwlock); errno = err ? savederrno : 0; return err; } static void crypto_fini_config( knet_handle_t knet_h, uint8_t config_num) { if (knet_h->crypto_instance[config_num]) { if (crypto_modules_cmds[knet_h->crypto_instance[config_num]->model].ops->fini != NULL) { crypto_modules_cmds[knet_h->crypto_instance[config_num]->model].ops->fini(knet_h, knet_h->crypto_instance[config_num]); } free(knet_h->crypto_instance[config_num]); knet_h->crypto_instance[config_num] = NULL; } } void crypto_fini( knet_handle_t knet_h, uint8_t config_num) { int savederrno = 0, i; savederrno = pthread_rwlock_wrlock(&shlib_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_CRYPTO, "Unable to get write lock: %s", strerror(savederrno)); return; } if (config_num > KNET_MAX_CRYPTO_INSTANCES) { for (i = 1; i <= KNET_MAX_CRYPTO_INSTANCES; i++) { crypto_fini_config(knet_h, i); } } else { crypto_fini_config(knet_h, config_num); } pthread_rwlock_unlock(&shlib_rwlock); return; } int knet_handle_crypto_set_config(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg, uint8_t config_num) { int savederrno = 0; int err = 0; if (!knet_h) { errno = EINVAL; return -1; } if (!knet_handle_crypto_cfg) { errno = EINVAL; return -1; } if ((config_num < 1) || (config_num > KNET_MAX_CRYPTO_INSTANCES)) { errno = EINVAL; return -1; } savederrno = get_global_wrlock(knet_h); if (savederrno) { log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } if (knet_h->crypto_in_use_config == config_num) { savederrno = EBUSY; err = -1; goto exit_unlock; } if ((!strncmp("none", knet_handle_crypto_cfg->crypto_model, 4)) || ((!strncmp("none", knet_handle_crypto_cfg->crypto_cipher_type, 4)) && (!strncmp("none", knet_handle_crypto_cfg->crypto_hash_type, 4)))) { crypto_fini(knet_h, config_num); log_debug(knet_h, KNET_SUB_CRYPTO, "crypto config %u is not enabled", config_num); err = 0; goto exit_unlock; } if (knet_handle_crypto_cfg->private_key_len < KNET_MIN_KEY_LEN) { log_debug(knet_h, KNET_SUB_CRYPTO, "private key len too short for config %u (min %d): %u", config_num, KNET_MIN_KEY_LEN, knet_handle_crypto_cfg->private_key_len); savederrno = EINVAL; err = -1; goto exit_unlock; } if (knet_handle_crypto_cfg->private_key_len > KNET_MAX_KEY_LEN) { log_debug(knet_h, KNET_SUB_CRYPTO, "private key len too long for config %u (max %d): %u", config_num, KNET_MAX_KEY_LEN, knet_handle_crypto_cfg->private_key_len); savederrno = EINVAL; err = -1; goto exit_unlock; } err = crypto_init(knet_h, knet_handle_crypto_cfg, config_num); if (err) { err = -2; savederrno = errno; } exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = err ? savederrno : 0; return err; } int knet_handle_crypto_rx_clear_traffic(knet_handle_t knet_h, uint8_t value) { int savederrno = 0; if (!knet_h) { errno = EINVAL; return -1; } if (value > KNET_CRYPTO_RX_DISALLOW_CLEAR_TRAFFIC) { errno = EINVAL; return -1; } savederrno = get_global_wrlock(knet_h); if (savederrno) { log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } knet_h->crypto_only = value; if (knet_h->crypto_only) { log_debug(knet_h, KNET_SUB_CRYPTO, "Only crypto traffic allowed for RX"); } else { log_debug(knet_h, KNET_SUB_CRYPTO, "Both crypto and clear traffic allowed for RX"); } pthread_rwlock_unlock(&knet_h->global_rwlock); return 0; } int knet_handle_crypto_use_config(knet_handle_t knet_h, uint8_t config_num) { int savederrno = 0; int err = 0; if (!knet_h) { errno = EINVAL; return -1; } if (config_num > KNET_MAX_CRYPTO_INSTANCES) { errno = EINVAL; return -1; } savederrno = get_global_wrlock(knet_h); if (savederrno) { log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } err = crypto_use_config(knet_h, config_num); savederrno = errno; pthread_rwlock_unlock(&knet_h->global_rwlock); errno = err ? savederrno : 0; return err; } int knet_get_crypto_list(struct knet_crypto_info *crypto_list, size_t *crypto_list_entries) { int err = 0; int idx = 0; int outidx = 0; if (!crypto_list_entries) { errno = EINVAL; return -1; } while (crypto_modules_cmds[idx].model_name != NULL) { if (crypto_modules_cmds[idx].built_in) { if (crypto_list) { crypto_list[outidx].name = crypto_modules_cmds[idx].model_name; } outidx++; } idx++; } *crypto_list_entries = outidx; if (!err) errno = 0; return err; } diff --git a/libknet/crypto_gcrypt.c b/libknet/crypto_gcrypt.c new file mode 100644 index 00000000..11c83ad8 --- /dev/null +++ b/libknet/crypto_gcrypt.c @@ -0,0 +1,598 @@ +/* + * Copyright (C) 2017-2020 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under LGPL-2.0+ + */ +#define KNET_MODULE + +#include "config.h" + +#include +#include +#include + +/* + * make sure NOT to use deprecated API + */ +#define GCRYPTO_NO_DEPRECATED 1 + +#define NEED_LIBGCRYPT_VERSION "1.8.0" + +#include + +#include "logging.h" +#include "crypto_model.h" + +/* + * crypto definitions and conversion tables + */ + +#define SALT_SIZE 16 + +/* + * gcrypt rejects private key len > crypto max keylen. openssl/nss automatically trim the key. + * we need to store a crypto key len and a hash keylen separately + * and crypto key len is trimmed automatically at gcrypt_init time. + */ + +struct gcryptcrypto_instance { + void *private_key; + size_t crypt_private_key_len; + size_t hash_private_key_len; + int crypto_cipher_type; + int crypto_hash_type; +}; + +static int gcrypt_is_init = 0; + +/* + * crypt/decrypt functions + */ + +static int encrypt_gcrypt( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + const struct iovec *iov, + int iovcnt, + unsigned char *buf_out, + ssize_t *buf_out_len) +{ + struct gcryptcrypto_instance *instance = crypto_instance->model_instance; + gcry_error_t gerr; + gcry_cipher_hd_t handle = NULL; + int err = 0; + int i; + unsigned char *salt = buf_out; + size_t output_len = 0, pad_len = 0; + unsigned char inbuf[KNET_DATABUFSIZE_CRYPT]; + unsigned char *data = buf_out + SALT_SIZE; + + gerr = gcry_cipher_open(&handle, instance->crypto_cipher_type, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to allocate gcrypt cipher context: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_cipher_setkey(handle, instance->private_key, instance->crypt_private_key_len); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to load private key: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gcry_randomize(salt, SALT_SIZE, GCRY_VERY_STRONG_RANDOM); + + gerr = gcry_cipher_setiv(handle, salt, SALT_SIZE); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to load init vector: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + /* + * libgcrypt requires an input buffer that is + * already aligned to block size. + * The easiest way is to build the data in + * a dedicated buffer + */ + output_len = 0; + for (i=0; isec_block_size - (output_len % crypto_instance->sec_block_size)); + + memset(inbuf + output_len, pad_len, pad_len); + + output_len = output_len + pad_len; + + /* + * some ciphers methods require _final to be called + * before the last call to _encrypt, for example when + * encrypting big chunks of data split in multiple buffers. + * knet only has one buffer, so we can safely call _final here. + * adding a comment as the code looks backwards compared to other + * cipher implementations that do final _after_ encrypting the last block + */ + gcry_cipher_final(handle); + + gerr = gcry_cipher_encrypt(handle, + data, output_len, + inbuf, output_len); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to encrypt data: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + *buf_out_len = output_len + SALT_SIZE; + +out_err: + if (handle) { + gcry_cipher_close(handle); + } + return err; +} + +static int decrypt_gcrypt( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + const unsigned char *buf_in, + const ssize_t buf_in_len, + unsigned char *buf_out, + ssize_t *buf_out_len, + uint8_t log_level) +{ + struct gcryptcrypto_instance *instance = crypto_instance->model_instance; + gcry_error_t gerr; + gcry_cipher_hd_t handle = NULL; + unsigned char *salt = (unsigned char *)buf_in; + unsigned char *data = salt + SALT_SIZE; + int datalen = buf_in_len - SALT_SIZE; + int err = 0; + + if (datalen <= 0) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Packet is too short"); + err = -1; + goto out_err; + } + + gerr = gcry_cipher_open(&handle, instance->crypto_cipher_type, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to allocate gcrypt cipher context: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_cipher_setkey(handle, instance->private_key, instance->crypt_private_key_len); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to load private key: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_cipher_setiv(handle, salt, SALT_SIZE); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to load init vector: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_cipher_decrypt(handle, + buf_out, KNET_DATABUFSIZE_CRYPT, + data, datalen); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to decrypt data: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + /* + * drop the padding size based on PCKS standards + * (see also crypt above) + */ + *buf_out_len = datalen - buf_out[datalen - 1]; + +out_err: + if (handle) { + gcry_cipher_close(handle); + } + return err; +} + +/* + * hash/hmac/digest functions + */ + +static int calculate_gcrypt_hash( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + const unsigned char *buf, + const size_t buf_len, + unsigned char *hash, + uint8_t log_level) +{ + struct gcryptcrypto_instance *instance = crypto_instance->model_instance; + gcry_error_t gerr; + gcry_mac_hd_t handle = NULL; + int err = 0; + size_t outlen = crypto_instance->sec_hash_size; + + gerr = gcry_mac_open(&handle, instance->crypto_hash_type, GCRY_MAC_FLAG_SECURE, 0); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to allocate gcrypt hmac context: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_mac_setkey(handle, instance->private_key, instance->hash_private_key_len); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to set gcrypt hmac key: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_mac_write(handle, buf, buf_len); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to calculate gcrypt hmac: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + + gerr = gcry_mac_read(handle, hash, &outlen); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to retrive gcrypt hmac: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + err = -1; + goto out_err; + } + +out_err: + if (handle) { + gcry_mac_close(handle); + } + + return err; +} + +/* + * exported API + */ + +static int gcryptcrypto_encrypt_and_signv ( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + const struct iovec *iov_in, + int iovcnt_in, + unsigned char *buf_out, + ssize_t *buf_out_len) +{ + struct gcryptcrypto_instance *instance = crypto_instance->model_instance; + int i; + + if (instance->crypto_cipher_type) { + if (encrypt_gcrypt(knet_h, crypto_instance, iov_in, iovcnt_in, buf_out, buf_out_len) < 0) { + return -1; + } + } else { + *buf_out_len = 0; + for (i=0; icrypto_hash_type) { + if (calculate_gcrypt_hash(knet_h, crypto_instance, buf_out, *buf_out_len, buf_out + *buf_out_len, KNET_LOG_ERR) < 0) { + return -1; + } + *buf_out_len = *buf_out_len + crypto_instance->sec_hash_size; + } + + return 0; +} + +static int gcryptcrypto_encrypt_and_sign ( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + const unsigned char *buf_in, + const ssize_t buf_in_len, + unsigned char *buf_out, + ssize_t *buf_out_len) +{ + struct iovec iov_in; + + memset(&iov_in, 0, sizeof(iov_in)); + iov_in.iov_base = (unsigned char *)buf_in; + iov_in.iov_len = buf_in_len; + + return gcryptcrypto_encrypt_and_signv(knet_h, crypto_instance, &iov_in, 1, buf_out, buf_out_len); +} + +static int gcryptcrypto_authenticate_and_decrypt ( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + const unsigned char *buf_in, + const ssize_t buf_in_len, + unsigned char *buf_out, + ssize_t *buf_out_len, + uint8_t log_level) +{ + struct gcryptcrypto_instance *instance = crypto_instance->model_instance; + ssize_t temp_len = buf_in_len; + + if (instance->crypto_hash_type) { + unsigned char tmp_hash[crypto_instance->sec_hash_size]; + ssize_t temp_buf_len = buf_in_len - crypto_instance->sec_hash_size; + + if ((temp_buf_len <= 0) || (temp_buf_len > KNET_MAX_PACKET_SIZE)) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Incorrect packet size."); + return -1; + } + + if (calculate_gcrypt_hash(knet_h, crypto_instance, buf_in, temp_buf_len, tmp_hash, log_level) < 0) { + return -1; + } + + if (memcmp(tmp_hash, buf_in + temp_buf_len, crypto_instance->sec_hash_size) != 0) { + if (log_level == KNET_LOG_DEBUG) { + log_debug(knet_h, KNET_SUB_GCRYPTCRYPTO, "Digest does not match"); + } else { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Digest does not match"); + } + return -1; + } + + temp_len = temp_len - crypto_instance->sec_hash_size; + *buf_out_len = temp_len; + } + if (instance->crypto_cipher_type) { + if (decrypt_gcrypt(knet_h, crypto_instance, buf_in, temp_len, buf_out, buf_out_len, log_level) < 0) { + return -1; + } + } else { + memmove(buf_out, buf_in, temp_len); + *buf_out_len = temp_len; + } + + return 0; +} + +static void gcryptcrypto_fini( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance) +{ + struct gcryptcrypto_instance *gcryptcrypto_instance = crypto_instance->model_instance; + + if (gcryptcrypto_instance) { + if (gcryptcrypto_instance->private_key) { + free(gcryptcrypto_instance->private_key); + gcryptcrypto_instance->private_key = NULL; + } + free(gcryptcrypto_instance); + crypto_instance->model_instance = NULL; + } + + return; +} + +static int gcryptcrypto_init( + knet_handle_t knet_h, + struct crypto_instance *crypto_instance, + struct knet_handle_crypto_cfg *knet_handle_crypto_cfg) +{ + struct gcryptcrypto_instance *gcryptcrypto_instance = NULL; + gcry_error_t gerr; + int savederrno; + /* + * gcrypt name to ID mapping requires HMAC_ in the name. + * so for example to use SHA1, the name should be HMAC_SHA1 + * that makes it not compatible with nss/openssl naming. + * make sure to add HMAC_ transparently so that changing crypto config + * can be done transparently. + */ + char remap_hash_type[sizeof(knet_handle_crypto_cfg->crypto_hash_type) + strlen("HMAC_") + 1]; + + log_debug(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Initizializing gcrypt crypto module [%s/%s]", + knet_handle_crypto_cfg->crypto_cipher_type, + knet_handle_crypto_cfg->crypto_hash_type); + + if (!gcrypt_is_init) { + if (!gcry_check_version(NEED_LIBGCRYPT_VERSION)) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "libgcrypt is too old (need %s, have %s)", + NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL)); + errno = EINVAL; + return -1; + } + + gerr = gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to suppress sec mem warnings: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + errno = EINVAL; + return -1; + } + + gerr = gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to init sec mem: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + errno = ENOMEM; + return -1; + } + + gerr = gcry_control(GCRYCTL_RESUME_SECMEM_WARN); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to restore sec mem warnings: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + errno = EINVAL; + return -1; + } + + gerr = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + if (gerr) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "Unable to notify gcrypt that init is completed: %s/%s", + gcry_strsource(gerr), gcry_strerror(gerr)); + errno = EINVAL; + return -1; + } + + if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, + "gcrypt could not initialize properly"); + errno = EINVAL; + return -1; + } + + gcrypt_is_init = 1; + } + + crypto_instance->model_instance = malloc(sizeof(struct gcryptcrypto_instance)); + if (!crypto_instance->model_instance) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Unable to allocate memory for gcrypt model instance"); + errno = ENOMEM; + return -1; + } + + gcryptcrypto_instance = crypto_instance->model_instance; + + memset(gcryptcrypto_instance, 0, sizeof(struct gcryptcrypto_instance)); + + gcryptcrypto_instance->private_key = malloc(knet_handle_crypto_cfg->private_key_len); + if (!gcryptcrypto_instance->private_key) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Unable to allocate memory for gcrypt private key"); + savederrno = ENOMEM; + goto out_err; + } + memmove(gcryptcrypto_instance->private_key, knet_handle_crypto_cfg->private_key, knet_handle_crypto_cfg->private_key_len); + + if (strcmp(knet_handle_crypto_cfg->crypto_cipher_type, "none") == 0) { + gcryptcrypto_instance->crypto_cipher_type = 0; + } else { + gcryptcrypto_instance->crypto_cipher_type = gcry_cipher_map_name(knet_handle_crypto_cfg->crypto_cipher_type); + if (!gcryptcrypto_instance->crypto_cipher_type) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "unknown crypto cipher type requested"); + savederrno = EINVAL; + goto out_err; + } + if (gcry_cipher_test_algo(gcryptcrypto_instance->crypto_cipher_type)) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "requested crypto cipher type not available for use"); + savederrno = EINVAL; + goto out_err; + } + if (gcry_cipher_get_algo_keylen(gcryptcrypto_instance->crypto_cipher_type) < knet_handle_crypto_cfg->private_key_len) { + log_warn(knet_h, KNET_SUB_GCRYPTCRYPTO, "requested crypto cipher key len (%u) too big (max: %zu)", + knet_handle_crypto_cfg->private_key_len, gcry_cipher_get_algo_keylen(gcryptcrypto_instance->crypto_cipher_type)); + gcryptcrypto_instance->crypt_private_key_len = gcry_cipher_get_algo_keylen(gcryptcrypto_instance->crypto_cipher_type); + } else { + gcryptcrypto_instance->crypt_private_key_len = knet_handle_crypto_cfg->private_key_len; + } + + } + + if (strcmp(knet_handle_crypto_cfg->crypto_hash_type, "none") == 0) { + gcryptcrypto_instance->crypto_hash_type = 0; + } else { + if (!strncasecmp(knet_handle_crypto_cfg->crypto_hash_type, "HMAC_", strlen("HMAC_"))) { + strncpy(remap_hash_type, knet_handle_crypto_cfg->crypto_hash_type, sizeof(remap_hash_type) - 1); + } else { + snprintf(remap_hash_type, sizeof(remap_hash_type) - 1, "%s%s", "HMAC_", knet_handle_crypto_cfg->crypto_hash_type); + } + gcryptcrypto_instance->crypto_hash_type = gcry_mac_map_name(remap_hash_type); + if (!gcryptcrypto_instance->crypto_hash_type) { + savederrno = EINVAL; + goto out_err; + } + if (gcry_mac_test_algo(gcryptcrypto_instance->crypto_hash_type)) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "requested crypto hash type not available for use"); + savederrno = EINVAL; + goto out_err; + } + gcryptcrypto_instance->hash_private_key_len = knet_handle_crypto_cfg->private_key_len; + } + + if ((gcryptcrypto_instance->crypto_cipher_type) && + (!gcryptcrypto_instance->crypto_hash_type)) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "crypto communication requires hash specified"); + savederrno = EINVAL; + goto out_err; + } + + if (gcryptcrypto_instance->crypto_hash_type) { + crypto_instance->sec_hash_size = gcry_mac_get_algo_maclen(gcryptcrypto_instance->crypto_hash_type); + if (!crypto_instance->sec_hash_size) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "unable to gather hash digest size"); + savederrno = EINVAL; + goto out_err; + } + } + + if (gcryptcrypto_instance->crypto_cipher_type) { + size_t block_size; + + block_size = gcry_cipher_get_algo_blklen(gcryptcrypto_instance->crypto_cipher_type); + if (!block_size) { + log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "unable to gather cipher blocksize"); + savederrno = EINVAL; + goto out_err; + } + + crypto_instance->sec_salt_size = SALT_SIZE; + crypto_instance->sec_block_size = block_size; + } + + return 0; + +out_err: + gcryptcrypto_fini(knet_h, crypto_instance); + + errno = savederrno; + return -1; +} + +crypto_ops_t crypto_model = { + KNET_CRYPTO_MODEL_ABI, + gcryptcrypto_init, + gcryptcrypto_fini, + gcryptcrypto_encrypt_and_sign, + gcryptcrypto_encrypt_and_signv, + gcryptcrypto_authenticate_and_decrypt +}; diff --git a/libknet/libknet.h b/libknet/libknet.h index ce76ef41..d5d5e833 100644 --- a/libknet/libknet.h +++ b/libknet/libknet.h @@ -1,2456 +1,2457 @@ /* * Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under LGPL-2.0+ */ #ifndef __LIBKNET_H__ #define __LIBKNET_H__ #include #include #include #include #include /** * @file libknet.h * @brief kronosnet API include file * @copyright Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved. * * Kronosnet is an advanced VPN system for High Availability applications. */ #define KNET_API_VER 2 /* * libknet limits */ /* * Maximum number of hosts */ typedef uint16_t knet_node_id_t; #define KNET_MAX_HOST 65536 /* * Maximum number of links between 2 hosts */ #define KNET_MAX_LINK 8 /* * Maximum packet size that should be written to datafd * see knet_handle_new for details */ #define KNET_MAX_PACKET_SIZE 65536 /* * Buffers used for pretty logging * host is used to store both ip addresses and hostnames */ #define KNET_MAX_HOST_LEN 256 #define KNET_MAX_PORT_LEN 6 /* * Some notifications can be generated either on TX or RX */ #define KNET_NOTIFY_TX 0 #define KNET_NOTIFY_RX 1 /* * Link flags */ /* * Where possible, set traffic priority to high. * On Linux this sets the TOS to INTERACTIVE (6), * see tc-prio(8) for more infomation */ #define KNET_LINK_FLAG_TRAFFICHIPRIO (1ULL << 0) /* * Handle flags */ /* * Use privileged operations during socket setup. */ #define KNET_HANDLE_FLAG_PRIVILEGED (1ULL << 0) /* * threads timer resolution (see knet_handle_set_threads_timer_res below) */ #define KNET_THREADS_TIMER_RES 200000 typedef struct knet_handle *knet_handle_t; /* * Handle structs/API calls */ /** * knet_handle_new * * @brief create a new instance of a knet handle * * host_id - Each host in a knet is identified with a unique * ID. when creating a new handle local host_id * must be specified (0 to UINT16_MAX are all valid). * It is the user's responsibility to check that the value * is unique, or bad things might happen. * * log_fd - Write file descriptor. If set to a value > 0, it will be used * to write log packets from libknet to the application. * Setting to 0 will disable logging from libknet. * It is possible to enable logging at any given time (see logging API). * Make sure to either read from this filedescriptor properly and/or * mark it O_NONBLOCK, otherwise if the fd becomes full, libknet could * block. * It is strongly encouraged to use pipes (ex: pipe(2) or pipe2(2)) for * logging fds due to the atomic nature of writes between fds. * See also libknet test suite for reference and guidance. * * default_log_level - * If logfd is specified, it will initialize all subsystems to log * at default_log_level value. (see logging API) * * flags - bitwise OR of some of the following flags: * KNET_HANDLE_FLAG_PRIVILEGED: use privileged operations setting up the * communication sockets. If disabled, failure to acquire large * enough socket buffers is ignored but logged. Inadequate buffers * lead to poor performance. * * @return * on success, a new knet_handle_t is returned. * on failure, NULL is returned and errno is set. * knet-specific errno values: * ENAMETOOLONG - socket buffers couldn't be set big enough and KNET_HANDLE_FLAG_PRIVILEGED was specified * ERANGE - buffer size readback returned unexpected type */ knet_handle_t knet_handle_new(knet_node_id_t host_id, int log_fd, uint8_t default_log_level, uint64_t flags); /** * knet_handle_free * * @brief Destroy a knet handle, free all resources * * knet_h - pointer to knet_handle_t * * @return * knet_handle_free returns * 0 on success * -1 on error and errno is set. */ int knet_handle_free(knet_handle_t knet_h); /** * knet_handle_set_threads_timer_res * * @brief Change internal thread timer resolution * * knet_h - pointer to knet_handle_t * * timeres - some threads inside knet will use usleep(timeres) * to check if any activity has to be performed, or wait * for the next cycle. 'timeres' (expressed in nano seconds) * defines this interval, with a default of KNET_THREADS_TIMER_RES * (200000). * The lower this value is, the more often knet will perform * those checks and allows a more (time) precise execution of * some operations (for example ping/pong), at the cost of higher * CPU usage. * Accepted values: * 0 - reset timer res to default * 1 - 999 invalid (as it would cause 100% CPU spinning on some * epoll operations) * 1000 or higher - valid * * Unless you know exactly what you are doing, stay away from * changing the default or seek written and notarized approval * from the knet developer team. * * @return * knet_handle_set_threads_timer_res returns * 0 on success * -1 on error and errno is set. */ int knet_handle_set_threads_timer_res(knet_handle_t knet_h, useconds_t timeres); /** * knet_handle_get_threads_timer_res * * @brief Get internal thread timer resolutions * * knet_h - pointer to knet_handle_t * * timeres - current timer res value * * @return * knet_handle_set_threads_timer_res returns * 0 on success and timerres will contain the current value * -1 on error and errno is set. */ int knet_handle_get_threads_timer_res(knet_handle_t knet_h, useconds_t *timeres); /** * knet_handle_enable_sock_notify * * @brief Register a callback to receive socket events * * knet_h - pointer to knet_handle_t * * sock_notify_fn_private_data * void pointer to data that can be used to identify * the callback. * * sock_notify_fn * A callback function that is invoked every time * a socket in the datafd pool will report an error (-1) * or an end of read (0) (see socket.7). * This function MUST NEVER block or add substantial delays. * The callback is invoked in an internal unlocked area * to allow calls to knet_handle_add_datafd/knet_handle_remove_datafd * to swap/replace the bad fd. * if both err and errno are 0, it means that the socket * has received a 0 byte packet (EOF?). * The callback function must either remove the fd from knet * (by calling knet_handle_remove_fd()) or dup a new fd in its place. * Failure to do this can cause problems. * * @return * knet_handle_enable_sock_notify returns * 0 on success * -1 on error and errno is set. */ int knet_handle_enable_sock_notify(knet_handle_t knet_h, void *sock_notify_fn_private_data, void (*sock_notify_fn) ( void *private_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno)); /* sorry! can't call it errno ;) */ #define KNET_DATAFD_MAX 32 /** * knet_handle_add_datafd * * @brief Install a file descriptor for communication * * IMPORTANT: In order to add datafd to knet, knet_handle_enable_sock_notify * _MUST_ be set and be able to handle both errors (-1) and * 0 bytes read / write from the provided datafd. * On read error (< 0) from datafd, the socket is automatically * removed from polling to avoid spinning on dead sockets. * It is safe to call knet_handle_remove_datafd even on sockets * that have been removed. * * knet_h - pointer to knet_handle_t * * *datafd - read/write file descriptor. * knet will read data here to send to the other hosts * and will write data received from the network. * Each data packet can be of max size KNET_MAX_PACKET_SIZE! * Applications using knet_send/knet_recv will receive a * proper error if the packet size is not within boundaries. * Applications using their own functions to write to the * datafd should NOT write more than KNET_MAX_PACKET_SIZE. * * Please refer to handle.c on how to set up a socketpair. * * datafd can be 0, and knet_handle_add_datafd will create a properly * populated socket pair the same way as ping_test, or a value * higher than 0. A negative number will return an error. * On exit knet_handle_free will take care to cleanup the * socketpair only if they have been created by knet_handle_add_datafd. * * It is possible to pass either sockets or normal fds. * User provided datafd will be marked as non-blocking and close-on-exec. * * *channel - This value is analogous to the tag in VLAN tagging. * A negative value will auto-allocate a channel. * Setting a value between 0 and 31 will try to allocate that * specific channel (unless already in use). * * It is possible to add up to 32 datafds but be aware that each * one of them must have a receiving end on the other host. * * Example: * hostA channel 0 will be delivered to datafd on hostB channel 0 * hostA channel 1 to hostB channel 1. * * Each channel must have a unique file descriptor. * * If your application could have 2 channels on one host and one * channel on another host, then you can use dst_host_filter * to manipulate channel values on TX and RX. * * @return * knet_handle_add_datafd returns * @retval 0 on success, * *datafd will be populated with a socket if the original value was 0 * or if a specific fd was set, the value is untouched. * *channel will be populated with a channel number if the original value * was negative or the value is untouched if a specific channel * was requested. * * @retval -1 on error and errno is set. * *datafd and *channel are untouched or empty. */ int knet_handle_add_datafd(knet_handle_t knet_h, int *datafd, int8_t *channel); /** * knet_handle_remove_datafd * * @brief Remove a file descriptor from knet * * knet_h - pointer to knet_handle_t * * datafd - file descriptor to remove. * NOTE that if the socket/fd was created by knet_handle_add_datafd, * the socket will be closed by libknet. * * @return * knet_handle_remove_datafd returns * 0 on success * -1 on error and errno is set. */ int knet_handle_remove_datafd(knet_handle_t knet_h, int datafd); /** * knet_handle_get_channel * * @brief Get the channel associated with a file descriptor * * knet_h - pointer to knet_handle_t * * datafd - get the channel associated to this datafd * * *channel - will contain the result * * @return * knet_handle_get_channel returns * @retval 0 on success * and *channel will contain the result * @retval -1 on error and errno is set. * and *channel content is meaningless */ int knet_handle_get_channel(knet_handle_t knet_h, const int datafd, int8_t *channel); /** * knet_handle_get_datafd * * @brief Get the file descriptor associated with a channel * * knet_h - pointer to knet_handle_t * * channel - get the datafd associated to this channel * * *datafd - will contain the result * * @return * knet_handle_get_datafd returns * @retval 0 on success * and *datafd will contain the results * @retval -1 on error and errno is set. * and *datafd content is meaningless */ int knet_handle_get_datafd(knet_handle_t knet_h, const int8_t channel, int *datafd); /** * knet_recv * * @brief Receive data from knet nodes * * knet_h - pointer to knet_handle_t * * buff - pointer to buffer to store the received data * * buff_len - buffer length * * channel - channel number * * @return * knet_recv is a commodity function to wrap iovec operations * around a socket. It returns a call to readv(2). */ ssize_t knet_recv(knet_handle_t knet_h, char *buff, const size_t buff_len, const int8_t channel); /** * knet_send * * @brief Send data to knet nodes * * knet_h - pointer to knet_handle_t * * buff - pointer to the buffer of data to send * * buff_len - length of data to send * * channel - channel number * * @return * knet_send is a commodity function to wrap iovec operations * around a socket. It returns a call to writev(2). */ ssize_t knet_send(knet_handle_t knet_h, const char *buff, const size_t buff_len, const int8_t channel); /** * knet_send_sync * * @brief Synchronously send data to knet nodes * * knet_h - pointer to knet_handle_t * * buff - pointer to the buffer of data to send * * buff_len - length of data to send * * channel - data channel to use (see knet_handle_add_datafd(3)) * * All knet RX/TX operations are async for performance reasons. * There are applications that might need a sync version of data * transmission and receive errors in case of failure to deliver * to another host. * knet_send_sync bypasses the whole TX async layer and delivers * data directly to the link layer, and returns errors accordingly. * knet_send_sync sends only one packet to one host at a time. * It does NOT support multiple destinations or multicast packets. * Decision is still based on dst_host_filter_fn. * * @return * knet_send_sync returns 0 on success and -1 on error. * In addition to normal sendmmsg errors, knet_send_sync can fail * due to: * * @retval ECANCELED - data forward is disabled * @retval EFAULT - dst_host_filter fatal error * @retval EINVAL - dst_host_filter did not provide dst_host_ids_entries on unicast pckts * @retval E2BIG - dst_host_filter did return more than one dst_host_ids_entries on unicast pckts * @retval ENOMSG - received unknown message type * @retval EHOSTDOWN - unicast pckt cannot be delivered because dest host is not connected yet * @retval ECHILD - crypto failed * @retval EAGAIN - sendmmsg was unable to send all messages and there was no progress during retry */ int knet_send_sync(knet_handle_t knet_h, const char *buff, const size_t buff_len, const int8_t channel); /** * knet_handle_enable_filter * * @brief install a filter to route packets * * knet_h - pointer to knet_handle_t * * dst_host_filter_fn_private_data * void pointer to data that can be used to identify * the callback. * * dst_host_filter_fn - * is a callback function that is invoked every time * a packet hits datafd (see knet_handle_new(3)). * the function allows users to tell libknet where the * packet has to be delivered. * * const unsigned char *outdata - is a pointer to the * current packet * ssize_t outdata_len - length of the above data * uint8_t tx_rx - filter is called on tx or rx * (KNET_NOTIFY_TX, KNET_NOTIFY_RX) * knet_node_id_t this_host_id - host_id processing the packet * knet_node_id_t src_host_id - host_id that generated the * packet * knet_node_id_t *dst_host_ids - array of KNET_MAX_HOST knet_node_id_t * where to store the destinations * size_t *dst_host_ids_entries - number of hosts to send the message * * dst_host_filter_fn should return * -1 on error, packet is discarded. * 0 packet is unicast and should be sent to dst_host_ids and there are * dst_host_ids_entries in the buffer. * 1 packet is broadcast/multicast and is sent all hosts. * contents of dst_host_ids and dst_host_ids_entries are ignored. * * @return * knet_handle_enable_filter returns * 0 on success * -1 on error and errno is set. */ int knet_handle_enable_filter(knet_handle_t knet_h, void *dst_host_filter_fn_private_data, int (*dst_host_filter_fn) ( void *private_data, const unsigned char *outdata, ssize_t outdata_len, uint8_t tx_rx, knet_node_id_t this_host_id, knet_node_id_t src_host_id, int8_t *channel, knet_node_id_t *dst_host_ids, size_t *dst_host_ids_entries)); /** * knet_handle_setfwd * * @brief Start packet forwarding * * knet_h - pointer to knet_handle_t * * enable - set to 1 to allow data forwarding, 0 to disable data forwarding. * * @return * knet_handle_setfwd returns * 0 on success * -1 on error and errno is set. * * By default data forwarding is off and no traffic will pass through knet until * it is set on. */ int knet_handle_setfwd(knet_handle_t knet_h, unsigned int enabled); /** * knet_handle_enable_access_lists * * @brief Enable or disable usage of access lists (default: off) * * knet_h - pointer to knet_handle_t * * enable - set to 1 to use access lists, 0 to disable access_lists. * * @return * knet_handle_enable_access_lists returns * 0 on success * -1 on error and errno is set. * * access lists are bound to links. There are 2 types of links: * 1) point to point, where both source and destinations are well known * at configuration time. * 2) open links, where only the source is known at configuration time. * * knet will automatically generate access lists for point to point links. * * For open links, knet provides 4 API calls to manipulate access lists: * knet_link_add_acl(3), knet_link_rm_acl(3), knet_link_insert_acl(3) * and knet_link_clear_acl(3). * Those API calls will work exclusively on open links as they * are of no use on point to point links. * * knet will not enforce any access list unless specifically enabled by * knet_handle_enable_access_lists(3). * * From a security / programming perspective we recommend: * - create the knet handle * - enable access lists * - configure hosts and links * - configure access lists for open links */ int knet_handle_enable_access_lists(knet_handle_t knet_h, unsigned int enabled); #define KNET_PMTUD_DEFAULT_INTERVAL 60 /** * knet_handle_pmtud_setfreq * * @brief Set the interval between PMTUd scans * * knet_h - pointer to knet_handle_t * * interval - define the interval in seconds between PMTUd scans * range from 1 to 86400 (24h) * * @return * knet_handle_pmtud_setfreq returns * 0 on success * -1 on error and errno is set. * * default interval is 60. */ int knet_handle_pmtud_setfreq(knet_handle_t knet_h, unsigned int interval); /** * knet_handle_pmtud_getfreq * * @brief Get the interval between PMTUd scans * * knet_h - pointer to knet_handle_t * * interval - pointer where to store the current interval value * * @return * knet_handle_pmtud_setfreq returns * 0 on success * -1 on error and errno is set. */ int knet_handle_pmtud_getfreq(knet_handle_t knet_h, unsigned int *interval); /** * knet_handle_enable_pmtud_notify * * @brief install a callback to receive PMTUd changes * * knet_h - pointer to knet_handle_t * * pmtud_notify_fn_private_data * void pointer to data that can be used to identify * the callback. * * pmtud_notify_fn * is a callback function that is invoked every time * a path MTU size change is detected. * The function allows libknet to notify the user * of data MTU, that's the max value that can be send * onwire without fragmentation. The data MTU will always * be lower than real link MTU because it accounts for * protocol overhead, knet packet header and (if configured) * crypto overhead, * This function MUST NEVER block or add substantial delays. * * @return * knet_handle_enable_pmtud_notify returns * 0 on success * -1 on error and errno is set. */ int knet_handle_enable_pmtud_notify(knet_handle_t knet_h, void *pmtud_notify_fn_private_data, void (*pmtud_notify_fn) ( void *private_data, unsigned int data_mtu)); /** * knet_handle_pmtud_set * * @brief Set the current interface MTU * * knet_h - pointer to knet_handle_t * * iface_mtu - current interface MTU, value 0 to 65535. 0 will * re-enable automatic MTU discovery. * In a setup with multiple interfaces, please specify * the lowest MTU between the selected intefaces. * knet will automatically adjust this value for * all headers overhead and set the correct data_mtu. * data_mtu can be retrivied with knet_handle_pmtud_get(3) * or applications will receive a pmtud_notify event * if enabled via knet_handle_enable_pmtud_notify(3). * * @return * knet_handle_pmtud_set returns * 0 on success * -1 on error and errno is set. */ int knet_handle_pmtud_set(knet_handle_t knet_h, unsigned int iface_mtu); /** * knet_handle_pmtud_get * * @brief Get the current data MTU * * knet_h - pointer to knet_handle_t * * data_mtu - pointer where to store data_mtu * * @return * knet_handle_pmtud_get returns * 0 on success * -1 on error and errno is set. */ int knet_handle_pmtud_get(knet_handle_t knet_h, unsigned int *data_mtu); #define KNET_MIN_KEY_LEN 128 #define KNET_MAX_KEY_LEN 4096 struct knet_handle_crypto_cfg { char crypto_model[16]; char crypto_cipher_type[16]; char crypto_hash_type[16]; unsigned char private_key[KNET_MAX_KEY_LEN]; unsigned int private_key_len; }; /** * knet_handle_crypto_set_config * * @brief set up packet cryptographic signing & encryption * * knet_h - pointer to knet_handle_t * * knet_handle_crypto_cfg - * pointer to a knet_handle_crypto_cfg structure * * crypto_model should contain the model name. - * Currently only "openssl" and "nss" are supported. + * Currently "openssl", "nss" and "gcrypt" are supported. * Setting to "none" will disable crypto. * * crypto_cipher_type * should contain the cipher algo name. * It can be set to "none" to disable * encryption. * Currently supported by "nss" model: * "aes128", "aes192" and "aes256". * "openssl" model supports more modes and it strictly * depends on the openssl build. See: EVP_get_cipherbyname * openssl API call for details. * * crypto_hash_type * should contain the hashing algo name. * It can be set to "none" to disable * hashing. * Currently supported by "nss" model: * "md5", "sha1", "sha256", "sha384" and "sha512". * "openssl" model supports more modes and it strictly * depends on the openssl build. See: EVP_get_digestbyname * openssl API call for details. * * private_key will contain the private shared key. * It has to be at least KNET_MIN_KEY_LEN long. * * private_key_len * length of the provided private_key. * * config_num - knet supports 2 concurrent sets of crypto configurations, * to allow runtime change of crypto config and keys. * On RX both configurations will be used sequentially * in an attempt to decrypt/validate a packet (when 2 are available). * Note that this might slow down performance during a reconfiguration. * See also knet_handle_crypto_rx_clear_traffic(3) to enable / disable * processing of clear (unencrypted) traffic. * For TX, the user needs to specify which configuration to use via * knet_handle_crypto_use_config(3). * config_num accepts 0, 1 or 2 as the value. 0 should be used when * all crypto is being disabled. * Calling knet_handle_crypto_set_config(3) twice with * the same config_num will REPLACE the configuration and * NOT activate the second key. If the configuration is currently in use * EBUSY will be returned. See also knet_handle_crypto_use_config(3). * The correct sequence to perform a runtime rekey / reconfiguration * is: * - knet_handle_crypto_set_config(..., 1). -> first time config, will use config1 * - knet_handle_crypto_use_config(..., 1). -> switch TX to config 1 * - knet_handle_crypto_set_config(..., 2). -> install config2 and use it only for RX * - knet_handle_crypto_use_config(..., 2). -> switch TX to config 2 * - knet_handle_crypto_set_config(..., 1). -> with a "none"/"none"/"none" configuration to * release the resources previously allocated * The application is responsible for synchronizing calls on the nodes * to make sure the new config is in place before switching the TX configuration. * Failure to do so will result in knet being unable to talk to some of the nodes. * * Implementation notes/current limitations: * - enabling crypto, will increase latency as packets have * to processed. * - enabling crypto might reduce the overall throughtput * due to crypto data overhead. * - private/public key encryption/hashing is not currently * planned. * - crypto key must be the same for all hosts in the same * knet instance / configX. * - it is safe to call knet_handle_crypto_set_config multiple times at runtime. * The last config will be used. * IMPORTANT: a call to knet_handle_crypto_set_config can fail due to: * 1) failure to obtain locking * 2) errors to initializing the crypto level. * This can happen even in subsequent calls to knet_handle_crypto_set_config(3). * A failure in crypto init will restore the previous crypto configuration if any. * * @return * knet_handle_crypto_set_config returns: * @retval 0 on success * @retval -1 on error and errno is set. * @retval -2 on crypto subsystem initialization error. No errno is provided at the moment (yet). */ int knet_handle_crypto_set_config(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg, uint8_t config_num); #define KNET_CRYPTO_RX_ALLOW_CLEAR_TRAFFIC 0 #define KNET_CRYPTO_RX_DISALLOW_CLEAR_TRAFFIC 1 /** * knet_handle_crypto_rx_clear_traffic * * @brief enable or disable RX processing of clear (unencrypted) traffic * * knet_h - pointer to knet_handle_t * * value - KNET_CRYPTO_RX_ALLOW_CLEAR_TRAFFIC or KNET_CRYPTO_RX_DISALLOW_CLEAR_TRAFFIC * * @return * knet_handle_crypto_use_config returns: * @retval 0 on success * @retval -1 on error and errno is set. */ int knet_handle_crypto_rx_clear_traffic(knet_handle_t knet_h, uint8_t value); /** * knet_handle_crypto_use_config * * @brief specify crypto configuration to use for TX * * knet_h - pointer to knet_handle_t * * config_num - 1|2 use configuration 1 or 2, 0 for clear (unencrypted) traffic. * * @return * knet_handle_crypto_use_config returns: * @retval 0 on success * @retval -1 on error and errno is set. */ int knet_handle_crypto_use_config(knet_handle_t knet_h, uint8_t config_num); #define KNET_COMPRESS_THRESHOLD 100 struct knet_handle_compress_cfg { char compress_model[16]; uint32_t compress_threshold; int compress_level; }; /** * knet_handle_compress * * @brief Set up packet compression * * knet_h - pointer to knet_handle_t * * knet_handle_compress_cfg - * pointer to a knet_handle_compress_cfg structure * * compress_model contains the model name. * See "compress_level" for the list of accepted values. * Setting the value to "none" disables compression. * * compress_threshold * tells the transmission thread to NOT compress * any packets that are smaller than the value * indicated. Default 100 bytes. * Set to 0 to reset to the default. * Set to 1 to compress everything. * Max accepted value is KNET_MAX_PACKET_SIZE. * * compress_level is the "level" parameter for most models: * zlib: 0 (no compression), 1 (minimal) .. 9 (max compression). * lz4: 1 (max compression)... 9 (fastest compression). * lz4hc: 1 (min compression) ... LZ4HC_MAX_CLEVEL (16) or LZ4HC_CLEVEL_MAX (12) * depending on the version of lz4hc libknet was built with. * lzma: 0 (minimal) .. 9 (max compression) * bzip2: 1 (minimal) .. 9 (max compression) * For lzo2 it selects the algorithm to use: * 1 : lzo1x_1_compress (default) * 11 : lzo1x_1_11_compress * 12 : lzo1x_1_12_compress * 15 : lzo1x_1_15_compress * 999: lzo1x_999_compress * Other values select the default algorithm. * Please refer to the documentation of the respective * compression library for guidance about setting this * value. * * Implementation notes: * - it is possible to enable/disable compression at any time. * - nodes can be using a different compression algorithm at any time. * - knet does NOT implement the compression algorithm directly. it relies * on external libraries for this functionality. Please read * the libraries man pages to figure out which algorithm/compression * level is best for the data you are planning to transmit. * * @return * knet_handle_compress returns * 0 on success * -1 on error and errno is set. EINVAL means that either the model or the * level are not supported. */ int knet_handle_compress(knet_handle_t knet_h, struct knet_handle_compress_cfg *knet_handle_compress_cfg); struct knet_handle_stats { size_t size; uint64_t tx_uncompressed_packets; uint64_t tx_compressed_packets; uint64_t tx_compressed_original_bytes; uint64_t tx_compressed_size_bytes; uint64_t tx_compress_time_ave; uint64_t tx_compress_time_min; uint64_t tx_compress_time_max; uint64_t tx_failed_to_compress; uint64_t tx_unable_to_compress; uint64_t rx_compressed_packets; uint64_t rx_compressed_original_bytes; uint64_t rx_compressed_size_bytes; uint64_t rx_compress_time_ave; uint64_t rx_compress_time_min; uint64_t rx_compress_time_max; uint64_t rx_failed_to_decompress; /* Overhead times, measured in usecs */ uint64_t tx_crypt_packets; uint64_t tx_crypt_byte_overhead; uint64_t tx_crypt_time_ave; uint64_t tx_crypt_time_min; uint64_t tx_crypt_time_max; uint64_t rx_crypt_packets; uint64_t rx_crypt_time_ave; uint64_t rx_crypt_time_min; uint64_t rx_crypt_time_max; }; /** * knet_handle_get_stats * * @brief Get statistics for compression & crypto * * knet_h - pointer to knet_handle_t * * knet_handle_stats * pointer to a knet_handle_stats structure * * struct_size * size of knet_handle_stats structure to allow * for backwards compatibility. libknet will only * copy this much data into the stats structure * so that older callers will not get overflowed if * new fields are added. * * @return * 0 on success * -1 on error and errno is set. * */ int knet_handle_get_stats(knet_handle_t knet_h, struct knet_handle_stats *stats, size_t struct_size); /* * Tell knet_handle_clear_stats whether to clear just the handle stats * or all of them. */ #define KNET_CLEARSTATS_HANDLE_ONLY 1 #define KNET_CLEARSTATS_HANDLE_AND_LINK 2 /** * knet_handle_clear_stats * * @brief Clear knet stats, link and/or handle * * knet_h - pointer to knet_handle_t * * clear_option - Which stats to clear, must be one of * * KNET_CLEARSTATS_HANDLE_ONLY or * KNET_CLEARSTATS_HANDLE_AND_LINK * * @return * 0 on success * -1 on error and errno is set. * */ int knet_handle_clear_stats(knet_handle_t knet_h, int clear_option); struct knet_crypto_info { const char *name; /* openssl,nss,etc.. */ uint8_t properties; /* currently unused */ char pad[256]; /* currently unused */ }; /** * knet_get_crypto_list * * @brief Get a list of supported crypto libraries * * crypto_list - array of struct knet_crypto_info * * If NULL then only the number of structs is returned in crypto_list_entries * to allow the caller to allocate sufficient space. * libknet does not allow more than 256 crypto methods at the moment. * it is safe to allocate 256 structs to avoid calling * knet_get_crypto_list twice. * * crypto_list_entries - returns the number of structs in crypto_list * * @return * knet_get_crypto_list returns * 0 on success * -1 on error and errno is set. */ int knet_get_crypto_list(struct knet_crypto_info *crypto_list, size_t *crypto_list_entries); struct knet_compress_info { const char *name; /* bzip2, lz4, etc.. */ uint8_t properties; /* currently unused */ char pad[256]; /* currently unused */ }; /** * knet_get_compress_list * * @brief Get a list of support compression types * * compress_list - array of struct knet_compress_info * * If NULL then only the number of structs is returned in compress_list_entries * to allow the caller to allocate sufficient space. * libknet does not allow more than 256 compress methods at the moment. * it is safe to allocate 256 structs to avoid calling * knet_get_compress_list twice. * * compress_list_entries - returns the number of structs in compress_list * * @return * knet_get_compress_list returns * 0 on success * -1 on error and errno is set. */ int knet_get_compress_list(struct knet_compress_info *compress_list, size_t *compress_list_entries); /** * knet_handle_enable_onwire_ver_notify * * @brief install a callback to receive onwire changes * * knet_h - pointer to knet_handle_t * * onwire_ver_notify_fn_private_data * void pointer to data that can be used to identify * the callback. * * onwire_ver_notify_fn * is a callback function that is invoked every time * an onwire version change is detected. * The function allows libknet to notify the user * of onwire version changes. * onwire_min_ver - minimum onwire version supported * onwire_max_ver - maximum onwire version supported * onwire_ver - currently onwire version in use * This function MUST NEVER block or add substantial delays. * * NOTE: the callback function will be invoked upon install to * immediately notify the user of the current configuration. * During startup, it is safer to use onwire_min_ver and * onwire_ver on subsequent calls. * * @return * knet_handle_enable_onwire_ver_notify returns * 0 on success * -1 on error and errno is set. */ int knet_handle_enable_onwire_ver_notify(knet_handle_t knet_h, void *onwire_ver_notify_fn_private_data, void (*onwire_ver_notify_fn) ( void *private_data, uint8_t onwire_min_ver, uint8_t onwire_max_ver, uint8_t onwire_ver)); /** * knet_handle_get_onwire_ver * * @brief get onwire protocol version information * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * onwire_min_ver - minimum onwire version supported by local node. * this value is set to 0 for remote nodes. * * onwire_max_ver - maximum onwire version supported by local or * remote node. * * onwire_ver - currently onwire version in use by local or * remote node. * * @return * knet_handle_get_onwire_ver returns * 0 on success * -1 on error and errno is set. */ int knet_handle_get_onwire_ver(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t *onwire_min_ver, uint8_t *onwire_max_ver, uint8_t *onwire_ver); /** * knet_handle_set_onwire_ver * * @brief force onwire protocol version * * knet_h - pointer to knet_handle_t * * onwire_ver - onwire version to use. * reset to 0 to allow knet to detect * automatically the highest version. * * @return * knet_handle_get_onwire_ver returns * 0 on success * -1 on error and errno is set. */ int knet_handle_set_onwire_ver(knet_handle_t knet_h, uint8_t onwire_ver); /* * host structs/API calls */ /** * knet_host_add * * @brief Add a new host ID to knet * * knet_h - pointer to knet_handle_t * * host_id - each host in a knet is identified with a unique ID * (see also knet_handle_new(3)) * * @return * knet_host_add returns: * 0 on success * -1 on error and errno is set. */ int knet_host_add(knet_handle_t knet_h, knet_node_id_t host_id); /** * knet_host_remove * * @brief Remove a host ID from knet * * knet_h - pointer to knet_handle_t * * host_id - each host in a knet is identified with a unique ID * (see also knet_handle_new(3)) * * @return * knet_host_remove returns: * 0 on success * -1 on error and errno is set. */ int knet_host_remove(knet_handle_t knet_h, knet_node_id_t host_id); /** * knet_host_set_name * * @brief Set the name of a knet host * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * name - this name will be used for pretty logging and eventually * search for hosts (see also knet_handle_host_get_name(2) and knet_handle_host_get_id(3)). * Only up to KNET_MAX_HOST_LEN - 1 bytes will be accepted and * name has to be unique for each host. * * @return * knet_host_set_name returns: * 0 on success * -1 on error and errno is set. */ int knet_host_set_name(knet_handle_t knet_h, knet_node_id_t host_id, const char *name); /** * knet_host_get_name_by_host_id * * @brief Get the name of a host given its ID * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * name - pointer to a preallocated buffer of at least size KNET_MAX_HOST_LEN * where the current host name will be stored * (as set by knet_host_set_name or default by knet_host_add) * * @return * knet_host_get_name_by_host_id returns: * 0 on success * -1 on error and errno is set (name is left untouched) */ int knet_host_get_name_by_host_id(knet_handle_t knet_h, knet_node_id_t host_id, char *name); /** * knet_host_get_id_by_host_name * * @brief Get the ID of a host given its name * * knet_h - pointer to knet_handle_t * * name - name to lookup, max len KNET_MAX_HOST_LEN * * host_id - where to store the result * * @return * knet_host_get_id_by_host_name returns: * 0 on success * -1 on error and errno is set. */ int knet_host_get_id_by_host_name(knet_handle_t knet_h, const char *name, knet_node_id_t *host_id); /** * knet_host_get_host_list * * @brief Get a list of hosts known to knet * * knet_h - pointer to knet_handle_t * * host_ids - array of at lest KNET_MAX_HOST size * * host_ids_entries - * number of entries writted in host_ids * * @return * knet_host_get_host_list returns * 0 on success * -1 on error and errno is set. */ int knet_host_get_host_list(knet_handle_t knet_h, knet_node_id_t *host_ids, size_t *host_ids_entries); /* * define switching policies */ #define KNET_LINK_POLICY_PASSIVE 0 #define KNET_LINK_POLICY_ACTIVE 1 #define KNET_LINK_POLICY_RR 2 /** * knet_host_set_policy * * @brief Set the switching policy for a host's links * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * policy - there are currently 3 kind of simple switching policies * based on link configuration. * KNET_LINK_POLICY_PASSIVE - the active link with the highest * priority (highest number) will be used. * if one or more active links share * the same priority, the one with * lowest link_id will be used. * * KNET_LINK_POLICY_ACTIVE - all active links will be used * simultaneously to send traffic. * link priority is ignored. * * KNET_LINK_POLICY_RR - round-robin policy, every packet * will be send on a different active * link. * * @return * knet_host_set_policy returns * 0 on success * -1 on error and errno is set. */ int knet_host_set_policy(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t policy); /** * knet_host_get_policy * * @brief Get the switching policy for a host's links * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * policy - will contain the current configured switching policy. * Default is passive when creating a new host. * * @return * knet_host_get_policy returns * 0 on success * -1 on error and errno is set. */ int knet_host_get_policy(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t *policy); /** * knet_host_enable_status_change_notify * * @brief Install a callback to get host status change events * * knet_h - pointer to knet_handle_t * * host_status_change_notify_fn_private_data - * void pointer to data that can be used to identify * the callback * * host_status_change_notify_fn - * is a callback function that is invoked every time * there is a change in the host status. * host status is identified by: * - reachable, this host can send/receive data to/from host_id * - remote, 0 if the host_id is connected locally or 1 if * the there is one or more knet host(s) in between. * NOTE: re-switching is NOT currently implemented, * but this is ready for future and can avoid * an API/ABI breakage later on. * - external, 0 if the host_id is configured locally or 1 if * it has been added from remote nodes config. * NOTE: dynamic topology is NOT currently implemented, * but this is ready for future and can avoid * an API/ABI breakage later on. * This function MUST NEVER block or add substantial delays. * * @return * knet_host_status_change_notify returns * 0 on success * -1 on error and errno is set. */ int knet_host_enable_status_change_notify(knet_handle_t knet_h, void *host_status_change_notify_fn_private_data, void (*host_status_change_notify_fn) ( void *private_data, knet_node_id_t host_id, uint8_t reachable, uint8_t remote, uint8_t external)); /* * define host status structure for quick lookup * struct is in flux as more stats will be added soon * * reachable host_id can be seen either directly connected * or via another host_id * * remote 0 = node is connected locally, 1 is visible via * via another host_id * * external 0 = node is configured/known locally, * 1 host_id has been received via another host_id */ struct knet_host_status { uint8_t reachable; uint8_t remote; uint8_t external; /* add host statistics */ }; /** * knet_host_get_status * * @brief Get the status of a host * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * status - pointer to knet_host_status struct * * @return * knet_handle_pmtud_get returns * 0 on success * -1 on error and errno is set. */ int knet_host_get_status(knet_handle_t knet_h, knet_node_id_t host_id, struct knet_host_status *status); /* * link structs/API calls * * every host allocated/managed by knet_host_* has * KNET_MAX_LINK structures to define the network * paths that connect 2 hosts. * * Each link is identified by a link_id that has a * values between 0 and KNET_MAX_LINK - 1. * * KNOWN LIMITATIONS: * * - let's assume the scenario where two hosts are connected * with any number of links. link_id must match on both sides. * If host_id 0 link_id 0 is configured to connect IP1 to IP2 and * host_id 0 link_id 1 is configured to connect IP3 to IP4, * host_id 1 link_id 0 _must_ connect IP2 to IP1 and likewise * host_id 1 link_id 1 _must_ connect IP4 to IP3. * We might be able to lift this restriction in future, by using * other data to determine src/dst link_id, but for now, deal with it. */ /* * commodity functions to convert strings to sockaddr and viceversa */ /** * knet_strtoaddr * * @brief Convert a hostname string to an address * * host - IPaddr/hostname to convert * be aware only the first IP address will be returned * in case a hostname resolves to multiple IP * * port - port to connect to * * ss - sockaddr_storage where to store the converted data * * sslen - len of the sockaddr_storage * * @return * knet_strtoaddr returns same error codes as getaddrinfo * */ int knet_strtoaddr(const char *host, const char *port, struct sockaddr_storage *ss, socklen_t sslen); /** * knet_addrtostr * * @brief Convert an address to a host name * * ss - sockaddr_storage to convert * * sslen - len of the sockaddr_storage * * host - IPaddr/hostname where to store data * (recommended size: KNET_MAX_HOST_LEN) * * port - port buffer where to store data * (recommended size: KNET_MAX_PORT_LEN) * * @return * knet_strtoaddr returns same error codes as getnameinfo */ int knet_addrtostr(const struct sockaddr_storage *ss, socklen_t sslen, char *addr_buf, size_t addr_buf_size, char *port_buf, size_t port_buf_size); #define KNET_TRANSPORT_LOOPBACK 0 #define KNET_TRANSPORT_UDP 1 #define KNET_TRANSPORT_SCTP 2 #define KNET_MAX_TRANSPORTS UINT8_MAX /* * The Loopback transport is only valid for connections to localhost, the host * with the same node_id specified in knet_handle_new(). Only one link of this * type is allowed. Data sent down a LOOPBACK link will be copied directly from * the knet send datafd to the knet receive datafd so the application must be set * up to take data from that socket at least as often as it is sent or deadlocks * could occur. If used, a LOOPBACK link must be the only link configured to the * local host. */ struct knet_transport_info { const char *name; /* UDP/SCTP/etc... */ uint8_t id; /* value that can be used for link_set_config */ uint8_t properties; /* currently unused */ char pad[256]; /* currently unused */ }; /** * knet_get_transport_list * * @brief Get a list of the transports support by this build of knet * * transport_list - an array of struct transport_info that must be * at least of size struct transport_info * KNET_MAX_TRANSPORTS * * transport_list_entries - pointer to a size_t where to store how many transports * are available in this build of libknet. * * @return * knet_get_transport_list returns * 0 on success * -1 on error and errno is set. */ int knet_get_transport_list(struct knet_transport_info *transport_list, size_t *transport_list_entries); /** * knet_get_transport_name_by_id * * @brief Get a transport name from its ID number * * transport - one of the KNET_TRANSPORT_xxx constants * * @return * knet_get_transport_name_by_id returns: * * @retval pointer to the name on success or * @retval NULL on error and errno is set. */ const char *knet_get_transport_name_by_id(uint8_t transport); /** * knet_get_transport_id_by_name * * @brief Get a transport ID from its name * * name - transport name (UDP/SCTP/etc) * * @return * knet_get_transport_name_by_id returns: * * @retval KNET_MAX_TRANSPORTS on error and errno is set accordingly * @retval KNET_TRANSPORT_xxx on success. */ uint8_t knet_get_transport_id_by_name(const char *name); #define KNET_TRANSPORT_DEFAULT_RECONNECT_INTERVAL 1000 /** * knet_handle_set_transport_reconnect_interval * * @brief Set the interval between transport attempts to reconnect a failed link * * knet_h - pointer to knet_handle_t * * msecs - milliseconds * * @return * knet_handle_set_transport_reconnect_interval returns * 0 on success * -1 on error and errno is set. */ int knet_handle_set_transport_reconnect_interval(knet_handle_t knet_h, uint32_t msecs); /** * knet_handle_get_transport_reconnect_interval * * @brief Get the interval between transport attempts to reconnect a failed link * * knet_h - pointer to knet_handle_t * * msecs - milliseconds * * @return * knet_handle_get_transport_reconnect_interval returns * 0 on success * -1 on error and errno is set. */ int knet_handle_get_transport_reconnect_interval(knet_handle_t knet_h, uint32_t *msecs); /** * knet_link_set_config * * @brief Configure the link to a host * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * transport - one of the KNET_TRANSPORT_xxx constants * * src_addr - sockaddr_storage that can be either IPv4 or IPv6 * * dst_addr - sockaddr_storage that can be either IPv4 or IPv6 * this can be null if we don't know the incoming * IP address/port and the link will remain quiet * till the node on the other end will initiate a * connection * * flags - KNET_LINK_FLAG_* * * @return * knet_link_set_config returns * 0 on success * -1 on error and errno is set. */ int knet_link_set_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t transport, struct sockaddr_storage *src_addr, struct sockaddr_storage *dst_addr, uint64_t flags); /** * knet_link_get_config * * @brief Get the link configutation information * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * transport - see knet_link_set_config(3) * * src_addr - sockaddr_storage that can be either IPv4 or IPv6 * * dst_addr - sockaddr_storage that can be either IPv4 or IPv6 * * dynamic - 0 if dst_addr is static or 1 if dst_addr is dynamic. * In case of 1, dst_addr can be NULL and it will be left * untouched. * * flags - KNET_LINK_FLAG_* * * @return * knet_link_get_config returns * 0 on success. * -1 on error and errno is set. */ int knet_link_get_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t *transport, struct sockaddr_storage *src_addr, struct sockaddr_storage *dst_addr, uint8_t *dynamic, uint64_t *flags); /** * knet_link_clear_config * * @brief Clear link information and disconnect the link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * @return * knet_link_clear_config returns * 0 on success. * -1 on error and errno is set. */ int knet_link_clear_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id); /* * Access lists management for open links * see also knet_handle_enable_access_lists(3) */ /** * check_type_t * @brief address type enum for knet access lists * * CHECK_TYPE_ADDRESS is the equivalent of a single entry / IP address. * for example: 10.1.9.3 * and the entry is stored in ss1. ss2 can be NULL. * * CHECK_TYPE_MASK is used to configure network/netmask. * for example: 192.168.0.0/24 * the network is stored in ss1 and the netmask in ss2. * * CHECK_TYPE_RANGE defines a value / range of ip addresses. * for example: 172.16.0.1-172.16.0.10 * the start is stored in ss1 and the end in ss2. * * Please be aware that the above examples refer only to IP based protocols. * Other protocols might use ss1 and ss2 in slightly different ways. * At the moment knet only supports IP based protocol, though that might change * in the future. */ typedef enum { CHECK_TYPE_ADDRESS, CHECK_TYPE_MASK, CHECK_TYPE_RANGE } check_type_t; /** * check_acceptreject_t * * @brief enum for accept/reject in knet access lists * * accept or reject incoming packets defined in the access list entry */ typedef enum { CHECK_ACCEPT, CHECK_REJECT } check_acceptreject_t; /** * knet_link_add_acl * * @brief Add access list entry to an open link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * ss1 / ss2 / type / acceptreject - see typedef definitions for details * * IMPORTANT: the order in which access lists are added is critical and it * is left to the user to add them in the right order. knet * will not attempt to logically sort them. * * For example: * 1 - accept from 10.0.0.0/8 * 2 - reject from 10.0.0.1/32 * * is not the same as: * * 1 - reject from 10.0.0.1/32 * 2 - accept from 10.0.0.0/8 * * In the first example, rule number 2 will never match because * packets from 10.0.0.1 will be accepted by rule number 1. * * @return * knet_link_add_acl returns * 0 on success. * -1 on error and errno is set. */ int knet_link_add_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, struct sockaddr_storage *ss1, struct sockaddr_storage *ss2, check_type_t type, check_acceptreject_t acceptreject); /** * knet_link_insert_acl * * @brief Insert access list entry to an open link at given index * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * index - insert at position "index" where 0 is the first entry and -1 * appends to the current list. * * ss1 / ss2 / type / acceptreject - see typedef definitions for details * * @return * knet_link_insert_acl returns * 0 on success. * -1 on error and errno is set. */ int knet_link_insert_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, int index, struct sockaddr_storage *ss1, struct sockaddr_storage *ss2, check_type_t type, check_acceptreject_t acceptreject); /** * knet_link_rm_acl * * @brief Remove access list entry from an open link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * ss1 / ss2 / type / acceptreject - see typedef definitions for details * * IMPORTANT: the data passed to this API call must match exactly that passed * to knet_link_add_acl(3). * * @return * knet_link_rm_acl returns * 0 on success. * -1 on error and errno is set. */ int knet_link_rm_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, struct sockaddr_storage *ss1, struct sockaddr_storage *ss2, check_type_t type, check_acceptreject_t acceptreject); /** * knet_link_clear_acl * * @brief Remove all access list entries from an open link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * @return * knet_link_clear_acl returns * 0 on success. * -1 on error and errno is set. */ int knet_link_clear_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id); /** * knet_link_set_enable * * @brief Enable traffic on a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * enabled - 0 disable the link, 1 enable the link * * @return * knet_link_set_enable returns * 0 on success * -1 on error and errno is set. */ int knet_link_set_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, unsigned int enabled); /** * knet_link_get_enable * * @brief Find out whether a link is enabled or not * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * enabled - 0 disable the link, 1 enable the link * * @return * knet_link_get_enable returns * 0 on success * -1 on error and errno is set. */ int knet_link_get_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, unsigned int *enabled); #define KNET_LINK_DEFAULT_PING_INTERVAL 1000 /* 1 second */ #define KNET_LINK_DEFAULT_PING_TIMEOUT 2000 /* 2 seconds */ #define KNET_LINK_DEFAULT_PING_PRECISION 2048 /* samples */ /** * knet_link_set_ping_timers * * @brief Set the ping timers for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * interval - specify the ping interval in milliseconds. * * timeout - if no pong is received within this time, * the link is declared dead, in milliseconds. * NOTE: in future it will be possible to set timeout to 0 * for an autocalculated timeout based on interval, pong_count * and latency. The API already accept 0 as value and it will * return ENOSYS / -1. Once the automatic calculation feature * will be implemented, this call will only return EINVAL * for incorrect values. * * precision - how many values of latency are used to calculate * the average link latency (see also knet_link_get_status(3)) * * @return * knet_link_set_ping_timers returns * 0 on success * -1 on error and errno is set. */ int knet_link_set_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, time_t interval, time_t timeout, unsigned int precision); /** * knet_link_get_ping_timers * * @brief Get the ping timers for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * interval - ping interval * * timeout - if no pong is received within this time, * the link is declared dead * * precision - how many values of latency are used to calculate * the average link latency (see also knet_link_get_status(3)) * * @return * knet_link_get_ping_timers returns * 0 on success * -1 on error and errno is set. */ int knet_link_get_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, time_t *interval, time_t *timeout, unsigned int *precision); #define KNET_LINK_DEFAULT_PONG_COUNT 5 /** * knet_link_set_pong_count * * @brief Set the pong count for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * pong_count - how many valid ping/pongs before a link is marked UP. * default: 5, value should be > 0 * * @return * knet_link_set_pong_count returns * 0 on success * -1 on error and errno is set. */ int knet_link_set_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t pong_count); /** * knet_link_get_pong_count * * @brief Get the pong count for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * pong_count - how many valid ping/pongs before a link is marked UP. * default: 5, value should be > 0 * * @return * knet_link_get_pong_count returns * 0 on success * -1 on error and errno is set. */ int knet_link_get_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t *pong_count); /** * knet_link_set_priority * * @brief Set the priority for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * priority - specify the switching priority for this link * see also knet_host_set_policy * * @return * knet_link_set_priority returns * 0 on success * -1 on error and errno is set. */ int knet_link_set_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t priority); /** * knet_link_get_priority * * @brief Get the priority for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * priority - gather the switching priority for this link * see also knet_host_set_policy * * @return * knet_link_get_priority returns * 0 on success * -1 on error and errno is set. */ int knet_link_get_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t *priority); /** * knet_link_get_link_list * * @brief Get a list of links connecting a host * * knet_h - pointer to knet_handle_t * * link_ids - array of at lest KNET_MAX_LINK size * with the list of configured links for a certain host. * * link_ids_entries - * number of entries contained in link_ids * * @return * knet_link_get_link_list returns * 0 on success * -1 on error and errno is set. */ int knet_link_get_link_list(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t *link_ids, size_t *link_ids_entries); /* * define link status structure for quick lookup * * src/dst_{ipaddr,port} strings are filled by * getnameinfo(3) when configuring the link. * if the link is dynamic (see knet_link_set_config(3)) * dst_ipaddr/port will contain ipaddr/port of the currently * connected peer or "Unknown" if it was not possible * to determine the ipaddr/port at runtime. * * enabled see also knet_link_set/get_enable. * * connected the link is connected to a peer and ping/pong traffic * is flowing. * * dynconnected the link has dynamic ip on the other end, and * we can see the other host is sending pings to us. * * pong_last if the link is down, this value tells us how long * ago this link was active. A value of 0 means that the link * has never been active. * * knet_link_stats structure that contains details statistics for the link */ #define MAX_LINK_EVENTS 16 struct knet_link_stats { /* onwire values */ uint64_t tx_data_packets; uint64_t rx_data_packets; uint64_t tx_data_bytes; uint64_t rx_data_bytes; uint64_t rx_ping_packets; uint64_t tx_ping_packets; uint64_t rx_ping_bytes; uint64_t tx_ping_bytes; uint64_t rx_pong_packets; uint64_t tx_pong_packets; uint64_t rx_pong_bytes; uint64_t tx_pong_bytes; uint64_t rx_pmtu_packets; uint64_t tx_pmtu_packets; uint64_t rx_pmtu_bytes; uint64_t tx_pmtu_bytes; /* Only filled in when requested */ uint64_t tx_total_packets; uint64_t rx_total_packets; uint64_t tx_total_bytes; uint64_t rx_total_bytes; uint64_t tx_total_errors; uint64_t tx_total_retries; uint32_t tx_pmtu_errors; uint32_t tx_pmtu_retries; uint32_t tx_ping_errors; uint32_t tx_ping_retries; uint32_t tx_pong_errors; uint32_t tx_pong_retries; uint32_t tx_data_errors; uint32_t tx_data_retries; /* measured in usecs */ uint32_t latency_min; uint32_t latency_max; uint32_t latency_ave; uint32_t latency_samples; /* how many times the link has been going up/down */ uint32_t down_count; uint32_t up_count; /* * circular buffer of time_t structs collecting the history * of up/down events on this link. * the index indicates current/last event. * it is safe to walk back the history by decreasing the index */ time_t last_up_times[MAX_LINK_EVENTS]; time_t last_down_times[MAX_LINK_EVENTS]; int8_t last_up_time_index; int8_t last_down_time_index; /* Always add new stats at the end */ }; struct knet_link_status { size_t size; /* For ABI checking */ char src_ipaddr[KNET_MAX_HOST_LEN]; char src_port[KNET_MAX_PORT_LEN]; char dst_ipaddr[KNET_MAX_HOST_LEN]; char dst_port[KNET_MAX_PORT_LEN]; uint8_t enabled; /* link is configured and admin enabled for traffic */ uint8_t connected; /* link is connected for data (local view) */ uint8_t dynconnected; /* link has been activated by remote dynip */ struct timespec pong_last; unsigned int mtu; /* current detected MTU on this link */ unsigned int proto_overhead; /* contains the size of the IP protocol, knet headers and * crypto headers (if configured). This value is filled in * ONLY after the first PMTUd run on that given link, * and can change if link configuration or crypto configuration * changes at runtime. * WARNING: in general mtu + proto_overhead might or might * not match the output of ifconfig mtu due to crypto * requirements to pad packets to some specific boundaries. */ /* Link statistics */ struct knet_link_stats stats; }; /** * knet_link_get_status * * @brief Get the status (and statistics) for a link * * knet_h - pointer to knet_handle_t * * host_id - see knet_host_add(3) * * link_id - see knet_link_set_config(3) * * status - pointer to knet_link_status struct * * struct_size - max size of knet_link_status - allows library to * add fields without ABI change. Returned structure * will be truncated to this length and .size member * indicates the full size. * * @return * knet_link_get_status returns * 0 on success * -1 on error and errno is set. */ int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, struct knet_link_status *status, size_t struct_size); /** * knet_link_enable_status_change_notify * * @brief Install a callback to get a link status change events * * knet_h - pointer to knet_handle_t * * host_status_change_notify_fn_private_data - * void pointer to data that can be used to identify * the callback * * host_status_change_notify_fn - * is a callback function that is invoked every time * there is a change in a link status. * host status is identified by: * - connected, 0 if the link has been disconnected, 1 if the link * is connected. * - remote, 0 if the host_id is connected locally or 1 if * the there is one or more knet host(s) in between. * NOTE: re-switching is NOT currently implemented, * but this is ready for future and can avoid * an API/ABI breakage later on. * - external, 0 if the host_id is configured locally or 1 if * it has been added from remote nodes config. * NOTE: dynamic topology is NOT currently implemented, * but this is ready for future and can avoid * an API/ABI breakage later on. * This function MUST NEVER block or add substantial delays. * * @return * knet_host_status_change_notify returns * 0 on success * -1 on error and errno is set. */ int knet_link_enable_status_change_notify(knet_handle_t knet_h, void *link_status_change_notify_fn_private_data, void (*link_status_change_notify_fn) ( void *private_data, knet_node_id_t host_id, uint8_t link_id, uint8_t connected, uint8_t remote, uint8_t external)); /* * logging structs/API calls */ /* * libknet is composed of several subsystems. In order * to easily distinguish log messages coming from different * places, each subsystem has its own ID. * * 0-19 config/management * 20-39 internal threads * 40-59 transports * 60-69 crypto implementations */ #define KNET_SUB_COMMON 0 /* common.c */ #define KNET_SUB_HANDLE 1 /* handle.c alloc/dealloc config changes */ #define KNET_SUB_HOST 2 /* host add/del/modify */ #define KNET_SUB_LISTENER 3 /* listeners add/del/modify... */ #define KNET_SUB_LINK 4 /* link add/del/modify */ #define KNET_SUB_TRANSPORT 5 /* Transport common */ #define KNET_SUB_CRYPTO 6 /* crypto.c config generic layer */ #define KNET_SUB_COMPRESS 7 /* compress.c config generic layer */ #define KNET_SUB_FILTER 19 /* allocated for users to log from dst_filter */ #define KNET_SUB_DSTCACHE 20 /* switching thread (destination cache handling) */ #define KNET_SUB_HEARTBEAT 21 /* heartbeat thread */ #define KNET_SUB_PMTUD 22 /* Path MTU Discovery thread */ #define KNET_SUB_TX 23 /* send to link thread */ #define KNET_SUB_RX 24 /* recv from link thread */ #define KNET_SUB_TRANSP_BASE 40 /* Base log level for transports */ #define KNET_SUB_TRANSP_LOOPBACK (KNET_SUB_TRANSP_BASE + KNET_TRANSPORT_LOOPBACK) #define KNET_SUB_TRANSP_UDP (KNET_SUB_TRANSP_BASE + KNET_TRANSPORT_UDP) #define KNET_SUB_TRANSP_SCTP (KNET_SUB_TRANSP_BASE + KNET_TRANSPORT_SCTP) -#define KNET_SUB_NSSCRYPTO 60 /* nsscrypto.c */ -#define KNET_SUB_OPENSSLCRYPTO 61 /* opensslcrypto.c */ +#define KNET_SUB_NSSCRYPTO 60 /* crypto_nss.c */ +#define KNET_SUB_OPENSSLCRYPTO 61 /* crypto_openssl.c */ +#define KNET_SUB_GCRYPTCRYPTO 62 /* crypto_gcrypt.c */ #define KNET_SUB_ZLIBCOMP 70 /* compress_zlib.c */ #define KNET_SUB_LZ4COMP 71 /* compress_lz4.c */ #define KNET_SUB_LZ4HCCOMP 72 /* compress_lz4.c */ #define KNET_SUB_LZO2COMP 73 /* compress_lzo.c */ #define KNET_SUB_LZMACOMP 74 /* compress_lzma.c */ #define KNET_SUB_BZIP2COMP 75 /* compress_bzip2.c */ #define KNET_SUB_ZSTDCOMP 76 /* compress_zstd.c */ #define KNET_SUB_UNKNOWN UINT8_MAX - 1 #define KNET_MAX_SUBSYSTEMS UINT8_MAX /* * Convert between subsystem IDs and names */ /** * knet_log_get_subsystem_name * * @brief Get a logging system name from its numeric ID * * @return * returns internal name of the subsystem or "common" */ const char *knet_log_get_subsystem_name(uint8_t subsystem); /** * knet_log_get_subsystem_id * * @brief Get a logging system ID from its name * * @return * returns internal ID of the subsystem or KNET_SUB_COMMON */ uint8_t knet_log_get_subsystem_id(const char *name); /* * 4 log levels are enough for everybody */ #define KNET_LOG_ERR 0 /* unrecoverable errors/conditions */ #define KNET_LOG_WARN 1 /* recoverable errors/conditions */ #define KNET_LOG_INFO 2 /* info, link up/down, config changes.. */ #define KNET_LOG_DEBUG 3 /* * Convert between log level values and names */ /** * knet_log_get_loglevel_name * * @brief Get a logging level name from its numeric ID * * @return * returns internal name of the log level or "ERROR" for unknown values */ const char *knet_log_get_loglevel_name(uint8_t level); /** * knet_log_get_loglevel_id * * @brief Get a logging level ID from its name * * @return * returns internal log level ID or KNET_LOG_ERR for invalid names */ uint8_t knet_log_get_loglevel_id(const char *name); /* * every log message is composed by a text message * and message level/subsystem IDs. * In order to make debugging easier it is possible to send those packets * straight to stdout/stderr (see knet_bench.c stdout option). */ #define KNET_MAX_LOG_MSG_SIZE 254 #if KNET_MAX_LOG_MSG_SIZE > PIPE_BUF #error KNET_MAX_LOG_MSG_SIZE cannot be bigger than PIPE_BUF for guaranteed system atomic writes #endif struct knet_log_msg { char msg[KNET_MAX_LOG_MSG_SIZE]; uint8_t subsystem; /* KNET_SUB_* */ uint8_t msglevel; /* KNET_LOG_* */ knet_handle_t knet_h; /* pointer to the handle generating the log */ }; /** * knet_log_set_loglevel * * @brief Set the logging level for a subsystem * * knet_h - same as above * * subsystem - same as above * * level - same as above * * knet_log_set_loglevel allows fine control of log levels by subsystem. * See also knet_handle_new for defaults. * * @return * knet_log_set_loglevel returns * 0 on success * -1 on error and errno is set. */ int knet_log_set_loglevel(knet_handle_t knet_h, uint8_t subsystem, uint8_t level); /** * knet_log_get_loglevel * * @brief Get the logging level for a subsystem * * knet_h - same as above * * subsystem - same as above * * level - same as above * * @return * knet_log_get_loglevel returns * 0 on success * -1 on error and errno is set. */ int knet_log_get_loglevel(knet_handle_t knet_h, uint8_t subsystem, uint8_t *level); #endif diff --git a/libknet/logging.c b/libknet/logging.c index 9ae89e93..61c585f7 100644 --- a/libknet/logging.c +++ b/libknet/logging.c @@ -1,249 +1,250 @@ /* * Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under LGPL-2.0+ */ #include "config.h" #include #include #include #include #include #include #include #include "internals.h" #include "logging.h" #include "threads_common.h" static struct pretty_names subsystem_names[KNET_MAX_SUBSYSTEMS] = { { "common", KNET_SUB_COMMON }, { "handle", KNET_SUB_HANDLE }, { "host", KNET_SUB_HOST }, { "listener", KNET_SUB_LISTENER }, { "link", KNET_SUB_LINK }, { "transport", KNET_SUB_TRANSPORT }, { "crypto", KNET_SUB_CRYPTO }, { "compress", KNET_SUB_COMPRESS }, { "filter", KNET_SUB_FILTER }, { "dstcache", KNET_SUB_DSTCACHE }, { "heartbeat", KNET_SUB_HEARTBEAT }, { "pmtud", KNET_SUB_PMTUD }, { "tx", KNET_SUB_TX }, { "rx", KNET_SUB_RX }, { "loopback", KNET_SUB_TRANSP_LOOPBACK }, { "udp", KNET_SUB_TRANSP_UDP }, { "sctp", KNET_SUB_TRANSP_SCTP }, { "nsscrypto", KNET_SUB_NSSCRYPTO }, { "opensslcrypto", KNET_SUB_OPENSSLCRYPTO }, + { "gcryptcrypto", KNET_SUB_GCRYPTCRYPTO }, { "zlibcomp", KNET_SUB_ZLIBCOMP }, { "lz4comp", KNET_SUB_LZ4COMP }, { "lz4hccomp", KNET_SUB_LZ4HCCOMP }, { "lzo2comp", KNET_SUB_LZO2COMP }, { "lzmacomp", KNET_SUB_LZMACOMP }, { "bzip2comp", KNET_SUB_BZIP2COMP }, { "zstdcomp", KNET_SUB_ZSTDCOMP }, { "unknown", KNET_SUB_UNKNOWN } /* unknown MUST always be last in this array */ }; const char *knet_log_get_subsystem_name(uint8_t subsystem) { unsigned int i; for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) { if (subsystem_names[i].val == KNET_SUB_UNKNOWN) { break; } if (subsystem_names[i].val == subsystem) { errno = 0; return subsystem_names[i].name; } } return "unknown"; } uint8_t knet_log_get_subsystem_id(const char *name) { unsigned int i; for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) { if (subsystem_names[i].val == KNET_SUB_UNKNOWN) { break; } if (strcasecmp(name, subsystem_names[i].name) == 0) { errno = 0; return subsystem_names[i].val; } } return KNET_SUB_UNKNOWN; } static int is_valid_subsystem(uint8_t subsystem) { unsigned int i; for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) { if ((subsystem != KNET_SUB_UNKNOWN) && (subsystem_names[i].val == KNET_SUB_UNKNOWN)) { break; } if (subsystem_names[i].val == subsystem) { return 0; } } return -1; } static struct pretty_names loglevel_names[KNET_LOG_DEBUG + 1] = { { "ERROR", KNET_LOG_ERR }, { "WARNING", KNET_LOG_WARN }, { "info", KNET_LOG_INFO }, { "debug", KNET_LOG_DEBUG } }; const char *knet_log_get_loglevel_name(uint8_t level) { unsigned int i; for (i = 0; i <= KNET_LOG_DEBUG; i++) { if (loglevel_names[i].val == level) { errno = 0; return loglevel_names[i].name; } } return "ERROR"; } uint8_t knet_log_get_loglevel_id(const char *name) { unsigned int i; for (i = 0; i <= KNET_LOG_DEBUG; i++) { if (strcasecmp(name, loglevel_names[i].name) == 0) { errno = 0; return loglevel_names[i].val; } } return KNET_LOG_ERR; } int knet_log_set_loglevel(knet_handle_t knet_h, uint8_t subsystem, uint8_t level) { int savederrno = 0; if (!knet_h) { errno = EINVAL; return -1; } if (is_valid_subsystem(subsystem) < 0) { errno = EINVAL; return -1; } if (level > KNET_LOG_DEBUG) { errno = EINVAL; return -1; } savederrno = get_global_wrlock(knet_h); if (savederrno) { log_err(knet_h, subsystem, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } knet_h->log_levels[subsystem] = level; pthread_rwlock_unlock(&knet_h->global_rwlock); errno = 0; return 0; } int knet_log_get_loglevel(knet_handle_t knet_h, uint8_t subsystem, uint8_t *level) { int savederrno = 0; if (!knet_h) { errno = EINVAL; return -1; } if (is_valid_subsystem(subsystem) < 0) { errno = EINVAL; return -1; } if (!level) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, subsystem, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } *level = knet_h->log_levels[subsystem]; pthread_rwlock_unlock(&knet_h->global_rwlock); errno = 0; return 0; } void log_msg(knet_handle_t knet_h, uint8_t subsystem, uint8_t msglevel, const char *fmt, ...) { va_list ap; struct knet_log_msg msg; size_t byte_cnt = 0; int len; if ((!knet_h) || (subsystem == KNET_MAX_SUBSYSTEMS) || (msglevel > knet_h->log_levels[subsystem])) return; if (knet_h->logfd <= 0) goto out; memset(&msg, 0, sizeof(struct knet_log_msg)); msg.subsystem = subsystem; msg.msglevel = msglevel; msg.knet_h = knet_h; va_start(ap, fmt); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-nonliteral" #endif vsnprintf(msg.msg, sizeof(msg.msg), fmt, ap); #ifdef __clang__ #pragma clang diagnostic pop #endif va_end(ap); while (byte_cnt < sizeof(struct knet_log_msg)) { len = write(knet_h->logfd, &msg, sizeof(struct knet_log_msg) - byte_cnt); if (len <= 0) { goto out; } byte_cnt += len; } out: return; }