diff --git a/lib/transport/CMakeLists.txt b/lib/transport/CMakeLists.txt index 6ea7e75e0c3..45f727b7ac6 100644 --- a/lib/transport/CMakeLists.txt +++ b/lib/transport/CMakeLists.txt @@ -6,6 +6,11 @@ set(TRANSPORT_HEADERS transport/transport-pipe.h transport/transport-socket.h transport/transport-factory-id.h + transport/transport-factory.h + transport/transport-factory-registry.h + transport/multitransport.h + transport/transport-factory-tls.h + transport/transport-factory-socket.h PARENT_SCOPE) set(TRANSPORT_SOURCES @@ -16,6 +21,10 @@ set(TRANSPORT_SOURCES transport/transport-socket.c transport/transport-tls.c transport/transport-factory-id.c + transport/transport-factory-registry.c + transport/multitransport.c + transport/transport-factory-tls.c + transport/transport-factory-socket.c PARENT_SCOPE) add_test_subdirectory(tests) diff --git a/lib/transport/Makefile.am b/lib/transport/Makefile.am index 5fb7e346bd6..fac35f3673d 100644 --- a/lib/transport/Makefile.am +++ b/lib/transport/Makefile.am @@ -7,7 +7,12 @@ transportinclude_HEADERS = \ lib/transport/transport-file.h \ lib/transport/transport-pipe.h \ lib/transport/transport-socket.h \ - lib/transport/transport-factory-id.h + lib/transport/transport-factory-id.h \ + lib/transport/transport-factory.h \ + lib/transport/transport-factory-registry.h \ + lib/transport/multitransport.h \ + lib/transport/transport-factory-tls.h \ + lib/transport/transport-factory-socket.h transport_sources = \ lib/transport/logtransport.c \ @@ -15,7 +20,11 @@ transport_sources = \ lib/transport/transport-file.c \ lib/transport/transport-pipe.c \ lib/transport/transport-socket.c \ - lib/transport/transport-factory-id.c + lib/transport/transport-factory-id.c \ + lib/transport/transport-factory-registry.c \ + lib/transport/multitransport.c \ + lib/transport/transport-factory-tls.c \ + lib/transport/transport-factory-socket.c transport_crypto_sources = \ lib/transport/transport-tls.c diff --git a/lib/transport/logtransport.c b/lib/transport/logtransport.c index 367c568f11c..a69b6297a7e 100644 --- a/lib/transport/logtransport.c +++ b/lib/transport/logtransport.c @@ -52,3 +52,13 @@ log_transport_free(LogTransport *self) self->free_fn(self); g_free(self); } + +gint +log_transport_release_fd(LogTransport *s) +{ + gint fd = s->fd; + s->fd = -1; + + return fd; +} + diff --git a/lib/transport/logtransport.h b/lib/transport/logtransport.h index f60660de85d..3ffd04f9f61 100644 --- a/lib/transport/logtransport.h +++ b/lib/transport/logtransport.h @@ -34,6 +34,7 @@ struct _LogTransport { gint fd; GIOCondition cond; + const gchar *name; gssize (*read)(LogTransport *self, gpointer buf, gsize count, LogTransportAuxData *aux); gssize (*write)(LogTransport *self, const gpointer buf, gsize count); void (*free_fn)(LogTransport *self); @@ -54,5 +55,6 @@ log_transport_read(LogTransport *self, gpointer buf, gsize count, LogTransportAu void log_transport_init_instance(LogTransport *s, gint fd); void log_transport_free_method(LogTransport *s); void log_transport_free(LogTransport *s); +gint log_transport_release_fd(LogTransport *s); #endif diff --git a/lib/transport/multitransport.c b/lib/transport/multitransport.c new file mode 100644 index 00000000000..286b903f224 --- /dev/null +++ b/lib/transport/multitransport.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/multitransport.h" +#include "transport/transport-factory-registry.h" +#include "messages.h" + +void multitransport_add_factory(MultiTransport *self, TransportFactory *transport_factory) +{ + transport_factory_registry_add(self->registry, transport_factory); +} + +static void +_do_transport_switch(MultiTransport *self, LogTransport *new_transport, const TransportFactory *new_transport_factory) +{ + self->super.fd = log_transport_release_fd(self->active_transport); + self->super.cond = new_transport->cond; + log_transport_free(self->active_transport); + self->active_transport = new_transport; + self->active_transport_factory = new_transport_factory; +} + +static const TransportFactory * +_lookup_transport_factory(TransportFactoryRegistry *registry, const TransportFactoryId *factory_id) +{ + const TransportFactory *factory = transport_factory_registry_lookup(registry, factory_id); + + if (!factory) + { + msg_error("Requested transport not found", + evt_tag_str("transport", transport_factory_id_get_transport_name(factory_id))); + return NULL; + } + + return factory; +} + +static LogTransport * +_construct_transport(const TransportFactory *factory, gint fd) +{ + LogTransport *transport = transport_factory_construct_transport(factory, fd); + const TransportFactoryId *factory_id = transport_factory_get_id(factory); + + if (!transport) + { + msg_error("Failed to construct transport", + evt_tag_str("transport", transport_factory_id_get_transport_name(factory_id))); + return NULL; + } + + return transport; +} + +gboolean multitransport_switch(MultiTransport *self, const TransportFactoryId *factory_id) +{ + msg_debug("Transport switch requested", + evt_tag_str("active-transport", self->active_transport->name), + evt_tag_str("requested-transport", transport_factory_id_get_transport_name(factory_id))); + + const TransportFactory *transport_factory = _lookup_transport_factory(self->registry, factory_id); + if (!transport_factory) + return FALSE; + + LogTransport *transport = _construct_transport(transport_factory, self->super.fd); + if (!transport) + return FALSE; + + _do_transport_switch(self, transport, transport_factory); + + msg_debug("Transport switch succeded", + evt_tag_str("new-active-transport", self->active_transport->name)); + + return TRUE; +} + +static gssize +_multitransport_write(LogTransport *s, gpointer buf, gsize count) +{ + MultiTransport *self = (MultiTransport *)s; + gssize r = log_transport_write(self->active_transport, buf, count); + return r; +} + +static gssize +_multitransport_read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux) +{ + MultiTransport *self = (MultiTransport *)s; + gssize r = log_transport_read(self->active_transport, buf, count, aux); + return r; +} + +static void +_multitransport_free(LogTransport *s) +{ + MultiTransport *self = (MultiTransport *)s; + s->fd = log_transport_release_fd(self->active_transport); + log_transport_free(self->active_transport); + transport_factory_registry_free(self->registry); + log_transport_free_method(s); +} + +LogTransport * +multitransport_new(TransportFactory *default_transport_factory, gint fd) +{ + MultiTransport *self = g_new0(MultiTransport, 1); + self->registry = transport_factory_registry_new(); + transport_factory_registry_add(self->registry, default_transport_factory); + + log_transport_init_instance(&self->super, fd); + self->super.read = _multitransport_read; + self->super.write = _multitransport_write; + self->super.free_fn = _multitransport_free; + self->active_transport = transport_factory_construct_transport(default_transport_factory, fd); + self->active_transport_factory = default_transport_factory; + + return &self->super; +} diff --git a/lib/transport/multitransport.h b/lib/transport/multitransport.h new file mode 100644 index 00000000000..56da8c9e38f --- /dev/null +++ b/lib/transport/multitransport.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef MULTITRANSPORT_H_INCLUDED +#define MULTITRANSPORT_H_INCLUDED + +#include "transport/logtransport.h" +#include "transport/transport-factory.h" +#include "transport/transport-factory-registry.h" + +typedef struct _MultiTransport MultiTransport; + +struct _MultiTransport +{ + LogTransport super; + TransportFactoryRegistry *registry; + LogTransport *active_transport; + const TransportFactory *active_transport_factory; +}; + +LogTransport *multitransport_new(TransportFactory *default_transport_factory, gint fd); +void multitransport_add_factory(MultiTransport *, TransportFactory *); +gboolean multitransport_switch(MultiTransport *, const TransportFactoryId *); + +#endif + diff --git a/lib/transport/tests/CMakeLists.txt b/lib/transport/tests/CMakeLists.txt index 75d28d665a4..49ee6178c5c 100644 --- a/lib/transport/tests/CMakeLists.txt +++ b/lib/transport/tests/CMakeLists.txt @@ -1,2 +1,5 @@ add_unit_test(LIBTEST TARGET test_aux_data) add_unit_test(LIBTEST TARGET test_transport_factory_id) +add_unit_test(LIBTEST TARGET test_transport_factory) +add_unit_test(LIBTEST TARGET test_transport_factory_registry) +add_unit_test(LIBTEST TARGET test_multitransport) diff --git a/lib/transport/tests/Makefile.am b/lib/transport/tests/Makefile.am index b72b9e15de4..7dcbdbd4577 100644 --- a/lib/transport/tests/Makefile.am +++ b/lib/transport/tests/Makefile.am @@ -1,6 +1,9 @@ lib_transport_tests_TESTS = \ lib/transport/tests/test_aux_data \ - lib/transport/tests/test_transport_factory_id + lib/transport/tests/test_transport_factory_id \ + lib/transport/tests/test_transport_factory \ + lib/transport/tests/test_transport_factory_registry \ + lib/transport/tests/test_multitransport check_PROGRAMS += ${lib_transport_tests_TESTS} @@ -15,3 +18,21 @@ lib_transport_tests_test_transport_factory_id_CFLAGS = $(TEST_CFLAGS) \ lib_transport_tests_test_transport_factory_id_LDADD = $(TEST_LDADD) lib_transport_tests_test_transport_factory_id_SOURCES = \ lib/transport/tests/test_transport_factory_id.c + +lib_transport_tests_test_transport_factory_CFLAGS = $(TEST_CFLAGS) \ + -I${top_srcdir}/lib/transport/tests +lib_transport_tests_test_transport_factory_LDADD = $(TEST_LDADD) +lib_transport_tests_test_transport_factory_SOURCES = \ + lib/transport/tests/test_transport_factory.c + +lib_transport_tests_test_transport_factory_registry_CFLAGS = $(TEST_CFLAGS) \ + -I${top_srcdir}/lib/transport/tests +lib_transport_tests_test_transport_factory_registry_LDADD = $(TEST_LDADD) +lib_transport_tests_test_transport_factory_registry_SOURCES = \ + lib/transport/tests/test_transport_factory_registry.c + +lib_transport_tests_test_multitransport_CFLAGS = $(TEST_CFLAGS) \ + -I${top_srcdir}/lib/transport/tests +lib_transport_tests_test_multitransport_LDADD = $(TEST_LDADD) +lib_transport_tests_test_multitransport_SOURCES = \ + lib/transport/tests/test_multitransport.c diff --git a/lib/transport/tests/test_multitransport.c b/lib/transport/tests/test_multitransport.c new file mode 100644 index 00000000000..8f13a3c069f --- /dev/null +++ b/lib/transport/tests/test_multitransport.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2002-2018 Balabit + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/multitransport.h" +#include "transport/transport-factory.h" +#include "apphook.h" +#include + +#define DEFINE_TEST_TRANSPORT_WITH_FACTORY(TypePrefix, FunPrefix) \ + typedef struct TypePrefix ## Transport_ TypePrefix ## Transport; \ + typedef struct TypePrefix ## TransportFactory_ TypePrefix ## TransportFactory; \ + struct TypePrefix ## Transport_ \ + { \ + LogTransport super; \ + }; \ + static gssize \ + FunPrefix ## _read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux) \ + { \ + return count; \ + }\ + static gssize \ + FunPrefix ## _write(LogTransport *s, const gpointer buf, gsize count) \ + { \ + return count; \ + }\ + LogTransport * \ + FunPrefix ## _transport_new(void) \ + { \ + TypePrefix ## Transport *self = g_new0(TypePrefix ## Transport, 1); \ + self->super.read = FunPrefix ## _read; \ + self->super.write = FunPrefix ## _write; \ + return &self->super; \ + } \ + struct TypePrefix ## TransportFactory_\ + { \ + TransportFactory super; \ + }; \ + DEFINE_TRANSPORT_FACTORY_ID_FUN(#FunPrefix, FunPrefix ## _transport_factory_id); \ + static LogTransport * \ + FunPrefix ## _factory_construct(const TransportFactory *s, gint fd) \ + {\ + LogTransport *transport = FunPrefix ## _transport_new(); \ + log_transport_init_instance(transport, fd); \ + return transport; \ + } \ + TransportFactory * \ + FunPrefix ## _transport_factory_new(void) \ + { \ + TypePrefix ## TransportFactory *self = g_new0(TypePrefix ## TransportFactory, 1); \ + self->super.id = FunPrefix ## _transport_factory_id(); \ + self->super.construct_transport = FunPrefix ## _factory_construct; \ + return &self->super; \ + } \ + +TestSuite(multitransport, .init = app_startup, .fini = app_shutdown); + +DEFINE_TEST_TRANSPORT_WITH_FACTORY(Fake, fake); +DEFINE_TEST_TRANSPORT_WITH_FACTORY(Default, default); +DEFINE_TEST_TRANSPORT_WITH_FACTORY(Unregistered, unregistered); + +Test(multitransport, test_switch_transport) +{ + TransportFactory *default_factory = default_transport_factory_new(); + TransportFactory *fake_factory = fake_transport_factory_new(); + gint fd = -2; + + MultiTransport *multi_transport = (MultiTransport *) multitransport_new(default_factory, fd); + + cr_expect_eq(multi_transport->active_transport->read, default_read); + cr_expect_eq(multi_transport->active_transport->write, default_write); + cr_expect_str_eq(multi_transport->active_transport->name, "default"); + + multitransport_add_factory(multi_transport, fake_factory); + cr_expect_not(multitransport_switch(multi_transport, unregistered_transport_factory_id())); + cr_expect_eq(multi_transport->active_transport->read, default_read); + cr_expect_eq(multi_transport->active_transport->write, default_write); + cr_expect_eq(multi_transport->active_transport_factory, default_factory); + cr_expect_str_eq(multi_transport->active_transport->name, "default"); + + cr_expect(multitransport_switch(multi_transport, fake_transport_factory_id())); + cr_expect_eq(multi_transport->active_transport->read, fake_read); + cr_expect_eq(multi_transport->active_transport->write, fake_write); + cr_expect_eq(multi_transport->active_transport_factory, fake_factory); + cr_expect_str_eq(multi_transport->active_transport->name, "fake"); + + log_transport_free(&multi_transport->super); +} + diff --git a/lib/transport/tests/test_transport_factory.c b/lib/transport/tests/test_transport_factory.c new file mode 100644 index 00000000000..2ba12a094d5 --- /dev/null +++ b/lib/transport/tests/test_transport_factory.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2002-2018 Balabit + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/transport-factory.h" +#include "apphook.h" +#include + +typedef struct _FakeTransport FakeTransport; +typedef struct _FakeTransportFactory FakeTransportFactory; + +struct _FakeTransport +{ + LogTransport super; + gboolean constructed; +}; + +static gssize +_fake_read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *auc) +{ + return count; +} + +static gssize +_fake_write(LogTransport *s, const gpointer buf, gsize count) +{ + return count; +} + +static void +_fake_free(LogTransport *s) +{ +} + +LogTransport * +_fake_transport_new(void) +{ + FakeTransport *instance = g_new0(FakeTransport, 1); + + instance->super.read = _fake_read; + instance->super.write = _fake_write; + instance->constructed = TRUE; + + return &instance->super; +} + +struct _FakeTransportFactory +{ + TransportFactory super; + gboolean destroyed; +}; + +DEFINE_TRANSPORT_FACTORY_ID_FUN("fake", _fake_transport_factory_id); + +static LogTransport * +_transport_factory_construct(const TransportFactory *s, gint fd) +{ + LogTransport *fake_transport = _fake_transport_new(); + log_transport_init_instance(fake_transport, fd); + fake_transport->free_fn = _fake_free; + + return fake_transport; +} + +static void +_transport_factory_free(TransportFactory *s) +{ + FakeTransportFactory *self = (FakeTransportFactory *)s; + self->destroyed = TRUE; +} + +TransportFactory * +_fake_transport_factory_new(void) +{ + FakeTransportFactory *instance = g_new0(FakeTransportFactory, 1); + instance->super.id = _fake_transport_factory_id(); + instance->super.construct_transport = _transport_factory_construct; + instance->super.free_fn = _transport_factory_free; + return &instance->super; +} + +TestSuite(transport_factory, .init = app_startup, .fini = app_shutdown); + +Test(transport_factory, fake_transport_factory) +{ + FakeTransportFactory *fake_factory = (FakeTransportFactory *)_fake_transport_factory_new(); + cr_expect_not_null(fake_factory->super.id); + cr_expect_eq(fake_factory->destroyed, FALSE); + + gint fd = 11; + FakeTransport *fake_transport = (FakeTransport *) transport_factory_construct_transport(&fake_factory->super, fd); + cr_expect_eq(fake_transport->constructed, TRUE); + cr_expect_eq(fake_transport->super.read, _fake_read); + cr_expect_eq(fake_transport->super.write, _fake_write); + log_transport_free(&fake_transport->super); + + transport_factory_free(&fake_factory->super); + cr_expect_eq(fake_factory->destroyed, TRUE); +} diff --git a/lib/transport/tests/test_transport_factory_id.c b/lib/transport/tests/test_transport_factory_id.c index f2759882519..bf8a3a0c419 100644 --- a/lib/transport/tests/test_transport_factory_id.c +++ b/lib/transport/tests/test_transport_factory_id.c @@ -29,20 +29,19 @@ TestSuite(transport_factory_id, .init = app_startup, .fini = app_shutdown); Test(transport_factory_id, lifecycle) { - transport_factory_id_global_init(); GList *ids = transport_factory_id_clone_registered_ids(); cr_expect_null(ids); - TransportFactoryId *id = TRANSPORT_FACTORY_ID_NEW("tcp"); - TransportFactoryId *expected = TRANSPORT_FACTORY_ID_CLONE(id); + TransportFactoryId *id = transport_factory_id_new("tcp"); + TransportFactoryId *expected = transport_factory_id_clone(id); transport_factory_id_register(id); ids = transport_factory_id_clone_registered_ids(); cr_assert_not_null(ids, "transport_factory_id_register failed"); - cr_expect(TRANSPORT_FACTORY_ID_CMP_FUNC(ids->data, expected)); - TRANSPORT_FACTORY_ID_FREE_FUNC(expected); - g_list_free_full(ids, TRANSPORT_FACTORY_ID_FREE_FUNC); + cr_expect(transport_factory_id_equal(ids->data, expected)); + transport_factory_id_free(expected); + g_list_free_full(ids, (GDestroyNotify)transport_factory_id_free); transport_factory_id_global_deinit(); @@ -52,15 +51,15 @@ Test(transport_factory_id, lifecycle) Test(transport_factory_id_basic_macros, generated_ids_are_uniq) { - TransportFactoryId *id = TRANSPORT_FACTORY_ID_NEW("tcp"); - TransportFactoryId *id2 = TRANSPORT_FACTORY_ID_NEW("tcp"); - cr_expect_not(TRANSPORT_FACTORY_ID_CMP_FUNC(id, id2)); + TransportFactoryId *id = transport_factory_id_new("tcp"); + TransportFactoryId *id2 = transport_factory_id_new("tcp"); + cr_expect_not(transport_factory_id_equal(id, id2)); } Test(transport_factory_id_basic_macros, clones_are_equals) { - TransportFactoryId *id = TRANSPORT_FACTORY_ID_NEW("tcp"); - TransportFactoryId *cloned = TRANSPORT_FACTORY_ID_CLONE(id); - cr_expect(TRANSPORT_FACTORY_ID_CMP_FUNC(id, cloned)); - cr_expect_eq(TRANSPORT_FACTORY_ID_HASH_FUNC(id), TRANSPORT_FACTORY_ID_HASH_FUNC(cloned)); + TransportFactoryId *id = transport_factory_id_new("tcp"); + TransportFactoryId *cloned = transport_factory_id_clone(id); + cr_expect(transport_factory_id_equal(id, cloned)); + cr_expect_eq(transport_factory_id_hash(id), transport_factory_id_hash(cloned)); } diff --git a/lib/transport/tests/test_transport_factory_registry.c b/lib/transport/tests/test_transport_factory_registry.c new file mode 100644 index 00000000000..33175575c84 --- /dev/null +++ b/lib/transport/tests/test_transport_factory_registry.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2018 Balabit + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/transport-factory-registry.h" +#include "apphook.h" +#include + +typedef struct _TestTransportFactory +{ + TransportFactory super; +} TestTransportFactory; + +DEFINE_TRANSPORT_FACTORY_ID_FUN("test", test_transport_factory_id); + +static TestTransportFactory * +_test_transport_factory_new(void) +{ + TestTransportFactory *instance = g_new0(TestTransportFactory, 1); + + instance->super.id = test_transport_factory_id(); + + return instance; +} + +TestSuite(transport_factory_registry, .init = app_startup, .fini = app_shutdown); + +Test(transport_factory_registry, basic_functionality) +{ + TransportFactoryRegistry *registry = transport_factory_registry_new(); + + TestTransportFactory *factory = _test_transport_factory_new(); + + transport_factory_registry_add(registry, &factory->super); + const TransportFactory *looked_up_factory = (TransportFactory *)transport_factory_registry_lookup(registry, + test_transport_factory_id()); + cr_expect_eq((gpointer)factory, (gpointer)looked_up_factory); + + transport_factory_registry_free(registry); +} diff --git a/lib/transport/transport-factory-id.c b/lib/transport/transport-factory-id.c index 5e14c6be152..8b0c97fb809 100644 --- a/lib/transport/transport-factory-id.c +++ b/lib/transport/transport-factory-id.c @@ -25,15 +25,53 @@ #include "transport/transport-factory-id.h" #include "mainloop.h" +struct _TransportFactoryId +{ + gchar *transport_name; + gint uniq_id; +}; + +typedef struct _Sequence Sequence; + +struct _Sequence +{ + gint ctr; +} sequence; + +static void +sequence_inc(Sequence *seq) +{ + seq->ctr++; +} + +static gint +sequence_get(Sequence *seq) +{ + return seq->ctr; +} + +static void +sequence_reset(Sequence *seq, gint init_value) +{ + seq->ctr = init_value; +} + static GList *transport_factory_ids; void transport_factory_id_global_init(void) { + sequence_reset(&sequence, 1); +} + +static inline void +_free(gpointer s) +{ + transport_factory_id_free((TransportFactoryId *)s); } void transport_factory_id_global_deinit(void) { - g_list_free_full(transport_factory_ids, TRANSPORT_FACTORY_ID_FREE_FUNC); + g_list_free_full(transport_factory_ids, _free); transport_factory_ids = NULL; } @@ -45,32 +83,68 @@ transport_factory_id_register(TransportFactoryId *id) } static gpointer -_clone_func(gconstpointer src, gpointer data) +_clone(gconstpointer s) { - return TRANSPORT_FACTORY_ID_CLONE(src); + TransportFactoryId *id = (TransportFactoryId *)s; + TransportFactoryId *cloned = g_new0(TransportFactoryId, 1); + + cloned->transport_name = g_strdup(id->transport_name); + cloned->uniq_id = id->uniq_id; + + return cloned; +} + +TransportFactoryId *transport_factory_id_clone(const TransportFactoryId *id) +{ + return (TransportFactoryId *)_clone((gconstpointer) id); +} + +static gpointer +_copy_func(gconstpointer src, gpointer data) +{ + return _clone(src); } GList * transport_factory_id_clone_registered_ids(void) { - return g_list_copy_deep(transport_factory_ids, _clone_func, NULL); + return g_list_copy_deep(transport_factory_ids, _copy_func, NULL); } void -transport_factory_id_free(gpointer id) +transport_factory_id_free(TransportFactoryId *id) { - g_string_free((GString *)id, TRUE); + g_free(id->transport_name); + g_free(id); } -gpointer -transport_factory_id_clone(gconstpointer id) +guint +transport_factory_id_hash(gconstpointer key) { - return g_string_new(((const GString *)id)->str); + TransportFactoryId *id = (TransportFactoryId *)key; + return g_direct_hash(GINT_TO_POINTER(id->uniq_id)); +} + +gboolean +transport_factory_id_equal(const TransportFactoryId *id1, const TransportFactoryId *id2) +{ + return (id1->uniq_id == id2->uniq_id) ? TRUE : FALSE; } const gchar * -transport_factory_id_to_string(TransportFactoryId *id) +transport_factory_id_get_transport_name(const TransportFactoryId *id) +{ + return id->transport_name; +} + +TransportFactoryId * +transport_factory_id_new(const gchar *transport_name) { - GString *str = (GString *)id; - return str->str; + TransportFactoryId *id = g_new0(TransportFactoryId, 1); + + sequence_inc(&sequence); + id->transport_name = g_strdup(transport_name); + id->uniq_id = sequence_get(&sequence); + + return id; } diff --git a/lib/transport/transport-factory-id.h b/lib/transport/transport-factory-id.h index 49f553a5038..e99b3611820 100644 --- a/lib/transport/transport-factory-id.h +++ b/lib/transport/transport-factory-id.h @@ -27,20 +27,29 @@ #include "syslog-ng.h" -typedef GString TransportFactoryId; +typedef struct _TransportFactoryId TransportFactoryId; void transport_factory_id_global_init(void); void transport_factory_id_global_deinit(void); void transport_factory_id_register(TransportFactoryId *); GList *transport_factory_id_clone_registered_ids(void); -void transport_factory_id_free(gpointer); -gpointer transport_factory_id_clone(gconstpointer); -const gchar *transport_factory_id_to_string(TransportFactoryId *); +void transport_factory_id_free(TransportFactoryId *); +guint transport_factory_id_hash(gconstpointer); +gboolean transport_factory_id_equal(const TransportFactoryId *, const TransportFactoryId *); +TransportFactoryId *transport_factory_id_clone(const TransportFactoryId *); +TransportFactoryId *transport_factory_id_new(const gchar *transport_name); +const gchar *transport_factory_id_get_transport_name(const TransportFactoryId *); -#define TRANSPORT_FACTORY_ID_NEW(name) ({GString *str = g_string_new(""); g_string_printf(str, "%s-%s:%s:%d", name, __FILE__, __func__, __LINE__); str;}) -#define TRANSPORT_FACTORY_ID_FREE_FUNC transport_factory_id_free -#define TRANSPORT_FACTORY_ID_HASH_FUNC g_string_hash -#define TRANSPORT_FACTORY_ID_CMP_FUNC g_string_equal -#define TRANSPORT_FACTORY_ID_CLONE transport_factory_id_clone +#define DEFINE_TRANSPORT_FACTORY_ID_FUN(transport_name, func_name) \ + const TransportFactoryId* func_name(void) \ + {\ + static TransportFactoryId *id;\ + if (!id)\ + {\ + id = transport_factory_id_new(transport_name);\ + transport_factory_id_register(id);\ + }\ + return id;\ + } #endif diff --git a/lib/transport/transport-factory-registry.c b/lib/transport/transport-factory-registry.c new file mode 100644 index 00000000000..21a7f34d213 --- /dev/null +++ b/lib/transport/transport-factory-registry.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/transport-factory-registry.h" + +struct _TransportFactoryRegistry +{ + /* + * hash_table + * */ + GHashTable *registry; +}; + +static void +_transport_factory_destroy_notify(gpointer s) +{ + TransportFactory *self = (TransportFactory *)s; + transport_factory_free(self); +} + +TransportFactoryRegistry *transport_factory_registry_new(void) +{ + TransportFactoryRegistry *instance = g_new0(TransportFactoryRegistry, 1); + + instance->registry = g_hash_table_new_full((GHashFunc)transport_factory_id_hash, + (GEqualFunc)transport_factory_id_equal, + NULL,_transport_factory_destroy_notify); + + return instance; +} + +void transport_factory_registry_free(TransportFactoryRegistry *self) +{ + g_hash_table_unref(self->registry); + g_free(self); +} + +gboolean +transport_factory_registry_add(TransportFactoryRegistry *self, TransportFactory *factory) +{ + const TransportFactoryId *id = transport_factory_get_id(factory); + return g_hash_table_insert(self->registry, (TransportFactoryId *)id, factory); +} + +const TransportFactory * +transport_factory_registry_lookup(TransportFactoryRegistry *self, const TransportFactoryId *id) +{ + return g_hash_table_lookup(self->registry, id); +} diff --git a/lib/transport/transport-factory-registry.h b/lib/transport/transport-factory-registry.h new file mode 100644 index 00000000000..0fe6e61a6b0 --- /dev/null +++ b/lib/transport/transport-factory-registry.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef TRANSPORT_FACTORY_REGISTRY_H_INCLUDED +#define TRANSPORT_FACTORY_REGISTRY_H_INCLUDED + +#include "syslog-ng.h" +#include "transport/transport-factory.h" +#include "transport/transport-factory-id.h" + +typedef struct _TransportFactoryRegistry TransportFactoryRegistry; + +TransportFactoryRegistry *transport_factory_registry_new(void); +void transport_factory_registry_free(TransportFactoryRegistry *self); + +gboolean transport_factory_registry_add(TransportFactoryRegistry *self, TransportFactory *factory); +const TransportFactory *transport_factory_registry_lookup(TransportFactoryRegistry *self, const TransportFactoryId *id); + +#endif + diff --git a/lib/transport/transport-factory-socket.c b/lib/transport/transport-factory-socket.c new file mode 100644 index 00000000000..171684ec57f --- /dev/null +++ b/lib/transport/transport-factory-socket.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/transport-factory-socket.h" +#include "transport/transport-socket.h" + +typedef struct _TransportFactorySocket TransportFactorySocket; + +DEFINE_TRANSPORT_FACTORY_ID_FUN("socket", transport_factory_socket_id); + +struct _TransportFactorySocket +{ + TransportFactory super; +}; + +static LogTransport * +_construct_transport_dgram(const TransportFactory *s, gint fd) +{ + return log_transport_dgram_socket_new(fd); +} + +static LogTransport * +_construct_transport_stream(const TransportFactory *s, gint fd) +{ + return log_transport_stream_socket_new(fd); +} + +TransportFactory * +transport_factory_socket_new(int sock_type) +{ + TransportFactorySocket *self = g_new0(TransportFactorySocket, 1); + + if (sock_type == SOCK_DGRAM) + self->super.construct_transport = _construct_transport_dgram; + else + self->super.construct_transport = _construct_transport_stream; + + self->super.id = transport_factory_socket_id(); + + return &self->super; +} + diff --git a/lib/transport/transport-factory-socket.h b/lib/transport/transport-factory-socket.h new file mode 100644 index 00000000000..97f62f7bdd2 --- /dev/null +++ b/lib/transport/transport-factory-socket.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef TRANSPORT_FACTORY_SOCKET_H_INCLUDED +#define TRANSPORT_FACTORY_SOCKET_H_INCLUDED + +#include "transport/transport-factory.h" +#include "transport/transport-socket.h" + +TransportFactory *transport_factory_socket_new(gint sock_type); + +const TransportFactoryId *transport_factory_socket_id(void); + +#endif diff --git a/lib/transport/transport-factory-tls.c b/lib/transport/transport-factory-tls.c new file mode 100644 index 00000000000..ad78f22e821 --- /dev/null +++ b/lib/transport/transport-factory-tls.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transport/transport-factory-tls.h" +#include "transport/transport-tls.h" + +DEFINE_TRANSPORT_FACTORY_ID_FUN("tls", transport_factory_tls_id); + +typedef struct _TransportFactoryTLS TransportFactoryTLS; + +struct _TransportFactoryTLS +{ + TransportFactory super; + TLSContext *tls_context; + TLSSessionVerifyFunc tls_verify_cb; + gpointer tls_verify_data; +}; + +static LogTransport * +_construct_transport(const TransportFactory *s, gint fd) +{ + TransportFactoryTLS *self = (TransportFactoryTLS *)s; + TLSSession *tls_session = tls_context_setup_session(self->tls_context); + if (!tls_session) + return NULL; + tls_session_set_verify(tls_session, self->tls_verify_cb, self->tls_verify_data, NULL); + return log_transport_tls_new(tls_session, fd); +} + +TransportFactory * +transport_factory_tls_new(TLSContext *ctx, + TLSSessionVerifyFunc tls_verify_cb, + gpointer tls_verify_data) +{ + TransportFactoryTLS *instance = g_new0(TransportFactoryTLS, 1); + + instance->tls_context = ctx; + instance->tls_verify_cb = tls_verify_cb; + instance->tls_verify_data = tls_verify_data; + + instance->super.id = transport_factory_tls_id(); + instance->super.construct_transport = _construct_transport; + + return &instance->super; +} diff --git a/lib/transport/transport-factory-tls.h b/lib/transport/transport-factory-tls.h new file mode 100644 index 00000000000..a1b88f09187 --- /dev/null +++ b/lib/transport/transport-factory-tls.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef TRANSPORT_FACTORY_TLS_H_INCLUDED +#define TRANSPORT_FACTORY_TLS_H_INCLUDED + +#include "transport/transport-factory.h" +#include "tlscontext.h" + +TransportFactory *transport_factory_tls_new(TLSContext *ctx, + TLSSessionVerifyFunc tls_verify_cb, + gpointer tls_verify_data); + +const TransportFactoryId *transport_factory_tls_id(void); + +#endif diff --git a/lib/transport/transport-factory.h b/lib/transport/transport-factory.h new file mode 100644 index 00000000000..49bc7655dad --- /dev/null +++ b/lib/transport/transport-factory.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002-2018 Balabit + * Copyright (c) 2018 Laszlo Budai + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef TRANSPORT_FACTORY_H_INCLUDED +#define TRANSPORT_FACTORY_H_INCLUDED + +#include "transport/logtransport.h" +#include "transport/transport-factory-id.h" + +/* TransportFactory is an interface for representing + * concrete TransportFactory instances + * Each TransportFactory has + * - a reference to a unique id + * - a construct method for creating new LogTransport instances + * - a destroy method for releasing resources that are needed for construct() + */ +typedef struct _TransportFactory TransportFactory; + +struct _TransportFactory +{ + const TransportFactoryId *id; + LogTransport *(*construct_transport)(const TransportFactory *self, gint fd); + void (*free_fn)(TransportFactory *self); +}; + +static inline LogTransport +*transport_factory_construct_transport(const TransportFactory *self, gint fd) +{ + g_assert(self->construct_transport); + + LogTransport *transport = self->construct_transport(self, fd); + transport->name = transport_factory_id_get_transport_name(self->id); + + return transport; +} + +static inline void +transport_factory_free(TransportFactory *self) +{ + if (self->free_fn) + self->free_fn(self); + g_free(self); +} + +static inline const +TransportFactoryId *transport_factory_get_id(const TransportFactory *self) +{ + /* each concrete TransportFactory has to have an id + */ + g_assert(self->id); + return self->id; +} + +#endif diff --git a/modules/afsocket/transport-mapper-inet.c b/modules/afsocket/transport-mapper-inet.c index 3f5acc0c60a..11c1a422b79 100644 --- a/modules/afsocket/transport-mapper-inet.c +++ b/modules/afsocket/transport-mapper-inet.c @@ -26,6 +26,9 @@ #include "messages.h" #include "stats/stats-registry.h" #include "transport/transport-tls.h" +#include "transport/multitransport.h" +#include "transport/transport-factory-tls.h" +#include "transport/transport-factory-socket.h" #include "secret-storage/secret-storage.h" #include @@ -83,24 +86,51 @@ transport_mapper_inet_apply_transport_method(TransportMapper *s, GlobalConfig *c return transport_mapper_inet_validate_tls_options(self); } +static LogTransport * +_construct_tls_transport(TransportMapperInet *self, gint fd) +{ + LogTransport *transport = NULL; + TLSSession *tls_session = tls_context_setup_session(self->tls_context); + if (!tls_session) + return NULL; + + tls_session_set_verify(tls_session, self->tls_verify_callback, self->tls_verify_data, NULL); + transport = log_transport_tls_new(tls_session, fd); + + return transport; +} + +static LogTransport * +_construct_multitransport_with_plain_and_tls_factories(TransportMapperInet *self, gint fd) +{ + LogTransport *transport = NULL; + + TransportFactory *default_factory = transport_factory_socket_new(self->super.sock_type); + transport = multitransport_new(default_factory, fd); + TransportFactory *tls_factory = transport_factory_tls_new(self->tls_context, + self->tls_verify_callback, + self->tls_verify_data); + multitransport_add_factory((MultiTransport *)transport, tls_factory); + + return transport; +} + static LogTransport * transport_mapper_inet_construct_log_transport(TransportMapper *s, gint fd) { TransportMapperInet *self = (TransportMapperInet *) s; - if (self->tls_context) + if (self->tls_context && _is_tls_allowed(self)) { - TLSSession *tls_session; - - tls_session = tls_context_setup_session(self->tls_context); - if (!tls_session) - return NULL; + return _construct_tls_transport(self, fd); + } - tls_session_set_verify(tls_session, self->tls_verify_callback, self->tls_verify_data, NULL); - return log_transport_tls_new(tls_session, fd); + if (self->tls_context) + { + return _construct_multitransport_with_plain_and_tls_factories(self, fd); } - else - return transport_mapper_construct_log_transport_method(s, fd); + + return transport_mapper_construct_log_transport_method(s, fd); } static gboolean @@ -335,7 +365,23 @@ transport_mapper_network_apply_transport(TransportMapper *s, GlobalConfig *cfg) self->super.sock_proto = IPPROTO_TCP; /* FIXME: look up port/protocol from the logproto */ self->server_port = TCP_PORT; - self->allow_tls = TRUE; + if (!transport) + { + /* + * THIS CASE IS FOR SUPPORTING TLS IN LEGACY TCP DRIVER + * example: source s_inetssl { + * tcp(port(5555) + * tls(peer-verify(none) + * cert-file("ssl.crt") + * key-file(ssl.key"))); + * }; + * + * When transport("plugin") is used with with a valid TLSContext, + * Multitransport is used, this is why allow_tls is set only when + * transport() is not used. + * */ + self->allow_tls = TRUE; + } } g_assert(self->server_port != 0);