| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*************************************************************************
- *
- * Copyright (C) 2018-2023 Ruilin Peng (Nick) <[email protected]>.
- *
- * smartdns is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * smartdns 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "dns_plugin.h"
- #include "include/conf.h"
- #include "include/hashtable.h"
- #include "include/list.h"
- #include "util.h"
- #include <dlfcn.h>
- #include <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "tlog.h"
- struct dns_plugin_ops {
- struct list_head list;
- struct smartdns_operations ops;
- };
- #define DNS_PLUGIN_MAX_ARGS 32
- struct dns_plugin {
- struct hlist_node node;
- char file[PATH_MAX];
- char args[PATH_MAX];
- int argc;
- char *argv[DNS_PLUGIN_MAX_ARGS];
- void *handle;
- dns_plugin_init_func init_func;
- dns_plugin_exit_func exit_func;
- };
- struct dns_plugins {
- struct list_head list;
- DECLARE_HASHTABLE(plugin, 4);
- };
- static struct dns_plugins plugins;
- static int is_plugin_init;
- int smartdns_plugin_func_server_recv(struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
- struct sockaddr_storage *local, socklen_t local_len, struct sockaddr_storage *from,
- socklen_t from_len)
- {
- struct dns_plugin_ops *chain = NULL;
- int ret = 0;
- list_for_each_entry(chain, &plugins.list, list)
- {
- if (!chain->ops.server_recv) {
- continue;
- }
- ret = chain->ops.server_recv(packet, inpacket, inpacket_len, local, local_len, from, from_len);
- if (ret != 0) {
- return ret;
- }
- }
- return 0;
- }
- void smartdns_plugin_func_server_complete_request(struct dns_request *request)
- {
- struct dns_plugin_ops *chain = NULL;
- list_for_each_entry(chain, &plugins.list, list)
- {
- if (!chain->ops.server_query_complete) {
- continue;
- }
- chain->ops.server_query_complete(request);
- }
- return;
- }
- int smartdns_operations_register(struct smartdns_operations *operations)
- {
- struct dns_plugin_ops *chain = NULL;
- chain = (struct dns_plugin_ops *)malloc(sizeof(struct dns_plugin_ops));
- if (!chain) {
- return -1;
- }
- memcpy(&chain->ops, operations, sizeof(struct smartdns_operations));
- list_add_tail(&chain->list, &plugins.list);
- return 0;
- }
- int smartdns_operations_unregister(struct smartdns_operations *operations)
- {
- struct dns_plugin_ops *chain = NULL;
- struct dns_plugin_ops *tmp = NULL;
- list_for_each_entry_safe(chain, tmp, &plugins.list, list)
- {
- if (memcmp(&chain->ops, operations, sizeof(struct smartdns_operations)) == 0) {
- list_del(&chain->list);
- free(chain);
- return 0;
- }
- }
- return -1;
- }
- static struct dns_plugin *_dns_plugin_get(const char *plugin_file)
- {
- struct dns_plugin *plugin = NULL;
- unsigned int key = 0;
- key = hash_string(plugin_file);
- hash_for_each_possible(plugins.plugin, plugin, node, key)
- {
- if (strncmp(plugin->file, plugin_file, PATH_MAX - 1) == 0) {
- return plugin;
- }
- }
- return NULL;
- }
- static int _dns_plugin_load_library(struct dns_plugin *plugin)
- {
- void *handle = NULL;
- dns_plugin_init_func init_func = NULL;
- dns_plugin_exit_func exit_func = NULL;
- handle = dlopen(plugin->file, RTLD_LAZY | RTLD_LOCAL);
- if (!handle) {
- tlog(TLOG_ERROR, "load plugin %s failed: %s", plugin->file, dlerror());
- return -1;
- }
- init_func = (dns_plugin_init_func)dlsym(handle, DNS_PLUGIN_INIT_FUNC);
- if (!init_func) {
- tlog(TLOG_ERROR, "load plugin %s failed: %s", plugin->file, dlerror());
- goto errout;
- }
- exit_func = (dns_plugin_exit_func)dlsym(handle, DNS_PLUGIN_EXIT_FUNC);
- if (!exit_func) {
- tlog(TLOG_ERROR, "load plugin %s failed: %s", plugin->file, dlerror());
- goto errout;
- }
- conf_getopt_reset();
- int ret = init_func(plugin);
- conf_getopt_reset();
- if (ret != 0) {
- tlog(TLOG_ERROR, "init plugin %s failed", plugin->file);
- goto errout;
- }
- plugin->handle = handle;
- plugin->init_func = init_func;
- plugin->exit_func = exit_func;
- return 0;
- errout:
- if (handle) {
- dlclose(handle);
- }
- return -1;
- }
- static int _dns_plugin_unload_library(struct dns_plugin *plugin)
- {
- int ret = 0;
- if (plugin->exit_func) {
- ret = plugin->exit_func(plugin);
- if (ret != 0) {
- tlog(TLOG_ERROR, "exit plugin %s failed", plugin->file);
- }
- }
- if (plugin->handle) {
- dlclose(plugin->handle);
- plugin->handle = NULL;
- }
- return 0;
- }
- static struct dns_plugin *_dns_plugin_new(const char *plugin_file)
- {
- struct dns_plugin *plugin = NULL;
- plugin = _dns_plugin_get(plugin_file);
- if (plugin) {
- return NULL;
- }
- plugin = (struct dns_plugin *)malloc(sizeof(struct dns_plugin));
- if (!plugin) {
- return NULL;
- }
- memset(plugin, 0, sizeof(struct dns_plugin));
- strncpy(plugin->file, plugin_file, PATH_MAX - 1);
- return plugin;
- }
- static int _dns_plugin_remove(struct dns_plugin *plugin)
- {
- _dns_plugin_unload_library(plugin);
- hash_del(&plugin->node);
- free(plugin);
- return 0;
- }
- int dns_plugin_get_argc(struct dns_plugin *plugin)
- {
- return plugin->argc;
- }
- const char **dns_plugin_get_argv(struct dns_plugin *plugin)
- {
- return (const char **)plugin->argv;
- }
- int dns_plugin_add(const char *plugin_file, int argc, const char *args, int args_len)
- {
- struct dns_plugin *plugin = NULL;
- const char *plugin_args = NULL;
- plugin = _dns_plugin_new(plugin_file);
- if (!plugin) {
- tlog(TLOG_ERROR, "add plugin %s failed", plugin_file);
- return -1;
- }
- memcpy(plugin->args, args, PATH_MAX - 1);
- plugin->argc = argc;
- plugin_args = plugin->args;
- for (int i = 0; i < argc && i < DNS_PLUGIN_MAX_ARGS; i++) {
- plugin->argv[i] = (char *)plugin_args;
- plugin_args += strlen(plugin_args) + 1;
- }
- if (_dns_plugin_load_library(plugin) != 0) {
- goto errout;
- }
- hash_add(plugins.plugin, &plugin->node, hash_string(plugin_file));
- return 0;
- errout:
- if (plugin) {
- _dns_plugin_remove(plugin);
- }
- return -1;
- }
- int dns_plugin_remove(const char *plugin_file)
- {
- struct dns_plugin *plugin = NULL;
- plugin = _dns_plugin_get(plugin_file);
- if (plugin == NULL) {
- return 0;
- }
- return _dns_plugin_remove(plugin);
- }
- static int _dns_plugin_remove_all_ops(void)
- {
- struct dns_plugin_ops *chain = NULL;
- struct dns_plugin_ops *tmp = NULL;
- list_for_each_entry_safe(chain, tmp, &plugins.list, list)
- {
- list_del(&chain->list);
- free(chain);
- }
- return 0;
- }
- static int _dns_plugin_remove_all(void)
- {
- struct dns_plugin *plugin = NULL;
- struct hlist_node *tmp = NULL;
- unsigned int key = 0;
- hash_for_each_safe(plugins.plugin, key, tmp, plugin, node)
- {
- _dns_plugin_remove(plugin);
- }
- return -1;
- }
- int dns_server_plugin_init(void)
- {
- if (is_plugin_init == 1) {
- return 0;
- }
- hash_init(plugins.plugin);
- INIT_LIST_HEAD(&plugins.list);
- is_plugin_init = 1;
- return 0;
- }
- void dns_server_plugin_exit(void)
- {
- if (is_plugin_init == 0) {
- return;
- }
- _dns_plugin_remove_all_ops();
- _dns_plugin_remove_all();
- return;
- }
- void smartdns_plugin_log(smartdns_log_level level, const char *file, int line, const char *func, const char *msg)
- {
- tlog_ext((tlog_level)level, file, line, func, NULL, "%s", msg);
- }
|