Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62826a4627 | ||
|
|
35e7bc8aeb | ||
|
|
9a5fabddb4 | ||
|
|
088e85a423 | ||
|
|
43f1d58f29 | ||
|
|
a6b29a01a2 | ||
|
|
5d65d87dfb | ||
|
|
ddf28feaf8 | ||
|
|
a57049be63 | ||
|
|
7f53e315c5 | ||
|
|
48756520dd | ||
|
|
4f23b242f3 | ||
|
|
c371b74e12 | ||
|
|
c014d20fca | ||
|
|
9b2480d552 | ||
|
|
1ae10c21ca | ||
|
|
4698009b59 | ||
|
|
d0e0b70f81 | ||
|
|
914f42da5c | ||
|
|
273b641820 | ||
|
|
4f9de7a6fb | ||
|
|
d3c529abd7 | ||
|
|
a8e19ba28a | ||
|
|
64a8cd1f4b | ||
|
|
cc6e531410 | ||
|
|
ca608d0b87 | ||
|
|
0e095d2347 | ||
|
|
4fe2a0a3eb | ||
|
|
1a4d275616 | ||
|
|
803c870493 | ||
|
|
0d97fba466 | ||
|
|
41100260ec | ||
|
|
07c9606594 | ||
|
|
4ba361d83d | ||
|
|
662fb86eae | ||
|
|
1df8b51abb | ||
|
|
d2d01e5183 | ||
|
|
3d96c3907e | ||
|
|
fb483185ff | ||
|
|
d6eb00e18e | ||
|
|
34d47bd62a | ||
|
|
2846eba3af |
@@ -1278,24 +1278,6 @@ jobs:
|
||||
echo ""
|
||||
done
|
||||
|
||||
test_heal_ec_rdma:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
container: ${{env.TEST_IMAGE}}:${{github.sha}}
|
||||
steps:
|
||||
- name: Run test
|
||||
id: test
|
||||
timeout-minutes: 10
|
||||
run: TEST_NAME=ec_rdma RDMA=1 SCHEME=ec /root/vitastor/tests/test_heal.sh
|
||||
- name: Print logs
|
||||
if: always() && steps.test.outcome == 'failure'
|
||||
run: |
|
||||
for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do
|
||||
echo "-------- $i --------"
|
||||
cat $i
|
||||
echo ""
|
||||
done
|
||||
|
||||
test_checksum:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8...3.30)
|
||||
|
||||
project(vitastor)
|
||||
|
||||
set(VITASTOR_VERSION "3.0.10")
|
||||
set(VITASTOR_VERSION "3.0.9")
|
||||
|
||||
include(CTest)
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
VITASTOR_VERSION ?= v3.0.10
|
||||
VITASTOR_VERSION ?= v3.0.9
|
||||
|
||||
all: build push
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ spec:
|
||||
capabilities:
|
||||
add: ["SYS_ADMIN"]
|
||||
allowPrivilegeEscalation: true
|
||||
image: vitalif/vitastor-csi:v3.0.10
|
||||
image: vitalif/vitastor-csi:v3.0.9
|
||||
args:
|
||||
- "--node=$(NODE_ID)"
|
||||
- "--endpoint=$(CSI_ENDPOINT)"
|
||||
|
||||
@@ -121,7 +121,7 @@ spec:
|
||||
privileged: true
|
||||
capabilities:
|
||||
add: ["SYS_ADMIN"]
|
||||
image: vitalif/vitastor-csi:v3.0.10
|
||||
image: vitalif/vitastor-csi:v3.0.9
|
||||
args:
|
||||
- "--node=$(NODE_ID)"
|
||||
- "--endpoint=$(CSI_ENDPOINT)"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ package vitastor
|
||||
|
||||
const (
|
||||
vitastorCSIDriverName = "csi.vitastor.io"
|
||||
vitastorCSIDriverVersion = "3.0.10"
|
||||
vitastorCSIDriverVersion = "3.0.9"
|
||||
)
|
||||
|
||||
// Config struct fills the parameters of request or user input
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
vitastor (3.0.10-1) unstable; urgency=medium
|
||||
vitastor (3.0.9-1) unstable; urgency=medium
|
||||
|
||||
* Bugfixes
|
||||
|
||||
|
||||
Vendored
+8
-6
@@ -12,18 +12,20 @@ ARG REL=
|
||||
WORKDIR /root
|
||||
|
||||
RUN set -e -x; \
|
||||
perl -i -pe 's/deb.debian.org/archive.debian.org/' /etc/apt/sources.list; \
|
||||
apt-get update; \
|
||||
apt-get -y install wget; \
|
||||
wget https://vitastor.io/debian/pubkey.gpg -O /etc/apt/trusted.gpg.d/vitastor.gpg; \
|
||||
echo "deb https://vitastor.io/debian $REL main" >> /etc/apt/sources.list; \
|
||||
if [ "$REL" = "buster" ]; then \
|
||||
perl -i -pe 's/deb.debian.org/archive.debian.org/' /etc/apt/sources.list; \
|
||||
apt-get update; \
|
||||
apt-get -y install wget; \
|
||||
wget https://vitastor.io/debian/pubkey.gpg -O /etc/apt/trusted.gpg.d/vitastor.gpg; \
|
||||
echo "deb https://vitastor.io/debian $REL main" >> /etc/apt/sources.list; \
|
||||
fi; \
|
||||
grep '^deb ' /etc/apt/sources.list | perl -pe 's/^deb/deb-src/' >> /etc/apt/sources.list; \
|
||||
perl -i -pe 's/Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/*.sources || true; \
|
||||
echo 'APT::Install-Recommends false;' >> /etc/apt/apt.conf; \
|
||||
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install fio libgoogle-perftools-dev devscripts libjerasure-dev cmake libc-ares-dev libisal-crypto-dev \
|
||||
apt-get -y install fio libgoogle-perftools-dev devscripts libjerasure-dev cmake libc-ares-dev \
|
||||
libibverbs-dev librdmacm-dev libisal-dev libnl-3-dev libnl-genl-3-dev curl nodejs npm node-nan node-bindings && \
|
||||
apt-get -y build-dep fio && \
|
||||
apt-get --download-only source fio
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
VITASTOR_VERSION ?= v3.0.10
|
||||
VITASTOR_VERSION ?= v3.0.9
|
||||
|
||||
all: build push
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
# Desired Vitastor version
|
||||
VITASTOR_VERSION=v3.0.10
|
||||
VITASTOR_VERSION=v3.0.9
|
||||
|
||||
# Additional arguments for all containers
|
||||
# For example, you may want to specify a custom logging driver here
|
||||
|
||||
@@ -25,7 +25,7 @@ Most of them can be set in /etc/vitastor/vitastor.conf and in etcd, but don't su
|
||||
- [vault_timeout_ms](#vault_timeout_ms)
|
||||
- [vault_error_timeout_sec](#vault_error_timeout_sec)
|
||||
- [vault_refresh_leeway_sec](#vault_refresh_leeway_sec)
|
||||
- [max_cipher_pool_size](#max_cipher_pool_size)
|
||||
- [max_aes_xts_pool_size](#max_aes_xts_pool_size)
|
||||
|
||||
## etcd_client_cert
|
||||
|
||||
@@ -141,10 +141,10 @@ Time (in seconds) to wait before retrying after receiving an error from Vault.
|
||||
Extra time (in seconds) before real Vault token lease_timeout to refresh it, just
|
||||
in case of system clock drift.
|
||||
|
||||
## max_cipher_pool_size
|
||||
## max_aes_xts_pool_size
|
||||
|
||||
- Type: integer
|
||||
- Default: 256
|
||||
|
||||
Maximum number of OpenSSL cipher contexts cached in OSD memory, counted separately
|
||||
for each cipher and for encryption/decryption. Probably doesn't require modification.
|
||||
Maximum number of OpenSSL encryption contexts cached in OSD memory. Probably
|
||||
doesn't require modification.
|
||||
|
||||
@@ -27,7 +27,7 @@ OSD, мониторами и клиентами.
|
||||
- [vault_timeout_ms](#vault_timeout_ms)
|
||||
- [vault_error_timeout_sec](#vault_error_timeout_sec)
|
||||
- [vault_refresh_leeway_sec](#vault_refresh_leeway_sec)
|
||||
- [max_cipher_pool_size](#max_cipher_pool_size)
|
||||
- [max_aes_xts_pool_size](#max_aes_xts_pool_size)
|
||||
|
||||
## etcd_client_cert
|
||||
|
||||
@@ -145,10 +145,10 @@ OSD, клиенты и мониторы должны иметь разные п
|
||||
Зазор времени (в секундах), чтобы обновлять токены Vault чуть раньше их реального
|
||||
lease_timeout, на случай "ухода" системных часов.
|
||||
|
||||
## max_cipher_pool_size
|
||||
## max_aes_xts_pool_size
|
||||
|
||||
- Тип: целое число
|
||||
- Значение по умолчанию: 256
|
||||
|
||||
Максимальное количество кэшируемых в памяти OSD контекстов шифра OpenSSL, учитываемое
|
||||
отдельно для каждого шифра и для шифрования и расшифровки. Вряд ли требует изменения.
|
||||
Максимальное количество кэшируемых в памяти OSD контекстов шифрования OpenSSL.
|
||||
Вряд ли требует изменения.
|
||||
|
||||
@@ -120,12 +120,12 @@
|
||||
info_ru: |
|
||||
Зазор времени (в секундах), чтобы обновлять токены Vault чуть раньше их реального
|
||||
lease_timeout, на случай "ухода" системных часов.
|
||||
- name: max_cipher_pool_size
|
||||
- name: max_aes_xts_pool_size
|
||||
type: int
|
||||
default: 256
|
||||
info: |
|
||||
Maximum number of OpenSSL cipher contexts cached in OSD memory, counted separately
|
||||
for each cipher and for encryption/decryption. Probably doesn't require modification.
|
||||
Maximum number of OpenSSL encryption contexts cached in OSD memory. Probably
|
||||
doesn't require modification.
|
||||
info_ru: |
|
||||
Максимальное количество кэшируемых в памяти OSD контекстов шифра OpenSSL, учитываемое
|
||||
отдельно для каждого шифра и для шифрования и расшифровки. Вряд ли требует изменения.
|
||||
Максимальное количество кэшируемых в памяти OSD контекстов шифрования OpenSSL.
|
||||
Вряд ли требует изменения.
|
||||
|
||||
@@ -26,9 +26,9 @@ at Vitastor Kubernetes operator: https://github.com/Antilles7227/vitastor-operat
|
||||
The instruction is very simple.
|
||||
|
||||
1. Download a Docker image of the desired version: \
|
||||
`docker pull vitalif/vitastor:v3.0.10`
|
||||
`docker pull vitalif/vitastor:v3.0.9`
|
||||
2. Install scripts to the host system: \
|
||||
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.10 install.sh`
|
||||
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.9 install.sh`
|
||||
3. Reload udev rules: \
|
||||
`udevadm control --reload-rules`
|
||||
4. Enable the vitastor-host service: \
|
||||
|
||||
@@ -25,9 +25,9 @@ Vitastor можно установить в Docker/Podman. При этом etcd,
|
||||
Инструкция по установке максимально простая.
|
||||
|
||||
1. Скачайте Docker-образ желаемой версии: \
|
||||
`docker pull vitalif/vitastor:v3.0.10`
|
||||
`docker pull vitalif/vitastor:v3.0.9`
|
||||
2. Установите скрипты в хост-систему командой: \
|
||||
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.10 install.sh`
|
||||
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.9 install.sh`
|
||||
3. Перезагрузите правила udev: \
|
||||
`udevadm control --reload-rules`
|
||||
4. Включите сервис vitastor-host: \
|
||||
|
||||
@@ -262,4 +262,3 @@ Options:
|
||||
| `--logfile <FILE>` | log to the specified file |
|
||||
| `--enforce 1` | enforce permissions at the server side (no by default) |
|
||||
| `--foreground 1` | stay in foreground, do not daemonize |
|
||||
| `--trace` | trace all NFS requests |
|
||||
|
||||
@@ -274,4 +274,3 @@ VitastorFS из GPUDirect.
|
||||
| `--logfile <FILE>` | записывать логи в заданный файл |
|
||||
| `--enforce 1` | проверять права доступа на стороне сервера (по умолчанию нет) |
|
||||
| `--foreground 1` | не уходить в фон после запуска |
|
||||
| `--trace` | логгировать все запросы NFS |
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vitastor-mon",
|
||||
"version": "3.0.10",
|
||||
"version": "3.0.9",
|
||||
"description": "Vitastor SDS monitor service",
|
||||
"main": "mon-main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vitastor",
|
||||
"version": "3.0.10",
|
||||
"version": "3.0.9",
|
||||
"description": "Low-level native bindings to Vitastor client library",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
|
||||
@@ -50,7 +50,7 @@ from cinder.volume import configuration
|
||||
from cinder.volume import driver
|
||||
from cinder.volume import volume_utils
|
||||
|
||||
VITASTOR_VERSION = '3.0.10'
|
||||
VITASTOR_VERSION = '3.0.9'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Name: vitastor
|
||||
Version: 3.0.10
|
||||
Version: 3.0.9
|
||||
Release: 1%{?dist}
|
||||
Summary: Vitastor, a fast software-defined clustered block storage
|
||||
|
||||
License: Vitastor Network Public License 1.1
|
||||
URL: https://vitastor.io/
|
||||
Source0: vitastor-3.0.10.el10.tar.gz
|
||||
Source0: vitastor-3.0.9.el10.tar.gz
|
||||
|
||||
BuildRequires: gperftools-devel
|
||||
BuildRequires: gcc-c++
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Name: vitastor
|
||||
Version: 3.0.10
|
||||
Version: 3.0.9
|
||||
Release: 1%{?dist}
|
||||
Summary: Vitastor, a fast software-defined clustered block storage
|
||||
|
||||
License: Vitastor Network Public License 1.1
|
||||
URL: https://vitastor.io/
|
||||
Source0: vitastor-3.0.10.el7.tar.gz
|
||||
Source0: vitastor-3.0.9.el7.tar.gz
|
||||
|
||||
BuildRequires: gperftools-devel
|
||||
BuildRequires: devtoolset-9-gcc-c++
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Name: vitastor
|
||||
Version: 3.0.10
|
||||
Version: 3.0.9
|
||||
Release: 1%{?dist}
|
||||
Summary: Vitastor, a fast software-defined clustered block storage
|
||||
|
||||
License: Vitastor Network Public License 1.1
|
||||
URL: https://vitastor.io/
|
||||
Source0: vitastor-3.0.10.el8.tar.gz
|
||||
Source0: vitastor-3.0.9.el8.tar.gz
|
||||
|
||||
BuildRequires: gperftools-devel
|
||||
BuildRequires: gcc-toolset-9-gcc-c++
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Name: vitastor
|
||||
Version: 3.0.10
|
||||
Version: 3.0.9
|
||||
Release: 1%{?dist}
|
||||
Summary: Vitastor, a fast software-defined clustered block storage
|
||||
|
||||
License: Vitastor Network Public License 1.1
|
||||
URL: https://vitastor.io/
|
||||
Source0: vitastor-3.0.10.el9.tar.gz
|
||||
Source0: vitastor-3.0.9.el9.tar.gz
|
||||
|
||||
BuildRequires: gperftools-devel
|
||||
BuildRequires: gcc-c++
|
||||
|
||||
+4
-6
@@ -20,7 +20,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
|
||||
endif()
|
||||
set(ENABLE_COVERAGE false CACHE BOOL "Enable code coverage")
|
||||
|
||||
add_definitions(-DVITASTOR_VERSION="3.0.10")
|
||||
add_definitions(-DVITASTOR_VERSION="3.0.9")
|
||||
add_definitions(-D_GNU_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -fvisibility=hidden -I ${CMAKE_SOURCE_DIR}/src)
|
||||
add_link_options(-fno-omit-frame-pointer)
|
||||
if (${WITH_ASAN})
|
||||
@@ -69,17 +69,15 @@ pkg_check_modules(ISAL libisal)
|
||||
if (ISAL_LIBRARIES)
|
||||
add_definitions(-DWITH_ISAL)
|
||||
endif (ISAL_LIBRARIES)
|
||||
pkg_check_modules(ISAL_CRYPTO libisal_crypto)
|
||||
if (ISAL_CRYPTO_LIBRARIES)
|
||||
add_definitions(-DWITH_ISAL_CRYPTO)
|
||||
endif (ISAL_CRYPTO_LIBRARIES)
|
||||
pkg_check_modules(RDMACM librdmacm)
|
||||
if (RDMACM_LIBRARIES)
|
||||
add_definitions(-DWITH_RDMACM)
|
||||
endif (RDMACM_LIBRARIES)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
add_definitions(-DWITH_OPENSSL)
|
||||
if (OPENSSL_FOUND)
|
||||
add_definitions(-DWITH_OPENSSL)
|
||||
endif (OPENSSL_FOUND)
|
||||
|
||||
pkg_check_modules(CARES REQUIRED libcares)
|
||||
include_directories(${CARES_INCLUDE_DIRS})
|
||||
|
||||
@@ -12,11 +12,11 @@ if (RDMACM_LIBRARIES)
|
||||
set(MSGR_RDMACM "msgr_rdmacm.cpp")
|
||||
endif (RDMACM_LIBRARIES)
|
||||
add_library(vitastor_common STATIC
|
||||
../util/epoll_manager.cpp etcd_state_client.cpp messenger.cpp ../util/addr_util.cpp ../util/xxh_x86dispatch.c ../util/openssl_util.cpp
|
||||
msgr_encrypt.cpp msgr_handshake.cpp msgr_stop.cpp msgr_op.cpp msgr_send.cpp msgr_receive.cpp ../util/ringloop.cpp ../../json11/json11.cpp
|
||||
../util/epoll_manager.cpp etcd_state_client.cpp messenger.cpp ../util/addr_util.cpp ../util/xxh_x86dispatch.c
|
||||
msgr_encrypt.cpp msgr_stop.cpp msgr_op.cpp msgr_send.cpp msgr_receive.cpp ../util/ringloop.cpp ../../json11/json11.cpp
|
||||
http_client.cpp osd_ops.cpp pg_states.cpp ../util/timerfd_manager.cpp ../util/str_util.cpp ../util/json_util.cpp ${MSGR_RDMA} ${MSGR_RDMACM}
|
||||
)
|
||||
target_link_libraries(vitastor_common pthread ${OPENSSL_LIBRARIES} ${CARES_LIBRARIES} ${ISAL_CRYPTO_LIBRARIES})
|
||||
target_link_libraries(vitastor_common pthread ${OPENSSL_LIBRARIES} ${CARES_LIBRARIES})
|
||||
target_compile_options(vitastor_common PUBLIC -fPIC)
|
||||
|
||||
# libvitastor_client.so
|
||||
@@ -35,7 +35,6 @@ target_link_libraries(vitastor_client
|
||||
${IBVERBS_LIBRARIES}
|
||||
${RDMACM_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${ISAL_CRYPTO_LIBRARIES}
|
||||
)
|
||||
set_target_properties(vitastor_client PROPERTIES VERSION ${VITASTOR_VERSION} SOVERSION 0)
|
||||
configure_file(vitastor.pc.in vitastor.pc @ONLY)
|
||||
@@ -102,9 +101,9 @@ add_executable(test_cluster_client
|
||||
EXCLUDE_FROM_ALL
|
||||
../test/test_cluster_client.cpp
|
||||
pg_states.cpp osd_ops.cpp cluster_client.cpp cluster_client_list.cpp cluster_client_wb.cpp cluster_client_icache.cpp msgr_op.cpp ../test/mock/messenger.cpp msgr_stop.cpp msgr_encrypt.cpp
|
||||
etcd_state_client.cpp ../util/timerfd_manager.cpp ../util/addr_util.cpp ../util/str_util.cpp ../util/json_util.cpp ../util/xxh_x86dispatch.c ../util/openssl_util.cpp ../../json11/json11.cpp
|
||||
etcd_state_client.cpp ../util/timerfd_manager.cpp ../util/addr_util.cpp ../util/str_util.cpp ../util/json_util.cpp ../util/xxh_x86dispatch.c ../../json11/json11.cpp
|
||||
)
|
||||
target_link_libraries(test_cluster_client ${OPENSSL_LIBRARIES} ${ISAL_CRYPTO_LIBRARIES})
|
||||
target_link_libraries(test_cluster_client ${OPENSSL_LIBRARIES})
|
||||
target_compile_definitions(test_cluster_client PUBLIC -D__MOCK__)
|
||||
target_include_directories(test_cluster_client BEFORE PUBLIC ${CMAKE_SOURCE_DIR}/src/test/mock)
|
||||
add_dependencies(build_tests test_cluster_client)
|
||||
|
||||
@@ -51,7 +51,7 @@ cluster_client_t::cluster_client_t(ring_loop_t *ringloop, timerfd_manager_t *tfd
|
||||
msgr.stop_client(op->client_id);
|
||||
delete op;
|
||||
};
|
||||
msgr.parse_config(config, true);
|
||||
msgr.parse_config(config);
|
||||
|
||||
st_cli.tfd = tfd;
|
||||
st_cli.on_load_config_hook = [this](json11::Json::object & cfg) { on_load_config_hook(cfg); };
|
||||
@@ -481,7 +481,7 @@ void cluster_client_t::on_load_config_hook(json11::Json::object & etcd_global_co
|
||||
}
|
||||
// vault
|
||||
vault_parse_config();
|
||||
msgr.parse_config(config, false);
|
||||
msgr.parse_config(config);
|
||||
st_cli.parse_config(config);
|
||||
st_cli.load_pgs();
|
||||
}
|
||||
@@ -1600,9 +1600,6 @@ static inline void mem_or(void *res, const void *r2, unsigned int len)
|
||||
}
|
||||
}
|
||||
|
||||
// Error priority: others > EPERM > EIO > ENOSPC > ETIMEDOUT > EPIPE
|
||||
#define ERR_PRIO(e) (((e) == -EPERM ? 5 : ((e) == -EIO ? 4 : ((e) == -ENOSPC ? 3 : ((e) == -ETIMEDOUT ? 2 : ((e) == -EPIPE ? 1 : (!(e) ? 0 : 10)))))))
|
||||
|
||||
void cluster_client_t::handle_op_part(cluster_op_part_t *part)
|
||||
{
|
||||
cluster_op_t *op = part->parent;
|
||||
@@ -1611,10 +1608,15 @@ void cluster_client_t::handle_op_part(cluster_op_part_t *part)
|
||||
{
|
||||
// Operation failed, retry
|
||||
part->flags |= PART_ERROR;
|
||||
if (ERR_PRIO(part->op.reply.hdr.retval) > ERR_PRIO(op->retval))
|
||||
if (!op->retval || op->retval == -EPIPE ||
|
||||
part->op.reply.hdr.retval == -ENOSPC && op->retval == -ETIMEDOUT ||
|
||||
part->op.reply.hdr.retval == -EIO)
|
||||
{
|
||||
// Error priority: EIO > ENOSPC > ETIMEDOUT > EPIPE
|
||||
op->retval = part->op.reply.hdr.retval;
|
||||
}
|
||||
uint64_t stop_client_id = 0;
|
||||
if (op->retval != -EINTR && op->retval != -EIO && op->retval != -ENOSPC && op->retval != -EPERM)
|
||||
if (op->retval != -EINTR && op->retval != -EIO && op->retval != -ENOSPC)
|
||||
{
|
||||
stop_client_id = part->op.client_id;
|
||||
if (op->retval != -EPIPE || log_level > 0)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "http_client.h"
|
||||
#endif
|
||||
#include "str_util.h"
|
||||
#include "json_util.h"
|
||||
|
||||
etcd_state_client_t::~etcd_state_client_t()
|
||||
{
|
||||
@@ -81,46 +80,6 @@ std::vector<std::string> etcd_state_client_t::get_addresses()
|
||||
return addrs;
|
||||
}
|
||||
|
||||
std::shared_ptr<user_info_t> etcd_state_client_t::get_user(const std::string & username)
|
||||
{
|
||||
auto user_it = user_info.find(username);
|
||||
if (user_it != user_info.end())
|
||||
{
|
||||
return user_it->second;
|
||||
}
|
||||
auto inf = std::make_shared<user_info_t>();
|
||||
inf->name = username;
|
||||
return inf;
|
||||
}
|
||||
|
||||
bool etcd_state_client_t::check_image_perm(const std::shared_ptr<user_info_t> & user_info, inode_t inode_num, bool write)
|
||||
{
|
||||
if (user_info->type == user_type_t::ADMIN)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
auto cache_it = user_info->perm_cache.find(inode_num);
|
||||
if (cache_it != user_info->perm_cache.end() &&
|
||||
cache_it->second.mod_revision == user_perm_cache_revision)
|
||||
{
|
||||
return write ? (cache_it->second.perm == user_perm_t::OWNER) : (cache_it->second.perm != user_perm_t::DENY);
|
||||
}
|
||||
auto inode_it = inode_config.find(inode_num);
|
||||
if (inode_it == inode_config.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// FIXME Implement cache reset after reworking etcd interaction to not keep everything in memory
|
||||
auto & perm_item = user_info->perm_cache[inode_num];
|
||||
perm_item.mod_revision = user_perm_cache_revision;
|
||||
perm_item.perm = (user_info->name == inode_it->second.owner || inode_it->second.owner_group != "" &&
|
||||
user_info->groups.find(inode_it->second.owner_group) != user_info->groups.end()
|
||||
? user_perm_t::OWNER : (inode_it->second.reader_group != "" &&
|
||||
user_info->groups.find(inode_it->second.reader_group) != user_info->groups.end()
|
||||
? user_perm_t::READER : user_perm_t::DENY));
|
||||
return write ? (perm_item.perm == user_perm_t::OWNER) : (perm_item.perm != user_perm_t::DENY);
|
||||
}
|
||||
|
||||
http_context_t *etcd_state_client_t::get_http_ctx()
|
||||
{
|
||||
if (!http_ctx)
|
||||
@@ -293,21 +252,17 @@ void etcd_state_client_t::parse_config(const json11::Json & config)
|
||||
}
|
||||
if (this->osd_num)
|
||||
{
|
||||
this->etcd_client_cert = config["osd_cert"].string_value();
|
||||
this->etcd_client_key = config["osd_pkey"].string_value();
|
||||
this->etcd_client_cert = config["osd_etcd_client_cert"].string_value();
|
||||
this->etcd_client_key = config["osd_etcd_client_key"].string_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->etcd_client_cert = config["cert"].string_value();
|
||||
this->etcd_client_key = config["pkey"].string_value();
|
||||
}
|
||||
if (this->etcd_client_cert == "")
|
||||
{
|
||||
this->etcd_client_cert = config["etcd_client_cert"].string_value();
|
||||
this->etcd_client_key = config["etcd_client_key"].string_value();
|
||||
}
|
||||
this->etcd_ca = config["etcd_ca"].string_value();
|
||||
this->etcd_prefix = config["etcd_prefix"].string_value();
|
||||
this->use_auth = config["use_auth"].bool_value();
|
||||
if (this->etcd_prefix == "")
|
||||
{
|
||||
this->etcd_prefix = "/vitastor";
|
||||
@@ -1384,10 +1339,6 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
||||
{
|
||||
on_inode_change_hook(inode_num, true);
|
||||
}
|
||||
if (this->inode_config.find(inode_num) != this->inode_config.end())
|
||||
{
|
||||
user_perm_cache_revision = kv.mod_revision;
|
||||
}
|
||||
this->inode_config.erase(inode_num);
|
||||
}
|
||||
else
|
||||
@@ -1403,39 +1354,13 @@ void etcd_state_client_t::parse_state(const etcd_kv_t & kv)
|
||||
if (on_change_node_placement_hook)
|
||||
on_change_node_placement_hook();
|
||||
}
|
||||
else if (key.substr(0, etcd_prefix.length()+13) == etcd_prefix+"/config/user/")
|
||||
else if (use_auth && key.substr(0, etcd_prefix.length()+13) == etcd_prefix+"/config/user/")
|
||||
{
|
||||
// <etcd_prefix>/config/user/<username>
|
||||
auto name = key.substr(etcd_prefix.length()+13);
|
||||
auto & inf = user_info[name];
|
||||
if (!value.is_object())
|
||||
{
|
||||
if (inf)
|
||||
{
|
||||
inf->type = user_type_t::CLIENT;
|
||||
inf->groups.clear();
|
||||
inf->perm_cache.clear();
|
||||
}
|
||||
user_info.erase(name);
|
||||
}
|
||||
user_info.erase(key.substr(etcd_prefix.length()+13));
|
||||
else
|
||||
{
|
||||
if (!inf)
|
||||
{
|
||||
inf = std::make_shared<user_info_t>();
|
||||
inf->name = name;
|
||||
}
|
||||
inf->type = value["type"] == "admin" ? user_type_t::ADMIN :
|
||||
(value["type"] == "mon" ? user_type_t::MON :
|
||||
(value["type"] == "osd" ? user_type_t::OSD : user_type_t::CLIENT));
|
||||
inf->groups.clear();
|
||||
for (auto & group: value["groups"].array_items())
|
||||
{
|
||||
if (group.string_value() != "")
|
||||
inf->groups.insert(group.string_value());
|
||||
}
|
||||
inf->perm_cache.clear();
|
||||
}
|
||||
user_info[key.substr(etcd_prefix.length()+13)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1459,12 +1384,7 @@ uint32_t etcd_state_client_t::parse_scheme(const std::string & scheme)
|
||||
|
||||
void etcd_state_client_t::insert_inode_config(const inode_config_t & cfg)
|
||||
{
|
||||
auto & cfg_ref = this->inode_config[cfg.num];
|
||||
if (cfg_ref.mod_revision != cfg.mod_revision)
|
||||
{
|
||||
user_perm_cache_revision = cfg.mod_revision;
|
||||
}
|
||||
cfg_ref = cfg;
|
||||
this->inode_config[cfg.num] = cfg;
|
||||
if (cfg.name != "")
|
||||
{
|
||||
this->inode_by_name[cfg.name] = cfg.num;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "json11/json11.hpp"
|
||||
#include "object_id.h"
|
||||
#include "timerfd_manager.h"
|
||||
#include "../util/robin_hood.h"
|
||||
|
||||
#define ETCD_CONFIG_WATCH_ID 1
|
||||
#define ETCD_OSD_STATE_WATCH_ID 2
|
||||
@@ -111,32 +110,6 @@ struct http_url_t
|
||||
std::string path;
|
||||
};
|
||||
|
||||
enum class user_type_t
|
||||
{
|
||||
CLIENT = 0,
|
||||
ADMIN = 1,
|
||||
MON = 2,
|
||||
OSD = 3,
|
||||
};
|
||||
|
||||
struct user_perm_t
|
||||
{
|
||||
enum class perm_type_t: uint8_t;
|
||||
constexpr static perm_type_t DENY = (perm_type_t)0;
|
||||
constexpr static perm_type_t READER = (perm_type_t)1;
|
||||
constexpr static perm_type_t OWNER = (perm_type_t)2;
|
||||
uint64_t mod_revision = 0;
|
||||
perm_type_t perm = DENY;
|
||||
};
|
||||
|
||||
struct user_info_t
|
||||
{
|
||||
std::string name;
|
||||
user_type_t type;
|
||||
robin_hood::unordered_flat_set<std::string> groups;
|
||||
robin_hood::unordered_flat_map<inode_t, user_perm_t> perm_cache;
|
||||
};
|
||||
|
||||
struct http_co_t;
|
||||
struct http_context_t;
|
||||
|
||||
@@ -172,6 +145,7 @@ public:
|
||||
int etcd_slow_timeout = 5000;
|
||||
int etcd_min_reload_interval = 1000;
|
||||
bool infinite_start = true;
|
||||
bool use_auth = false;
|
||||
uint64_t global_block_size = DEFAULT_BLOCK_SIZE;
|
||||
uint32_t global_bitmap_granularity = DEFAULT_BITMAP_GRANULARITY;
|
||||
uint32_t global_immediate_commit = IMMEDIATE_NONE;
|
||||
@@ -197,8 +171,7 @@ public:
|
||||
std::set<osd_num_t> seen_peers;
|
||||
std::map<inode_t, inode_config_t> inode_config;
|
||||
std::map<std::string, inode_t> inode_by_name;
|
||||
robin_hood::unordered_flat_map<std::string, std::shared_ptr<user_info_t>> user_info;
|
||||
uint64_t user_perm_cache_revision = 0;
|
||||
std::map<std::string, json11::Json> user_info;
|
||||
json11::Json node_placement;
|
||||
|
||||
std::function<void(std::map<std::string, etcd_kv_t> &)> on_change_hook;
|
||||
@@ -220,8 +193,6 @@ public:
|
||||
inode_config_t deserialize_inode_cfg(uint64_t inode_num, json11::Json value, uint64_t mod_revision);
|
||||
etcd_kv_t parse_etcd_kv(const json11::Json & kv_json);
|
||||
std::vector<std::string> get_addresses();
|
||||
std::shared_ptr<user_info_t> get_user(const std::string & username);
|
||||
bool check_image_perm(const std::shared_ptr<user_info_t> & user_info, inode_t inode_num, bool write);
|
||||
http_context_t *get_http_ctx();
|
||||
void etcd_call_oneshot(const std::string & etcd_address, const std::string & api, json11::Json payload, int timeout, std::function<void(std::string, json11::Json)> callback);
|
||||
void etcd_call(const std::string & api, json11::Json payload, int timeout, int retries, int interval, std::function<void(std::string, json11::Json)> callback);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include "openssl_util.h"
|
||||
#endif
|
||||
|
||||
// libc-ares
|
||||
@@ -164,6 +163,105 @@ void http_ares_cb(void *data, ares_socket_t socket_fd, int readable, int writabl
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
bool openssl_ctx_add_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
|
||||
{
|
||||
std::string pem;
|
||||
BIO *bio = NULL;
|
||||
if (file_or_pem.substr(0, 5) != "-----")
|
||||
{
|
||||
pem = read_file(file_or_pem);
|
||||
bio = BIO_new_mem_buf(pem.data(), pem.size());
|
||||
}
|
||||
else
|
||||
bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
|
||||
if (!bio)
|
||||
return false;
|
||||
X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
bool ok = !!x509;
|
||||
if (x509)
|
||||
{
|
||||
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
|
||||
X509_STORE_add_cert(store, x509);
|
||||
X509_free(x509);
|
||||
}
|
||||
BIO_free(bio);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool openssl_ctx_use_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
|
||||
{
|
||||
if (file_or_pem.substr(0, 5) == "-----")
|
||||
{
|
||||
return openssl_ctx_add_ca(ssl_ctx, file_or_pem);
|
||||
}
|
||||
return file_or_pem.empty()
|
||||
? !!SSL_CTX_set_default_verify_paths(ssl_ctx)
|
||||
: !!SSL_CTX_load_verify_locations(ssl_ctx, file_or_pem.c_str(), NULL);
|
||||
}
|
||||
|
||||
std::string openssl_get_cn(X509 *x509)
|
||||
{
|
||||
X509_NAME* subj = X509_get_subject_name(x509);
|
||||
int pos = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
|
||||
if (pos != -1)
|
||||
{
|
||||
X509_NAME_ENTRY* cn = X509_NAME_get_entry(subj, pos);
|
||||
ASN1_STRING* str = X509_NAME_ENTRY_get_data(cn);
|
||||
return std::string((const char*)ASN1_STRING_get0_data(str), ASN1_STRING_length(str));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool openssl_ctx_use_cert(SSL_CTX *ssl_ctx, const std::string & file_or_pem, std::string & common_name)
|
||||
{
|
||||
BIO *bio = NULL;
|
||||
std::string contents;
|
||||
if (file_or_pem.substr(0, 5) == "-----")
|
||||
bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
|
||||
else
|
||||
{
|
||||
contents = read_file(file_or_pem);
|
||||
if (!contents.size())
|
||||
return false;
|
||||
bio = BIO_new_mem_buf(contents.data(), contents.size());
|
||||
}
|
||||
if (!bio)
|
||||
return false;
|
||||
X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
bool ok = !!x509;
|
||||
if (x509)
|
||||
{
|
||||
ok = SSL_CTX_use_certificate(ssl_ctx, x509);
|
||||
if (ok)
|
||||
common_name = openssl_get_cn(x509);
|
||||
X509_free(x509);
|
||||
}
|
||||
BIO_free(bio);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool openssl_ctx_use_key(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
|
||||
{
|
||||
if (file_or_pem.substr(0, 5) == "-----")
|
||||
{
|
||||
BIO *bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
|
||||
if (!bio)
|
||||
return false;
|
||||
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
||||
bool ok = !!pkey;
|
||||
if (pkey)
|
||||
{
|
||||
ok = SSL_CTX_use_PrivateKey(ssl_ctx, pkey);
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
BIO_free(bio);
|
||||
return ok;
|
||||
}
|
||||
return !!SSL_CTX_use_PrivateKey_file(ssl_ctx, file_or_pem.c_str(), SSL_FILETYPE_PEM);
|
||||
}
|
||||
#endif
|
||||
|
||||
http_context_t* http_context_init(timerfd_manager_t *tfd, const std::string & ssl_cert, const std::string & ssl_key,
|
||||
const std::string & ssl_ca, bool verify_peer, std::string & error)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include <functional>
|
||||
#include "json11/json11.hpp"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/types.h>
|
||||
#endif
|
||||
|
||||
#define WS_CONTINUATION 0
|
||||
#define WS_TEXT 1
|
||||
#define WS_BINARY 2
|
||||
@@ -69,3 +73,11 @@ void http_close(http_co_t *co);
|
||||
void http_destroy(http_co_t *co);
|
||||
|
||||
#pragma GCC visibility pop
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
bool openssl_ctx_add_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
|
||||
bool openssl_ctx_use_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
|
||||
std::string openssl_get_cn(X509 *x509);
|
||||
bool openssl_ctx_use_cert(SSL_CTX *ssl_ctx, const std::string & file_or_pem, std::string & common_name);
|
||||
bool openssl_ctx_use_key(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
|
||||
#endif
|
||||
|
||||
+163
-119
@@ -15,6 +15,13 @@
|
||||
#ifdef WITH_RDMA
|
||||
#include "msgr_rdma.h"
|
||||
#endif
|
||||
#include "http_client.h"
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
@@ -118,7 +125,50 @@ void msgr_iothread_t::run()
|
||||
|
||||
void osd_messenger_t::init()
|
||||
{
|
||||
init_tls();
|
||||
if (!tls_cert.empty() || !tls_key.empty() || !osd_tls_ca.empty() || !client_tls_ca.empty())
|
||||
{
|
||||
// Initialize TLS context
|
||||
// FIXME: require OpenSSL
|
||||
#ifndef WITH_OPENSSL
|
||||
fprintf(stderr, "Vitastor is built without OpenSSL support\n");
|
||||
exit(1);
|
||||
#else
|
||||
if (tls_cert.empty() || tls_key.empty() || osd_tls_ca.empty() || osd_num && client_tls_ca.empty())
|
||||
{
|
||||
if (osd_num)
|
||||
fprintf(stderr, "Vitastor OSD TLS requires osd_tls_cert, osd_tls_key, osd_tls_ca, client_tls_ca\n");
|
||||
else
|
||||
fprintf(stderr, "Vitastor client TLS requires tls_cert, tls_key and osd_tls_ca\n");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl_ctx = SSL_CTX_new(TLS_method());
|
||||
if (!ssl_ctx)
|
||||
{
|
||||
init_err:
|
||||
fprintf(stderr, "OpenSSL initialization failed: %s\n", ERR_error_string(ERR_get_error(), NULL));
|
||||
exit(1);
|
||||
}
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
bool ok = SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
|
||||
ok = ok && openssl_ctx_add_ca(ssl_ctx, osd_tls_ca);
|
||||
if (osd_num)
|
||||
{
|
||||
// OSD uses 2 separate root certificates to distinguish between clients and peer OSDs
|
||||
ok = ok && openssl_ctx_add_ca(ssl_ctx, client_tls_ca);
|
||||
}
|
||||
ok = ok && openssl_ctx_use_cert(ssl_ctx, tls_cert, tls_cn);
|
||||
ok = ok && openssl_ctx_use_key(ssl_ctx, tls_key);
|
||||
if (!ok)
|
||||
{
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
ssl_ctx = NULL;
|
||||
goto init_err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef WITH_RDMACM
|
||||
if (use_rdmacm)
|
||||
{
|
||||
@@ -191,12 +241,9 @@ void osd_messenger_t::init()
|
||||
{
|
||||
auto cl = cl_it->second;
|
||||
cl_it++;
|
||||
if (!cl->osd_num && !cl->in_osd_num ||
|
||||
cl->peer_state != PEER_CONNECTED &&
|
||||
cl->peer_state != PEER_RDMA_CONNECTING_OUT &&
|
||||
cl->peer_state != PEER_RDMA)
|
||||
if (!cl->osd_num && !cl->in_osd_num || cl->peer_state != PEER_CONNECTED && cl->peer_state != PEER_RDMA)
|
||||
{
|
||||
// Do not run keepalive on regular and unconnected clients
|
||||
// Do not run keepalive on regular clients
|
||||
continue;
|
||||
}
|
||||
if (cl->ping_time_remaining > 0)
|
||||
@@ -204,21 +251,10 @@ void osd_messenger_t::init()
|
||||
cl->ping_time_remaining--;
|
||||
if (!cl->ping_time_remaining)
|
||||
{
|
||||
// Ping timed out
|
||||
if (cl->peer_state == PEER_RDMA_CONNECTING_OUT && cl->peer_fd >= 0)
|
||||
{
|
||||
fprintf(stderr, "Ping timed out for OSD %ju over RDMA (client %ju), switching back to TCP\n",
|
||||
cl->in_osd_num ? cl->in_osd_num : cl->osd_num, cl->client_id);
|
||||
delete cl->rdma_conn;
|
||||
cl->rdma_conn = NULL;
|
||||
cl->peer_state = PEER_CONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Ping timed out for OSD %ju (client %ju), disconnecting peer\n",
|
||||
cl->in_osd_num ? cl->in_osd_num : cl->osd_num, cl->client_id);
|
||||
clients_to_stop.push_back(cl->client_id);
|
||||
}
|
||||
// Ping timed out, stop the client
|
||||
fprintf(stderr, "Ping timed out for OSD %ju (client %ju), disconnecting peer\n",
|
||||
cl->in_osd_num ? cl->in_osd_num : cl->osd_num, cl->client_id);
|
||||
clients_to_stop.push_back(cl->client_id);
|
||||
}
|
||||
}
|
||||
else if (cl->idle_time_remaining > 0)
|
||||
@@ -236,7 +272,7 @@ void osd_messenger_t::init()
|
||||
.opcode = OSD_OP_PING,
|
||||
},
|
||||
};
|
||||
op->callback = [this](osd_op_t *op)
|
||||
op->callback = [this, cl](osd_op_t *op)
|
||||
{
|
||||
auto cl_it = clients.find(op->client_id);
|
||||
if (cl_it == clients.end())
|
||||
@@ -245,25 +281,14 @@ void osd_messenger_t::init()
|
||||
delete op;
|
||||
return;
|
||||
}
|
||||
auto cl = cl_it->second;
|
||||
bool failed = (op->reply.hdr.retval != 0);
|
||||
uint64_t fail_client_id = (op->reply.hdr.retval != 0 ? op->client_id : 0);
|
||||
auto fail_osd_num = cl->in_osd_num ? cl->in_osd_num : cl->osd_num;
|
||||
cl->ping_time_remaining = 0;
|
||||
delete op;
|
||||
if (failed)
|
||||
if (fail_client_id)
|
||||
{
|
||||
auto fail_osd_num = cl->in_osd_num ? cl->in_osd_num : cl->osd_num;
|
||||
if (cl->peer_state == PEER_RDMA_CONNECTING_OUT && cl->peer_fd >= 0)
|
||||
{
|
||||
fprintf(stderr, "Ping failed for OSD %ju over RDMA (client %ju), switching back to TCP\n", fail_osd_num, cl->client_id);
|
||||
delete cl->rdma_conn;
|
||||
cl->rdma_conn = NULL;
|
||||
cl->peer_state = PEER_CONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Ping failed for OSD %ju (client %ju), disconnecting peer\n", fail_osd_num, cl->client_id);
|
||||
stop_client(cl->client_id);
|
||||
}
|
||||
fprintf(stderr, "Ping failed for OSD %ju (client %ju), disconnecting peer\n", fail_osd_num, fail_client_id);
|
||||
stop_client(fail_client_id);
|
||||
}
|
||||
};
|
||||
cl->ping_time_remaining = osd_ping_timeout;
|
||||
@@ -322,52 +347,25 @@ osd_messenger_t::~osd_messenger_t()
|
||||
rdmacm_evch = NULL;
|
||||
}
|
||||
#endif
|
||||
for (auto encrypt_ctx: encrypt_xts_pool)
|
||||
for (auto encrypt_ctx: encrypt_ctx_pool)
|
||||
{
|
||||
destroy_aes_xts_encrypt(encrypt_ctx);
|
||||
}
|
||||
for (auto decrypt_ctx: decrypt_xts_pool)
|
||||
for (auto decrypt_ctx: decrypt_ctx_pool)
|
||||
{
|
||||
destroy_aes_xts_decrypt(decrypt_ctx);
|
||||
}
|
||||
destroy_tls();
|
||||
#ifdef WITH_OPENSSL
|
||||
if (ssl_ctx)
|
||||
{
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
ssl_ctx = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void osd_messenger_t::parse_config(const json11::Json & config, bool init)
|
||||
void osd_messenger_t::parse_config(const json11::Json & config)
|
||||
{
|
||||
this->max_cipher_pool_size = config["max_cipher_pool_size"].uint64_value();
|
||||
if (!this->max_cipher_pool_size)
|
||||
this->max_cipher_pool_size = 256;
|
||||
if (config["proto_checksums"].is_null())
|
||||
this->use_proto_checksums = MSGR_CSUM_PAYLOAD;
|
||||
else if (config["proto_checksums"].is_bool())
|
||||
this->use_proto_checksums = config["proto_checksums"].bool_value() ? MSGR_CSUM_FULL : 0;
|
||||
else if (config["proto_checksums"].string_value() != "")
|
||||
this->use_proto_checksums = config["proto_checksums"].string_value() == "full" ? MSGR_CSUM_FULL : MSGR_CSUM_PAYLOAD;
|
||||
else
|
||||
this->use_proto_checksums = 0;
|
||||
this->receive_buffer_size = (uint32_t)config["tcp_header_buffer_size"].uint64_value();
|
||||
if (!this->receive_buffer_size || this->receive_buffer_size > 1024*1024*1024)
|
||||
this->receive_buffer_size = 65536;
|
||||
this->min_zerocopy_send_size = config["min_zerocopy_send_size"].is_null()
|
||||
? DEFAULT_MIN_ZEROCOPY_SEND_SIZE
|
||||
: (int)config["min_zerocopy_send_size"].int64_value();
|
||||
this->peer_connect_interval = config["peer_connect_interval"].uint64_value();
|
||||
if (!this->peer_connect_interval)
|
||||
this->peer_connect_interval = 5;
|
||||
this->peer_connect_timeout = config["peer_connect_timeout"].uint64_value();
|
||||
if (!this->peer_connect_timeout)
|
||||
this->peer_connect_timeout = 5;
|
||||
this->osd_idle_timeout = config["osd_idle_timeout"].uint64_value();
|
||||
if (!this->osd_idle_timeout)
|
||||
this->osd_idle_timeout = 5;
|
||||
this->osd_ping_timeout = config["osd_ping_timeout"].uint64_value();
|
||||
if (!this->osd_ping_timeout)
|
||||
this->osd_ping_timeout = 5;
|
||||
this->log_level = config["log_level"].uint64_value();
|
||||
// All other parameters are only set on init
|
||||
if (!init)
|
||||
return;
|
||||
#ifdef WITH_RDMA
|
||||
if (!config["use_rdma"].is_null())
|
||||
{
|
||||
@@ -398,25 +396,58 @@ void osd_messenger_t::parse_config(const json11::Json & config, bool init)
|
||||
if (!this->rdma_max_msg || this->rdma_max_msg > 128*1024*1024)
|
||||
this->rdma_max_msg = 129*1024;
|
||||
#endif
|
||||
this->max_aes_xts_pool_size = config["max_aes_xts_pool_size"].uint64_value();
|
||||
if (!this->max_aes_xts_pool_size)
|
||||
this->max_aes_xts_pool_size = 256;
|
||||
if (config["proto_checksums"].is_null())
|
||||
this->use_proto_checksums = MSGR_CSUM_PAYLOAD;
|
||||
else if (config["proto_checksums"].is_bool())
|
||||
this->use_proto_checksums = config["proto_checksums"].bool_value() ? MSGR_CSUM_FULL : 0;
|
||||
else if (config["proto_checksums"].string_value() != "")
|
||||
this->use_proto_checksums = config["proto_checksums"].string_value() == "full" ? MSGR_CSUM_FULL : MSGR_CSUM_PAYLOAD;
|
||||
else
|
||||
this->use_proto_checksums = 0;
|
||||
if (!osd_num)
|
||||
{
|
||||
tls_cert = config["cert"].string_value();
|
||||
tls_key = config["pkey"].string_value();
|
||||
osd_tls_ca = config["osd_ca"].string_value();
|
||||
tls_cert = config["tls_cert"].string_value();
|
||||
tls_key = config["tls_key"].string_value();
|
||||
osd_tls_ca = config["osd_tls_ca"].string_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
tls_cert = config["osd_cert"].string_value();
|
||||
tls_key = config["osd_pkey"].string_value();
|
||||
osd_tls_ca = config["osd_ca"].string_value();
|
||||
client_tls_ca = config["client_ca"].string_value();
|
||||
tls_cert = config["osd_tls_cert"].string_value();
|
||||
tls_key = config["osd_tls_key"].string_value();
|
||||
osd_tls_ca = config["osd_tls_ca"].string_value();
|
||||
client_tls_ca = config["client_tls_ca"].string_value();
|
||||
}
|
||||
test_osd_aes_key.resize(32);
|
||||
if (fromhexstr(config["test_osd_aes_key"].string_value(), 32, (uint8_t*)test_osd_aes_key.data()) != 32)
|
||||
test_osd_aes_key.clear();
|
||||
if (!osd_num)
|
||||
this->iothread_count = (uint32_t)config["client_iothread_count"].uint64_value();
|
||||
else
|
||||
this->iothread_count = (uint32_t)config["osd_iothread_count"].uint64_value();
|
||||
this->receive_buffer_size = (uint32_t)config["tcp_header_buffer_size"].uint64_value();
|
||||
if (!this->receive_buffer_size || this->receive_buffer_size > 1024*1024*1024)
|
||||
this->receive_buffer_size = 65536;
|
||||
this->use_sync_send_recv = config["use_sync_send_recv"].bool_value() ||
|
||||
config["use_sync_send_recv"].uint64_value() || !ringloop;
|
||||
this->min_zerocopy_send_size = config["min_zerocopy_send_size"].is_null()
|
||||
? DEFAULT_MIN_ZEROCOPY_SEND_SIZE
|
||||
: (int)config["min_zerocopy_send_size"].int64_value();
|
||||
this->peer_connect_interval = config["peer_connect_interval"].uint64_value();
|
||||
if (!this->peer_connect_interval)
|
||||
this->peer_connect_interval = 5;
|
||||
this->peer_connect_timeout = config["peer_connect_timeout"].uint64_value();
|
||||
if (!this->peer_connect_timeout)
|
||||
this->peer_connect_timeout = 5;
|
||||
this->osd_idle_timeout = config["osd_idle_timeout"].uint64_value();
|
||||
if (!this->osd_idle_timeout)
|
||||
this->osd_idle_timeout = 5;
|
||||
this->osd_ping_timeout = config["osd_ping_timeout"].uint64_value();
|
||||
if (!this->osd_ping_timeout)
|
||||
this->osd_ping_timeout = 5;
|
||||
this->log_level = config["log_level"].uint64_value();
|
||||
// OSD public & cluster networks
|
||||
this->osd_networks.clear();
|
||||
if (config["osd_network"].is_string())
|
||||
@@ -622,7 +653,7 @@ void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
||||
handle_peer_epoll(peer_fd, epoll_events);
|
||||
});
|
||||
// Check OSD number
|
||||
init_tls_client(cl);
|
||||
ssl_init(cl, false);
|
||||
check_peer_config(cl);
|
||||
}
|
||||
|
||||
@@ -633,17 +664,6 @@ void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
||||
if (epoll_events & EPOLLRDHUP)
|
||||
{
|
||||
// Stop client
|
||||
if (cl->rdma_close_tcp && (cl->peer_state == PEER_RDMA ||
|
||||
cl->peer_state == PEER_RDMA_CONNECTING_IN ||
|
||||
cl->peer_state == PEER_RDMA_CONNECTING_OUT))
|
||||
{
|
||||
// It's allowed to stop the TCP socket during RDMA transition
|
||||
tfd->set_fd_handler(cl->peer_fd, false, NULL);
|
||||
clients_by_fd.erase(cl->peer_fd);
|
||||
close(cl->peer_fd);
|
||||
cl->peer_fd = -1;
|
||||
return;
|
||||
}
|
||||
if (log_level > 0)
|
||||
{
|
||||
fprintf(stderr, "[OSD %ju] client %ju disconnected\n", this->osd_num, cl->client_id);
|
||||
@@ -723,10 +743,7 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
||||
// Inform that we're OSD <osd_num>
|
||||
payload["osd_num"] = osd_num;
|
||||
}
|
||||
auto features = json11::Json::object{
|
||||
{ "check_sequencing", true },
|
||||
{ "rdma_close_tcp", true },
|
||||
};
|
||||
auto features = json11::Json::object{ { "check_sequencing", true } };
|
||||
if (use_proto_checksums)
|
||||
{
|
||||
features["proto_checksums"] = use_proto_checksums;
|
||||
@@ -771,11 +788,6 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
||||
err = true;
|
||||
fprintf(stderr, "Failed to get config from OSD %ju (retval=%jd), disconnecting peer\n", cl->osd_num, op->reply.hdr.retval);
|
||||
}
|
||||
else if (cl->gcm_enabled && !cl->hs_result.peer_is_osd)
|
||||
{
|
||||
err = true;
|
||||
fprintf(stderr, "Client %ju is not authenticated as an OSD, disconnecting peer\n", cl->client_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = json11::Json::parse(std::string((char*)op->buf), json_err);
|
||||
@@ -820,10 +832,6 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
||||
cl->proto_csum_status = MSGR_CSUM_PAYLOAD;
|
||||
}
|
||||
#ifdef WITH_RDMA
|
||||
if (config["features"]["rdma_close_tcp"].bool_value())
|
||||
{
|
||||
cl->rdma_close_tcp = true;
|
||||
}
|
||||
if (!use_rdmacm && cl->rdma_conn && config["rdma_address"].is_string())
|
||||
{
|
||||
msgr_rdma_address_t addr;
|
||||
@@ -848,14 +856,9 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl)
|
||||
{
|
||||
fprintf(stderr, "Connected to OSD %ju using RDMA\n", cl->osd_num);
|
||||
}
|
||||
cl->peer_state = (cl->rdma_close_tcp ? PEER_RDMA_CONNECTING_OUT : PEER_RDMA);
|
||||
cl->peer_state = PEER_RDMA;
|
||||
// Add the initial receive request
|
||||
init_recv_rdma(cl);
|
||||
// Check the connection by using a ping
|
||||
cl->ping_time_remaining = osd_ping_timeout;
|
||||
cl->idle_time_remaining = 0;
|
||||
delete op;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -892,7 +895,7 @@ void osd_messenger_t::accept_connections(int listen_fd)
|
||||
cl->peer_fd = peer_fd;
|
||||
cl->peer_state = PEER_CONNECTED;
|
||||
cl->in_buf = (uint8_t*)malloc_or_die(receive_buffer_size);
|
||||
init_tls_client(cl);
|
||||
ssl_init(cl, true);
|
||||
// Add FD to epoll
|
||||
tfd->set_fd_handler(peer_fd, false, [this](int peer_fd, int epoll_events)
|
||||
{
|
||||
@@ -907,6 +910,52 @@ void osd_messenger_t::accept_connections(int listen_fd)
|
||||
}
|
||||
}
|
||||
|
||||
void osd_messenger_t::ssl_init(osd_client_t *cl, bool server_mode)
|
||||
{
|
||||
if (!tls_cert.empty())
|
||||
{
|
||||
cl->write_to_ssl = BIO_new(BIO_s_mem());
|
||||
cl->read_from_ssl = BIO_new(BIO_s_mem());
|
||||
cl->ssl_cli = SSL_new(ssl_ctx);
|
||||
if (!cl->ssl_cli)
|
||||
{
|
||||
fprintf(stderr, "OpenSSL initialization failed: %s\n", ERR_error_string(ERR_get_error(), NULL));
|
||||
exit(1);
|
||||
}
|
||||
if (server_mode)
|
||||
{
|
||||
SSL_set_accept_state(cl->ssl_cli);
|
||||
}
|
||||
else
|
||||
{
|
||||
SSL_set_connect_state(cl->ssl_cli);
|
||||
}
|
||||
SSL_set_bio(cl->ssl_cli, cl->write_to_ssl, cl->read_from_ssl);
|
||||
bool ok = ssl_do_handshake(cl);
|
||||
assert(ok);
|
||||
}
|
||||
else if (!test_osd_aes_key.empty())
|
||||
{
|
||||
int r;
|
||||
cl->enc_ctx = EVP_CIPHER_CTX_new();
|
||||
assert(cl->enc_ctx);
|
||||
r = EVP_EncryptInit_ex(cl->enc_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
|
||||
assert(r == 1);
|
||||
r = EVP_CIPHER_CTX_set_padding(cl->enc_ctx, 0);
|
||||
assert(r == 1);
|
||||
r = EVP_CIPHER_CTX_ctrl(cl->enc_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
|
||||
assert(r == 1);
|
||||
cl->dec_ctx = EVP_CIPHER_CTX_new();
|
||||
assert(cl->dec_ctx);
|
||||
r = EVP_DecryptInit_ex(cl->dec_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
|
||||
assert(r == 1);
|
||||
r = EVP_CIPHER_CTX_set_padding(cl->dec_ctx, 0);
|
||||
assert(r == 1);
|
||||
r = EVP_CIPHER_CTX_ctrl(cl->dec_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
|
||||
assert(r == 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_RDMA
|
||||
msgr_rdma_context_t* osd_messenger_t::choose_rdma_context(osd_client_t *cl)
|
||||
{
|
||||
@@ -935,11 +984,6 @@ bool osd_messenger_t::is_use_rdmacm()
|
||||
}
|
||||
#endif
|
||||
|
||||
bool osd_messenger_t::is_encryption_enabled()
|
||||
{
|
||||
return tls_cert != "" || tls_key != "" || osd_tls_ca != "";
|
||||
}
|
||||
|
||||
json11::Json::object osd_messenger_t::read_config(const json11::Json & config)
|
||||
{
|
||||
json11::Json::object file_config;
|
||||
|
||||
+44
-56
@@ -12,10 +12,8 @@
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/types.h>
|
||||
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
#include <isa-l_crypto/aes_gcm.h>
|
||||
#endif
|
||||
|
||||
#include "../util/xxh_x86dispatch.h"
|
||||
@@ -25,7 +23,6 @@
|
||||
#include "msgr_op.h"
|
||||
#include "timerfd_manager.h"
|
||||
#include "addr_util.h"
|
||||
#include "msgr_handshake.h"
|
||||
#include <ringloop.h>
|
||||
|
||||
#define CL_READ_HDR 1
|
||||
@@ -35,10 +32,9 @@
|
||||
|
||||
#define PEER_CONNECTING 1
|
||||
#define PEER_CONNECTED 2
|
||||
#define PEER_RDMA_CONNECTING_IN 3
|
||||
#define PEER_RDMA_CONNECTING_OUT 4
|
||||
#define PEER_RDMA 5
|
||||
#define PEER_STOPPED 6
|
||||
#define PEER_RDMA_CONNECTING 3
|
||||
#define PEER_RDMA 4
|
||||
#define PEER_STOPPED 5
|
||||
|
||||
#define MSGR_CSUM_PAYLOAD 1
|
||||
#define MSGR_CSUM_FULL 2
|
||||
@@ -48,11 +44,6 @@
|
||||
|
||||
#define DEFAULT_MIN_ZEROCOPY_SEND_SIZE 32*1024
|
||||
|
||||
#define AES_256_GCM_KEY_SIZE 32
|
||||
#define AES_256_GCM_IV_SIZE 12
|
||||
|
||||
#define MAX_SIMPLE_PAYLOAD_SIZE 1048576
|
||||
|
||||
struct msgr_sendp_t
|
||||
{
|
||||
osd_op_t *op;
|
||||
@@ -69,7 +60,13 @@ struct op_aes_xts_decrypt_t;
|
||||
void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_ctx);
|
||||
void destroy_aes_xts_decrypt(op_aes_xts_decrypt_t *decrypt_ctx);
|
||||
|
||||
struct user_info_t;
|
||||
// Standard TLS record header. We are only interested in the record size
|
||||
struct __attribute__((__packed__)) msgr_tls_record_hdr_t
|
||||
{
|
||||
uint8_t content_type;
|
||||
uint16_t version;
|
||||
uint16_t size;
|
||||
};
|
||||
|
||||
struct osd_client_t
|
||||
{
|
||||
@@ -93,27 +90,29 @@ struct osd_client_t
|
||||
msgr_rdma_connection_t *rdma_conn = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
SSL *ssl_cli = NULL;
|
||||
BIO *write_to_ssl = NULL;
|
||||
// FIXME: use custom bio to avoid 1 more memory copy?
|
||||
BIO *read_from_ssl = NULL;
|
||||
uint8_t *ssl_out_buf = NULL;
|
||||
size_t ssl_out_buf_size = 0, ssl_out_buf_cap = 0;
|
||||
bool ssl_handshake_done = false;
|
||||
msgr_tls_record_hdr_t ssl_read_record;
|
||||
size_t ssl_read_header_size = 0;
|
||||
bool ssl_more_to_buffer = false;
|
||||
|
||||
bool gcm_enabled = false;
|
||||
msgr_handshake_i *hs = NULL;
|
||||
msgr_handshake_result_t hs_result;
|
||||
std::shared_ptr<user_info_t> user_info;
|
||||
std::vector<uint8_t> my_key, peer_key;
|
||||
uint64_t my_iv_ctr = 0, peer_iv_ctr = 0;
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
isal_gcm_key_data my_key_isal, peer_key_isal;
|
||||
isal_gcm_context_data *enc_ctx = NULL;
|
||||
isal_gcm_context_data *dec_ctx = NULL;
|
||||
#else
|
||||
EVP_CIPHER_CTX *enc_ctx = NULL;
|
||||
EVP_CIPHER_CTX *dec_ctx = NULL;
|
||||
#endif
|
||||
uint8_t enc_tag[16];
|
||||
size_t enc_tag_size = 0;
|
||||
bool enc_batch = false;
|
||||
EVP_CIPHER_CTX *dec_ctx = NULL;
|
||||
uint8_t dec_tag[16];
|
||||
size_t dec_tag_size = 0;
|
||||
uint32_t dec_batch_size = 0;
|
||||
size_t dec_batch_size_size = 0;
|
||||
std::vector<osd_op_t*> unverified_ops;
|
||||
#endif
|
||||
|
||||
// Read state
|
||||
bool io_error = false;
|
||||
@@ -127,9 +126,8 @@ struct osd_client_t
|
||||
std::vector<int> recv_flags;
|
||||
uint64_t read_op_id = 1;
|
||||
bool check_sequencing = false;
|
||||
bool rdma_close_tcp = false;
|
||||
bool enable_pg_locks = false;
|
||||
op_aes_xts_decrypt_t *xts_dec_ctx = NULL;
|
||||
op_aes_xts_decrypt_t *decrypt_ctx = NULL;
|
||||
size_t read_op_inline_decrypt_pos = 0;
|
||||
size_t read_op_inline_decrypt_in = 0;
|
||||
int proto_csum_status = 0;
|
||||
@@ -155,7 +153,7 @@ struct osd_client_t
|
||||
size_t send_list_size = 0;
|
||||
std::deque<osd_op_t*> send_free_ops;
|
||||
std::vector<osd_op_t*> zc_free_list;
|
||||
op_aes_xts_encrypt_t *xts_enc_ctx = NULL;
|
||||
op_aes_xts_encrypt_t *encrypt_ctx = NULL;
|
||||
XXH3_state_t* write_csum_state = NULL;
|
||||
|
||||
~osd_client_t();
|
||||
@@ -241,9 +239,11 @@ struct __attribute__((visibility("default"))) osd_messenger_t
|
||||
{
|
||||
protected:
|
||||
friend class copy_op_reader_t;
|
||||
friend class ssl_op_reader_t;
|
||||
friend class gcm_op_reader_t;
|
||||
friend class get_op_reader_t;
|
||||
friend class copy_op_writer_t;
|
||||
friend class ssl_op_writer_t;
|
||||
friend class gcm_op_writer_t;
|
||||
friend class get_op_writer_t;
|
||||
|
||||
@@ -258,12 +258,13 @@ protected:
|
||||
bool use_sync_send_recv = false;
|
||||
int min_zerocopy_send_size = DEFAULT_MIN_ZEROCOPY_SEND_SIZE;
|
||||
int iothread_count = 0;
|
||||
int max_cipher_pool_size = 256;
|
||||
int max_aes_xts_pool_size = 256;
|
||||
|
||||
std::string tls_cert;
|
||||
std::string tls_key;
|
||||
std::string osd_tls_ca;
|
||||
std::string client_tls_ca;
|
||||
std::string test_osd_aes_key; // FIXME Insecure, only for PoC tests
|
||||
|
||||
#ifdef WITH_RDMA
|
||||
bool use_rdma = true;
|
||||
@@ -281,14 +282,13 @@ protected:
|
||||
robin_hood::unordered_flat_map<rdma_cm_id*, rdmacm_connecting_t*> rdmacm_connecting;
|
||||
#endif
|
||||
|
||||
bool gcm_enabled = false;
|
||||
msgr_handshake_ctx_i *hs_ctx = NULL;
|
||||
#ifdef WITH_OPENSSL
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
std::string tls_cn;
|
||||
|
||||
void init_tls();
|
||||
void destroy_tls();
|
||||
void init_tls_client(osd_client_t *cl);
|
||||
bool do_tls_handshake(osd_client_t *cl, bool from_recv = false);
|
||||
bool derive_aes_keys(osd_client_t *cl, bool update_my, bool update_peer);
|
||||
void ssl_init(osd_client_t *cl, bool server_mode);
|
||||
bool ssl_do_handshake(osd_client_t *cl);
|
||||
#endif
|
||||
|
||||
std::vector<msgr_iothread_t*> iothreads;
|
||||
std::vector<uint64_t> read_ready_clients;
|
||||
@@ -296,27 +296,16 @@ protected:
|
||||
// We don't use ringloop->set_immediate here because we may have no ringloop in client :)
|
||||
std::deque<osd_op_t*> set_immediate_ops;
|
||||
|
||||
std::vector<op_aes_xts_encrypt_t*> encrypt_xts_pool;
|
||||
std::vector<op_aes_xts_decrypt_t*> decrypt_xts_pool;
|
||||
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
std::vector<isal_gcm_context_data*> encrypt_gcm_pool;
|
||||
std::vector<isal_gcm_context_data*> decrypt_gcm_pool;
|
||||
#else
|
||||
std::vector<EVP_CIPHER_CTX*> encrypt_gcm_pool;
|
||||
std::vector<EVP_CIPHER_CTX*> decrypt_gcm_pool;
|
||||
#endif
|
||||
std::vector<op_aes_xts_encrypt_t*> encrypt_ctx_pool;
|
||||
std::vector<op_aes_xts_decrypt_t*> decrypt_ctx_pool;
|
||||
|
||||
public:
|
||||
timerfd_manager_t *tfd = NULL;
|
||||
ring_loop_t *ringloop = NULL;
|
||||
bool has_sendmsg_zc = false;
|
||||
// osd_num_t is only for logging and asserts
|
||||
uint64_t next_client_id = 1;
|
||||
// osd_num = 0 for client messenger, osd_num > 0 for OSD messenger
|
||||
osd_num_t osd_num = 0;
|
||||
uint32_t clean_entry_bitmap_size = 0;
|
||||
uint32_t bs_block_size = 0;
|
||||
uint32_t max_write_request_size = 0;
|
||||
osd_num_t osd_num;
|
||||
robin_hood::unordered_flat_map<uint64_t, osd_client_t*> clients;
|
||||
robin_hood::unordered_flat_map<uint64_t, osd_client_t*> osd_peers;
|
||||
robin_hood::unordered_flat_map<int, osd_client_t*> clients_by_fd;
|
||||
@@ -332,7 +321,7 @@ public:
|
||||
osd_op_stats_t stats, recovery_stats;
|
||||
|
||||
void init();
|
||||
void parse_config(const json11::Json & config, bool init);
|
||||
void parse_config(const json11::Json & config);
|
||||
void connect_peer(uint64_t osd_num, json11::Json peer_state);
|
||||
void stop_client(uint64_t client_id, bool force_delete = false);
|
||||
void destroy_client(osd_client_t *cl);
|
||||
@@ -341,7 +330,6 @@ public:
|
||||
std::function<void(osd_num_t)> repeer_pgs;
|
||||
std::function<void(osd_num_t)> break_pg_locks;
|
||||
std::function<bool(osd_client_t*, json11::Json)> check_config_hook;
|
||||
std::function<void(osd_client_t*)> handshake_hook;
|
||||
void read_requests();
|
||||
void send_replies();
|
||||
void accept_connections(int listen_fd);
|
||||
@@ -362,7 +350,6 @@ public:
|
||||
rdma_cm_id *rdmacm_listen(const std::string & bind_address, int rdmacm_port, int *bound_port, int log_level);
|
||||
void rdmacm_destroy_listener(rdma_cm_id *listener);
|
||||
#endif
|
||||
bool is_encryption_enabled();
|
||||
|
||||
void inc_op_stats(osd_op_stats_t & stats, uint64_t opcode, timespec & tv_begin, timespec & tv_end, uint64_t len);
|
||||
void measure_exec(osd_op_t *cur_op);
|
||||
@@ -394,6 +381,7 @@ protected:
|
||||
bool allocate_reply_buffers(osd_client_t *cl, osd_op_t *op);
|
||||
bool op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr);
|
||||
bool handle_finished_op(osd_client_t *cl);
|
||||
void execute_verified_op(osd_client_t *cl, osd_op_t *op);
|
||||
void handle_immediate_ops();
|
||||
|
||||
void op_encrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf, size_t enc_len, uint8_t *plain, size_t plain_len, size_t & done_plain, size_t & done_enc);
|
||||
|
||||
+53
-187
@@ -3,23 +3,13 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
#include <isa-l_crypto/isal_crypto_api.h>
|
||||
#endif
|
||||
|
||||
#include "str_util.h"
|
||||
#include "etcd_state_client.h"
|
||||
#include "messenger.h"
|
||||
#include "msgr_encrypt.h"
|
||||
#include "http_client.h"
|
||||
#include "openssl_util.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
op_aes_xts_encrypt_t::op_aes_xts_encrypt_t()
|
||||
{
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
if (!(ctx = EVP_CIPHER_CTX_new()))
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -31,13 +21,16 @@ op_aes_xts_encrypt_t::op_aes_xts_encrypt_t()
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Error: Vitastor is built without encryption support\n");
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
op_aes_xts_encrypt_t::~op_aes_xts_encrypt_t()
|
||||
{
|
||||
assert(!encrypted);
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
#endif
|
||||
if (tmp)
|
||||
@@ -59,7 +52,7 @@ void op_aes_xts_encrypt_t::start(uint8_t *key, uint64_t start_offset, size_t blo
|
||||
tmp = NULL;
|
||||
tmp_size = 0;
|
||||
}
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL) != 1)
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -70,12 +63,9 @@ void op_aes_xts_encrypt_t::start(uint8_t *key, uint64_t start_offset, size_t blo
|
||||
|
||||
void op_aes_xts_encrypt_t::encrypt_block(uint8_t *in, uint8_t *out)
|
||||
{
|
||||
#ifdef WITH_OPENSSL
|
||||
uint8_t iv[16] = { 0 };
|
||||
*((uint64_t*)iv) = start_offset + offset - offset%block_size;
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_xts_enc_256(key+32, key, iv, block_size, in, out);
|
||||
assert(r == 0 || r == ISAL_CRYPTO_ERR_XTS_SAME_KEYS);
|
||||
#else
|
||||
if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) != 1)
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -108,10 +98,7 @@ void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size
|
||||
done_out += max_out;
|
||||
tmp_pos += max_out;
|
||||
if (tmp_pos >= block_size)
|
||||
{
|
||||
encrypted = false;
|
||||
done_in += 1;
|
||||
}
|
||||
}
|
||||
else if (max_in < block_size - offset%block_size)
|
||||
{
|
||||
@@ -139,7 +126,7 @@ void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size
|
||||
encrypted = true;
|
||||
memcpy(out, tmp, max_out);
|
||||
tmp_pos = max_out;
|
||||
done_in += max_in-1;
|
||||
done_in += max_in;
|
||||
offset += max_in;
|
||||
done_out += max_out;
|
||||
}
|
||||
@@ -171,7 +158,7 @@ void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_ctx)
|
||||
|
||||
op_aes_xts_decrypt_t::op_aes_xts_decrypt_t()
|
||||
{
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
if (!(ctx = EVP_CIPHER_CTX_new()))
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -183,13 +170,16 @@ op_aes_xts_decrypt_t::op_aes_xts_decrypt_t()
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Error: Vitastor is built without encryption support\n");
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
op_aes_xts_decrypt_t::~op_aes_xts_decrypt_t()
|
||||
{
|
||||
assert(!decrypted);
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
#endif
|
||||
if (tmp)
|
||||
@@ -200,9 +190,9 @@ void op_aes_xts_decrypt_t::start(uint8_t **key_chain, size_t chain_size, void *k
|
||||
{
|
||||
assert(!decrypted);
|
||||
this->start_offset = start_offset;
|
||||
this->key_chain = key_chain;
|
||||
this->chain_size = chain_size;
|
||||
this->key_indexes = key_indexes;
|
||||
this->key_chain = chain_size > 1 ? key_chain : 0;
|
||||
this->chain_size = chain_size > 1 ? chain_size : 0;
|
||||
this->key_indexes = chain_size > 1 ? key_indexes : NULL;
|
||||
this->key_index_bytes = osd_op_rw_t::chain_info_bytes(chain_size);
|
||||
assert(chain_size <= 1 || key_indexes != NULL);
|
||||
this->block_size = block_size;
|
||||
@@ -214,7 +204,7 @@ void op_aes_xts_decrypt_t::start(uint8_t **key_chain, size_t chain_size, void *k
|
||||
tmp = NULL;
|
||||
tmp_size = 0;
|
||||
}
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
if (chain_size == 1 && key_chain[0] && EVP_DecryptInit_ex(ctx, NULL, NULL, key_chain[0], NULL) != 1)
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -226,7 +216,7 @@ void op_aes_xts_decrypt_t::start(uint8_t **key_chain, size_t chain_size, void *k
|
||||
void op_aes_xts_decrypt_t::decrypt_block(uint8_t *in, uint8_t *out)
|
||||
{
|
||||
uint8_t *key = NULL;
|
||||
if (chain_size > 1)
|
||||
if (chain_size)
|
||||
{
|
||||
uint32_t key_index = key_index_bytes == 1
|
||||
? ((uint8_t*)key_indexes)[offset/block_size]
|
||||
@@ -237,24 +227,17 @@ void op_aes_xts_decrypt_t::decrypt_block(uint8_t *in, uint8_t *out)
|
||||
: UINT32_MAX));
|
||||
assert(key_index < chain_size);
|
||||
key = key_chain[key_index];
|
||||
if (!key)
|
||||
{
|
||||
if (in != out)
|
||||
memcpy(out, in, block_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key = key_chain[0];
|
||||
}
|
||||
if (!key)
|
||||
{
|
||||
if (in != out)
|
||||
memcpy(out, in, block_size);
|
||||
return;
|
||||
}
|
||||
#ifdef WITH_OPENSSL
|
||||
uint8_t iv[16] = { 0 };
|
||||
*((uint64_t*)iv) = start_offset + offset - offset%block_size;
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_xts_dec_256(key+32, key, iv, block_size, in, out);
|
||||
assert(r == 0 || r == ISAL_CRYPTO_ERR_XTS_SAME_KEYS);
|
||||
#else
|
||||
if (EVP_DecryptInit_ex(ctx, NULL, NULL, chain_size == 1 ? NULL : key, iv) != 1)
|
||||
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) != 1)
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
@@ -289,10 +272,7 @@ void op_aes_xts_decrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size
|
||||
done_out += max_out;
|
||||
tmp_pos += max_out;
|
||||
if (tmp_pos >= block_size)
|
||||
{
|
||||
decrypted = false;
|
||||
done_in += 1;
|
||||
}
|
||||
}
|
||||
else if (max_in < block_size - offset%block_size)
|
||||
{
|
||||
@@ -321,7 +301,7 @@ void op_aes_xts_decrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size
|
||||
if (out)
|
||||
memcpy(out, tmp, max_out);
|
||||
tmp_pos = max_out;
|
||||
done_in += max_in-1;
|
||||
done_in += max_in;
|
||||
offset += max_in;
|
||||
done_out += max_out;
|
||||
}
|
||||
@@ -355,23 +335,23 @@ void destroy_aes_xts_decrypt(op_aes_xts_decrypt_t *decrypt_ctx)
|
||||
|
||||
void osd_messenger_t::op_encrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf, size_t enc_len, uint8_t *plain, size_t plain_len, size_t & done_plain, size_t & done_enc)
|
||||
{
|
||||
if (!cl->xts_enc_ctx)
|
||||
if (!cl->encrypt_ctx)
|
||||
{
|
||||
if (encrypt_xts_pool.size())
|
||||
if (encrypt_ctx_pool.size())
|
||||
{
|
||||
cl->xts_enc_ctx = encrypt_xts_pool.back();
|
||||
encrypt_xts_pool.pop_back();
|
||||
cl->encrypt_ctx = encrypt_ctx_pool.back();
|
||||
encrypt_ctx_pool.pop_back();
|
||||
}
|
||||
else
|
||||
cl->xts_enc_ctx = new op_aes_xts_encrypt_t();
|
||||
cl->encrypt_ctx = new op_aes_xts_encrypt_t();
|
||||
assert(cl->write_op->enc->key_chain[0]);
|
||||
cl->xts_enc_ctx->start(cl->write_op->enc->key_chain[0], cl->write_op->req.rw.offset, cl->write_op->enc->bitmap_granularity);
|
||||
cl->encrypt_ctx->start(cl->write_op->enc->key_chain[0], cl->write_op->req.rw.offset, cl->write_op->enc->bitmap_granularity);
|
||||
}
|
||||
while (done_plain < plain_len && done_enc < enc_len)
|
||||
while (done_enc < enc_len && (done_plain < plain_len || cl->encrypt_ctx->has_buffered()))
|
||||
{
|
||||
size_t done_in = 0;
|
||||
size_t done_out = 0;
|
||||
cl->xts_enc_ctx->update(plain+done_plain, plain_len-done_plain, enc_buf+done_enc, enc_len-done_enc, done_in, done_out);
|
||||
cl->encrypt_ctx->update(plain+done_plain, plain_len-done_plain, enc_buf+done_enc, enc_len-done_enc, done_in, done_out);
|
||||
if (cl->write_csum_state && done_out > 0)
|
||||
XXH3_64bits_update(cl->write_csum_state, enc_buf+done_enc, done_out);
|
||||
done_enc += done_out;
|
||||
@@ -388,7 +368,7 @@ void osd_messenger_t::op_decrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf,
|
||||
size_t done_in = 0;
|
||||
size_t done_out = 0;
|
||||
// plain == NULL means skip output
|
||||
cl->xts_dec_ctx->update(enc_buf+done_enc, enc_len-done_enc, plain ? plain+done_plain : NULL, plain_len-done_plain, done_in, done_out);
|
||||
cl->decrypt_ctx->update(enc_buf+done_enc, enc_len-done_enc, plain ? plain+done_plain : NULL, plain_len-done_plain, done_in, done_out);
|
||||
if (cl->read_csum_state && done_in > 0)
|
||||
XXH3_64bits_update(cl->read_csum_state, enc_buf+done_enc, done_in);
|
||||
done_enc += done_in;
|
||||
@@ -400,18 +380,18 @@ void osd_messenger_t::op_decrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf,
|
||||
|
||||
void osd_messenger_t::op_decrypt_start(osd_client_t* cl)
|
||||
{
|
||||
if (!cl->xts_dec_ctx)
|
||||
if (!cl->decrypt_ctx)
|
||||
{
|
||||
if (decrypt_xts_pool.size())
|
||||
if (decrypt_ctx_pool.size())
|
||||
{
|
||||
cl->xts_dec_ctx = decrypt_xts_pool.back();
|
||||
decrypt_xts_pool.pop_back();
|
||||
cl->decrypt_ctx = decrypt_ctx_pool.back();
|
||||
decrypt_ctx_pool.pop_back();
|
||||
}
|
||||
else
|
||||
cl->xts_dec_ctx = new op_aes_xts_decrypt_t();
|
||||
cl->decrypt_ctx = new op_aes_xts_decrypt_t();
|
||||
auto & enc = cl->read_op->enc;
|
||||
assert(cl->read_op->req.hdr.opcode == OSD_OP_READ);
|
||||
cl->xts_dec_ctx->start(enc->key_chain, enc->chain_size,
|
||||
cl->decrypt_ctx->start(enc->key_chain, enc->chain_size,
|
||||
(cl->read_op->req.rw.flags & OSD_OP_RETURN_CHAIN) ? (uint8_t*)cl->read_op->bitmap + enc->read_chain_bitmap_pos : 0,
|
||||
cl->read_op->req.rw.offset, enc->bitmap_granularity);
|
||||
}
|
||||
@@ -443,7 +423,7 @@ void osd_messenger_t::op_decrypt_inline(osd_client_t* cl)
|
||||
size_t out_len = op->iov.buf[j].iov_len - from_out;
|
||||
size_t done_in = 0;
|
||||
size_t done_out = 0;
|
||||
cl->xts_dec_ctx->update(in, in_len, out, out_len, done_in, done_out);
|
||||
cl->decrypt_ctx->update(in, in_len, out, out_len, done_in, done_out);
|
||||
if (done_in >= in_len)
|
||||
{
|
||||
i++;
|
||||
@@ -464,138 +444,24 @@ void osd_messenger_t::op_decrypt_inline(osd_client_t* cl)
|
||||
|
||||
void osd_messenger_t::op_decrypt_free(osd_client_t* cl)
|
||||
{
|
||||
if (cl->xts_dec_ctx)
|
||||
if (cl->decrypt_ctx)
|
||||
{
|
||||
if (decrypt_xts_pool.size() > max_cipher_pool_size)
|
||||
delete cl->xts_dec_ctx;
|
||||
if (decrypt_ctx_pool.size() > max_aes_xts_pool_size)
|
||||
delete cl->decrypt_ctx;
|
||||
else
|
||||
decrypt_xts_pool.push_back(cl->xts_dec_ctx);
|
||||
cl->xts_dec_ctx = NULL;
|
||||
decrypt_ctx_pool.push_back(cl->decrypt_ctx);
|
||||
cl->decrypt_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void osd_messenger_t::op_encrypt_free(osd_client_t* cl)
|
||||
{
|
||||
if (cl->xts_enc_ctx)
|
||||
if (cl->encrypt_ctx)
|
||||
{
|
||||
if (encrypt_xts_pool.size() > max_cipher_pool_size)
|
||||
delete cl->xts_enc_ctx;
|
||||
if (encrypt_ctx_pool.size() > max_aes_xts_pool_size)
|
||||
delete cl->encrypt_ctx;
|
||||
else
|
||||
encrypt_xts_pool.push_back(cl->xts_enc_ctx);
|
||||
cl->xts_enc_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool osd_messenger_t::derive_aes_keys(osd_client_t *cl, bool update_my, bool update_peer)
|
||||
{
|
||||
if (!cl->hs_result.shared_secret.size())
|
||||
{
|
||||
cl->hs_result = cl->hs->get_result();
|
||||
if (handshake_hook)
|
||||
{
|
||||
handshake_hook(cl);
|
||||
}
|
||||
}
|
||||
std::vector<uint8_t> old_my = cl->my_key, old_peer = cl->peer_key;
|
||||
// Both keys include AES key and iv + xxhash3 secret
|
||||
const auto len = AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE + XXH_SECRET_DEFAULT_SIZE;
|
||||
cl->my_key.resize(len);
|
||||
cl->peer_key.resize(len);
|
||||
bool ok = true;
|
||||
if (update_my || !old_my.size())
|
||||
{
|
||||
ok = ok && hs_ctx->derive_kdf(cl->hs_result.shared_secret.data(), cl->hs_result.shared_secret.size(),
|
||||
old_my.size() ? old_my.data() : NULL, old_my.size(),
|
||||
cl->is_incoming ? "server key" : "client key", cl->my_key.data(), len);
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
if (ok)
|
||||
isal_aes_gcm_pre_256(cl->my_key.data(), &cl->my_key_isal);
|
||||
#endif
|
||||
cl->my_iv_ctr = 0;
|
||||
}
|
||||
if (update_peer || !old_peer.size())
|
||||
{
|
||||
ok = ok && hs_ctx->derive_kdf(cl->hs_result.shared_secret.data(), cl->hs_result.shared_secret.size(),
|
||||
old_peer.size() ? old_peer.data() : NULL, old_peer.size(),
|
||||
!cl->is_incoming ? "server key" : "client key", cl->peer_key.data(), len);
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
if (ok)
|
||||
isal_aes_gcm_pre_256(cl->peer_key.data(), &cl->peer_key_isal);
|
||||
#endif
|
||||
cl->peer_iv_ctr = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void osd_messenger_t::init_tls()
|
||||
{
|
||||
if (!tls_cert.empty() || !tls_key.empty() || !osd_tls_ca.empty() || !client_tls_ca.empty())
|
||||
{
|
||||
if (tls_cert.empty() || tls_key.empty() || osd_tls_ca.empty() || osd_num && client_tls_ca.empty())
|
||||
{
|
||||
if (osd_num)
|
||||
fprintf(stderr, "Vitastor transport encryption requires osd_cert, osd_pkey, osd_ca, client_ca options for OSDs\n");
|
||||
else
|
||||
fprintf(stderr, "Vitastor transport encryption requires cert, pkey and osd_ca options\n");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef __MOCK__
|
||||
gcm_enabled = true;
|
||||
hs_ctx = msgr_handshake_ctx_i::create_ctx();
|
||||
if (!hs_ctx->init(tls_cert, tls_key, osd_tls_ca, client_tls_ca))
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", hs_ctx->get_error().c_str());
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void osd_messenger_t::init_tls_client(osd_client_t *cl)
|
||||
{
|
||||
if (gcm_enabled)
|
||||
{
|
||||
cl->gcm_enabled = true;
|
||||
cl->hs = hs_ctx->create();
|
||||
cl->hs->init(cl->is_incoming);
|
||||
if (cl->hs->get_out().size())
|
||||
{
|
||||
if (cl->write_state == 0)
|
||||
{
|
||||
cl->write_state = CL_WRITE_READY;
|
||||
write_ready_clients.push_back(cl->client_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void osd_messenger_t::destroy_tls()
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
for (isal_gcm_context_data *ctx: encrypt_gcm_pool)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
for (isal_gcm_context_data *ctx: decrypt_gcm_pool)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
#else
|
||||
for (EVP_CIPHER_CTX *ctx: encrypt_gcm_pool)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
for (EVP_CIPHER_CTX *ctx: decrypt_gcm_pool)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
#endif
|
||||
if (hs_ctx)
|
||||
{
|
||||
delete hs_ctx;
|
||||
hs_ctx = NULL;
|
||||
encrypt_ctx_pool.push_back(cl->encrypt_ctx);
|
||||
cl->encrypt_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
#include <isa-l_crypto/aes_xts.h>
|
||||
#endif
|
||||
|
||||
#include "../util/xxh_x86dispatch.h"
|
||||
// WITH_OPENSSL is left to possibly support other crypto libraries
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
class op_aes_xts_encrypt_t
|
||||
{
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
EVP_CIPHER_CTX *ctx = NULL;
|
||||
#endif
|
||||
uint64_t start_offset = 0;
|
||||
@@ -32,6 +31,7 @@ public:
|
||||
op_aes_xts_encrypt_t();
|
||||
~op_aes_xts_encrypt_t();
|
||||
|
||||
inline bool has_buffered() { return encrypted; };
|
||||
void start(uint8_t *key, uint64_t start_offset, size_t block_size);
|
||||
void update(uint8_t *in, size_t max_in, uint8_t *out, size_t max_out, size_t & done_in, size_t & done_out);
|
||||
};
|
||||
@@ -40,7 +40,7 @@ void destroy_aes_xts_encrypt(op_aes_xts_encrypt_t *encrypt_ctx);
|
||||
|
||||
class op_aes_xts_decrypt_t
|
||||
{
|
||||
#ifndef WITH_ISAL_CRYPTO
|
||||
#ifdef WITH_OPENSSL
|
||||
EVP_CIPHER_CTX *ctx = NULL;
|
||||
#endif
|
||||
uint64_t start_offset = 0;
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
op_aes_xts_decrypt_t();
|
||||
~op_aes_xts_decrypt_t();
|
||||
|
||||
inline bool has_buffered() { return decrypted; };
|
||||
void start(uint8_t **key_chain, size_t chain_size, void *key_indexes, uint64_t start_offset, size_t block_size);
|
||||
void update(uint8_t *in, size_t max_in, uint8_t *out, size_t max_out, size_t & done_in, size_t & done_out);
|
||||
};
|
||||
|
||||
@@ -1,765 +0,0 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2026+
|
||||
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "msgr_handshake.h"
|
||||
#include "openssl_util.h"
|
||||
#include "str_util.h"
|
||||
|
||||
#define AES_256_GCM_KEY_SIZE 32
|
||||
#define AES_256_GCM_IV_SIZE 12
|
||||
|
||||
// TLS 1.3-like handshake
|
||||
|
||||
// 1. Client->server: EC public key
|
||||
// 2. Server->client: EC public key, encrypted certificate and digital signature of the handshake
|
||||
// 3. Client->server: encrypted certificate and digital signature of the handshake
|
||||
|
||||
// "vitaECDH" interleaved
|
||||
#define MSGR_HS_MAGIC 0x4861447443694576l
|
||||
#define MSGR_HS_MAX_LEN 131072
|
||||
|
||||
#define MSGR_HS_SERVER_INIT 0
|
||||
#define MSGR_HS_CLIENT_INIT 1
|
||||
#define MSGR_HS_SERVER_REPLY 2
|
||||
#define MSGR_HS_CLIENT_REPLY 3
|
||||
#define MSGR_HS_DONE 100
|
||||
#define MSGR_HS_ERROR 101
|
||||
|
||||
struct __attribute__((__packed__)) msgr_handshake_hdr_t
|
||||
{
|
||||
uint32_t msg_len;
|
||||
uint64_t magic;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
class msgr_handshake_ctx_t: public msgr_handshake_ctx_i
|
||||
{
|
||||
friend class msgr_handshake_t;
|
||||
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *params = NULL;
|
||||
X509_STORE *ca = NULL;
|
||||
X509 *osd_ca = NULL;
|
||||
X509 *client_ca = NULL;
|
||||
std::string my_cert_pem;
|
||||
X509 *my_cert = NULL;
|
||||
EVP_PKEY *my_pubkey = NULL;
|
||||
const EVP_MD *md = NULL;
|
||||
EVP_PKEY *my_privkey = NULL;
|
||||
EVP_KDF_CTX* kdf_ctx = NULL;
|
||||
std::string error;
|
||||
|
||||
bool on_error(const std::string & prefix);
|
||||
|
||||
public:
|
||||
~msgr_handshake_ctx_t();
|
||||
msgr_handshake_i* create() override;
|
||||
bool init(const std::string & pem_cert, const std::string & pem_key,
|
||||
const std::string & pem_osd_ca, const std::string & pem_client_ca) override;
|
||||
std::string get_error() override;
|
||||
bool derive_kdf(const uint8_t* insecret, size_t insecret_len,
|
||||
const uint8_t* salt, size_t salt_len, const char *label, uint8_t *outsecret, size_t outsize) override;
|
||||
};
|
||||
|
||||
class msgr_handshake_t: public msgr_handshake_i
|
||||
{
|
||||
msgr_handshake_ctx_t *ctx = NULL;
|
||||
bool is_server = false;
|
||||
|
||||
std::vector<uint8_t> full_handshake;
|
||||
std::vector<uint8_t> in_buf;
|
||||
std::vector<uint8_t> out_buf;
|
||||
std::string error;
|
||||
|
||||
int state = 0;
|
||||
|
||||
EVP_PKEY *ec_key = NULL;
|
||||
X509 *peer_cert = NULL;
|
||||
bool peer_is_osd = false;
|
||||
std::vector<uint8_t> shared_secret;
|
||||
std::vector<uint8_t> hs_key, peer_hs_key;
|
||||
|
||||
msgr_handshake_hdr_t *cur_hdr = NULL;
|
||||
uint8_t *cur_buf = NULL;
|
||||
size_t cur_left = 0;
|
||||
|
||||
bool on_error(const std::string & prefix);
|
||||
bool derive_shared_secret(EVP_PKEY *peer_ec_key);
|
||||
bool derive_hs_keys(const uint8_t *encoded_peer_key, size_t encoded_key_len);
|
||||
bool sign(std::vector<uint8_t> & out);
|
||||
bool verify(const uint8_t *signature, size_t signature_len);
|
||||
bool encrypt(const uint8_t* src, size_t len, uint8_t* dest);
|
||||
bool decrypt(const uint8_t* src, size_t & len, uint8_t* dest);
|
||||
bool make_client_init();
|
||||
bool make_server_reply();
|
||||
bool make_client_reply();
|
||||
bool verify_peer(const uint8_t *peer_cert_pem, size_t peer_cert_len);
|
||||
ssize_t start_msg(uint8_t* src, size_t len, uint32_t expected_type);
|
||||
bool read_with_len(const uint8_t* & dst, uint32_t & dst_len);
|
||||
bool handle_client_init();
|
||||
bool handle_server_reply();
|
||||
bool handle_client_reply();
|
||||
bool handle_peer_cert(const uint8_t *key, uint32_t key_len);
|
||||
void complete();
|
||||
|
||||
public:
|
||||
// Workflow: create -> init -> handle -> get_result/get_error -> destruct
|
||||
msgr_handshake_t(msgr_handshake_ctx_t *ctx): ctx(ctx) {}
|
||||
~msgr_handshake_t();
|
||||
bool init(bool server_mode) override;
|
||||
ssize_t handle(uint8_t* in_buf, size_t in_size) override;
|
||||
bool done() override;
|
||||
std::vector<uint8_t>& get_out() override;
|
||||
msgr_handshake_result_t get_result() override;
|
||||
std::string get_error() override;
|
||||
};
|
||||
|
||||
msgr_handshake_ctx_i* msgr_handshake_ctx_i::create_ctx()
|
||||
{
|
||||
return new msgr_handshake_ctx_t();
|
||||
}
|
||||
|
||||
msgr_handshake_i* msgr_handshake_ctx_t::create()
|
||||
{
|
||||
return new msgr_handshake_t(this);
|
||||
}
|
||||
|
||||
bool msgr_handshake_ctx_t::init(const std::string & pem_cert, const std::string & pem_key,
|
||||
const std::string & pem_osd_ca, const std::string & pem_client_ca)
|
||||
{
|
||||
if (pem_cert.substr(0, 5) == "-----")
|
||||
my_cert_pem = pem_cert;
|
||||
else
|
||||
{
|
||||
my_cert_pem = read_file(pem_cert);
|
||||
if (my_cert_pem.empty())
|
||||
{
|
||||
error = "Failed to load certificate file";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
{
|
||||
BIO *bio = BIO_new_mem_buf(my_cert_pem.data(), my_cert_pem.size());
|
||||
if (!bio)
|
||||
return on_error("BIO_new_mem_buf: ");
|
||||
my_cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
BIO_free(bio);
|
||||
if (!my_cert)
|
||||
return on_error("Failed to load certificate: ");
|
||||
}
|
||||
if (!(my_pubkey = X509_get0_pubkey(my_cert)))
|
||||
return on_error("X509_get0_pubkey: ");
|
||||
if (!(md = EVP_get_digestbynid(NID_sha384)))
|
||||
return on_error("EVP_get_digestbynid SHA384: ");
|
||||
if (!(my_privkey = openssl_load_key(pem_key)))
|
||||
return on_error("Failed to load private key: ");
|
||||
if (!(ca = X509_STORE_new()))
|
||||
return on_error("X509_STORE_CTX_new: ");
|
||||
if (!(osd_ca = openssl_load_cert(pem_osd_ca)))
|
||||
return on_error("Failed to load OSD CA certificate: ");
|
||||
if (X509_STORE_add_cert(ca, osd_ca) <= 0)
|
||||
return on_error("X509_STORE_add_cert OSD CA: ");
|
||||
if (!pem_client_ca.empty() && !(client_ca = openssl_load_cert(pem_client_ca)))
|
||||
return on_error("Failed to load client CA certificate: ");
|
||||
if (client_ca && X509_STORE_add_cert(ca, client_ca) <= 0)
|
||||
return on_error("X509_STORE_add_cert client CA: ");
|
||||
if (!(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)))
|
||||
return on_error("EVP_PKEY_CTX_new_id: ");
|
||||
if (EVP_PKEY_paramgen_init(pctx) <= 0)
|
||||
return on_error("EVP_PKEY_paramgen_init: ");
|
||||
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, /*NID_X9_62_prime256v1*/NID_secp384r1) <= 0)
|
||||
return on_error("EVP_PKEY_CTX_set_ec_paramgen_curve_nid: ");
|
||||
if (EVP_PKEY_paramgen(pctx, ¶ms) <= 0)
|
||||
return on_error("EVP_PKEY_paramgen: ");
|
||||
EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL);
|
||||
if (!kdf)
|
||||
return on_error("EVP_KDF_fetch: ");
|
||||
kdf_ctx = EVP_KDF_CTX_new(kdf);
|
||||
EVP_KDF_free(kdf);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string msgr_handshake_ctx_t::get_error()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
msgr_handshake_ctx_t::~msgr_handshake_ctx_t()
|
||||
{
|
||||
if (pctx)
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (params)
|
||||
EVP_PKEY_free(params);
|
||||
if (ca)
|
||||
X509_STORE_free(ca);
|
||||
if (osd_ca)
|
||||
X509_free(osd_ca);
|
||||
if (client_ca)
|
||||
X509_free(client_ca);
|
||||
my_pubkey = NULL;
|
||||
if (my_cert)
|
||||
X509_free(my_cert);
|
||||
if (my_privkey)
|
||||
EVP_PKEY_free(my_privkey);
|
||||
if (kdf_ctx)
|
||||
EVP_KDF_CTX_free(kdf_ctx);
|
||||
}
|
||||
|
||||
bool msgr_handshake_ctx_t::on_error(const std::string & prefix)
|
||||
{
|
||||
error = prefix+ERR_error_string(ERR_get_error(), NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool msgr_handshake_ctx_t::derive_kdf(const uint8_t* insecret, size_t insecret_len,
|
||||
const uint8_t* salt, size_t salt_len, const char *label, uint8_t *outsecret, size_t outsize)
|
||||
{
|
||||
OSSL_PARAM params[5];
|
||||
int n = 0;
|
||||
params[n++] = OSSL_PARAM_construct_utf8_string("digest", (char*)"sha384", (size_t)7);
|
||||
params[n++] = OSSL_PARAM_construct_octet_string("key", (void*)insecret, insecret_len);
|
||||
params[n++] = OSSL_PARAM_construct_octet_string("info", (void*)label, strlen(label)+1);
|
||||
params[n++] = OSSL_PARAM_construct_octet_string("salt", (salt ? (void*)salt : (void*)""), salt_len);
|
||||
params[n++] = OSSL_PARAM_construct_end();
|
||||
assert(n <= sizeof(params)/sizeof(OSSL_PARAM));
|
||||
if (EVP_KDF_CTX_set_params(kdf_ctx, params) <= 0)
|
||||
return false;
|
||||
if (EVP_KDF_derive(kdf_ctx, outsecret, outsize, NULL) <= 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
msgr_handshake_t::~msgr_handshake_t()
|
||||
{
|
||||
if (peer_cert)
|
||||
X509_free(peer_cert);
|
||||
if (ec_key)
|
||||
EVP_PKEY_free(ec_key);
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::on_error(const std::string & prefix)
|
||||
{
|
||||
error = prefix+ERR_error_string(ERR_get_error(), NULL);
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::init(bool server_mode)
|
||||
{
|
||||
this->ctx = ctx;
|
||||
std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> kctx(EVP_PKEY_CTX_new(ctx->params, NULL), EVP_PKEY_CTX_free);
|
||||
if (!kctx)
|
||||
return on_error("EVP_PKEY_CTX_new with EC params: ");
|
||||
if (EVP_PKEY_keygen_init(kctx.get()) <= 0)
|
||||
return on_error("EVP_PKEY_keygen_init: ");
|
||||
if (EVP_PKEY_keygen(kctx.get(), &ec_key) <= 0)
|
||||
return on_error("EVP_PKEY_keygen: ");
|
||||
if (!server_mode)
|
||||
{
|
||||
// Send initial message - only the EC public key
|
||||
if (!make_client_init())
|
||||
return false;
|
||||
}
|
||||
this->is_server = server_mode;
|
||||
this->state = server_mode ? MSGR_HS_SERVER_INIT : MSGR_HS_CLIENT_INIT;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void copy_to(std::vector<uint8_t> & buf, const void* src, uint32_t len)
|
||||
{
|
||||
size_t old_size = buf.size();
|
||||
buf.resize(buf.size() + len);
|
||||
memcpy(buf.data() + old_size, src, len);
|
||||
}
|
||||
|
||||
static void copy_to_with_len(std::vector<uint8_t> & buf, const void* src, uint32_t len)
|
||||
{
|
||||
copy_to(buf, &len, sizeof(len));
|
||||
copy_to(buf, src, len);
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::derive_shared_secret(EVP_PKEY *peer_ec_key)
|
||||
{
|
||||
EVP_PKEY_CTX *dh_ctx = NULL;
|
||||
if (!(dh_ctx = EVP_PKEY_CTX_new(ec_key, NULL)))
|
||||
return on_error("EVP_PKEY_CTX_new for ECDH: ");
|
||||
if (!EVP_PKEY_derive_init(dh_ctx))
|
||||
{
|
||||
EVP_PKEY_CTX_free(dh_ctx);
|
||||
return on_error("EVP_PKEY_derive_init: ");
|
||||
}
|
||||
if (!EVP_PKEY_derive_set_peer(dh_ctx, peer_ec_key))
|
||||
{
|
||||
EVP_PKEY_CTX_free(dh_ctx);
|
||||
return on_error("EVP_PKEY_derive_set_peer: ");
|
||||
}
|
||||
size_t len = 0;
|
||||
if (!EVP_PKEY_derive(dh_ctx, NULL, &len))
|
||||
{
|
||||
EVP_PKEY_CTX_free(dh_ctx);
|
||||
return on_error("EVP_PKEY_derive get length: ");
|
||||
}
|
||||
shared_secret.resize(len);
|
||||
assert(len == 48);
|
||||
if (!EVP_PKEY_derive(dh_ctx, shared_secret.data(), &len))
|
||||
{
|
||||
EVP_PKEY_CTX_free(dh_ctx);
|
||||
return on_error("EVP_PKEY_derive: ");
|
||||
}
|
||||
assert(len == shared_secret.size());
|
||||
shared_secret.resize(len);
|
||||
EVP_PKEY_CTX_free(dh_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::derive_hs_keys(const uint8_t *encoded_peer_key, size_t encoded_key_len)
|
||||
{
|
||||
std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> peer_ec_key(EVP_PKEY_new(), EVP_PKEY_free);
|
||||
if (!peer_ec_key)
|
||||
return on_error("EVP_PKEY_new: ");
|
||||
if (EVP_PKEY_copy_parameters(peer_ec_key.get(), ec_key) <= 0)
|
||||
return on_error("EVP_PKEY_copy_parameters: ");
|
||||
if (EVP_PKEY_set1_encoded_public_key(peer_ec_key.get(), encoded_peer_key, encoded_key_len) <= 0)
|
||||
return on_error("Invalid handshake peer key: ");
|
||||
if (!derive_shared_secret(peer_ec_key.get()))
|
||||
return false;
|
||||
hs_key.resize(AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE);
|
||||
peer_hs_key.resize(AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE);
|
||||
if (!ctx->derive_kdf(shared_secret.data(), shared_secret.size(),
|
||||
NULL, 0, (state == MSGR_HS_SERVER_INIT ? "server hs key" : "client hs key"),
|
||||
hs_key.data(), hs_key.size()))
|
||||
return on_error("derive_kdf: ");
|
||||
if (!ctx->derive_kdf(shared_secret.data(), shared_secret.size(),
|
||||
NULL, 0, (state != MSGR_HS_SERVER_INIT ? "server hs key" : "client hs key"),
|
||||
peer_hs_key.data(), peer_hs_key.size()))
|
||||
return on_error("derive_kdf: ");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::sign(std::vector<uint8_t> & out)
|
||||
{
|
||||
std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> md_ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
|
||||
if (!md_ctx)
|
||||
return on_error("EVP_MD_CTX_create: ");
|
||||
if (EVP_DigestSignInit(md_ctx.get(), NULL, ctx->md, NULL, ctx->my_privkey) <= 0)
|
||||
return on_error("EVP_DigestSignInit: ");
|
||||
if (EVP_DigestSignUpdate(md_ctx.get(), full_handshake.data(), full_handshake.size()) <= 0)
|
||||
return on_error("EVP_DigestSignUpdate: ");
|
||||
size_t siglen = 0;
|
||||
if (EVP_DigestSignFinal(md_ctx.get(), NULL, &siglen) <= 0)
|
||||
return on_error("EVP_DigestSignFinal get length: ");
|
||||
size_t oldsize = out.size();
|
||||
out.resize(oldsize + siglen);
|
||||
if (EVP_DigestSignFinal(md_ctx.get(), out.data() + oldsize, &siglen) <= 0)
|
||||
return on_error("EVP_DigestSignFinal: ");
|
||||
out.resize(oldsize + siglen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::verify(const uint8_t *signature, size_t signature_len)
|
||||
{
|
||||
std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> md_ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
|
||||
if (!md_ctx)
|
||||
return on_error("EVP_MD_CTX_create: ");
|
||||
if (EVP_DigestVerifyInit(md_ctx.get(), NULL, ctx->md, NULL, X509_get0_pubkey(peer_cert)) <= 0)
|
||||
return on_error("EVP_DigestVerifyInit: ");
|
||||
if (EVP_DigestVerifyUpdate(md_ctx.get(), full_handshake.data(), full_handshake.size()) <= 0)
|
||||
return on_error("EVP_DigestVerifyUpdate: ");
|
||||
if (EVP_DigestVerifyFinal(md_ctx.get(), signature, signature_len) <= 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::encrypt(const uint8_t* src, size_t len, uint8_t* dest)
|
||||
{
|
||||
std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)> enc_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
|
||||
if (!ctx)
|
||||
return on_error("EVP_CIPHER_CTX_new: ");
|
||||
if (EVP_EncryptInit_ex(enc_ctx.get(), EVP_aes_256_gcm(), NULL, hs_key.data(), hs_key.data() + AES_256_GCM_KEY_SIZE) <= 0)
|
||||
return on_error("EVP_EncryptInit AES-256-GCM: ");
|
||||
int actual_out;
|
||||
if (EVP_EncryptUpdate(enc_ctx.get(), dest, &actual_out, src, len) <= 0)
|
||||
return on_error("EVP_EncryptUpdate: ");
|
||||
assert(actual_out == len);
|
||||
if (EVP_EncryptFinal_ex(enc_ctx.get(), NULL, &actual_out) <= 0)
|
||||
return on_error("EVP_EncryptFinal: ");
|
||||
if (EVP_CIPHER_CTX_ctrl(enc_ctx.get(), EVP_CTRL_GCM_GET_TAG, 16, dest+len) <= 0)
|
||||
return on_error("EVP_CTRL_GCM_GET_TAG: ");
|
||||
(*(uint64_t*)(hs_key.data() + AES_256_GCM_KEY_SIZE))++; // change IV
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::decrypt(const uint8_t *src, size_t & len, uint8_t* dest)
|
||||
{
|
||||
if (len <= 16) // only tag?!
|
||||
{
|
||||
len = 0;
|
||||
error = "Handshake decryption failed";
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)> dec_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
|
||||
if (!ctx)
|
||||
return on_error("EVP_CIPHER_CTX_new: ");
|
||||
if (EVP_DecryptInit_ex(dec_ctx.get(), EVP_aes_256_gcm(), NULL, peer_hs_key.data(), peer_hs_key.data() + AES_256_GCM_KEY_SIZE) <= 0)
|
||||
return on_error("EVP_DecryptInit AES-256-GCM: ");
|
||||
int actual_out;
|
||||
len -= 16;
|
||||
if (EVP_DecryptUpdate(dec_ctx.get(), dest, &actual_out, src, len) <= 0)
|
||||
return on_error("EVP_DecryptUpdate: ");
|
||||
assert(actual_out == len);
|
||||
if (EVP_CIPHER_CTX_ctrl(dec_ctx.get(), EVP_CTRL_GCM_SET_TAG, 16, (void*)(src+len)) <= 0)
|
||||
return on_error("EVP_CTRL_GCM_SET_TAG: ");
|
||||
if (EVP_DecryptFinal_ex(dec_ctx.get(), NULL, &actual_out) <= 0)
|
||||
{
|
||||
error = "Handshake decryption failed";
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
(*(uint64_t*)(peer_hs_key.data() + AES_256_GCM_KEY_SIZE))++; // change IV
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::make_client_init()
|
||||
{
|
||||
uint8_t *key = NULL;
|
||||
size_t key_len = EVP_PKEY_get1_encoded_public_key(ec_key, &key);
|
||||
if (!key_len)
|
||||
return on_error("EVP_PKEY_get1_encoded_public_key: ");
|
||||
const size_t old_len = out_buf.size();
|
||||
out_buf.resize(out_buf.size() + key_len + sizeof(msgr_handshake_hdr_t));
|
||||
uint8_t *buf = out_buf.data() + old_len;
|
||||
msgr_handshake_hdr_t *hdr = (msgr_handshake_hdr_t *)buf;
|
||||
hdr->msg_len = key_len + sizeof(msgr_handshake_hdr_t);
|
||||
hdr->magic = MSGR_HS_MAGIC;
|
||||
hdr->type = MSGR_HS_CLIENT_INIT;
|
||||
memcpy(buf + sizeof(msgr_handshake_hdr_t), key, key_len);
|
||||
copy_to(full_handshake, &hdr->type, sizeof(hdr->type));
|
||||
copy_to_with_len(full_handshake, key, key_len);
|
||||
OPENSSL_free(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::make_server_reply()
|
||||
{
|
||||
uint8_t *key = NULL;
|
||||
size_t key_len = EVP_PKEY_get1_encoded_public_key(ec_key, &key);
|
||||
if (!key_len)
|
||||
return on_error("EVP_PKEY_get1_encoded_public_key: ");
|
||||
// Append type, key and raw certificate to signed data and sign it
|
||||
msgr_handshake_hdr_t hdr = { .magic = MSGR_HS_MAGIC, .type = MSGR_HS_SERVER_REPLY };
|
||||
copy_to(full_handshake, &hdr.type, sizeof(hdr.type));
|
||||
copy_to_with_len(full_handshake, key, key_len);
|
||||
copy_to_with_len(full_handshake, ctx->my_cert_pem.data(), ctx->my_cert_pem.size());
|
||||
std::vector<uint8_t> signature;
|
||||
if (!sign(signature))
|
||||
{
|
||||
OPENSSL_free(key);
|
||||
return false;
|
||||
}
|
||||
// Encrypt certificate and signature
|
||||
std::vector<uint8_t> encrypt_data;
|
||||
copy_to_with_len(encrypt_data, ctx->my_cert_pem.data(), ctx->my_cert_pem.size());
|
||||
copy_to_with_len(encrypt_data, signature.data(), signature.size());
|
||||
encrypt_data.resize(encrypt_data.size()+16);
|
||||
if (!encrypt(encrypt_data.data(), encrypt_data.size()-16, encrypt_data.data()))
|
||||
{
|
||||
OPENSSL_free(key);
|
||||
return false;
|
||||
}
|
||||
// Construct message
|
||||
hdr.msg_len = sizeof(msgr_handshake_hdr_t) + 4 + key_len + encrypt_data.size();
|
||||
copy_to(out_buf, &hdr, sizeof(hdr));
|
||||
copy_to_with_len(out_buf, key, key_len);
|
||||
copy_to(out_buf, encrypt_data.data(), encrypt_data.size());
|
||||
OPENSSL_free(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::make_client_reply()
|
||||
{
|
||||
// Append type and raw certificate to signed data and sign it
|
||||
msgr_handshake_hdr_t hdr = { .magic = MSGR_HS_MAGIC, .type = MSGR_HS_CLIENT_REPLY };
|
||||
copy_to(full_handshake, &hdr.type, sizeof(hdr.type));
|
||||
copy_to_with_len(full_handshake, ctx->my_cert_pem.data(), ctx->my_cert_pem.size());
|
||||
std::vector<uint8_t> signature;
|
||||
if (!sign(signature))
|
||||
return false;
|
||||
// Encrypt certificate and signature
|
||||
std::vector<uint8_t> encrypt_data;
|
||||
copy_to_with_len(encrypt_data, ctx->my_cert_pem.data(), ctx->my_cert_pem.size());
|
||||
copy_to_with_len(encrypt_data, signature.data(), signature.size());
|
||||
encrypt_data.resize(encrypt_data.size()+16);
|
||||
if (!encrypt(encrypt_data.data(), encrypt_data.size()-16, encrypt_data.data()))
|
||||
return false;
|
||||
// Construct message
|
||||
hdr.msg_len = sizeof(msgr_handshake_hdr_t) + encrypt_data.size();
|
||||
copy_to(out_buf, &hdr, sizeof(hdr));
|
||||
copy_to(out_buf, encrypt_data.data(), encrypt_data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::verify_peer(const uint8_t *peer_cert_pem, size_t peer_cert_len)
|
||||
{
|
||||
BIO *bio = BIO_new_mem_buf(peer_cert_pem, peer_cert_len);
|
||||
if (!bio)
|
||||
return on_error("BIO_new_mem_buf: ");
|
||||
peer_cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
BIO_free(bio);
|
||||
if (!peer_cert)
|
||||
{
|
||||
error = "Invalid peer certificate";
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<X509_STORE_CTX, decltype(&X509_STORE_CTX_free)> ca_ctx(X509_STORE_CTX_new(), X509_STORE_CTX_free);
|
||||
if (!ca_ctx)
|
||||
return on_error("X509_STORE_CTX_new: ");
|
||||
if (X509_STORE_CTX_init(ca_ctx.get(), ctx->ca, peer_cert, NULL) <= 0)
|
||||
return on_error("X509_STORE_CTX_init: ");
|
||||
// Maybe use X509_VERIFY_PARAM_set_auth_level(X509_STORE_CTX_get0_param(ca_ctx.get()), 2) ?
|
||||
X509_STORE_CTX_set_default(ca_ctx.get(), is_server ? "ssl_client" : "ssl_server");
|
||||
if (X509_verify_cert(ca_ctx.get()) <= 0)
|
||||
{
|
||||
error = "Peer certificate verification failed: ";
|
||||
error += X509_verify_cert_error_string(X509_STORE_CTX_get_error(ca_ctx.get()));
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
peer_is_osd = (X509_verify(peer_cert, X509_get0_pubkey(ctx->osd_ca)) > 0);
|
||||
if (!is_server && !peer_is_osd)
|
||||
{
|
||||
error = "Peer is not an OSD";
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t msgr_handshake_t::start_msg(uint8_t* src, size_t len, uint32_t expected_type)
|
||||
{
|
||||
size_t orig_len = len;
|
||||
size_t to_buffer = (len < sizeof(msgr_handshake_hdr_t)-in_buf.size()
|
||||
? len : sizeof(msgr_handshake_hdr_t)-in_buf.size());
|
||||
in_buf.insert(in_buf.end(), src, src+to_buffer);
|
||||
len -= to_buffer;
|
||||
src += to_buffer;
|
||||
if (in_buf.size() < sizeof(msgr_handshake_hdr_t))
|
||||
return 0;
|
||||
cur_hdr = (msgr_handshake_hdr_t *)in_buf.data();
|
||||
if (cur_hdr->magic != MSGR_HS_MAGIC ||
|
||||
cur_hdr->type != expected_type ||
|
||||
cur_hdr->msg_len <= sizeof(msgr_handshake_hdr_t) ||
|
||||
cur_hdr->msg_len >= MSGR_HS_MAX_LEN)
|
||||
{
|
||||
error = "Invalid handshake packet magic, type or size";
|
||||
state = MSGR_HS_ERROR;
|
||||
return -1;
|
||||
}
|
||||
to_buffer = (len < cur_hdr->msg_len-in_buf.size()
|
||||
? len : cur_hdr->msg_len-in_buf.size());
|
||||
in_buf.insert(in_buf.end(), src, src+to_buffer);
|
||||
cur_hdr = (msgr_handshake_hdr_t *)in_buf.data();
|
||||
len -= to_buffer;
|
||||
src += to_buffer;
|
||||
if (in_buf.size() < cur_hdr->msg_len)
|
||||
return 0;
|
||||
cur_left = cur_hdr->msg_len - sizeof(msgr_handshake_hdr_t);
|
||||
cur_buf = in_buf.data() + sizeof(msgr_handshake_hdr_t);
|
||||
return orig_len - len;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::read_with_len(const uint8_t* & dst, uint32_t & dst_len)
|
||||
{
|
||||
if (cur_left < 4)
|
||||
{
|
||||
error = "Handshake packet too short";
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
dst_len = *(uint32_t*)cur_buf;
|
||||
cur_buf += 4;
|
||||
cur_left -= 4;
|
||||
if (cur_left < dst_len)
|
||||
{
|
||||
error = "Handshake packet too short";
|
||||
state = MSGR_HS_ERROR;
|
||||
return false;
|
||||
}
|
||||
dst = cur_buf;
|
||||
cur_buf += dst_len;
|
||||
cur_left -= dst_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::handle_client_init()
|
||||
{
|
||||
// Derive shared secret and handshake keys
|
||||
if (!derive_hs_keys(cur_buf, cur_left))
|
||||
return false;
|
||||
// Add type and key to full_handshake
|
||||
copy_to(full_handshake, &cur_hdr->type, sizeof(cur_hdr->type));
|
||||
copy_to_with_len(full_handshake, cur_buf, cur_left);
|
||||
in_buf.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decrypt and check peer certificate
|
||||
bool msgr_handshake_t::handle_peer_cert(const uint8_t *key, uint32_t key_len)
|
||||
{
|
||||
if (!decrypt(cur_buf, cur_left, cur_buf))
|
||||
return false;
|
||||
const uint8_t *peer_cert_pem = NULL;
|
||||
uint32_t peer_cert_len = 0;
|
||||
if (!read_with_len(peer_cert_pem, peer_cert_len))
|
||||
return false;
|
||||
// Parse and verify certificate
|
||||
if (!verify_peer(peer_cert_pem, peer_cert_len))
|
||||
return false;
|
||||
// Verify signature
|
||||
copy_to(full_handshake, &cur_hdr->type, sizeof(cur_hdr->type));
|
||||
if (key)
|
||||
copy_to_with_len(full_handshake, key, key_len);
|
||||
copy_to_with_len(full_handshake, peer_cert_pem, peer_cert_len);
|
||||
const uint8_t *signature = NULL;
|
||||
uint32_t signature_len = 0;
|
||||
if (!read_with_len(signature, signature_len))
|
||||
return false;
|
||||
if (!verify(signature, signature_len))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::handle_server_reply()
|
||||
{
|
||||
// Derive shared secret and handshake keys
|
||||
const uint8_t *key = NULL;
|
||||
uint32_t key_len = 0;
|
||||
if (!read_with_len(key, key_len))
|
||||
return false;
|
||||
if (!derive_hs_keys(key, key_len))
|
||||
return false;
|
||||
// Decrypt and check peer certificate
|
||||
if (!handle_peer_cert(key, key_len))
|
||||
return false;
|
||||
in_buf.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::handle_client_reply()
|
||||
{
|
||||
// Decrypt and check peer certificate
|
||||
if (!handle_peer_cert(NULL, 0))
|
||||
return false;
|
||||
in_buf.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void msgr_handshake_t::complete()
|
||||
{
|
||||
state = MSGR_HS_DONE;
|
||||
hs_key.clear();
|
||||
peer_hs_key.clear();
|
||||
full_handshake.clear();
|
||||
}
|
||||
|
||||
ssize_t msgr_handshake_t::handle(uint8_t* in_buf, size_t in_size)
|
||||
{
|
||||
if (state == MSGR_HS_SERVER_INIT)
|
||||
{
|
||||
ssize_t r = start_msg(in_buf, in_size, MSGR_HS_CLIENT_INIT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return in_size;
|
||||
if (!handle_client_init())
|
||||
return -1;
|
||||
// Send encrypted & signed response
|
||||
if (!make_server_reply())
|
||||
return -1;
|
||||
state = MSGR_HS_SERVER_REPLY;
|
||||
return r;
|
||||
}
|
||||
else if (state == MSGR_HS_CLIENT_INIT)
|
||||
{
|
||||
ssize_t r = start_msg(in_buf, in_size, MSGR_HS_SERVER_REPLY);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return in_size;
|
||||
if (!handle_server_reply())
|
||||
return -1;
|
||||
// Verification passed, send certificate to the server
|
||||
if (!make_client_reply())
|
||||
return -1;
|
||||
// Finished!
|
||||
complete();
|
||||
return r;
|
||||
}
|
||||
else if (state == MSGR_HS_SERVER_REPLY)
|
||||
{
|
||||
ssize_t r = start_msg(in_buf, in_size, MSGR_HS_CLIENT_REPLY);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return in_size;
|
||||
if (!handle_client_reply())
|
||||
return -1;
|
||||
// Verification passed
|
||||
// Finished!
|
||||
complete();
|
||||
return r;
|
||||
}
|
||||
else if (state == MSGR_HS_DONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (state != MSGR_HS_ERROR)
|
||||
{
|
||||
error = "Unexpected handshake state: "+std::to_string(state);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool msgr_handshake_t::done()
|
||||
{
|
||||
return (state == MSGR_HS_DONE);
|
||||
}
|
||||
|
||||
std::vector<uint8_t>& msgr_handshake_t::get_out()
|
||||
{
|
||||
return out_buf;
|
||||
}
|
||||
|
||||
msgr_handshake_result_t msgr_handshake_t::get_result()
|
||||
{
|
||||
if (state != MSGR_HS_DONE)
|
||||
return msgr_handshake_result_t{};
|
||||
X509_up_ref(peer_cert);
|
||||
return msgr_handshake_result_t{
|
||||
.peer_cert = peer_cert,
|
||||
.peer_is_osd = peer_is_osd,
|
||||
.shared_secret = shared_secret,
|
||||
};
|
||||
}
|
||||
|
||||
std::string msgr_handshake_t::get_error()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2026+
|
||||
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/types.h>
|
||||
|
||||
#define AES_256_GCM_KEY_SIZE 32
|
||||
#define AES_256_GCM_IV_SIZE 12
|
||||
#define AES_256_GCM_MAX_IV_CTR ((uint64_t)1 << 32)
|
||||
|
||||
// TLS 1.3-like handshake
|
||||
|
||||
// 1. Client->server: EC public key
|
||||
// 2. Server->client: EC public key, encrypted certificate and digital signature of the handshake
|
||||
// 3. Client->server: encrypted certificate and digital signature of the handshake
|
||||
|
||||
struct msgr_handshake_result_t
|
||||
{
|
||||
X509 *peer_cert = NULL;
|
||||
bool peer_is_osd = false;
|
||||
std::vector<uint8_t> shared_secret;
|
||||
};
|
||||
|
||||
class msgr_handshake_i
|
||||
{
|
||||
public:
|
||||
// Workflow: create -> init -> handle_msg -> get_result/get_error -> destruct
|
||||
virtual ~msgr_handshake_i() = default;
|
||||
virtual bool init(bool server_mode) = 0;
|
||||
virtual ssize_t handle(uint8_t* in_buf, size_t in_size) = 0;
|
||||
virtual bool done() = 0;
|
||||
virtual std::vector<uint8_t> & get_out() = 0;
|
||||
virtual msgr_handshake_result_t get_result() = 0;
|
||||
virtual std::string get_error() = 0;
|
||||
};
|
||||
|
||||
class msgr_handshake_ctx_i
|
||||
{
|
||||
public:
|
||||
static msgr_handshake_ctx_i* create_ctx();
|
||||
virtual ~msgr_handshake_ctx_i() = default;
|
||||
virtual msgr_handshake_i* create() = 0;
|
||||
virtual bool init(const std::string & pem_cert, const std::string & pem_key,
|
||||
const std::string & pem_osd_ca, const std::string & pem_client_ca) = 0;
|
||||
virtual std::string get_error() = 0;
|
||||
virtual bool derive_kdf(const uint8_t* insecret, size_t insecret_len,
|
||||
const uint8_t* salt, size_t salt_len, const char *label, uint8_t *outsecret, size_t outsize) = 0;
|
||||
};
|
||||
@@ -8,7 +8,6 @@
|
||||
osd_op_t::~osd_op_t()
|
||||
{
|
||||
assert(!bs_op);
|
||||
assert(!op_data);
|
||||
if (bitmap_buf)
|
||||
{
|
||||
free(bitmap_buf);
|
||||
@@ -27,6 +26,10 @@ osd_op_t::~osd_op_t()
|
||||
{
|
||||
free(enc_buf);
|
||||
}
|
||||
if (op_data)
|
||||
{
|
||||
free(op_data);
|
||||
}
|
||||
}
|
||||
|
||||
bool osd_op_t::is_recovery_related()
|
||||
|
||||
@@ -181,7 +181,7 @@ struct __attribute__((visibility("default"))) osd_op_t
|
||||
// bitmap, bitmap_len, bmp_data are only meaningful for reads
|
||||
void *bitmap = NULL;
|
||||
unsigned bitmap_len = 0;
|
||||
size_t bmp_data = 0;
|
||||
unsigned bmp_data = 0;
|
||||
uint8_t *bitmap_buf = NULL;
|
||||
void *rmw_buf = NULL;
|
||||
std::shared_ptr<osd_op_enc_t> enc;
|
||||
|
||||
+32
-31
@@ -541,7 +541,7 @@ bool osd_messenger_t::connect_rdma(uint64_t client_id, std::string rdma_address,
|
||||
{
|
||||
// Remember connection, but switch to RDMA only after sending the configuration response
|
||||
cl->rdma_conn = rdma_conn;
|
||||
cl->peer_state = PEER_RDMA_CONNECTING_IN;
|
||||
cl->peer_state = PEER_RDMA_CONNECTING;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -590,7 +590,36 @@ void osd_messenger_t::try_send_rdma(osd_client_t *cl)
|
||||
while (!rc->send_out_full && copied > 0 && rc->cur_send < rc->max_send)
|
||||
{
|
||||
dst = (uint8_t*)rc->send_out.buf + rc->send_out_pos;
|
||||
dst_len = (rc->send_out_pos < rc->send_out_size ? rc->send_out_size-rc->send_out_pos : rc->send_done_pos-rc->send_out_pos);
|
||||
if (rc->send_out_pos >= rc->send_done_pos)
|
||||
{
|
||||
dst_len = rc->send_out_size-rc->send_out_pos;
|
||||
if (dst_len < 4096)
|
||||
{
|
||||
// free end of the buffer is too small, skip
|
||||
rc->send_out_pos = 0;
|
||||
if (rc->send_out_pos >= rc->send_done_pos)
|
||||
rc->send_out_full = true;
|
||||
if (!rc->send_sizes.size())
|
||||
{
|
||||
rc->send_done_pos += dst_len;
|
||||
rc->send_out_full = false;
|
||||
if (rc->send_done_pos == rc->send_out_size)
|
||||
rc->send_done_pos = 0;
|
||||
}
|
||||
else
|
||||
rc->send_sizes.back() += dst_len;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_len = rc->send_done_pos-rc->send_out_pos;
|
||||
if (dst_len < 4096)
|
||||
{
|
||||
// too small buffer, stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dst_len > rc->max_msg)
|
||||
dst_len = rc->max_msg;
|
||||
copied = copy_ops_to(cl, dst, dst_len);
|
||||
@@ -643,7 +672,6 @@ static void try_recv_rdma_wr(osd_client_t *cl, void *buf)
|
||||
|
||||
bool osd_messenger_t::init_recv_rdma(osd_client_t *cl)
|
||||
{
|
||||
return true;
|
||||
auto rc = cl->rdma_conn;
|
||||
assert(!rc->recv_buf.buf);
|
||||
rc->recv_buf.buf = (uint8_t*)malloc_or_die(rc->max_msg * rc->max_recv);
|
||||
@@ -699,14 +727,9 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context)
|
||||
continue;
|
||||
}
|
||||
auto rc = cl->rdma_conn;
|
||||
if (!rc)
|
||||
{
|
||||
// Connection destroyed (fallback to TCP)
|
||||
continue;
|
||||
}
|
||||
if (wc[i].status != IBV_WC_SUCCESS)
|
||||
{
|
||||
fprintf(stderr, "RDMA work request (%s) failed for client %ju", is_send ? "send" : "recv", client_id);
|
||||
fprintf(stderr, "RDMA work request failed for client %ju", client_id);
|
||||
if (cl->osd_num)
|
||||
{
|
||||
fprintf(stderr, " (OSD %ju)", cl->osd_num);
|
||||
@@ -717,28 +740,6 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context)
|
||||
}
|
||||
if (!is_send)
|
||||
{
|
||||
if (cl->peer_state == PEER_RDMA_CONNECTING_OUT)
|
||||
{
|
||||
// First message received over RDMA - TCP socket can be closed now
|
||||
if (log_level > 0)
|
||||
{
|
||||
fprintf(stderr, "Successfully connected with client %ju using RDMA\n", cl->client_id);
|
||||
}
|
||||
cl->peer_state = PEER_RDMA;
|
||||
if (cl->peer_fd >= 0 && cl->rdma_close_tcp)
|
||||
{
|
||||
// TCP socket is not needed anymore
|
||||
tfd->set_fd_handler(cl->peer_fd, false, NULL);
|
||||
clients_by_fd.erase(cl->peer_fd);
|
||||
close(cl->peer_fd);
|
||||
cl->peer_fd = -1;
|
||||
}
|
||||
if (cl->osd_num)
|
||||
{
|
||||
osd_peers[cl->osd_num] = cl;
|
||||
on_connect_peer(cl->osd_num, 0, cl->client_id);
|
||||
}
|
||||
}
|
||||
rc->cur_recv--;
|
||||
if (!handle_read_buffer(cl, rc->recv_buffers[rc->next_recv_buf], wc[i].byte_len))
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@ struct rdmacm_connecting_t
|
||||
int tcp_port = 0;
|
||||
int timeout_ms = 0;
|
||||
int timeout_id = -1;
|
||||
bool is_incoming = false;
|
||||
msgr_rdma_context_t *rdma_context = NULL;
|
||||
};
|
||||
|
||||
@@ -293,7 +292,6 @@ void osd_messenger_t::rdmacm_accept(rdma_cm_event *ev)
|
||||
conn->client_id = next_client_id++;
|
||||
conn->parsed_addr = *(sockaddr_storage*)rdma_get_peer_addr(ev->id);
|
||||
conn->rdma_context = rdma_context;
|
||||
conn->is_incoming = true;
|
||||
rdmacm_set_conn_timeout(conn);
|
||||
rdmacm_connecting[ev->id] = conn;
|
||||
fprintf(stderr, "[OSD %ju] new client %ju: connection from %s via RDMA-CM\n", this->osd_num, conn->client_id,
|
||||
@@ -494,13 +492,11 @@ void osd_messenger_t::rdmacm_established(rdma_cm_event *ev)
|
||||
cl->peer_addr = conn->parsed_addr;
|
||||
cl->peer_port = conn->rdmacm_port;
|
||||
cl->client_id = conn->client_id;
|
||||
cl->is_incoming = conn->is_incoming;
|
||||
cl->peer_state = PEER_RDMA;
|
||||
cl->connect_timeout_id = -1;
|
||||
cl->osd_num = peer_osd;
|
||||
cl->in_buf = (uint8_t*)malloc_or_die(receive_buffer_size);
|
||||
cl->rdma_conn = rc;
|
||||
init_tls_client(cl);
|
||||
clients[conn->client_id] = cl;
|
||||
if (conn->timeout_id >= 0)
|
||||
{
|
||||
|
||||
+279
-237
@@ -4,12 +4,15 @@
|
||||
#define _XOPEN_SOURCE
|
||||
#include <limits.h>
|
||||
#include "messenger.h"
|
||||
#include "openssl_util.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#define RDR_GCM 1
|
||||
#define RDR_TLS 1
|
||||
#define RDR_XTS 2
|
||||
#define RDR_NO_CSUM 4
|
||||
|
||||
@@ -88,7 +91,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class gcm_op_reader_t: public msgr_op_reader_t
|
||||
class ssl_op_reader_t: public msgr_op_reader_t
|
||||
{
|
||||
osd_messenger_t* msgr;
|
||||
osd_client_t* cl;
|
||||
@@ -99,7 +102,7 @@ class gcm_op_reader_t: public msgr_op_reader_t
|
||||
size_t done;
|
||||
|
||||
public:
|
||||
gcm_op_reader_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t *curbuf, size_t bufsize):
|
||||
ssl_op_reader_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t *curbuf, size_t bufsize):
|
||||
msgr(msgr), cl(cl), from(cl->read_op_pos), curbuf(curbuf), bufsize(bufsize), done(0)
|
||||
{
|
||||
}
|
||||
@@ -107,55 +110,51 @@ public:
|
||||
void reset()
|
||||
{
|
||||
from = cl->read_op_pos;
|
||||
if (!cl->dec_ctx)
|
||||
}
|
||||
|
||||
void buffer_encrypted()
|
||||
{
|
||||
if (cl->ssl_read_header_size < sizeof(msgr_tls_record_hdr_t))
|
||||
{
|
||||
if (msgr->decrypt_gcm_pool.size())
|
||||
size_t h = bufsize-done;
|
||||
if (bufsize-done <= sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_header_size)
|
||||
{
|
||||
cl->dec_ctx = msgr->decrypt_gcm_pool.back();
|
||||
msgr->decrypt_gcm_pool.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
cl->dec_ctx = (isal_gcm_context_data*)malloc_or_die(sizeof(isal_gcm_context_data));
|
||||
#else
|
||||
cl->dec_ctx = EVP_CIPHER_CTX_new();
|
||||
assert(cl->dec_ctx);
|
||||
int r = EVP_DecryptInit_ex(cl->dec_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "DecryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
// Less than record header or just record header
|
||||
memcpy(((uint8_t*)&cl->ssl_read_record) + cl->ssl_read_header_size, curbuf+done, h);
|
||||
cl->ssl_read_header_size += h;
|
||||
if (cl->ssl_read_header_size == sizeof(msgr_tls_record_hdr_t))
|
||||
cl->ssl_read_record.size = ntohs(cl->ssl_read_record.size);
|
||||
int r = BIO_write(cl->write_to_ssl, curbuf+done, h);
|
||||
assert(r == h);
|
||||
done += h;
|
||||
return;
|
||||
}
|
||||
// Record header and at least some data - copy both to BIO in a one BIO_write() call
|
||||
h = sizeof(msgr_tls_record_hdr_t)-cl->ssl_read_header_size;
|
||||
memcpy(((uint8_t*)&cl->ssl_read_record) + cl->ssl_read_header_size, curbuf+done, h);
|
||||
cl->ssl_read_header_size = sizeof(msgr_tls_record_hdr_t);
|
||||
cl->ssl_read_record.size = ntohs(cl->ssl_read_record.size);
|
||||
size_t n = h + cl->ssl_read_record.size;
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
int r = BIO_write(cl->write_to_ssl, curbuf+done, n);
|
||||
assert(r == n);
|
||||
done += n;
|
||||
cl->ssl_read_record.size -= (n - h);
|
||||
if (!cl->ssl_read_record.size)
|
||||
cl->ssl_read_header_size = 0;
|
||||
return;
|
||||
}
|
||||
if (cl->peer_iv_ctr >= AES_256_GCM_MAX_IV_CTR)
|
||||
{
|
||||
// Rotate key every 2^32 messages
|
||||
bool ok = msgr->derive_aes_keys(cl, false, true);
|
||||
assert(ok);
|
||||
}
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_gcm_init_256(&cl->peer_key_isal, cl->dec_ctx, cl->peer_key.data() + AES_256_GCM_KEY_SIZE, NULL, 0);
|
||||
if (r != 0)
|
||||
{
|
||||
fprintf(stderr, "isal_aes_gcm_init_256 error %d\n", r);
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
int r = EVP_DecryptInit_ex(cl->dec_ctx, NULL, NULL, cl->peer_key.data(), cl->peer_key.data() + AES_256_GCM_KEY_SIZE);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "DecryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
// Increase IV
|
||||
cl->peer_iv_ctr++;
|
||||
(*(uint64_t*)(cl->peer_key.data() + AES_256_GCM_KEY_SIZE))++;
|
||||
// Continued TLS data - buffer it to BIO
|
||||
size_t n = cl->ssl_read_record.size;
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
int r = BIO_write(cl->write_to_ssl, curbuf+done, n);
|
||||
assert(r == n);
|
||||
done += n;
|
||||
cl->ssl_read_record.size -= n;
|
||||
if (!cl->ssl_read_record.size)
|
||||
cl->ssl_read_header_size = 0;
|
||||
}
|
||||
|
||||
bool read(uint8_t *dst, size_t dst_len, int flags) override
|
||||
@@ -169,7 +168,7 @@ public:
|
||||
if (done >= bufsize)
|
||||
return false;
|
||||
size_t n = dst_len-from;
|
||||
if (!(flags & RDR_GCM))
|
||||
if (!(flags & RDR_TLS) || !cl->ssl_cli)
|
||||
{
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
@@ -201,13 +200,166 @@ public:
|
||||
{
|
||||
// Here, dst == NULL is not allowed
|
||||
assert(dst != NULL);
|
||||
buffer_again:
|
||||
buffer_encrypted();
|
||||
if (!cl->ssl_handshake_done)
|
||||
{
|
||||
if (!msgr->ssl_do_handshake(cl))
|
||||
return false;
|
||||
if (cl->write_state == 0)
|
||||
{
|
||||
// SSL_ERROR_WANT_WRITE is absolutely non-informative with memory BIO, it basically never happens
|
||||
// So we have to check memory BIO for outstanding data
|
||||
char *bio_buf = NULL;
|
||||
size_t bio_sz = BIO_get_mem_data(cl->read_from_ssl, &bio_buf);
|
||||
if (bio_sz > 0)
|
||||
{
|
||||
cl->write_state = CL_WRITE_READY;
|
||||
msgr->write_ready_clients.push_back(cl->client_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
int ok = SSL_read_ex(cl->ssl_cli, dst+from, n, &n);
|
||||
if (!ok)
|
||||
{
|
||||
ok = SSL_get_error(cl->ssl_cli, ok);
|
||||
if (ok == SSL_ERROR_WANT_READ)
|
||||
{
|
||||
if (done < bufsize)
|
||||
goto buffer_again;
|
||||
}
|
||||
else if (ok == SSL_ERROR_ZERO_RETURN)
|
||||
{
|
||||
fprintf(stderr, "Client %ju TLS disconnected\n", cl->client_id);
|
||||
cl->io_error = true;
|
||||
}
|
||||
else if (ok != 0 && ok != SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
fprintf(stderr, "Client %ju TLS read error: %s. Disconnecting client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
|
||||
cl->io_error = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (cl->read_csum_state && !(flags & RDR_NO_CSUM))
|
||||
{
|
||||
XXH3_64bits_update(cl->read_csum_state, dst+from, n);
|
||||
}
|
||||
cl->read_op_pos += n;
|
||||
from += n;
|
||||
if (from < dst_len)
|
||||
{
|
||||
if (done < bufsize)
|
||||
goto buffer_again;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
from = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool finish() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t get_done()
|
||||
{
|
||||
return done;
|
||||
}
|
||||
};
|
||||
|
||||
class gcm_op_reader_t: public msgr_op_reader_t
|
||||
{
|
||||
osd_messenger_t* msgr;
|
||||
osd_client_t* cl;
|
||||
size_t from;
|
||||
|
||||
uint8_t *curbuf;
|
||||
size_t bufsize;
|
||||
size_t done;
|
||||
|
||||
public:
|
||||
gcm_op_reader_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t *curbuf, size_t bufsize):
|
||||
msgr(msgr), cl(cl), from(cl->read_op_pos), curbuf(curbuf), bufsize(bufsize), done(0)
|
||||
{
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
from = cl->read_op_pos;
|
||||
}
|
||||
|
||||
bool read(uint8_t *dst, size_t dst_len, int flags) override
|
||||
{
|
||||
if (from >= dst_len)
|
||||
{
|
||||
// Skip
|
||||
from -= dst_len;
|
||||
return true;
|
||||
}
|
||||
if (done >= bufsize)
|
||||
return false;
|
||||
size_t n = dst_len-from;
|
||||
if (!(flags & RDR_TLS))
|
||||
{
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
if (flags & RDR_XTS)
|
||||
{
|
||||
msgr->op_decrypted_copy_buf(cl, curbuf, bufsize, dst, dst_len, from, done);
|
||||
n = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cl->read_csum_state && !(flags & RDR_NO_CSUM))
|
||||
{
|
||||
// data may be skipped if dst == NULL but checksum is still calculated
|
||||
XXH3_64bits_update(cl->read_csum_state, curbuf+done, n);
|
||||
}
|
||||
// Here, dst == NULL is allowed
|
||||
if (dst != NULL)
|
||||
memcpy(dst+from, curbuf+done, n);
|
||||
done += n;
|
||||
}
|
||||
cl->read_op_pos += n;
|
||||
from += n;
|
||||
if (from < dst_len)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Here, dst == NULL is not allowed
|
||||
assert(dst != NULL);
|
||||
if (cl->dec_batch_size_size < 4)
|
||||
{
|
||||
size_t n = 4-cl->dec_batch_size_size;
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
memcpy(&cl->dec_batch_size, curbuf+done, n);
|
||||
cl->dec_batch_size_size += n;
|
||||
done += n;
|
||||
if (cl->dec_batch_size_size < 4)
|
||||
return false;
|
||||
if (!cl->dec_batch_size)
|
||||
{
|
||||
fprintf(stderr, "Client %ju - empty batch received, disconnecting\n", cl->client_id);
|
||||
cl->io_error = true;
|
||||
return false;
|
||||
}
|
||||
uint8_t iv[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
int r = EVP_DecryptInit_ex(cl->dec_ctx, NULL, NULL, (uint8_t*)msgr->test_osd_aes_key.data(), iv);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "DecryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
size_t n = dst_len-from;
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_gcm_dec_256_update(&cl->peer_key_isal, cl->dec_ctx, dst+from, curbuf+done, n);
|
||||
assert(!r);
|
||||
#else
|
||||
int actual_out;
|
||||
if (EVP_DecryptUpdate(cl->dec_ctx, dst+from, &actual_out, curbuf+done, n) != 1)
|
||||
{
|
||||
@@ -216,7 +368,6 @@ public:
|
||||
abort();
|
||||
}
|
||||
assert(actual_out == n);
|
||||
#endif
|
||||
if (cl->read_csum_state && !(flags & RDR_NO_CSUM))
|
||||
{
|
||||
XXH3_64bits_update(cl->read_csum_state, dst+from, n);
|
||||
@@ -235,6 +386,12 @@ public:
|
||||
|
||||
bool finish() override
|
||||
{
|
||||
if (cl->dec_batch_size > 1)
|
||||
{
|
||||
// No tag yet
|
||||
cl->dec_batch_size--;
|
||||
return true;
|
||||
}
|
||||
if (cl->dec_tag_size+bufsize-done < 16)
|
||||
{
|
||||
// Buffer part of the tag
|
||||
@@ -243,62 +400,33 @@ public:
|
||||
done = bufsize;
|
||||
return false;
|
||||
}
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
uint8_t calc_tag[16];
|
||||
int r = isal_aes_gcm_dec_256_finalize(&cl->peer_key_isal, cl->dec_ctx, calc_tag, 16);
|
||||
assert(r == 0);
|
||||
if (cl->dec_tag_size > 0)
|
||||
{
|
||||
// Tag is partially buffered, append to it and compare
|
||||
memcpy(cl->dec_tag+cl->dec_tag_size, curbuf+done, 16-cl->dec_tag_size);
|
||||
done += 16-cl->dec_tag_size;
|
||||
r = !memcmp(calc_tag, cl->dec_tag, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compare the full tag directly from the source buffer
|
||||
r = !memcmp(calc_tag, curbuf+done, 16);
|
||||
done += 16;
|
||||
}
|
||||
#else
|
||||
int r;
|
||||
if (cl->dec_tag_size > 0)
|
||||
{
|
||||
// Tag is partially buffered, append to it and use it from there
|
||||
memcpy(cl->dec_tag+cl->dec_tag_size, curbuf+done, 16-cl->dec_tag_size);
|
||||
r = EVP_CIPHER_CTX_ctrl(cl->dec_ctx, EVP_CTRL_GCM_SET_TAG, 16, cl->dec_tag);
|
||||
assert(r == 1);
|
||||
done += 16-cl->dec_tag_size;
|
||||
r = EVP_CIPHER_CTX_ctrl(cl->dec_ctx, EVP_CTRL_GCM_SET_TAG, 16, cl->dec_tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take full tag directly from the source buffer
|
||||
r = EVP_CIPHER_CTX_ctrl(cl->dec_ctx, EVP_CTRL_GCM_SET_TAG, 16, curbuf+done);
|
||||
assert(r == 1);
|
||||
done += 16;
|
||||
}
|
||||
assert(r == 1);
|
||||
int len = 0;
|
||||
r = EVP_DecryptFinal_ex(cl->dec_ctx, NULL, &len);
|
||||
assert(len == 0);
|
||||
#endif
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "Client %ju AES-GCM decryption failed\n", cl->client_id);
|
||||
cl->io_error = true;
|
||||
return false;
|
||||
}
|
||||
if (msgr->decrypt_gcm_pool.size() < msgr->max_cipher_pool_size)
|
||||
msgr->decrypt_gcm_pool.push_back(cl->dec_ctx);
|
||||
else
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
free(cl->dec_ctx);
|
||||
#else
|
||||
EVP_CIPHER_CTX_free(cl->dec_ctx);
|
||||
#endif
|
||||
}
|
||||
cl->dec_ctx = NULL;
|
||||
cl->dec_tag_size = 0;
|
||||
assert(len == 0);
|
||||
cl->dec_batch_size = 0;
|
||||
cl->dec_batch_size_size = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -358,15 +486,17 @@ public:
|
||||
|
||||
bool read(uint8_t *dst, size_t dst_len, int flags) override
|
||||
{
|
||||
if (cl->dec_ctx)
|
||||
return false; // FIXME Only for tests, use copy-only with AES
|
||||
if (from >= dst_len)
|
||||
{
|
||||
// Skip
|
||||
from -= dst_len;
|
||||
return true;
|
||||
}
|
||||
if ((flags & RDR_GCM) && cl->gcm_enabled)
|
||||
if ((flags & RDR_TLS) && cl->ssl_cli)
|
||||
{
|
||||
// Can't inplace read encrypted data
|
||||
// Can't inplace read TLS data
|
||||
return false;
|
||||
}
|
||||
if (cl->recv_list.size() >= IOV_MAX)
|
||||
@@ -390,16 +520,12 @@ public:
|
||||
|
||||
bool finish() override
|
||||
{
|
||||
if (cl->gcm_enabled)
|
||||
if (cl->dec_ctx)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef WITH_RDMA
|
||||
#include "msgr_rdma.h"
|
||||
#endif
|
||||
|
||||
void osd_messenger_t::read_requests()
|
||||
{
|
||||
for (int i = 0; i < read_ready_clients.size(); i++)
|
||||
@@ -407,8 +533,7 @@ void osd_messenger_t::read_requests()
|
||||
uint64_t client_id = read_ready_clients[i];
|
||||
auto cl_it = clients.find(client_id);
|
||||
if (cl_it == clients.end() || !cl_it->second || cl_it->second->read_msg.msg_iovlen ||
|
||||
cl_it->second->peer_state == PEER_CONNECTING ||
|
||||
cl_it->second->peer_state == PEER_STOPPED)
|
||||
cl_it->second->peer_state != PEER_CONNECTED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -489,15 +614,6 @@ void osd_messenger_t::handle_read(int result, osd_client_t *cl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (cl->peer_state == PEER_RDMA_CONNECTING_IN || cl->peer_state == PEER_RDMA_CONNECTING_OUT)
|
||||
{
|
||||
// Data received over TCP, abort RDMA connection
|
||||
fprintf(stderr, "Data received for RDMA client %ju over TCP, falling back to TCP\n", cl->client_id);
|
||||
delete cl->rdma_conn;
|
||||
cl->rdma_conn = NULL;
|
||||
cl->peer_state = PEER_CONNECTED;
|
||||
assert(cl->peer_fd >= 0);
|
||||
}
|
||||
if (cl->peer_state == PEER_STOPPED)
|
||||
{
|
||||
if (cl->refs <= 0)
|
||||
@@ -560,6 +676,8 @@ out_wakeup:
|
||||
{
|
||||
goto out_wakeup;
|
||||
}
|
||||
execute_verified_op(cl, cl->read_op);
|
||||
cl->read_op = NULL;
|
||||
}
|
||||
}
|
||||
cl->read_msg.msg_iovlen = 0;
|
||||
@@ -600,49 +718,8 @@ void osd_messenger_t::handle_immediate_ops()
|
||||
|
||||
bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size_t bufsize)
|
||||
{
|
||||
if (cl->gcm_enabled)
|
||||
if (cl->dec_ctx)
|
||||
{
|
||||
if (cl->hs)
|
||||
{
|
||||
ssize_t done = cl->hs->handle(curbuf, bufsize);
|
||||
if (done < 0)
|
||||
{
|
||||
fprintf(stderr, "Client %ju handshake failed: %s\n", cl->client_id, cl->hs->get_error().c_str());
|
||||
stop_client(cl->client_id);
|
||||
return false;
|
||||
}
|
||||
if (cl->hs->done() && !derive_aes_keys(cl, true, true))
|
||||
{
|
||||
stop_client(cl->client_id);
|
||||
return false;
|
||||
}
|
||||
curbuf += done;
|
||||
bufsize -= done;
|
||||
if (cl->hs->get_out().size())
|
||||
{
|
||||
if (cl->write_state == 0)
|
||||
{
|
||||
cl->write_state = CL_WRITE_READY;
|
||||
write_ready_clients.push_back(cl->client_id);
|
||||
}
|
||||
}
|
||||
if (cl->hs->done() && !cl->hs->get_out().size())
|
||||
{
|
||||
// Delete hs when done and nothing to send
|
||||
delete cl->hs;
|
||||
cl->hs = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (done < bufsize)
|
||||
{
|
||||
fprintf(stderr, "Client %ju extra data after handshake\n", cl->client_id);
|
||||
stop_client(cl->client_id);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return handle_buffer_with<gcm_op_reader_t>(cl, curbuf, bufsize);
|
||||
}
|
||||
return handle_buffer_with<copy_op_reader_t>(cl, curbuf, bufsize);
|
||||
@@ -673,10 +750,7 @@ bool osd_messenger_t::handle_buffer_with(osd_client_t *cl, uint8_t *curbuf, size
|
||||
{
|
||||
if (!cl->read_csum_state)
|
||||
cl->read_csum_state = XXH3_createState();
|
||||
if (cl->peer_key.size() == AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE + XXH_SECRET_DEFAULT_SIZE)
|
||||
XXH3_64bits_reset_withSecret(cl->read_csum_state, cl->peer_key.data() + AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE, XXH_SECRET_DEFAULT_SIZE);
|
||||
else
|
||||
XXH3_64bits_reset(cl->read_csum_state);
|
||||
XXH3_64bits_reset(cl->read_csum_state);
|
||||
}
|
||||
if (!op_read_from(cl, rdr) || !handle_finished_op(cl))
|
||||
{
|
||||
@@ -687,6 +761,28 @@ bool osd_messenger_t::handle_buffer_with(osd_client_t *cl, uint8_t *curbuf, size
|
||||
}
|
||||
break;
|
||||
}
|
||||
if constexpr (std::is_same_v<T, gcm_op_reader_t>)
|
||||
{
|
||||
if (cl->dec_batch_size_size)
|
||||
{
|
||||
// Operation is not verified yet
|
||||
cl->unverified_ops.push_back(cl->read_op);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto & op: cl->unverified_ops)
|
||||
{
|
||||
execute_verified_op(cl, op);
|
||||
}
|
||||
cl->unverified_ops.clear();
|
||||
execute_verified_op(cl, cl->read_op);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
execute_verified_op(cl, cl->read_op);
|
||||
}
|
||||
cl->read_op = NULL;
|
||||
}
|
||||
assert(rdr.get_done() == bufsize);
|
||||
return true;
|
||||
@@ -745,42 +841,18 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
|
||||
{
|
||||
osd_op_t *cur_op = cl->read_op;
|
||||
cl->read_op_size = 0;
|
||||
if (!osd_num)
|
||||
{
|
||||
if (log_level > 1)
|
||||
fprintf(stderr, "Error: operation received from an OSD peer %ju, stopping\n", cl->client_id);
|
||||
return false;
|
||||
}
|
||||
else if (cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
|
||||
if (cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
|
||||
cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)
|
||||
{
|
||||
if (cur_op->req.sec_rw.attr_len > 0)
|
||||
{
|
||||
if (cur_op->req.sec_rw.attr_len > clean_entry_bitmap_size)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
fprintf(stderr, "Error: peer %ju secondary write request attr_len too large (%u > %u bytes), stopping\n", cl->client_id,
|
||||
cur_op->req.sec_rw.attr_len, clean_entry_bitmap_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (cur_op->req.sec_rw.attr_len > sizeof(cur_op->bmp_data))
|
||||
if (cur_op->req.sec_rw.attr_len > sizeof(unsigned))
|
||||
cur_op->bitmap = cur_op->rmw_buf = malloc_or_die(cur_op->req.sec_rw.attr_len);
|
||||
else
|
||||
cur_op->bitmap = &cur_op->bmp_data;
|
||||
}
|
||||
if (cur_op->req.sec_rw.len > 0)
|
||||
{
|
||||
if (cur_op->req.sec_rw.len > bs_block_size)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
fprintf(stderr, "Error: peer %ju secondary write request size too large (%u > %u bytes), stopping\n", cl->client_id,
|
||||
cur_op->req.sec_rw.len, bs_block_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.sec_rw.len);
|
||||
}
|
||||
cl->read_op_size = cur_op->req.sec_rw.len + cur_op->req.sec_rw.attr_len;
|
||||
@@ -790,15 +862,6 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
|
||||
{
|
||||
if (cur_op->req.sec_stab.len > 0)
|
||||
{
|
||||
if (cur_op->req.sec_stab.len > MAX_SIMPLE_PAYLOAD_SIZE)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
fprintf(stderr, "Error: peer %ju stabilize request size too large (%lu > %u bytes), stopping\n", cl->client_id,
|
||||
cur_op->req.sec_stab.len, MAX_SIMPLE_PAYLOAD_SIZE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.sec_stab.len);
|
||||
}
|
||||
cl->read_op_size = cur_op->req.sec_stab.len;
|
||||
@@ -807,15 +870,6 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
|
||||
{
|
||||
if (cur_op->req.sec_read_bmp.len > 0)
|
||||
{
|
||||
if (cur_op->req.sec_read_bmp.len > MAX_SIMPLE_PAYLOAD_SIZE)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
fprintf(stderr, "Error: peer %ju sec_read_bmp request size too large (%lu > %u bytes), stopping\n", cl->client_id,
|
||||
cur_op->req.sec_read_bmp.len, MAX_SIMPLE_PAYLOAD_SIZE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.sec_read_bmp.len);
|
||||
}
|
||||
cl->read_op_size = cur_op->req.sec_read_bmp.len;
|
||||
@@ -824,15 +878,6 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
|
||||
{
|
||||
if (cur_op->req.rw.len > 0)
|
||||
{
|
||||
if (cur_op->req.rw.len > max_write_request_size)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
fprintf(stderr, "Error: peer %ju write request size too large (%u > %u bytes), stopping\n", cl->client_id,
|
||||
cur_op->req.rw.len, max_write_request_size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.rw.len);
|
||||
}
|
||||
cl->read_op_size = cur_op->req.rw.len;
|
||||
@@ -841,15 +886,6 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
|
||||
{
|
||||
if (cur_op->req.show_conf.json_len > 0)
|
||||
{
|
||||
if (cur_op->req.show_conf.json_len > MAX_SIMPLE_PAYLOAD_SIZE)
|
||||
{
|
||||
if (log_level > 1)
|
||||
{
|
||||
fprintf(stderr, "Error: peer %ju show_config request length too large (%lu > %u bytes), stopping\n", cl->client_id,
|
||||
cur_op->req.show_conf.json_len, MAX_SIMPLE_PAYLOAD_SIZE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
cur_op->buf = malloc_or_die(cur_op->req.show_conf.json_len+1);
|
||||
((uint8_t*)cur_op->buf)[cur_op->req.show_conf.json_len] = 0;
|
||||
}
|
||||
@@ -928,7 +964,7 @@ bool osd_messenger_t::op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr)
|
||||
bool hdr = (cl->read_op_pos < OSD_PACKET_SIZE);
|
||||
if (hdr || op->op_type == OSD_OP_IN)
|
||||
{
|
||||
if (!rdr.read(op->req.buf, OSD_PACKET_SIZE, RDR_GCM | (cl->proto_csum_status == MSGR_CSUM_PAYLOAD ? RDR_NO_CSUM : 0)))
|
||||
if (!rdr.read(op->req.buf, OSD_PACKET_SIZE, RDR_TLS | (cl->proto_csum_status == MSGR_CSUM_PAYLOAD ? RDR_NO_CSUM : 0)))
|
||||
return false;
|
||||
if (hdr)
|
||||
{
|
||||
@@ -944,7 +980,7 @@ bool osd_messenger_t::op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr)
|
||||
if (op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
|
||||
op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->bitmap, op->req.sec_rw.attr_len, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->bitmap, op->req.sec_rw.attr_len, RDR_TLS))
|
||||
return false;
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.sec_rw.len, 0))
|
||||
return false;
|
||||
@@ -952,12 +988,12 @@ bool osd_messenger_t::op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr)
|
||||
else if (op->req.hdr.opcode == OSD_OP_SEC_STABILIZE ||
|
||||
op->req.hdr.opcode == OSD_OP_SEC_ROLLBACK)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.sec_stab.len, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.sec_stab.len, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if (op->req.hdr.opcode == OSD_OP_SEC_READ_BMP)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.sec_read_bmp.len, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.sec_read_bmp.len, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if (op->req.hdr.opcode == OSD_OP_WRITE)
|
||||
@@ -967,20 +1003,20 @@ bool osd_messenger_t::op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr)
|
||||
}
|
||||
else if (op->req.hdr.opcode == OSD_OP_SHOW_CONFIG)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.show_conf.json_len, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->buf, op->req.show_conf.json_len, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rdr.read(op->reply.buf, OSD_PACKET_SIZE, RDR_GCM | (cl->proto_csum_status == MSGR_CSUM_PAYLOAD ? RDR_NO_CSUM : 0)))
|
||||
if (!rdr.read(op->reply.buf, OSD_PACKET_SIZE, RDR_TLS | (cl->proto_csum_status == MSGR_CSUM_PAYLOAD ? RDR_NO_CSUM : 0)))
|
||||
return false;
|
||||
switched_type:
|
||||
if (op->reply.hdr.opcode == OSD_OP_SEC_READ)
|
||||
{
|
||||
if (op->reply.sec_rw.attr_len > 0)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->bitmap, op->reply.sec_rw.attr_len, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->bitmap, op->reply.sec_rw.attr_len, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
if (op->reply.hdr.retval > 0)
|
||||
@@ -994,7 +1030,7 @@ switched_type:
|
||||
{
|
||||
if (op->reply.rw.bitmap_len > 0)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->bitmap, op->reply.rw.bitmap_len, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->bitmap, op->reply.rw.bitmap_len, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
if (op->reply.hdr.retval > 0)
|
||||
@@ -1006,25 +1042,25 @@ switched_type:
|
||||
}
|
||||
else if (op->reply.hdr.opcode == OSD_OP_SEC_LIST && op->reply.hdr.retval > 0)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->buf, sizeof(obj_ver_id) * op->reply.hdr.retval, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->buf, sizeof(obj_ver_id) * op->reply.hdr.retval, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if ((op->reply.hdr.opcode == OSD_OP_SEC_READ_BMP ||
|
||||
op->reply.hdr.opcode == OSD_OP_SHOW_CONFIG) && op->reply.hdr.retval > 0)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->buf, op->reply.hdr.retval, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->buf, op->reply.hdr.retval, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if (op->reply.hdr.opcode == OSD_OP_DESCRIBE && op->reply.describe.result_bytes > 0)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)op->buf, op->reply.describe.result_bytes, RDR_GCM))
|
||||
if (!rdr.read((uint8_t*)op->buf, op->reply.describe.result_bytes, RDR_TLS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (cl->proto_csum_status == MSGR_CSUM_FULL ||
|
||||
cl->read_op_size > 0 && cl->proto_csum_status == MSGR_CSUM_PAYLOAD)
|
||||
{
|
||||
if (!rdr.read((uint8_t*)&op->csum, 8, RDR_GCM|RDR_NO_CSUM))
|
||||
if (!rdr.read((uint8_t*)&op->csum, 8, RDR_TLS|RDR_NO_CSUM))
|
||||
return false;
|
||||
}
|
||||
if (!rdr.finish())
|
||||
@@ -1052,12 +1088,7 @@ bool osd_messenger_t::handle_finished_op(osd_client_t *cl)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (op->op_type == OSD_OP_IN)
|
||||
{
|
||||
// Operation is ready
|
||||
cl->received_ops.push_back(op);
|
||||
}
|
||||
else
|
||||
if (op->op_type == OSD_OP_OUT)
|
||||
{
|
||||
// Inline decryption
|
||||
if (cl->read_op_inline_decrypt_pos != (size_t)-1)
|
||||
@@ -1065,6 +1096,20 @@ bool osd_messenger_t::handle_finished_op(osd_client_t *cl)
|
||||
op_decrypt_inline(cl);
|
||||
cl->read_op_inline_decrypt_pos = (size_t)-1;
|
||||
}
|
||||
}
|
||||
op_decrypt_free(cl);
|
||||
return true;
|
||||
}
|
||||
|
||||
void osd_messenger_t::execute_verified_op(osd_client_t *cl, osd_op_t *op)
|
||||
{
|
||||
if (op->op_type == OSD_OP_IN)
|
||||
{
|
||||
// Operation is ready
|
||||
cl->received_ops.push_back(op);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Measure subop (outbound op) latency
|
||||
timespec tv_end;
|
||||
clock_gettime(CLOCK_REALTIME, &tv_end);
|
||||
@@ -1079,8 +1124,5 @@ bool osd_messenger_t::handle_finished_op(osd_client_t *cl)
|
||||
(tv_end.tv_nsec - op->tv_begin.tv_nsec)/1000
|
||||
);
|
||||
}
|
||||
op_decrypt_free(cl);
|
||||
set_immediate_ops.push_back(op);
|
||||
cl->read_op = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
+365
-205
@@ -7,10 +7,14 @@
|
||||
|
||||
#include "messenger.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#define WR_GCM 1
|
||||
#define WR_TLS 1
|
||||
#define WR_XTS 2
|
||||
#define WR_NO_CSUM 4
|
||||
|
||||
@@ -82,7 +86,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class gcm_op_writer_t: public msgr_op_writer_t
|
||||
class ssl_op_writer_t: public msgr_op_writer_t
|
||||
{
|
||||
osd_messenger_t* msgr;
|
||||
osd_client_t* cl;
|
||||
@@ -93,7 +97,7 @@ class gcm_op_writer_t: public msgr_op_writer_t
|
||||
size_t done;
|
||||
|
||||
public:
|
||||
gcm_op_writer_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t *curbuf, size_t bufsize):
|
||||
ssl_op_writer_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t *curbuf, size_t bufsize):
|
||||
msgr(msgr), cl(cl), from(cl->write_op_pos), curbuf(curbuf), bufsize(bufsize), done(0)
|
||||
{
|
||||
}
|
||||
@@ -101,75 +105,148 @@ public:
|
||||
void reset()
|
||||
{
|
||||
from = cl->write_op_pos;
|
||||
init_ctx(msgr, cl);
|
||||
}
|
||||
|
||||
static void init_ctx(osd_messenger_t* msgr, osd_client_t *cl)
|
||||
void flush_ssl()
|
||||
{
|
||||
if (!cl->enc_ctx)
|
||||
if (!cl->ssl_handshake_done)
|
||||
{
|
||||
if (msgr->encrypt_gcm_pool.size())
|
||||
if (!msgr->ssl_do_handshake(cl))
|
||||
return;
|
||||
}
|
||||
_flush_ssl();
|
||||
}
|
||||
|
||||
bool _flush_ssl()
|
||||
{
|
||||
int r = BIO_read(cl->read_from_ssl, curbuf+done, bufsize-done);
|
||||
if (r > 0)
|
||||
done += r;
|
||||
if (done >= bufsize)
|
||||
{
|
||||
// Check if we've sent all buffered TLS data
|
||||
// ...Because we can't return true from this->write() if we haven't
|
||||
char *bio_buf = NULL;
|
||||
size_t bio_sz = BIO_get_mem_data(cl->read_from_ssl, &bio_buf);
|
||||
if (bio_sz > 0)
|
||||
{
|
||||
cl->enc_ctx = msgr->encrypt_gcm_pool.back();
|
||||
msgr->encrypt_gcm_pool.pop_back();
|
||||
cl->ssl_more_to_buffer = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool write_to_ssl(osd_client_t *cl, uint8_t *src, size_t src_len, int flags, size_t & from)
|
||||
{
|
||||
size_t n = src_len-from;
|
||||
int ok = SSL_write_ex(cl->ssl_cli, src+from, n, &n);
|
||||
if (ok)
|
||||
{
|
||||
if (cl->write_csum_state && !(flags & WR_NO_CSUM))
|
||||
XXH3_64bits_update(cl->write_csum_state, src+from, n);
|
||||
cl->write_op_pos += n;
|
||||
from += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = SSL_get_error(cl->ssl_cli, ok);
|
||||
if (ok == SSL_ERROR_ZERO_RETURN)
|
||||
{
|
||||
fprintf(stderr, "Client %ju TLS disconnected\n", cl->client_id);
|
||||
cl->io_error = true;
|
||||
return false;
|
||||
}
|
||||
else if (ok != SSL_ERROR_WANT_READ && ok != SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
fprintf(stderr, "Client %ju TLS write error: %s. Disconnecting client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
|
||||
cl->io_error = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write(uint8_t *src, size_t src_len, int flags) override
|
||||
{
|
||||
if (from >= src_len)
|
||||
{
|
||||
if (cl->ssl_more_to_buffer && !_flush_ssl())
|
||||
return false;
|
||||
from -= src_len;
|
||||
return true;
|
||||
}
|
||||
if (!(flags & WR_TLS) || !cl->ssl_cli)
|
||||
{
|
||||
if (flags & WR_XTS)
|
||||
{
|
||||
msgr->op_encrypted_copy_buf(cl, curbuf, bufsize, src, src_len, from, done);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
cl->enc_ctx = (isal_gcm_context_data*)malloc_or_die(sizeof(isal_gcm_context_data));
|
||||
#else
|
||||
cl->enc_ctx = EVP_CIPHER_CTX_new();
|
||||
assert(cl->enc_ctx);
|
||||
int r = EVP_EncryptInit_ex(cl->enc_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "EncryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
size_t n = src_len-from;
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
if (cl->write_csum_state && !(flags & WR_NO_CSUM))
|
||||
XXH3_64bits_update(cl->write_csum_state, src+from, n);
|
||||
memcpy(curbuf+done, src+from, n);
|
||||
done += n;
|
||||
cl->write_op_pos += n;
|
||||
from += n;
|
||||
}
|
||||
}
|
||||
if (cl->my_iv_ctr >= AES_256_GCM_MAX_IV_CTR)
|
||||
{
|
||||
// Rotate key every 2^32 messages
|
||||
bool ok = msgr->derive_aes_keys(cl, true, false);
|
||||
assert(ok);
|
||||
}
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_gcm_init_256(&cl->my_key_isal, cl->enc_ctx, cl->my_key.data() + AES_256_GCM_KEY_SIZE, NULL, 0);
|
||||
if (r != 0)
|
||||
{
|
||||
fprintf(stderr, "isal_aes_gcm_init_256 error %d\n", r);
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
int r = EVP_EncryptInit_ex(cl->enc_ctx, NULL, NULL, (uint8_t*)cl->my_key.data(), cl->my_key.data() + AES_256_GCM_KEY_SIZE);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "EncryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
// Increase IV
|
||||
cl->my_iv_ctr++;
|
||||
(*(uint64_t*)(cl->my_key.data() + AES_256_GCM_KEY_SIZE))++;
|
||||
}
|
||||
|
||||
static void free_ctx(osd_messenger_t* msgr, osd_client_t *cl)
|
||||
{
|
||||
if (msgr->encrypt_gcm_pool.size() < msgr->max_cipher_pool_size)
|
||||
msgr->encrypt_gcm_pool.push_back(cl->enc_ctx);
|
||||
else
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
free(cl->enc_ctx);
|
||||
#else
|
||||
EVP_CIPHER_CTX_free(cl->enc_ctx);
|
||||
#endif
|
||||
if (!cl->ssl_handshake_done)
|
||||
{
|
||||
if (!msgr->ssl_do_handshake(cl))
|
||||
return false;
|
||||
}
|
||||
if (cl->ssl_handshake_done)
|
||||
{
|
||||
if (!write_to_ssl(cl, src, src_len, flags, from))
|
||||
return false;
|
||||
}
|
||||
if (!_flush_ssl())
|
||||
return false;
|
||||
}
|
||||
cl->enc_ctx = NULL;
|
||||
if (from < src_len)
|
||||
return false;
|
||||
from = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool finish() override
|
||||
{
|
||||
return _flush_ssl();
|
||||
}
|
||||
|
||||
size_t get_done()
|
||||
{
|
||||
return done;
|
||||
}
|
||||
};
|
||||
|
||||
class gcm_op_writer_t: public msgr_op_writer_t
|
||||
{
|
||||
osd_messenger_t* msgr;
|
||||
osd_client_t* cl;
|
||||
size_t from;
|
||||
|
||||
uint8_t *curbuf;
|
||||
size_t bufsize;
|
||||
size_t done;
|
||||
uint32_t *batch_size_ptr;
|
||||
|
||||
public:
|
||||
gcm_op_writer_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t *curbuf, size_t bufsize):
|
||||
msgr(msgr), cl(cl), from(cl->write_op_pos), curbuf(curbuf), bufsize(bufsize), done(0), batch_size_ptr(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
from = cl->write_op_pos;
|
||||
}
|
||||
|
||||
bool write(uint8_t *src, size_t src_len, int flags) override
|
||||
@@ -179,7 +256,7 @@ public:
|
||||
from -= src_len;
|
||||
return true;
|
||||
}
|
||||
if (!(flags & WR_GCM))
|
||||
if (!(flags & WR_TLS))
|
||||
{
|
||||
if (flags & WR_XTS)
|
||||
{
|
||||
@@ -202,15 +279,37 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cl->write_op_pos)
|
||||
{
|
||||
if (batch_size_ptr)
|
||||
{
|
||||
if (bufsize-done < 1)
|
||||
return false;
|
||||
(*batch_size_ptr)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bufsize-done < 5)
|
||||
return false;
|
||||
batch_size_ptr = (uint32_t*)(curbuf+done);
|
||||
*batch_size_ptr = 1; // FIXME like header, but now for tests
|
||||
done += 4;
|
||||
cl->enc_batch = true;
|
||||
uint8_t iv[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
int r = EVP_EncryptInit_ex(cl->enc_ctx, NULL, NULL, (uint8_t*)msgr->test_osd_aes_key.data(), iv);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "EncryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t n = src_len-from;
|
||||
if (n > bufsize-done)
|
||||
n = bufsize-done;
|
||||
if (!n)
|
||||
return false;
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_gcm_enc_256_update(&cl->my_key_isal, cl->enc_ctx, curbuf+done, src+from, n);
|
||||
assert(!r);
|
||||
#else
|
||||
int actual_out;
|
||||
if (EVP_EncryptUpdate(cl->enc_ctx, curbuf+done, &actual_out, src+from, n) != 1)
|
||||
{
|
||||
@@ -219,7 +318,6 @@ public:
|
||||
abort();
|
||||
}
|
||||
assert(actual_out == n);
|
||||
#endif
|
||||
if (cl->write_csum_state && !(flags & WR_NO_CSUM))
|
||||
XXH3_64bits_update(cl->write_csum_state, src+from, n);
|
||||
done += n;
|
||||
@@ -232,12 +330,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static void write_tag_to(osd_messenger_t *msgr, osd_client_t *cl, uint8_t *dst)
|
||||
static void write_tag_to(osd_client_t *cl, uint8_t *dst)
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_gcm_enc_256_finalize(&cl->my_key_isal, cl->enc_ctx, dst, 16);
|
||||
assert(!r);
|
||||
#else
|
||||
int actual_out = 0;
|
||||
int r = EVP_EncryptFinal_ex(cl->enc_ctx, NULL, &actual_out);
|
||||
if (r != 1)
|
||||
@@ -249,38 +343,26 @@ public:
|
||||
assert(actual_out == 0);
|
||||
r = EVP_CIPHER_CTX_ctrl(cl->enc_ctx, EVP_CTRL_GCM_GET_TAG, 16, dst);
|
||||
assert(r == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool finish() override
|
||||
{
|
||||
if (bufsize-done >= OSD_PACKET_SIZE+16 && batch_size_ptr && cl->write_ops.size())
|
||||
{
|
||||
// More operations may fit, so don't finish the batch yet
|
||||
return true;
|
||||
}
|
||||
// Tag is 16 bytes
|
||||
if (done >= bufsize)
|
||||
if (bufsize-done < 16)
|
||||
{
|
||||
// No space for the tag
|
||||
return false;
|
||||
if (bufsize-done < 16 || cl->enc_tag_size)
|
||||
{
|
||||
// No space for the full tag, but msgr_rdma expects us to always fill the whole buffer
|
||||
if (!cl->enc_tag_size)
|
||||
{
|
||||
write_tag_to(msgr, cl, cl->enc_tag);
|
||||
cl->enc_tag_size = 16;
|
||||
}
|
||||
size_t n = bufsize-done;
|
||||
if (n > cl->enc_tag_size)
|
||||
n = cl->enc_tag_size;
|
||||
memcpy(curbuf+done, cl->enc_tag+16-cl->enc_tag_size, n);
|
||||
done += n;
|
||||
cl->enc_tag_size -= n;
|
||||
if (cl->enc_tag_size > 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The whole tag fits at once
|
||||
write_tag_to(msgr, cl, curbuf+done);
|
||||
done += 16;
|
||||
}
|
||||
free_ctx(msgr, cl);
|
||||
write_tag_to(cl, curbuf+done);
|
||||
done += 16;
|
||||
// Batch is completed
|
||||
cl->enc_batch = false;
|
||||
batch_size_ptr = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -290,22 +372,20 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME Split into 3 classes - basic, tls and gcm
|
||||
class get_op_writer_t: public msgr_op_writer_t
|
||||
{
|
||||
osd_messenger_t* msgr;
|
||||
osd_client_t* cl;
|
||||
size_t from;
|
||||
size_t done;
|
||||
size_t enc_size;
|
||||
size_t done_enc;
|
||||
|
||||
public:
|
||||
get_op_writer_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t*, size_t):
|
||||
msgr(msgr), cl(cl), from(cl->write_op_pos), done(0), enc_size(0), done_enc(0)
|
||||
{
|
||||
}
|
||||
bool have_batch;
|
||||
size_t batch_size_offset;
|
||||
size_t batch_bytes;
|
||||
|
||||
static void ssl_extend_buf(osd_client_t *cl, size_t more = 0)
|
||||
void ssl_extend_buf(size_t more = 0)
|
||||
{
|
||||
size_t min_cap = cl->ssl_out_buf_size*2;
|
||||
if (min_cap < cl->ssl_out_buf_size+more)
|
||||
@@ -314,19 +394,63 @@ public:
|
||||
min_cap = 16384;
|
||||
if (cl->ssl_out_buf_cap < min_cap)
|
||||
{
|
||||
uintptr_t old_buf = (uintptr_t)cl->ssl_out_buf;
|
||||
uintptr_t old_end = old_buf + cl->ssl_out_buf_cap;
|
||||
uint8_t *old_buf = cl->ssl_out_buf;
|
||||
uint8_t *old_end = old_buf + cl->ssl_out_buf_cap;
|
||||
cl->ssl_out_buf = (uint8_t*)realloc_or_die(cl->ssl_out_buf, min_cap);
|
||||
cl->ssl_out_buf_cap = min_cap;
|
||||
for (auto & iov: cl->send_list)
|
||||
{
|
||||
if ((uintptr_t)iov.iov_base >= old_buf && (uintptr_t)iov.iov_base < old_end)
|
||||
iov.iov_base = cl->ssl_out_buf + ((uintptr_t)iov.iov_base - old_buf);
|
||||
if (iov.iov_base >= old_buf && iov.iov_base < old_end)
|
||||
iov.iov_base = cl->ssl_out_buf + ((uint8_t*)iov.iov_base - old_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void send_out_buf(osd_client_t *cl, size_t n)
|
||||
void copy_ssl()
|
||||
{
|
||||
size_t prev_size = cl->ssl_out_buf_size;
|
||||
do
|
||||
{
|
||||
ssl_extend_buf();
|
||||
int r = BIO_read(cl->read_from_ssl, cl->ssl_out_buf+cl->ssl_out_buf_size, cl->ssl_out_buf_cap-cl->ssl_out_buf_size);
|
||||
if (r > 0)
|
||||
cl->ssl_out_buf_size += r;
|
||||
} while (cl->ssl_out_buf_size >= cl->ssl_out_buf_cap);
|
||||
if (cl->ssl_out_buf_size > prev_size)
|
||||
{
|
||||
cl->send_list.push_back((iovec){ .iov_base = cl->ssl_out_buf+prev_size, .iov_len = cl->ssl_out_buf_size-prev_size });
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
get_op_writer_t(osd_messenger_t* msgr, osd_client_t* cl):
|
||||
msgr(msgr), cl(cl), from(cl->write_op_pos), enc_size(0), done_enc(0),
|
||||
have_batch(false), batch_size_offset(0), batch_bytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
from = cl->write_op_pos;
|
||||
enc_size = 0;
|
||||
done_enc = 0;
|
||||
}
|
||||
|
||||
void flush_ssl()
|
||||
{
|
||||
if (!cl->ssl_handshake_done)
|
||||
{
|
||||
if (!msgr->ssl_do_handshake(cl))
|
||||
return;
|
||||
}
|
||||
if (cl->send_list.size() >= IOV_MAX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
copy_ssl();
|
||||
}
|
||||
|
||||
void send_out_buf(size_t n)
|
||||
{
|
||||
if (cl->send_list.size() > 0)
|
||||
{
|
||||
@@ -342,17 +466,6 @@ public:
|
||||
cl->ssl_out_buf_size += n;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
from = cl->write_op_pos;
|
||||
enc_size = 0;
|
||||
done_enc = 0;
|
||||
if (cl->gcm_enabled)
|
||||
{
|
||||
gcm_op_writer_t::init_ctx(msgr, cl);
|
||||
}
|
||||
}
|
||||
|
||||
bool write(uint8_t *src, size_t src_len, int flags) override
|
||||
{
|
||||
if (from >= src_len)
|
||||
@@ -365,17 +478,56 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (flags & WR_GCM)
|
||||
if (flags & WR_TLS)
|
||||
{
|
||||
if (cl->gcm_enabled)
|
||||
if (cl->ssl_cli)
|
||||
{
|
||||
if (!cl->ssl_handshake_done)
|
||||
{
|
||||
if (!msgr->ssl_do_handshake(cl))
|
||||
return false;
|
||||
}
|
||||
if (cl->ssl_handshake_done)
|
||||
{
|
||||
if (!ssl_op_writer_t::write_to_ssl(cl, src, src_len, flags, from))
|
||||
return false;
|
||||
}
|
||||
// Copy data to client's temporary SSL output buffer
|
||||
copy_ssl();
|
||||
if (from < src_len)
|
||||
return false;
|
||||
from = 0;
|
||||
return true;
|
||||
}
|
||||
else if (cl->enc_ctx)
|
||||
{
|
||||
// Encrypt data to client's temporary output buffer (all at once)
|
||||
if (!cl->write_op_pos)
|
||||
{
|
||||
if (have_batch)
|
||||
{
|
||||
(*(uint32_t*)(cl->ssl_out_buf+batch_size_offset))++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl_extend_buf(4);
|
||||
have_batch = true;
|
||||
batch_size_offset = cl->ssl_out_buf_size;
|
||||
(*(uint32_t*)(cl->ssl_out_buf+batch_size_offset)) = 1;
|
||||
send_out_buf(4);
|
||||
cl->enc_batch = true;
|
||||
uint8_t iv[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
int r = EVP_EncryptInit_ex(cl->enc_ctx, NULL, NULL, (uint8_t*)msgr->test_osd_aes_key.data(), iv);
|
||||
if (r != 1)
|
||||
{
|
||||
fprintf(stderr, "EncryptInit error: ");
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t n = src_len-from;
|
||||
ssl_extend_buf(cl, n);
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
int r = isal_aes_gcm_enc_256_update(&cl->my_key_isal, cl->enc_ctx, cl->ssl_out_buf+cl->ssl_out_buf_size, src+from, n);
|
||||
assert(!r);
|
||||
#else
|
||||
ssl_extend_buf(n);
|
||||
int actual_out;
|
||||
if (EVP_EncryptUpdate(cl->enc_ctx, cl->ssl_out_buf+cl->ssl_out_buf_size, &actual_out, src+from, n) != 1)
|
||||
{
|
||||
@@ -384,11 +536,10 @@ public:
|
||||
abort();
|
||||
}
|
||||
assert(actual_out == n);
|
||||
#endif
|
||||
if (cl->write_csum_state && !(flags & WR_NO_CSUM))
|
||||
XXH3_64bits_update(cl->write_csum_state, src+from, n);
|
||||
send_out_buf(cl, n);
|
||||
done += n;
|
||||
send_out_buf(n);
|
||||
batch_bytes += n;
|
||||
cl->write_op_pos += n;
|
||||
from += n;
|
||||
if (from < src_len)
|
||||
@@ -412,19 +563,20 @@ public:
|
||||
assert(enc_size > 0);
|
||||
cl->write_op->enc_buf = (uint8_t*)malloc_or_die(enc_size);
|
||||
cl->send_list.push_back((iovec){ .iov_base = cl->write_op->enc_buf, .iov_len = enc_size });
|
||||
done += enc_size;
|
||||
}
|
||||
assert(enc_size > 0);
|
||||
size_t old_from = from;
|
||||
msgr->op_encrypted_copy_buf(cl, cl->write_op->enc_buf, enc_size, src, src_len, from, done_enc);
|
||||
assert(from == src_len);
|
||||
batch_bytes += src_len-old_from;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cl->write_csum_state && !(flags & WR_NO_CSUM))
|
||||
XXH3_64bits_update(cl->write_csum_state, src+from, src_len-from);
|
||||
cl->send_list.push_back((iovec){ src+from, src_len-from });
|
||||
done += src_len-from;
|
||||
cl->write_op_pos += src_len-from;
|
||||
batch_bytes += src_len-from;
|
||||
}
|
||||
from = 0;
|
||||
return true;
|
||||
@@ -432,24 +584,31 @@ public:
|
||||
|
||||
bool finish() override
|
||||
{
|
||||
if (cl->enc_ctx)
|
||||
if (cl->ssl_cli)
|
||||
{
|
||||
if (cl->send_list.size() >= IOV_MAX)
|
||||
return false;
|
||||
copy_ssl();
|
||||
}
|
||||
else if (cl->enc_ctx)
|
||||
{
|
||||
if (cl->send_list.size() >= IOV_MAX)
|
||||
return false;
|
||||
if (batch_bytes < 131072 && have_batch && cl->write_ops.size())
|
||||
{
|
||||
// More operations may fit, so don't finish the batch yet
|
||||
return true;
|
||||
}
|
||||
// Tag is 16 bytes
|
||||
ssl_extend_buf(cl, 16);
|
||||
gcm_op_writer_t::write_tag_to(msgr, cl, cl->ssl_out_buf+cl->ssl_out_buf_size);
|
||||
send_out_buf(cl, 16);
|
||||
done += 16;
|
||||
gcm_op_writer_t::free_ctx(msgr, cl);
|
||||
ssl_extend_buf(16);
|
||||
gcm_op_writer_t::write_tag_to(cl, cl->ssl_out_buf+cl->ssl_out_buf_size);
|
||||
send_out_buf(16);
|
||||
cl->enc_batch = false;
|
||||
have_batch = false;
|
||||
batch_bytes = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t get_done()
|
||||
{
|
||||
return done;
|
||||
}
|
||||
};
|
||||
|
||||
void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
||||
@@ -487,7 +646,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
||||
}
|
||||
cl->write_ops.push_back(cur_op);
|
||||
#ifdef WITH_RDMA
|
||||
if (cl->peer_state == PEER_RDMA || cl->peer_state == PEER_RDMA_CONNECTING_OUT)
|
||||
if (cl->peer_state == PEER_RDMA)
|
||||
{
|
||||
try_send_rdma(cl);
|
||||
return;
|
||||
@@ -561,6 +720,30 @@ void osd_messenger_t::measure_exec(osd_op_t *cur_op)
|
||||
}
|
||||
}
|
||||
|
||||
bool osd_messenger_t::ssl_do_handshake(osd_client_t *cl)
|
||||
{
|
||||
if (cl->ssl_handshake_done)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
int r = SSL_do_handshake(cl->ssl_cli);
|
||||
if (r > 0)
|
||||
{
|
||||
cl->ssl_handshake_done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = SSL_get_error(cl->ssl_cli, r);
|
||||
if (r != 0 && r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
fprintf(stderr, "Client %ju TLS handshake error: %s, stopping client\n", cl->client_id, ERR_error_string(ERR_get_error(), NULL));
|
||||
cl->io_error = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool osd_messenger_t::try_send(osd_client_t *cl)
|
||||
{
|
||||
if (cl->peer_state == PEER_STOPPED || cl->peer_fd < 0)
|
||||
@@ -572,32 +755,32 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
|
||||
return false;
|
||||
}
|
||||
assert(cl->peer_state != PEER_RDMA);
|
||||
if (cl->hs)
|
||||
get_op_writer_t wr(this, cl);
|
||||
while ((cl->write_op || cl->write_ops.size()) && cl->send_list.size() < IOV_MAX)
|
||||
{
|
||||
// Send handshake message
|
||||
if (cl->hs->get_out().size())
|
||||
if (!cl->write_op)
|
||||
{
|
||||
get_op_writer_t::ssl_extend_buf(cl, cl->hs->get_out().size());
|
||||
memcpy(cl->ssl_out_buf+cl->ssl_out_buf_size, cl->hs->get_out().data(), cl->hs->get_out().size());
|
||||
get_op_writer_t::send_out_buf(cl, cl->hs->get_out().size());
|
||||
cl->hs->get_out().clear();
|
||||
next_write_op(cl);
|
||||
wr.reset();
|
||||
}
|
||||
if (!cl->hs->get_out().size() && cl->hs->done())
|
||||
osd_op_t *op = cl->write_op;
|
||||
if (!op_write_to(cl, wr))
|
||||
{
|
||||
delete cl->hs;
|
||||
cl->hs = NULL;
|
||||
goto copy_ops;
|
||||
if (cl->io_error)
|
||||
{
|
||||
stop_client(cl->client_id);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!cl->write_op && op->op_type == OSD_OP_IN)
|
||||
{
|
||||
cl->send_free_ops.push_back(op);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!cl->send_list.size() && cl->ssl_cli)
|
||||
{
|
||||
copy_ops:
|
||||
copy_ops_to_with<get_op_writer_t>(cl, NULL, 0);
|
||||
}
|
||||
if (cl->io_error)
|
||||
{
|
||||
stop_client(cl->client_id);
|
||||
return true;
|
||||
wr.flush_ssl();
|
||||
}
|
||||
if (!cl->send_list.size())
|
||||
{
|
||||
@@ -663,26 +846,8 @@ copy_ops:
|
||||
|
||||
size_t osd_messenger_t::copy_ops_to(osd_client_t *cl, uint8_t *dst, size_t dst_len)
|
||||
{
|
||||
if (cl->gcm_enabled)
|
||||
if (cl->enc_ctx)
|
||||
{
|
||||
if (cl->hs)
|
||||
{
|
||||
// Send handshake message
|
||||
size_t n = 0;
|
||||
if (cl->hs->get_out().size())
|
||||
{
|
||||
n = cl->hs->get_out().size() < dst_len ? cl->hs->get_out().size() : dst_len;
|
||||
memcpy(dst, cl->hs->get_out().data(), n);
|
||||
cl->hs->get_out().erase(cl->hs->get_out().begin(), cl->hs->get_out().begin() + n);
|
||||
}
|
||||
if (!cl->hs->get_out().size() && cl->hs->done())
|
||||
{
|
||||
delete cl->hs;
|
||||
cl->hs = NULL;
|
||||
n += copy_ops_to_with<gcm_op_writer_t>(cl, dst+n, dst_len-n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
return copy_ops_to_with<gcm_op_writer_t>(cl, dst, dst_len);
|
||||
}
|
||||
return copy_ops_to_with<copy_op_writer_t>(cl, dst, dst_len);
|
||||
@@ -696,8 +861,8 @@ size_t osd_messenger_t::copy_ops_to_with(osd_client_t *cl, uint8_t *dst, size_t
|
||||
{
|
||||
if (!cl->write_op)
|
||||
{
|
||||
wr.reset();
|
||||
next_write_op(cl);
|
||||
wr.reset();
|
||||
}
|
||||
osd_op_t *op = cl->write_op;
|
||||
if (!op_write_to(cl, wr))
|
||||
@@ -712,6 +877,10 @@ size_t osd_messenger_t::copy_ops_to_with(osd_client_t *cl, uint8_t *dst, size_t
|
||||
cl->send_free_ops.push_back(op);
|
||||
}
|
||||
}
|
||||
/*FIXME if (!wr.get_done() && cl->ssl_cli)
|
||||
{
|
||||
wr.flush_ssl();
|
||||
}*/
|
||||
return wr.get_done();
|
||||
}
|
||||
|
||||
@@ -723,10 +892,7 @@ void osd_messenger_t::next_write_op(osd_client_t *cl)
|
||||
{
|
||||
if (!cl->write_csum_state)
|
||||
cl->write_csum_state = XXH3_createState();
|
||||
if (cl->my_key.size() == AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE + XXH_SECRET_DEFAULT_SIZE)
|
||||
XXH3_64bits_reset_withSecret(cl->write_csum_state, cl->my_key.data() + AES_256_GCM_KEY_SIZE + AES_256_GCM_IV_SIZE, XXH_SECRET_DEFAULT_SIZE);
|
||||
else
|
||||
XXH3_64bits_reset(cl->write_csum_state);
|
||||
XXH3_64bits_reset(cl->write_csum_state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -826,20 +992,14 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t
|
||||
cl->proto_csum_status = cl->proto_csum_status & (~MSGR_CSUM_NEG);
|
||||
}
|
||||
#ifdef WITH_RDMA
|
||||
if (cl->rdma_conn && cl->peer_state == PEER_RDMA_CONNECTING_IN && !cl->write_op && !cl->write_ops.size())
|
||||
if (cl->rdma_conn && !cl->write_op && !cl->write_ops.size() && cl->peer_state == PEER_RDMA_CONNECTING)
|
||||
{
|
||||
if (cl->rdma_close_tcp)
|
||||
// FIXME: Ignore pings during RDMA state transition
|
||||
if (log_level > 0)
|
||||
{
|
||||
cl->peer_state = PEER_RDMA_CONNECTING_OUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log_level > 0)
|
||||
{
|
||||
fprintf(stderr, "Successfully connected with client %ju using RDMA\n", cl->client_id);
|
||||
}
|
||||
cl->peer_state = PEER_RDMA;
|
||||
fprintf(stderr, "Successfully connected with client %ju using RDMA\n", cl->client_id);
|
||||
}
|
||||
cl->peer_state = PEER_RDMA;
|
||||
// Add the initial receive request
|
||||
init_recv_rdma(cl);
|
||||
}
|
||||
@@ -877,7 +1037,7 @@ bool osd_messenger_t::op_write_to(osd_client_t *cl, msgr_op_writer_t & wr)
|
||||
osd_op_t *op = cl->write_op;
|
||||
// Header
|
||||
if (!wr.write((op->op_type == OSD_OP_IN ? op->reply.buf : op->req.buf), OSD_PACKET_SIZE,
|
||||
WR_GCM | (cl->proto_csum_status == MSGR_CSUM_PAYLOAD ? WR_NO_CSUM : 0)))
|
||||
WR_TLS | (cl->proto_csum_status == MSGR_CSUM_PAYLOAD ? WR_NO_CSUM : 0)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -886,17 +1046,17 @@ bool osd_messenger_t::op_write_to(osd_client_t *cl, msgr_op_writer_t & wr)
|
||||
{
|
||||
if (op->req.hdr.opcode == OSD_OP_SEC_READ && op->reply.sec_rw.attr_len > 0)
|
||||
{
|
||||
if (!wr.write((uint8_t*)op->bitmap, op->reply.sec_rw.attr_len, WR_GCM))
|
||||
if (!wr.write((uint8_t*)op->bitmap, op->reply.sec_rw.attr_len, WR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if (op->req.hdr.opcode == OSD_OP_SEC_READ_BMP && op->reply.hdr.retval > 0)
|
||||
{
|
||||
if (!wr.write((uint8_t*)op->buf, (size_t)op->reply.hdr.retval, WR_GCM))
|
||||
if (!wr.write((uint8_t*)op->buf, (size_t)op->reply.hdr.retval, WR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if (op->req.hdr.opcode == OSD_OP_READ && op->reply.rw.bitmap_len > 0)
|
||||
{
|
||||
if (!wr.write((uint8_t*)op->bitmap, op->reply.rw.bitmap_len, WR_GCM))
|
||||
if (!wr.write((uint8_t*)op->bitmap, op->reply.rw.bitmap_len, WR_TLS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -905,12 +1065,12 @@ bool osd_messenger_t::op_write_to(osd_client_t *cl, msgr_op_writer_t & wr)
|
||||
if ((op->req.hdr.opcode == OSD_OP_SEC_WRITE || op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE) &&
|
||||
op->req.sec_rw.attr_len > 0)
|
||||
{
|
||||
if (!wr.write((uint8_t*)op->bitmap, op->req.sec_rw.attr_len, WR_GCM))
|
||||
if (!wr.write((uint8_t*)op->bitmap, op->req.sec_rw.attr_len, WR_TLS))
|
||||
return false;
|
||||
}
|
||||
else if (op->req.hdr.opcode == OSD_OP_SEC_READ_BMP && op->req.sec_read_bmp.len > 0)
|
||||
{
|
||||
if (!wr.write((uint8_t*)op->buf, (size_t)op->req.sec_read_bmp.len, WR_GCM))
|
||||
if (!wr.write((uint8_t*)op->buf, (size_t)op->req.sec_read_bmp.len, WR_TLS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -920,7 +1080,7 @@ bool osd_messenger_t::op_write_to(osd_client_t *cl, msgr_op_writer_t & wr)
|
||||
for (int i = 0; i < cl->write_op->iov.count; i++)
|
||||
{
|
||||
auto & iov = cl->write_op->iov.buf[i];
|
||||
if (!wr.write((uint8_t*)iov.iov_base, iov.iov_len, WR_GCM))
|
||||
if (!wr.write((uint8_t*)iov.iov_base, iov.iov_len, WR_TLS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -937,7 +1097,7 @@ bool osd_messenger_t::op_write_to(osd_client_t *cl, msgr_op_writer_t & wr)
|
||||
cl->proto_csum_status == MSGR_CSUM_PAYLOAD && cl->write_op_pos > OSD_PACKET_SIZE)
|
||||
{
|
||||
cl->write_op->csum = XXH3_64bits_digest(cl->write_csum_state);
|
||||
if (!wr.write((uint8_t*)&cl->write_op->csum, 8, WR_GCM|WR_NO_CSUM))
|
||||
if (!wr.write((uint8_t*)&cl->write_op->csum, 8, WR_TLS|WR_NO_CSUM))
|
||||
return false;
|
||||
}
|
||||
if (!wr.finish())
|
||||
|
||||
+30
-29
@@ -9,8 +9,12 @@
|
||||
#ifdef WITH_RDMA
|
||||
#include "msgr_rdma.h"
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
void osd_client_t::cancel_ops()
|
||||
{
|
||||
@@ -82,21 +86,21 @@ void osd_messenger_t::stop_client(uint64_t client_id, bool force_delete)
|
||||
fprintf(stderr, "[OSD %ju] Stopping client %ju (regular client)\n", osd_num, client_id);
|
||||
}
|
||||
}
|
||||
if (cl->xts_enc_ctx)
|
||||
if (cl->encrypt_ctx)
|
||||
{
|
||||
if (encrypt_xts_pool.size() > max_cipher_pool_size)
|
||||
destroy_aes_xts_encrypt(cl->xts_enc_ctx);
|
||||
if (encrypt_ctx_pool.size() > max_aes_xts_pool_size)
|
||||
destroy_aes_xts_encrypt(cl->encrypt_ctx);
|
||||
else
|
||||
encrypt_xts_pool.push_back(cl->xts_enc_ctx);
|
||||
cl->xts_enc_ctx = NULL;
|
||||
encrypt_ctx_pool.push_back(cl->encrypt_ctx);
|
||||
cl->encrypt_ctx = NULL;
|
||||
}
|
||||
if (cl->xts_dec_ctx)
|
||||
if (cl->decrypt_ctx)
|
||||
{
|
||||
if (decrypt_xts_pool.size() > max_cipher_pool_size)
|
||||
destroy_aes_xts_decrypt(cl->xts_dec_ctx);
|
||||
if (decrypt_ctx_pool.size() > max_aes_xts_pool_size)
|
||||
destroy_aes_xts_decrypt(cl->decrypt_ctx);
|
||||
else
|
||||
decrypt_xts_pool.push_back(cl->xts_dec_ctx);
|
||||
cl->xts_dec_ctx = NULL;
|
||||
decrypt_ctx_pool.push_back(cl->decrypt_ctx);
|
||||
cl->decrypt_ctx = NULL;
|
||||
}
|
||||
// First set state to STOPPED so another stop_client() call doesn't try to free it again
|
||||
cl->refs++;
|
||||
@@ -206,6 +210,12 @@ osd_client_t::~osd_client_t()
|
||||
read_op->cancel();
|
||||
read_op = NULL;
|
||||
}
|
||||
while (unverified_ops.size())
|
||||
{
|
||||
auto op = unverified_ops.back();
|
||||
unverified_ops.pop_back();
|
||||
op->cancel();
|
||||
}
|
||||
// Cancel outbound ops
|
||||
cancel_ops();
|
||||
for (osd_op_t *op: send_free_ops)
|
||||
@@ -244,37 +254,28 @@ osd_client_t::~osd_client_t()
|
||||
XXH3_freeState(write_csum_state);
|
||||
write_csum_state = NULL;
|
||||
}
|
||||
#ifdef WITH_OPENSSL
|
||||
if (enc_ctx)
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
free(enc_ctx);
|
||||
#else
|
||||
EVP_CIPHER_CTX_free(enc_ctx);
|
||||
#endif
|
||||
enc_ctx = NULL;
|
||||
}
|
||||
if (dec_ctx)
|
||||
{
|
||||
#ifdef WITH_ISAL_CRYPTO
|
||||
free(dec_ctx);
|
||||
#else
|
||||
EVP_CIPHER_CTX_free(dec_ctx);
|
||||
#endif
|
||||
dec_ctx = NULL;
|
||||
}
|
||||
if (ssl_cli)
|
||||
{
|
||||
SSL_free(ssl_cli);
|
||||
ssl_cli = NULL;
|
||||
write_to_ssl = NULL;
|
||||
read_from_ssl = NULL;
|
||||
}
|
||||
if (ssl_out_buf)
|
||||
{
|
||||
free(ssl_out_buf);
|
||||
ssl_out_buf = NULL;
|
||||
}
|
||||
if (hs)
|
||||
{
|
||||
delete hs;
|
||||
hs = NULL;
|
||||
}
|
||||
if (hs_result.peer_cert)
|
||||
{
|
||||
X509_free(hs_result.peer_cert);
|
||||
hs_result.peer_cert = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
|
||||
Name: Vitastor
|
||||
Description: Vitastor client library
|
||||
Version: 3.0.10
|
||||
Version: 3.0.9
|
||||
Libs: -L${libdir} -lvitastor_client
|
||||
Cflags: -I${includedir}
|
||||
|
||||
|
||||
+3
-3
@@ -259,9 +259,9 @@ static const char* help_text =
|
||||
" Start HTTP server able to handle CLI commands over a REST API. Options:\n"
|
||||
" --bind_address ADDR Specify server IP address or addresses, separated by space. Default is 127.0.0.1.\n"
|
||||
" --port 8080 Specify server port.\n"
|
||||
" --server_cert FILE Path to server TLS certificate file (PEM format).\n"
|
||||
" --server_key FILE Path to server TLS private key file.\n"
|
||||
" --client_ca FILE Path to file with TLS CA certificates used to validate client connections.\n"
|
||||
" --ssl_cert FILE Path to server SSL certificate file (PEM format).\n"
|
||||
" --ssl_key FILE Path to server SSL private key file.\n"
|
||||
" --ssl_ca FILE Path to file with SSL CA certificates used to validate client connections.\n"
|
||||
"\n"
|
||||
"Use vitastor-cli --help <command> for command details or vitastor-cli --help --all for all details.\n"
|
||||
"\n"
|
||||
|
||||
+7
-2
@@ -27,7 +27,12 @@ struct cli_result_t
|
||||
json11::Json data;
|
||||
};
|
||||
|
||||
struct user_info_t;
|
||||
struct cli_user_t
|
||||
{
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::set<std::string> groups;
|
||||
};
|
||||
|
||||
class cli_tool_t
|
||||
{
|
||||
@@ -40,7 +45,7 @@ public:
|
||||
bool is_command_line = false;
|
||||
bool color = false;
|
||||
|
||||
std::shared_ptr<user_info_t> user; // for http mode
|
||||
std::unique_ptr<cli_user_t> user; // for http mode
|
||||
|
||||
ring_loop_t *ringloop = NULL;
|
||||
epoll_manager_t *epmgr = NULL;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
bool cli_tool_t::check_image_perm(const inode_config_t & cfg, bool write)
|
||||
{
|
||||
return !user ||
|
||||
user->type == user_type_t::ADMIN ||
|
||||
user->type == "admin" ||
|
||||
user->name == cfg.owner ||
|
||||
cfg.owner_group != "" && user->groups.find(cfg.owner_group) != user->groups.end() ||
|
||||
!write && cfg.reader_group != "" && user->groups.find(cfg.reader_group) != user->groups.end();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include "cli.h"
|
||||
@@ -121,7 +123,7 @@ struct image_creator_t
|
||||
|
||||
bool check_pool_permission()
|
||||
{
|
||||
if (!parent->user || parent->user->type == user_type_t::ADMIN)
|
||||
if (!parent->user || parent->user->type == "admin")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -626,12 +628,14 @@ std::function<bool(cli_result_t &)> cli_tool_t::start_create(json11::Json cfg)
|
||||
if (!cfg["enc_key"].is_null())
|
||||
{
|
||||
image_creator->set_key = true;
|
||||
#ifdef WITH_OPENSSL
|
||||
if (image_creator->enc_key == "random")
|
||||
{
|
||||
uint8_t newkey[64];
|
||||
RAND_bytes(newkey, 64);
|
||||
image_creator->enc_key = tohexstr(newkey, 64);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
image_creator->enc_key = cfg["enc_key"].string_value();
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ resume_1:
|
||||
inode_t inode_num = INODE_WITH_POOL(pool_id, only_inode_num);
|
||||
uint64_t used_size = kv.value["raw_used"].uint64_value();
|
||||
auto stat_it = stats.find(inode_num);
|
||||
if (parent->user && parent->user->type != user_type_t::ADMIN && stat_it == stats.end())
|
||||
if (parent->user && parent->user->type != "admin" && stat_it == stats.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
+25
-33
@@ -76,7 +76,6 @@ struct cli_serve_t
|
||||
int port = 0;
|
||||
int listen_backlog = 0;
|
||||
bool ssl = false;
|
||||
bool use_auth = false;
|
||||
std::vector<int> listen_fds;
|
||||
http_context_t *http_ctx = NULL;
|
||||
std::set<cli_serve_conn_t*> connections;
|
||||
@@ -112,34 +111,19 @@ struct cli_serve_t
|
||||
listen_backlog = options["listen_backlog"].uint64_value();
|
||||
if (!listen_backlog)
|
||||
listen_backlog = 128;
|
||||
ssl = json_is_true(options["ssl"]);
|
||||
if (ssl)
|
||||
{
|
||||
std::string tls_cert = (parent->cli->config.find("server_cert") != parent->cli->config.end()
|
||||
? parent->cli->config["server_cert"].string_value() : "");
|
||||
std::string tls_key = (parent->cli->config.find("server_key") != parent->cli->config.end()
|
||||
? parent->cli->config["server_key"].string_value() : "");
|
||||
std::string tls_ca = (parent->cli->config.find("client_ca") != parent->cli->config.end()
|
||||
? parent->cli->config["client_ca"].string_value() : "");
|
||||
if (tls_cert != "" || tls_key != "" || tls_ca != "")
|
||||
std::string ssl_cert = options["ssl_cert"].string_value();
|
||||
std::string ssl_key = options["ssl_key"].string_value();
|
||||
std::string ssl_ca = options["ssl_ca"].string_value();
|
||||
std::string error;
|
||||
http_ctx = http_context_init(parent->epmgr->tfd, ssl_cert, ssl_key, ssl_ca, ssl_ca != "", error);
|
||||
if (error != "")
|
||||
{
|
||||
ssl = true;
|
||||
if (tls_cert == "" || tls_key == "")
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "server_cert and server_key are required to serve HTTPS" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
// use_auth is enabled by default when client_ca is set
|
||||
use_auth = (parent->cli->config["use_auth"].is_null()
|
||||
? (tls_ca != "")
|
||||
: json_is_true(parent->cli->config["use_auth"]));
|
||||
std::string error;
|
||||
http_ctx = http_context_init(parent->epmgr->tfd, tls_cert, tls_key, tls_ca, tls_ca != "", error);
|
||||
if (error != "")
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = error };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
result = (cli_result_t){ .err = EINVAL, .text = error };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto & bind_address: bind_addresses)
|
||||
@@ -360,9 +344,17 @@ struct cli_serve_t
|
||||
conn->request_path = std::move(req_line[1]);
|
||||
conn->request_body = std::move(msg->body);
|
||||
conn->response_type = "";
|
||||
if (use_auth)
|
||||
if (parent->cli->st_cli.use_auth)
|
||||
{
|
||||
conn->p->user = parent->cli->st_cli.get_user(msg->headers["_tls_common_name"]);
|
||||
auto user = std::make_unique<cli_user_t>();
|
||||
user->name = msg->headers["_tls_common_name"];
|
||||
auto user_it = parent->cli->st_cli.user_info.find(user->name);
|
||||
auto userinfo = user_it == parent->cli->st_cli.user_info.end() ? user_it->second : json11::Json();
|
||||
user->type = user->name == "root" ? "admin" : userinfo["type"].string_value();
|
||||
for (auto & gr: userinfo["groups"].array_items())
|
||||
{
|
||||
user->groups.insert(gr.string_value());
|
||||
}
|
||||
}
|
||||
auto ctype = msg->headers["content-type"];
|
||||
if (conn->request_method != "GET" && conn->request_method != "POST")
|
||||
@@ -391,10 +383,10 @@ struct cli_serve_t
|
||||
{
|
||||
conn->response_type = "application/json";
|
||||
conn->result = { .text = openapi_description };
|
||||
if (use_auth)
|
||||
if (parent->cli->st_cli.use_auth)
|
||||
{
|
||||
// Filter available paths by privileges
|
||||
if (conn->p->user->type == user_type_t::CLIENT)
|
||||
if (conn->p->user->type == "client")
|
||||
{
|
||||
std::string error;
|
||||
auto openapi = json11::Json::parse(openapi_description, error).object_items();
|
||||
@@ -411,7 +403,7 @@ struct cli_serve_t
|
||||
conn->response_type = "application/json";
|
||||
conn->result = { .text = json11::Json(openapi).dump() };
|
||||
}
|
||||
else if (conn->p->user->type != user_type_t::ADMIN)
|
||||
else if (conn->p->user->type != "admin")
|
||||
{
|
||||
conn->response_type = "";
|
||||
conn->result = { .err = EACCES, .text = "Access denied" };
|
||||
@@ -426,7 +418,7 @@ struct cli_serve_t
|
||||
{
|
||||
conn->result = { .err = ENOSYS, .text = "method /"+uri[0]+" only allows POST requests" };
|
||||
}
|
||||
else if (use_auth && conn->p->user->type == user_type_t::CLIENT && !cmd_it->second.allow_client)
|
||||
else if (parent->cli->st_cli.use_auth && conn->p->user->type == "client" && !cmd_it->second.allow_client)
|
||||
{
|
||||
conn->result = { .err = EACCES, .text = "Access denied" };
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@ static const char* help_text =
|
||||
" --logfile <FILE> log to the specified file\n"
|
||||
" --enforce 1 enforce permissions at the server side (default is disabled)\n"
|
||||
" --foreground 1 stay in foreground, do not daemonize\n"
|
||||
" --trace trace all NFS requests\n"
|
||||
"\n"
|
||||
"NFS proxy is stateless if you use immediate_commit=all in your cluster and if\n"
|
||||
"you do not use client_enable_writeback=true, so you can freely use multiple\n"
|
||||
@@ -159,7 +158,7 @@ json11::Json::object nfs_proxy_t::parse_args(int narg, const char *args[])
|
||||
{
|
||||
const char *opt = args[i]+2;
|
||||
cfg[str_replace(opt, "-", "_")] = !strcmp(opt, "json") || !strcmp(opt, "block") ||
|
||||
!strcmp(opt, "dry-run") || !strcmp(opt, "recalc-stats") || !strcmp(opt, "trace") ||
|
||||
!strcmp(opt, "dry-run") || !strcmp(opt, "recalc-stats") ||
|
||||
!strcmp(opt, "include-empty") || !strcmp(opt, "no-rm") || i == narg-1 ? "1" : args[++i];
|
||||
}
|
||||
else
|
||||
|
||||
+1
-14
@@ -14,7 +14,6 @@
|
||||
#include "http_client.h"
|
||||
#include "str_util.h"
|
||||
#include "json_util.h"
|
||||
#include "openssl_util.h"
|
||||
|
||||
osd_t::osd_t(const json11::Json & config, ring_loop_t *ringloop)
|
||||
{
|
||||
@@ -68,11 +67,6 @@ osd_t::osd_t(const json11::Json & config, ring_loop_t *ringloop)
|
||||
msgr.repeer_pgs = [this](osd_num_t peer_osd) { repeer_pgs(peer_osd); };
|
||||
msgr.break_pg_locks = [this](osd_num_t peer_osd) { break_pg_locks(peer_osd); };
|
||||
msgr.check_config_hook = [this](osd_client_t *cl, json11::Json conf) { return check_peer_config(cl, conf); };
|
||||
msgr.handshake_hook = [this](osd_client_t *cl)
|
||||
{
|
||||
if (!cl->hs_result.peer_is_osd)
|
||||
cl->user_info = st_cli.get_user(openssl_get_cn(cl->hs_result.peer_cert));
|
||||
};
|
||||
msgr.init();
|
||||
|
||||
init_cluster();
|
||||
@@ -176,13 +170,9 @@ void osd_t::parse_config(bool init)
|
||||
bs->parse_config(bs_cfg);
|
||||
}
|
||||
st_cli.parse_config(config);
|
||||
msgr.parse_config(config, init);
|
||||
msgr.parse_config(config);
|
||||
if (init)
|
||||
{
|
||||
// use_auth is enabled by default when encryption is enabled
|
||||
use_auth = (config["use_auth"].is_null()
|
||||
? msgr.is_encryption_enabled()
|
||||
: json_is_true(config["use_auth"]));
|
||||
// Vital Blockstore parameters
|
||||
bs_block_size = config["block_size"].uint64_value();
|
||||
if (!bs_block_size)
|
||||
@@ -191,9 +181,6 @@ void osd_t::parse_config(bool init)
|
||||
if (!bs_bitmap_granularity)
|
||||
bs_bitmap_granularity = DEFAULT_BITMAP_GRANULARITY;
|
||||
clean_entry_bitmap_size = bs_block_size / bs_bitmap_granularity / 8;
|
||||
msgr.bs_block_size = bs_block_size;
|
||||
msgr.clean_entry_bitmap_size = clean_entry_bitmap_size;
|
||||
msgr.max_write_request_size = MAX_DATA_BLOCK_SIZE; // will be changed after pool config
|
||||
// immediate_commit
|
||||
if (config["immediate_commit"] == "all")
|
||||
immediate_commit = IMMEDIATE_ALL;
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
#define OSD_RECOVERING 0x10
|
||||
#define OSD_SCRUBBING 0x20
|
||||
|
||||
#define SELF_CLIENT 0
|
||||
|
||||
#define MAX_AUTOSYNC_INTERVAL 3600
|
||||
#define DEFAULT_AUTOSYNC_INTERVAL 5
|
||||
#define DEFAULT_AUTOSYNC_WRITES 128
|
||||
@@ -157,7 +155,6 @@ class osd_t
|
||||
|
||||
etcd_state_client_t st_cli;
|
||||
osd_messenger_t msgr;
|
||||
bool use_auth = false;
|
||||
int etcd_failed_attempts = 0;
|
||||
std::string etcd_lease_id;
|
||||
json11::Json self_state;
|
||||
|
||||
@@ -428,21 +428,6 @@ void osd_t::on_change_pool_config_hook()
|
||||
{
|
||||
apply_pg_locks_localize_only();
|
||||
}
|
||||
msgr.max_write_request_size = 0;
|
||||
for (auto & pc: st_cli.pool_config)
|
||||
{
|
||||
auto & pool_cfg = pc.second;
|
||||
uint32_t pg_data_size = (pool_cfg.scheme == POOL_SCHEME_REPLICATED ? 1 : pool_cfg.pg_size-pool_cfg.parity_chunks);
|
||||
uint32_t pg_block_size = pool_cfg.data_block_size * pg_data_size;
|
||||
if (msgr.max_write_request_size < pg_block_size)
|
||||
{
|
||||
msgr.max_write_request_size = pg_block_size;
|
||||
}
|
||||
}
|
||||
if (!msgr.max_write_request_size)
|
||||
{
|
||||
msgr.max_write_request_size = MAX_DATA_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void osd_t::apply_pg_locks_localize_only()
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "osd.h"
|
||||
|
||||
#define FLUSH_BATCH 512
|
||||
|
||||
static_assert(FLUSH_BATCH <= MAX_SIMPLE_PAYLOAD_SIZE / sizeof(obj_ver_id));
|
||||
#define SELF_CLIENT 0
|
||||
|
||||
void osd_t::submit_pg_flush_ops(pg_t & pg)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "str_util.h"
|
||||
#include "osd.h"
|
||||
|
||||
#define SELF_CLIENT 0
|
||||
|
||||
// Peering loop
|
||||
void osd_t::handle_peers()
|
||||
{
|
||||
|
||||
@@ -71,21 +71,6 @@ bool osd_t::prepare_primary_rw(osd_op_t *cur_op)
|
||||
finish_op(cur_op, -EINVAL);
|
||||
return false;
|
||||
}
|
||||
if (use_auth && cur_op->client_id != SELF_CLIENT)
|
||||
{
|
||||
osd_client_t *cl = msgr.clients.at(cur_op->client_id);
|
||||
if (cl->hs_result.peer_is_osd)
|
||||
{
|
||||
// OSDs are not allowed to execute "primary" operations
|
||||
finish_op(cur_op, -EPERM);
|
||||
return false;
|
||||
}
|
||||
if (!st_cli.check_image_perm(cl->user_info, cur_op->req.rw.inode, (cur_op->req.hdr.opcode != OSD_OP_READ)))
|
||||
{
|
||||
finish_op(cur_op, -EPERM);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int stripe_count = (cur_op->req.hdr.opcode == OSD_OP_SCRUB ? 0 :
|
||||
(pool_cfg.scheme == POOL_SCHEME_REPLICATED ? 1 : pg_it->second.pg_size));
|
||||
int chain_size = 0;
|
||||
|
||||
@@ -91,21 +91,6 @@ static void scan_lists(std::vector<unclean_list_t> & lists, uint64_t limit, desc
|
||||
// Describe unclean objects
|
||||
void osd_t::continue_primary_describe(osd_op_t *cur_op)
|
||||
{
|
||||
if (use_auth)
|
||||
{
|
||||
osd_client_t *cl = msgr.clients.at(cur_op->client_id);
|
||||
if (cl->hs_result.peer_is_osd)
|
||||
{
|
||||
// OSDs are not allowed to execute "primary" operations
|
||||
finish_op(cur_op, -EPERM);
|
||||
return;
|
||||
}
|
||||
if (cl->user_info->type != user_type_t::ADMIN)
|
||||
{
|
||||
finish_op(cur_op, -EPERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto & desc = cur_op->req.describe;
|
||||
if (!desc.object_state)
|
||||
desc.object_state = ~desc.object_state;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "osd_primary.h"
|
||||
|
||||
#define SELF_CLIENT 0
|
||||
|
||||
void osd_t::autosync()
|
||||
{
|
||||
if (immediate_commit != IMMEDIATE_ALL && !autosync_op)
|
||||
@@ -81,8 +83,6 @@ void osd_t::finish_op(osd_op_t *cur_op, int retval)
|
||||
rm_inflight(pg);
|
||||
}
|
||||
assert(!cur_op->op_data->subops);
|
||||
free(cur_op->op_data);
|
||||
cur_op->op_data = NULL;
|
||||
}
|
||||
cur_op->reply.hdr.magic = SECONDARY_OSD_REPLY_MAGIC;
|
||||
cur_op->reply.hdr.id = cur_op->req.hdr.id;
|
||||
|
||||
@@ -8,16 +8,6 @@ void osd_t::continue_primary_sync(osd_op_t *cur_op)
|
||||
{
|
||||
if (!cur_op->op_data)
|
||||
{
|
||||
if (use_auth && cur_op->client_id != SELF_CLIENT)
|
||||
{
|
||||
osd_client_t *cl = msgr.clients.at(cur_op->client_id);
|
||||
if (cl->hs_result.peer_is_osd)
|
||||
{
|
||||
// OSDs are not allowed to execute "primary" operations
|
||||
finish_op(cur_op, -EPERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cur_op->op_data = (osd_primary_op_data_t*)calloc_or_die(1, sizeof(osd_primary_op_data_t));
|
||||
}
|
||||
osd_primary_op_data_t *op_data = cur_op->op_data;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "osd_primary.h"
|
||||
|
||||
#define SELF_CLIENT 0
|
||||
|
||||
void osd_t::scrub_list(pool_pg_num_t pg_id, osd_num_t role_osd, object_id min_oid)
|
||||
{
|
||||
pool_id_t pool_id = pg_id.pool_id;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#include "json11/json11.hpp"
|
||||
|
||||
#include "osd.h"
|
||||
#ifdef WITH_RDMA
|
||||
#include "msgr_rdma.h"
|
||||
#endif
|
||||
#include "openssl_util.h"
|
||||
|
||||
#include "json11/json11.hpp"
|
||||
|
||||
void osd_t::secondary_op_callback(osd_op_t *op)
|
||||
{
|
||||
@@ -113,31 +112,6 @@ bool osd_t::sec_check_pg_lock(osd_num_t primary_osd, const object_id &oid, uint3
|
||||
|
||||
void osd_t::exec_secondary_real(osd_op_t *cur_op)
|
||||
{
|
||||
osd_client_t *cl = msgr.clients.at(cur_op->client_id);
|
||||
if (use_auth && !cl->hs_result.peer_is_osd)
|
||||
{
|
||||
// Non-OSDs are not allowed to execute "secondary" operations except LIST
|
||||
bool allowed = false;
|
||||
if (cur_op->req.hdr.opcode == OSD_OP_SEC_LIST)
|
||||
{
|
||||
if (cl->user_info->type == user_type_t::ADMIN)
|
||||
{
|
||||
// Admin is allowed to execute arbitrary listings
|
||||
allowed = true;
|
||||
}
|
||||
else if (cl->user_info->type == user_type_t::CLIENT && cur_op->req.sec_list.min_inode &&
|
||||
cur_op->req.sec_list.min_inode == cur_op->req.sec_list.max_inode)
|
||||
{
|
||||
// Clients are only allowed to execute listings for readable inodes
|
||||
allowed = st_cli.check_image_perm(cl->user_info, cur_op->req.sec_list.min_inode, false);
|
||||
}
|
||||
}
|
||||
if (!allowed)
|
||||
{
|
||||
finish_op(cur_op, -EPERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cur_op->req.hdr.opcode == OSD_OP_SEC_LIST &&
|
||||
(cur_op->req.sec_list.flags & OSD_LIST_PRIMARY))
|
||||
{
|
||||
@@ -154,6 +128,7 @@ void osd_t::exec_secondary_real(osd_op_t *cur_op)
|
||||
exec_sec_lock(cur_op);
|
||||
return;
|
||||
}
|
||||
osd_client_t *cl = msgr.clients.at(cur_op->client_id);
|
||||
cur_op->bs_op = new blockstore_op_t();
|
||||
cur_op->bs_op->callback = [this, cur_op](blockstore_op_t* bs_op) { secondary_op_callback(cur_op); };
|
||||
cur_op->bs_op->opcode = (cur_op->req.hdr.opcode == OSD_OP_SEC_READ ? BS_OP_READ
|
||||
@@ -373,13 +348,6 @@ void osd_t::exec_show_config(osd_op_t *cur_op)
|
||||
cl->read_op_id = cur_op->req.hdr.id + 1;
|
||||
}
|
||||
auto features = json11::Json::object{ { "pg_locks", true } };
|
||||
#ifdef WITH_RDMA
|
||||
if (msgr.is_rdma_enabled() && req_json["features"]["rdma_close_tcp"].bool_value())
|
||||
{
|
||||
cl->rdma_close_tcp = true;
|
||||
features["rdma_close_tcp"] = true;
|
||||
}
|
||||
#endif
|
||||
if (msgr.use_proto_checksums)
|
||||
{
|
||||
auto peer_csums = req_json["features"]["proto_checksums"].uint64_value();
|
||||
|
||||
@@ -26,7 +26,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
||||
cl->sent_ops[cur_op->req.hdr.id] = cur_op;
|
||||
}
|
||||
|
||||
void osd_messenger_t::parse_config(const json11::Json & config, bool init)
|
||||
void osd_messenger_t::parse_config(const json11::Json & config)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ int main(int narg, char *args[])
|
||||
msgr->repeer_pgs = [](osd_num_t) {};
|
||||
msgr->exec_op = [msgr](osd_op_t *op) { stub_exec_op(msgr, op); };
|
||||
json11::Json config = json11::Json::object { { "log_level", 1 } };
|
||||
msgr->parse_config(config, true);
|
||||
msgr->parse_config(config);
|
||||
// Accept new connections
|
||||
int listen_fd = create_and_bind_socket("0.0.0.0", 11203, 128, NULL);
|
||||
fcntl(listen_fd, F_SETFL, fcntl(listen_fd, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -554,6 +556,7 @@ void test_writeback_merge()
|
||||
printf("[ok] writeback merge test\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
void test_msgr_encrypt()
|
||||
{
|
||||
const size_t sz = 1048576;
|
||||
@@ -592,7 +595,7 @@ void test_msgr_encrypt()
|
||||
enc->start(key, 4096 * 114, 4096);
|
||||
in_pos = out_pos = 0;
|
||||
enc->update(src+4096, 4096, crypt2, 4095, in_pos, out_pos);
|
||||
assert(in_pos == 4095);
|
||||
assert(in_pos == 4096);
|
||||
assert(out_pos == 4095);
|
||||
enc->update(src+4096+in_pos, 4096-in_pos, crypt2+out_pos, 4096-out_pos, in_pos, out_pos);
|
||||
assert(in_pos == 4096);
|
||||
@@ -623,10 +626,10 @@ void test_msgr_encrypt()
|
||||
assert(in_pos == 3000);
|
||||
assert(out_pos == 0);
|
||||
dec->update(crypt+4096+3000, 3000, decrypt, 500, in_pos, out_pos);
|
||||
assert(in_pos == 4095);
|
||||
assert(in_pos == 4096);
|
||||
assert(out_pos == 500);
|
||||
dec->update(crypt+4096+in_pos, 6000-in_pos, decrypt+out_pos, 3000, in_pos, out_pos);
|
||||
assert(in_pos == 4095);
|
||||
assert(in_pos == 4096);
|
||||
assert(out_pos == 3500);
|
||||
dec->update(crypt+4096+in_pos, 6000-in_pos, decrypt+out_pos, 1000, in_pos, out_pos);
|
||||
assert(in_pos == 4096);
|
||||
@@ -635,10 +638,10 @@ void test_msgr_encrypt()
|
||||
assert(in_pos == 6000);
|
||||
assert(out_pos == 4096);
|
||||
dec->update(crypt+4096+in_pos, 8192-in_pos, decrypt+out_pos, 4500-out_pos, in_pos, out_pos);
|
||||
assert(in_pos == 8191);
|
||||
assert(in_pos == 8192);
|
||||
assert(out_pos == 4500);
|
||||
dec->update(crypt+4096+in_pos, 8192-in_pos, decrypt+out_pos, 7500-out_pos, in_pos, out_pos);
|
||||
assert(in_pos == 8191);
|
||||
assert(in_pos == 8192);
|
||||
assert(out_pos == 7500);
|
||||
dec->update(crypt+4096+in_pos, 8192-in_pos, decrypt+out_pos, 8192-out_pos, in_pos, out_pos);
|
||||
assert(in_pos == 8192);
|
||||
@@ -722,6 +725,7 @@ void test_msgr_decrypt_chain()
|
||||
free(src);
|
||||
printf("[ok] msgr aes-xts chained decrypt\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_vault()
|
||||
{
|
||||
@@ -790,8 +794,10 @@ int main(int narg, char *args[])
|
||||
test2();
|
||||
test_writeback();
|
||||
test_writeback_merge();
|
||||
#ifdef WITH_OPENSSL
|
||||
test_msgr_encrypt();
|
||||
test_msgr_decrypt_chain();
|
||||
#endif
|
||||
test_vault();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||
|
||||
#include "openssl_util.h"
|
||||
#include "str_util.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
X509 *openssl_load_cert(const std::string & file_or_pem)
|
||||
{
|
||||
std::string pem;
|
||||
BIO *bio = NULL;
|
||||
if (file_or_pem.substr(0, 5) != "-----")
|
||||
{
|
||||
pem = read_file(file_or_pem);
|
||||
bio = BIO_new_mem_buf(pem.data(), pem.size());
|
||||
}
|
||||
else
|
||||
bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
|
||||
if (!bio)
|
||||
return NULL;
|
||||
X509 *x509 = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
BIO_free(bio);
|
||||
return x509;
|
||||
}
|
||||
|
||||
EVP_PKEY *openssl_load_key(const std::string & file_or_pem)
|
||||
{
|
||||
std::string pem;
|
||||
BIO *bio = NULL;
|
||||
if (file_or_pem.substr(0, 5) != "-----")
|
||||
{
|
||||
pem = read_file(file_or_pem);
|
||||
bio = BIO_new_mem_buf(pem.data(), pem.size());
|
||||
}
|
||||
else
|
||||
bio = BIO_new_mem_buf(file_or_pem.data(), file_or_pem.size());
|
||||
if (!bio)
|
||||
return NULL;
|
||||
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
return pkey;
|
||||
}
|
||||
|
||||
bool openssl_ctx_add_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
|
||||
{
|
||||
X509 *cert = openssl_load_cert(file_or_pem);
|
||||
bool ok = !!cert;
|
||||
if (cert)
|
||||
{
|
||||
X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
|
||||
X509_STORE_add_cert(store, cert);
|
||||
X509_free(cert);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool openssl_ctx_use_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
|
||||
{
|
||||
if (file_or_pem.substr(0, 5) == "-----")
|
||||
{
|
||||
return openssl_ctx_add_ca(ssl_ctx, file_or_pem);
|
||||
}
|
||||
return file_or_pem.empty()
|
||||
? !!SSL_CTX_set_default_verify_paths(ssl_ctx)
|
||||
: !!SSL_CTX_load_verify_locations(ssl_ctx, file_or_pem.c_str(), NULL);
|
||||
}
|
||||
|
||||
std::string openssl_get_cn(X509 *x509)
|
||||
{
|
||||
X509_NAME* subj = X509_get_subject_name(x509);
|
||||
int pos = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
|
||||
if (pos != -1)
|
||||
{
|
||||
X509_NAME_ENTRY* cn = X509_NAME_get_entry(subj, pos);
|
||||
ASN1_STRING* str = X509_NAME_ENTRY_get_data(cn);
|
||||
return std::string((const char*)ASN1_STRING_get0_data(str), ASN1_STRING_length(str));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool openssl_ctx_use_cert(SSL_CTX *ssl_ctx, const std::string & file_or_pem, std::string & common_name)
|
||||
{
|
||||
X509 *cert = openssl_load_cert(file_or_pem);
|
||||
bool ok = false;
|
||||
if (cert)
|
||||
{
|
||||
common_name = openssl_get_cn(cert);
|
||||
ok = SSL_CTX_use_certificate(ssl_ctx, cert);
|
||||
X509_free(cert);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool openssl_ctx_use_key(SSL_CTX *ssl_ctx, const std::string & file_or_pem)
|
||||
{
|
||||
EVP_PKEY *pkey = openssl_load_key(file_or_pem);
|
||||
bool ok = false;
|
||||
if (pkey)
|
||||
{
|
||||
ok = SSL_CTX_use_PrivateKey(ssl_ctx, pkey);
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool openssl_bio_nonempty(BIO *bio)
|
||||
{
|
||||
// SSL_ERROR_WANT_WRITE is absolutely non-informative with memory BIO, it basically never happens
|
||||
// So we have to check memory BIO for outstanding data
|
||||
char *bio_buf = NULL;
|
||||
size_t bio_sz = BIO_get_mem_data(bio, &bio_buf);
|
||||
return bio_sz > 0;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
#include <openssl/types.h>
|
||||
#endif
|
||||
|
||||
X509 *openssl_load_cert(const std::string & file_or_pem);
|
||||
EVP_PKEY *openssl_load_key(const std::string & file_or_pem);
|
||||
bool openssl_ctx_add_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
|
||||
bool openssl_ctx_use_ca(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
|
||||
std::string openssl_get_cn(X509 *x509);
|
||||
bool openssl_ctx_use_cert(SSL_CTX *ssl_ctx, const std::string & file_or_pem, std::string & common_name);
|
||||
bool openssl_ctx_use_key(SSL_CTX *ssl_ctx, const std::string & file_or_pem);
|
||||
bool openssl_bio_nonempty(BIO *bio);
|
||||
@@ -535,12 +535,12 @@ std::string urldecode(const std::string & orig)
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t fromhexstr(const char *from, size_t from_len, uint8_t *to, size_t to_len)
|
||||
size_t fromhexstr(const std::string & from, size_t bytes, uint8_t *to)
|
||||
{
|
||||
if (to_len > from_len/2)
|
||||
to_len = from_len/2;
|
||||
if (bytes > from.size()/2)
|
||||
bytes = from.size()/2;
|
||||
size_t i = 0;
|
||||
while (i < to_len)
|
||||
while (i < bytes)
|
||||
{
|
||||
uint8_t x = fromhexchar(from[2*i], 16);
|
||||
uint8_t y = fromhexchar(from[2*i+1], 16);
|
||||
@@ -552,11 +552,6 @@ size_t fromhexstr(const char *from, size_t from_len, uint8_t *to, size_t to_len)
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t fromhexstr(const std::string & from, size_t bytes, uint8_t *to)
|
||||
{
|
||||
return fromhexstr(from.data(), from.size(), to, bytes);
|
||||
}
|
||||
|
||||
std::string tohexstr(const uint8_t *from, size_t bytes)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
@@ -35,7 +35,6 @@ std::string realpath_str(std::string path, bool nofail = true);
|
||||
std::string format_datetime(uint64_t unixtime);
|
||||
bool is_zero(void *buf, size_t size);
|
||||
std::string urldecode(const std::string & orig);
|
||||
size_t fromhexstr(const char *from, size_t from_len, uint8_t *to, size_t to_len);
|
||||
size_t fromhexstr(const std::string & from, size_t bytes, uint8_t *to);
|
||||
std::string tohexstr(const uint8_t *from, size_t bytes);
|
||||
bool ishexstr(const std::string & str);
|
||||
|
||||
@@ -34,8 +34,6 @@ extern "C" {
|
||||
# define XXH_NOESCAPE
|
||||
#endif
|
||||
|
||||
#define XXH_SECRET_DEFAULT_SIZE 192
|
||||
|
||||
typedef enum {
|
||||
XXH_OK = 0,
|
||||
XXH_ERROR
|
||||
|
||||
+8
-11
@@ -27,8 +27,7 @@ ETCD_COUNT=${ETCD_COUNT:-1}
|
||||
ANTIETCD=${ANTIETCD}
|
||||
USE_RAMDISK=${USE_RAMDISK}
|
||||
ETCD_SCHEME=${ETCD_SCHEME:-http}
|
||||
OSD_TLS=${OSD_TLS:-1}
|
||||
RDMA=${RDMA:-0}
|
||||
OSD_TLS=${OSD_TLS}
|
||||
|
||||
RAMDISK=/run/user/$(id -u)
|
||||
findmnt $RAMDISK >/dev/null || (sudo mkdir -p $RAMDISK && sudo mount -t tmpfs tmpfs $RAMDISK)
|
||||
@@ -126,8 +125,6 @@ VITASTOR_CFG='"etcd_address":"'$ETCD_URL'"'"$VITASTOR_CFG"
|
||||
if [[ "$ETCD_SCHEME" = "https" ]]; then
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"etcd_ca":"'$(pwd)'/testdata/etcd.crt"'
|
||||
fi
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_network":"'$ETCD_IP'/32"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"use_rdma":"'$RDMA'"'
|
||||
if [[ "$OSD_TLS" = "1" ]]; then
|
||||
cd ./testdata
|
||||
openssl req -days 3650 -x509 -new -newkey rsa:4096 -nodes -keyout client_ca.key -out client_ca.crt \
|
||||
@@ -138,14 +135,14 @@ if [[ "$OSD_TLS" = "1" ]]; then
|
||||
openssl x509 -req -days 3650 -CA client_ca.crt -CAkey client_ca.key -CAcreateserial -in cli.csr -out cli.crt
|
||||
rm cli.csr
|
||||
cd $(dirname $0)/..
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_cert":"'$(pwd)'/testdata/osd.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_pkey":"'$(pwd)'/testdata/osd.key"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_ca":"'$(pwd)'/testdata/osd.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"client_ca":"'$(pwd)'/testdata/client_ca.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"cert":"'$(pwd)'/testdata/cli.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"pkey":"'$(pwd)'/testdata/cli.key"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"use_auth":false'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_tls_cert":"'$(pwd)'/testdata/osd.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_tls_key":"'$(pwd)'/testdata/osd.key"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"osd_tls_ca":"'$(pwd)'/testdata/osd.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"client_tls_ca":"'$(pwd)'/testdata/client_ca.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"tls_cert":"'$(pwd)'/testdata/cli.crt"'
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"tls_key":"'$(pwd)'/testdata/cli.key"'
|
||||
fi
|
||||
VITASTOR_CFG="$VITASTOR_CFG"',"test_osd_aes_key":"'$(openssl rand -hex 32)'"'
|
||||
echo "{$VITASTOR_CFG}" > ./testdata/vitastor.conf
|
||||
VITASTOR_CFG=./testdata/vitastor.conf
|
||||
VITASTOR_CLI="build/src/cmd/vitastor-cli --config_path $VITASTOR_CFG"
|
||||
|
||||
+1
-9
@@ -40,7 +40,7 @@ start_osd_on()
|
||||
{
|
||||
local i=$1
|
||||
local dev=$2
|
||||
build/src/osd/vitastor-osd --osd_num $i $NO_SAME $OSD_ARGS \
|
||||
build/src/osd/vitastor-osd --osd_num $i --bind_address $ETCD_IP $NO_SAME $OSD_ARGS \
|
||||
$(build/src/disk_tool/vitastor-disk simple-offsets --format options $OFFSET_ARGS $dev $OFFSET_ARGS 2>/dev/null) \
|
||||
>>./testdata/osd$i.log 2>&1 &
|
||||
eval OSD${i}_PID=$!
|
||||
@@ -119,14 +119,6 @@ if [[ $OSD_COUNT -gt 0 ]]; then
|
||||
wait_up 120
|
||||
fi
|
||||
|
||||
if [[ "$RDMA" = 1 ]]; then
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
if ! grep 'RDMA initialized successfully' ./testdata/osd$i.log; then
|
||||
format_error "OSD $i failed to initialize RDMA, please try to enable rdma-rxe on the host"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
try_reweight()
|
||||
{
|
||||
osd=$1
|
||||
|
||||
@@ -100,7 +100,6 @@ PG_SIZE=2 ./test_heal.sh
|
||||
TEST_NAME=local_read POOLCFG='"local_reads":"random",' ./test_heal.sh
|
||||
SCHEME=ec ./test_heal.sh
|
||||
ANTIETCD=1 ./test_heal.sh
|
||||
TEST_NAME=ec_rdma RDMA=1 SCHEME=ec ./test_heal.sh
|
||||
|
||||
./test_checksum.sh
|
||||
TEST_NAME=xxhash OSD_ARGS="--data_csum_type xxh3_32" ./test_checksum.sh
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ if ! diff -q ./testdata/bin/read.bin ./testdata/bin/mirror.bin; then
|
||||
format_error Data lost during self-heal
|
||||
fi
|
||||
|
||||
if grep -qP 'Checksum mismatch|BUG|Received garbage' ./testdata/osd*.log; then
|
||||
if grep -qP 'Checksum mismatch|BUG' ./testdata/osd*.log; then
|
||||
format_error Checksum mismatches or BUGs detected during test
|
||||
fi
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ OSD_COUNT=5
|
||||
OSD_ARGS="$OSD_ARGS"
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
dd if=/dev/zero of=./testdata/bin/test_osd$i.bin bs=1024 count=1 seek=$((OSD_SIZE*1024-1))
|
||||
build/src/osd/vitastor-osd --log_level 10 --osd_num $i --etcd_stats_interval 5 $OSD_ARGS \
|
||||
build/src/osd/vitastor-osd --log_level 10 --osd_num $i --bind_address 127.0.0.1 --etcd_stats_interval 5 $OSD_ARGS \
|
||||
$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd$i.bin $OFFSET_ARGS 2>/dev/null) >>./testdata/osd$i.log 2>&1 &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
@@ -70,7 +70,7 @@ done
|
||||
$ETCDCTL del --prefix /vitastor/osd/state/
|
||||
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
build/src/osd/vitastor-osd --osd_num $i $NO_SAME $OSD_ARGS \
|
||||
build/src/osd/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $NO_SAME $OSD_ARGS \
|
||||
--meta_format $meta_format \
|
||||
--data_device ./testdata/bin/test_osd$i.bin \
|
||||
--meta_offset 0 \
|
||||
|
||||
@@ -21,7 +21,7 @@ $VITASTOR_FIO -bs=4k -direct=1 -iodepth=1 -fsync=1 \
|
||||
# Kill OSD 2, start OSD 1
|
||||
|
||||
kill $OSD2_PID
|
||||
build/src/osd/vitastor-osd --osd_num 1 $NO_SAME $OSD_ARGS \
|
||||
build/src/osd/vitastor-osd --osd_num 1 --bind_address 127.0.0.1 $NO_SAME $OSD_ARGS \
|
||||
$(build/src/disk_tool/vitastor-disk simple-offsets --format options --device ./testdata/bin/test_osd2.bin $OFFSET_ARGS 2>/dev/null) >>./testdata/osd2.log 2>&1 &
|
||||
sleep 2
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ OSD_COUNT=3
|
||||
OSD_ARGS="$OSD_ARGS"
|
||||
OFFSET_ARGS="$OFFSET_ARGS"
|
||||
for i in $(seq 1 $OSD_COUNT); do
|
||||
build/src/osd/vitastor-osd --osd_num $i $OSD_ARGS \
|
||||
build/src/osd/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $OSD_ARGS \
|
||||
$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd$i.bin $OFFSET_ARGS 2>/dev/null) >>./testdata/osd$i.log 2>&1 &
|
||||
eval OSD${i}_PID=$!
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user