From a2a19b273105c71da1d10d54bfa93cb1e56df56a Mon Sep 17 00:00:00 2001 From: Ludovic Ferrandis Date: Wed, 21 Aug 2013 14:18:17 +0200 Subject: [Network Filtering] Add Network Filtering support Add Network Filtering support in dLeyna. Add API to the core library to manage the GUPnPWhiteList object Manage 2 new settings: 1 - netf_enabled (boolean): To activate or deactivate the network filtering 2 - netf_entries (str list): List of supported network Signed-off-by: Ludovic Ferrandis --- Makefile.am | 8 ++- configure.ac | 4 +- libdleyna/core/settings.c | 157 ++++++++++++++++++++++++++++++++++++++++++-- libdleyna/core/settings.h | 4 ++ libdleyna/core/white-list.c | 125 +++++++++++++++++++++++++++++++++++ libdleyna/core/white-list.h | 50 ++++++++++++++ 6 files changed, 338 insertions(+), 10 deletions(-) create mode 100644 libdleyna/core/white-list.c create mode 100644 libdleyna/core/white-list.h diff --git a/Makefile.am b/Makefile.am index c166e83..9fc4360 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ libdleyna_coreincdir = $(includedir)/dleyna-1.0/libdleyna/core connectordir = $(libdir)/dleyna-1.0/connectors sysconfigdir = $(sysconfdir) -DLEYNA_CORE_VERSION = 1:2:0 +DLEYNA_CORE_VERSION = 2:0:1 AM_CFLAGS = $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \ @@ -25,7 +25,8 @@ libdleyna_coreinc_HEADERS = libdleyna/core/connector.h \ libdleyna/core/service-task.h \ libdleyna/core/settings.h \ libdleyna/core/task-atom.h \ - libdleyna/core/task-processor.h + libdleyna/core/task-processor.h \ + libdleyna/core/white-list.h libdleyna_core_1_0_la_LDFLAGS = -version-info $(DLEYNA_CORE_VERSION) \ @@ -38,7 +39,8 @@ libdleyna_core_1_0_la_SOURCES = $(libdleyna_coreinc_HEADERS) \ libdleyna/core/main-loop.c \ libdleyna/core/service-task.c \ libdleyna/core/settings.c \ - libdleyna/core/task-processor.c + libdleyna/core/task-processor.c \ + libdleyna/core/white-list.c libdleyna_core_1_0_la_LIBADD = $(GLIB_LIBS) \ $(GIO_LIBS) \ diff --git a/configure.ac b/configure.ac index 67dbcd2..d6a5af5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.66]) AC_INIT([dleyna-core], - [0.2.1], + [0.2.2], [https://github.com/01org/dleyna-core/issues/new], , [https://01.org/dleyna/]) @@ -39,7 +39,7 @@ PKG_PROG_PKG_CONFIG(0.16) PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.28]) PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.28]) PKG_CHECK_MODULES([GMODULE], [gmodule-2.0 >= 2.28]) -PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.19.1]) +PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.20.5]) # Checks for header files. AC_CHECK_HEADERS([stdlib.h string.h syslog.h]) diff --git a/libdleyna/core/settings.c b/libdleyna/core/settings.c index 701f527..c86ace9 100644 --- a/libdleyna/core/settings.c +++ b/libdleyna/core/settings.c @@ -25,6 +25,7 @@ #include "log.h" #include "settings.h" +#include "white-list.h" struct dleyna_settings_t_ { GKeyFile *keyfile; @@ -40,15 +41,23 @@ struct dleyna_settings_t_ { /* Log section */ dleyna_log_type_t log_type; int log_level; + + /* netf section */ + gboolean netf_enabled; + GVariant *netf_entries; }; #define DLEYNA_SETTINGS_GROUP_GENERAL "general" #define DLEYNA_SETTINGS_KEY_NEVER_QUIT "never-quit" #define DLEYNA_SETTINGS_KEY_CONNECTOR_NAME "connector-name" -#define DLEYNA_SETTINGS_GROUP_LOG "log" -#define DLEYNA_SETTINGS_KEY_LOG_TYPE "log-type" -#define DLEYNA_SETTINGS_KEY_LOG_LEVEL "log-level" +#define DLEYNA_SETTINGS_GROUP_LOG "log" +#define DLEYNA_SETTINGS_KEY_LOG_TYPE "log-type" +#define DLEYNA_SETTINGS_KEY_LOG_LEVEL "log-level" + +#define DLEYNA_SETTINGS_GROUP_NETF "netf" +#define DLEYNA_SETTINGS_KEY_NETF_ENABLED "netf-enabled" +#define DLEYNA_SETTINGS_KEY_NETF_LIST "netf-list" #define DLEYNA_SETTINGS_DEFAULT_NEVER_QUIT DLEYNA_NEVER_QUIT #define DLEYNA_SETTINGS_DEFAULT_CONNECTOR_NAME DLEYNA_CONNECTOR_NAME @@ -57,18 +66,30 @@ struct dleyna_settings_t_ { #define DLEYNA_SETTINGS_LOG_KEYS(sys, loc, settings) \ do { \ + gchar *str = NULL; \ + \ DLEYNA_LOG_DEBUG_NL(); \ DLEYNA_LOG_INFO("Load file [%s]", loc ? loc : sys); \ DLEYNA_LOG_DEBUG_NL(); \ + \ DLEYNA_LOG_DEBUG("[General settings]"); \ DLEYNA_LOG_DEBUG("Never Quit: %s", (settings)->never_quit ? "T" : "F");\ DLEYNA_LOG_DEBUG_NL(); \ DLEYNA_LOG_DEBUG("Connector Name: %s", (settings)->connector_name);\ DLEYNA_LOG_DEBUG_NL(); \ + \ DLEYNA_LOG_DEBUG("[Logging settings]"); \ DLEYNA_LOG_DEBUG("Log Type : %d", (settings)->log_type); \ DLEYNA_LOG_DEBUG("Log Level: 0x%02X", (settings)->log_level); \ DLEYNA_LOG_DEBUG_NL(); \ + \ + if ((settings)->netf_entries != NULL) \ + str = g_variant_print((settings)->netf_entries, FALSE); \ + DLEYNA_LOG_DEBUG("[Network filtering settings]"); \ + DLEYNA_LOG_DEBUG("Enabled : %s", (settings)->netf_enabled ? "T" : "F");\ + DLEYNA_LOG_DEBUG("Entries: %s", str); \ + g_free(str); \ + DLEYNA_LOG_DEBUG_NL(); \ } while (0) @@ -148,6 +169,25 @@ exit: return keyfile; } +static GVariant *prv_to_netf_entries(char **list) +{ + GVariantBuilder vb; + GVariant *result = NULL; + + if ((list != NULL) && (*list != NULL)) { + g_variant_builder_init(&vb, G_VARIANT_TYPE("as")); + + while (*list != NULL) { + g_variant_builder_add(&vb, "s", *list); + list++; + } + + result = g_variant_ref_sink(g_variant_builder_end(&vb)); + } + + return result; +} + static int prv_to_log_level(gint *int_list, gsize length) { gsize i; @@ -205,6 +245,7 @@ static void prv_read_keys(dleyna_settings_t *settings) gchar *s_val; gint *int_star; gsize length; + gchar **list; b_val = g_key_file_get_boolean(keyfile, DLEYNA_SETTINGS_GROUP_GENERAL, @@ -252,13 +293,38 @@ static void prv_read_keys(dleyna_settings_t *settings) &error); if (error == NULL) { - settings->log_level = prv_to_log_level(int_star, - length); + settings->log_level = prv_to_log_level(int_star, length); g_free(int_star); } else { g_error_free(error); error = NULL; } + + b_val = g_key_file_get_boolean(keyfile, + DLEYNA_SETTINGS_GROUP_NETF, + DLEYNA_SETTINGS_KEY_NETF_ENABLED, + &error); + + if (error == NULL) { + settings->netf_enabled = b_val; + } else { + g_error_free(error); + error = NULL; + } + + list = g_key_file_get_string_list(keyfile, + DLEYNA_SETTINGS_GROUP_NETF, + DLEYNA_SETTINGS_KEY_NETF_LIST, + NULL, + &error); + + if (error == NULL) { + settings->netf_entries = prv_to_netf_entries(list); + g_strfreev(list); + } else { + g_error_free(error); + error = NULL; + } } static void prv_init_default(dleyna_settings_t *settings) @@ -269,6 +335,9 @@ static void prv_init_default(dleyna_settings_t *settings) settings->log_type = DLEYNA_SETTINGS_DEFAULT_LOG_TYPE; settings->log_level = DLEYNA_SETTINGS_DEFAULT_LOG_LEVEL; + + settings->netf_enabled = FALSE; + settings->netf_entries = NULL; } static void prv_keyfile_init(dleyna_settings_t *settings, @@ -289,19 +358,64 @@ static void prv_keyfile_init(dleyna_settings_t *settings, static void prv_keyfile_finalize(dleyna_settings_t *settings) { + if (settings->netf_entries != NULL) { + g_variant_unref(settings->netf_entries); + settings->netf_entries = NULL; + } + if (settings->keyfile != NULL) { g_key_file_free(settings->keyfile); settings->keyfile = NULL; } } +static gboolean prv_netf_entries_are_equal(GVariant *old, GVariant *new) +{ + gboolean match; + GVariantIter iter1; + GVariantIter iter2; + gchar *entry1; + gchar *entry2; + + match = (old == new); + + if (match || + ((old == NULL) && (new != NULL)) || + ((old != NULL) && (new == NULL))) + goto exit; + + (void) g_variant_iter_init(&iter1, old); + + while (g_variant_iter_next(&iter1, "&s", &entry1)) { + (void) g_variant_iter_init(&iter2, new); + + while (g_variant_iter_next(&iter2, "&s", &entry2) && !match) + match = !strcmp(entry1, entry2); + + if (!match) + break; + } + +exit: + return match; +} + static void prv_reload(dleyna_settings_t *settings) { gchar *sys_path = NULL; gchar *loc_path = NULL; + gboolean saved_netf_enabled; + GVariant *saved_netf_entries; + GVariant *netf_entries; DLEYNA_LOG_INFO("Reload local configuration file"); + /* Save all White List information */ + saved_netf_enabled = settings->netf_enabled; + saved_netf_entries = settings->netf_entries; + /* Prevent prv_keyfile_finalize()) to free it */ + settings->netf_entries = NULL; + prv_keyfile_finalize(settings); prv_init_default(settings); prv_get_keyfile_path(settings->file_name, &sys_path, &loc_path); @@ -309,6 +423,32 @@ static void prv_reload(dleyna_settings_t *settings) if (sys_path || loc_path) prv_keyfile_init(settings, sys_path, loc_path); + netf_entries = settings->netf_entries; + + /* FIXME: Block white list signals instead */ + /* A little optimization hack: + * 1 - Updating the wl list has no effect if the wl is disabled. + * 2 - If the enabled settings has changed to disabled, apply first. + * 3 - If it has changed to enabled, update the list first, then + * apply the change last. + */ + if (!settings->netf_enabled && saved_netf_enabled) + dleyna_white_list_enable(settings->netf_enabled, TRUE); + + /* Remove old entries if new ones are different. + * Don't clear() to avoid to loose entries added by a client + */ + if (!prv_netf_entries_are_equal(saved_netf_entries, netf_entries)) { + dleyna_white_list_remove_entries(saved_netf_entries, FALSE); + dleyna_white_list_add_entries(netf_entries, TRUE); + } + + if (settings->netf_enabled && !saved_netf_enabled) + dleyna_white_list_enable(settings->netf_enabled, TRUE); + + if (saved_netf_entries != NULL) + g_variant_unref(saved_netf_entries); + DLEYNA_SETTINGS_LOG_KEYS(sys_path, loc_path, settings); g_free(sys_path); @@ -430,6 +570,7 @@ void dleyna_settings_delete(dleyna_settings_t *settings) g_file_monitor_cancel(settings->monitor); g_object_unref(settings->monitor); } + g_free(settings->connector_name); g_free(settings->file_name); @@ -437,3 +578,9 @@ void dleyna_settings_delete(dleyna_settings_t *settings) g_free(settings); } + +void dleyna_settings_init_white_list(dleyna_settings_t *settings) +{ + dleyna_white_list_add_entries(settings->netf_entries, TRUE); + dleyna_white_list_enable(settings->netf_enabled, TRUE); +} diff --git a/libdleyna/core/settings.h b/libdleyna/core/settings.h index 4274879..b09456f 100644 --- a/libdleyna/core/settings.h +++ b/libdleyna/core/settings.h @@ -28,9 +28,13 @@ typedef struct dleyna_settings_t_ dleyna_settings_t; void dleyna_settings_new(const gchar *server, dleyna_settings_t **settings); + void dleyna_settings_delete(dleyna_settings_t *settings); +void dleyna_settings_init_white_list(dleyna_settings_t *settings); + gboolean dleyna_settings_is_never_quit(dleyna_settings_t *settings); + const gchar *dleyna_settings_connector_name(dleyna_settings_t *settings); #endif /* DLEYNA_SETTINGS_H__ */ diff --git a/libdleyna/core/white-list.c b/libdleyna/core/white-list.c new file mode 100644 index 0000000..fa5d2d0 --- /dev/null +++ b/libdleyna/core/white-list.c @@ -0,0 +1,125 @@ +/* + * dLeyna + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Ludovic Ferrandis + * + */ + +#include + +#include "white-list.h" +#include "log.h" + +static dleyna_white_list_t g_wl_cb; + +#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG +static void prv_dump_wl_entries(GUPnPWhiteList *wl) +{ + GList *l; + + l = gupnp_white_list_get_entries(wl); + + DLEYNA_LOG_DEBUG_NL(); + DLEYNA_LOG_DEBUG("White List entries:"); + + if (l != NULL) { + while (l != NULL) { + DLEYNA_LOG_DEBUG(" Entry: [%s].", (char *)l->data); + l = l->next; + } + } else { + DLEYNA_LOG_DEBUG(" White List Empty."); + } + + DLEYNA_LOG_DEBUG_NL(); +} +#endif + +void dleyna_white_list_enable(gboolean enabled, gboolean notify) +{ + if (g_wl_cb.wl != NULL) { + gupnp_white_list_set_enabled(g_wl_cb.wl, enabled); + + DLEYNA_LOG_DEBUG("White List enabled: %d", enabled); + + if (notify && (g_wl_cb.cb_enabled != NULL)) + g_wl_cb.cb_enabled(g_wl_cb.user_data); + } +} + +void dleyna_white_list_add_entries(GVariant *entries, gboolean notify) +{ + GVariantIter viter; + gchar *entry; + + if ((entries != NULL) && (g_wl_cb.wl != NULL)) { + (void) g_variant_iter_init(&viter, entries); + + while (g_variant_iter_next(&viter, "&s", &entry)) + (void) gupnp_white_list_add_entry(g_wl_cb.wl, entry); + +#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG + prv_dump_wl_entries(g_wl_cb.wl); +#endif + + if (notify && (g_wl_cb.cb_entries != NULL)) + g_wl_cb.cb_entries(g_wl_cb.user_data); + } +} + +void dleyna_white_list_remove_entries(GVariant *entries, gboolean notify) +{ + GVariantIter viter; + gchar *entry; + + if ((entries != NULL) && (g_wl_cb.wl != NULL)) { + (void) g_variant_iter_init(&viter, entries); + + while (g_variant_iter_next(&viter, "&s", &entry)) + (void) gupnp_white_list_remove_entry(g_wl_cb.wl, entry); + +#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG + prv_dump_wl_entries(g_wl_cb.wl); +#endif + + if (notify && (g_wl_cb.cb_entries != NULL)) + g_wl_cb.cb_entries(g_wl_cb.user_data); + } +} + +void dleyna_white_list_clear(gboolean notify) +{ + if (g_wl_cb.wl != NULL) { + gupnp_white_list_clear(g_wl_cb.wl); + +#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG + prv_dump_wl_entries(g_wl_cb.wl); +#endif + + if (notify && (g_wl_cb.cb_entries != NULL)) + g_wl_cb.cb_entries(g_wl_cb.user_data); + } +} + +void dleyna_white_list_set_info(dleyna_white_list_t *data) +{ + if (data != NULL) + memcpy(&g_wl_cb, data, sizeof(dleyna_white_list_t)); + else + memset(&g_wl_cb, 0, sizeof(dleyna_white_list_t)); +} diff --git a/libdleyna/core/white-list.h b/libdleyna/core/white-list.h new file mode 100644 index 0000000..a0e760e --- /dev/null +++ b/libdleyna/core/white-list.h @@ -0,0 +1,50 @@ +/* + * dLeyna + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Ludovic Ferrandis + * + */ + +#ifndef DLEYNA_WHITE_LIST_H__ +#define DLEYNA_WHITE_LIST_H__ + +#include +#include + +typedef void (*dleyna_white_list_notify_t)(gpointer user_data); + +typedef struct dleyna_white_list_t_ dleyna_white_list_t; + +struct dleyna_white_list_t_ { + GUPnPWhiteList *wl; + dleyna_white_list_notify_t cb_enabled; + dleyna_white_list_notify_t cb_entries; + gpointer user_data; +}; + +void dleyna_white_list_enable(gboolean enabled, gboolean notify); + +void dleyna_white_list_add_entries(GVariant *entries, gboolean notify); + +void dleyna_white_list_remove_entries(GVariant *entries, gboolean notify); + +void dleyna_white_list_clear(gboolean notify); + +void dleyna_white_list_set_info(dleyna_white_list_t *data); + +#endif /* DLEYNA_WHITE_LIST_H__ */ -- cgit v1.2.1