20 #include <dnscrypt/plugin.h>
24 #include "plugin_support.h"
25 #include "plugin_support_p.h"
29 plugin_support_add_option(DCPluginSupport
* const dcps
, char * const arg
)
33 if (dcps
->argc
>= INT_MAX
) {
36 if (SIZE_MAX
/ sizeof *argv
<= (unsigned int) (dcps
->argc
+ 2U) ||
37 (argv
= realloc(dcps
->argv
, (unsigned int) (dcps
->argc
+ 2U) *
38 sizeof *argv
)) == NULL
) {
41 argv
[dcps
->argc
++] = arg
;
42 argv
[dcps
->argc
] = NULL
;
49 plugin_support_load_symbol(DCPluginSupport
* const dcps
,
50 const char * const symbol
)
52 assert(dcps
->handle
!= NULL
);
54 return lt_dlsym(dcps
->handle
, symbol
);
58 plugin_support_load_symbol_err(DCPluginSupport
* const dcps
,
59 const char * const symbol
)
63 if ((fn
= plugin_support_load_symbol(dcps
, symbol
)) == NULL
) {
64 logger(NULL
, LOG_ERR
, "Plugin: symbol [%s] not found in [%s]",
65 symbol
, dcps
->plugin_file
);
71 plugin_support_description(DCPluginSupport
* const dcps
)
73 DCPluginDescription dcplugin_description
;
74 const char *description
;
77 if ((dcplugin_description
=
78 plugin_support_load_symbol(dcps
, "dcplugin_description")) == NULL
) {
81 if ((description
= dcplugin_description(dcps
->plugin
)) == NULL
||
89 plugin_support_call_init(DCPluginSupport
* const dcps
)
91 DCPluginInit dcplugin_init
;
92 const char *description
;
95 plugin_support_load_symbol_err(dcps
, "dcplugin_init")) == NULL
) {
98 assert(dcps
->argc
> 0 && dcps
->argv
!= NULL
);
99 if (dcplugin_init(dcps
->plugin
, dcps
->argc
, dcps
->argv
) != 0) {
100 logger(NULL
, LOG_ERR
, "Unable to initialize plugin [%s]",
104 dcps
->sync_post_filter
=
105 plugin_support_load_symbol(dcps
, "dcplugin_sync_post_filter");
106 dcps
->sync_pre_filter
=
107 plugin_support_load_symbol(dcps
, "dcplugin_sync_pre_filter");
108 if ((description
= plugin_support_description(dcps
)) == NULL
) {
109 logger_noformat(NULL
, LOG_INFO
, "Plugin loaded");
111 logger(NULL
, LOG_INFO
, "Loaded plugin: [%s]", description
);
117 plugin_support_check_permissions(const char * const plugin_file
)
119 assert(plugin_file
!= NULL
);
124 if (stat(plugin_file
, &st
) != 0 || !S_ISREG(st
.st_mode
)) {
127 # ifndef RELAXED_PLUGINS_PERMISSIONS
128 const uid_t uid
= getuid();
130 if (st
.st_uid
!= (uid_t
) 0) {
131 if (uid
== (uid_t
) 0) {
135 if (access(plugin_file
, W_OK
) != 0) {
146 plugin_support_load(DCPluginSupport
* const dcps
)
151 assert(dcps
!= NULL
&& dcps
->plugin_file
!= NULL
);
152 assert(dcps
->handle
== NULL
);
153 if (lt_dladvise_init(&advise
) != 0) {
156 lt_dladvise_local(&advise
);
157 lt_dladvise_ext(&advise
);
158 logger(NULL
, LOG_INFO
, "Loading plugin [%s]", dcps
->plugin_file
);
160 if (plugin_support_check_permissions(dcps
->plugin_file
) != 0) {
161 logger(NULL
, LOG_ERR
, "Plugin [%s] can't be loaded: [%s]",
162 dcps
->plugin_file
, strerror(errno
));
163 lt_dladvise_destroy(&advise
);
166 if ((handle
= lt_dlopenadvise(dcps
->plugin_file
, advise
)) == NULL
) {
167 logger(NULL
, LOG_ERR
, "Unable to load [%s]: [%s]",
168 dcps
->plugin_file
, lt_dlerror());
169 lt_dladvise_destroy(&advise
);
172 lt_dladvise_destroy(&advise
);
173 dcps
->handle
= handle
;
175 return plugin_support_call_init(dcps
);
179 plugin_support_unload(DCPluginSupport
* const dcps
)
181 DCPluginDestroy dcplugin_destroy
;
183 if (dcps
->handle
== NULL
) {
186 dcplugin_destroy
= plugin_support_load_symbol(dcps
, "dcplugin_destroy");
187 if (dcplugin_destroy
!= NULL
) {
188 dcplugin_destroy(dcps
->plugin
);
190 if (lt_dlclose(dcps
->handle
) != 0) {
199 plugin_support_expand_plugin_file(const char * const plugin_file
)
201 char *expanded_plugin_file
;
202 size_t plugin_file_len
;
203 size_t plugins_root_len
= sizeof PLUGINS_ROOT
- (size_t) 1U;
204 size_t sizeof_expanded_plugin_file
;
206 #ifdef ENABLE_PLUGINS_ROOT
207 if (strstr(plugin_file
, "..") != NULL
|| *plugin_file
== '/') {
210 if (strncmp(plugin_file
, PLUGINS_ROOT
, plugins_root_len
) == 0) {
211 return strdup(plugin_file
);
215 const char *chr_column
;
216 const char *chr_pathsep
;
218 if (((chr_pathsep
= strchr(plugin_file
, '/')) != NULL
||
219 (chr_pathsep
= strchr(plugin_file
, '\\')) != NULL
) &&
220 (chr_pathsep
== plugin_file
||
221 ((chr_column
= strchr(plugin_file
, ':')) != NULL
&&
222 chr_column
- plugin_file
< chr_pathsep
- plugin_file
))) {
223 return strdup(plugin_file
);
226 if (*plugin_file
== '/') {
227 return strdup(plugin_file
);
231 plugin_file_len
= strlen(plugin_file
);
232 assert(SIZE_MAX
- plugins_root_len
> plugin_file_len
);
233 sizeof_expanded_plugin_file
= plugins_root_len
+ plugin_file_len
+ 1U;
234 if ((expanded_plugin_file
= malloc(sizeof_expanded_plugin_file
)) == NULL
) {
237 memcpy(expanded_plugin_file
, PLUGINS_ROOT
, plugins_root_len
);
238 memcpy(expanded_plugin_file
+ plugins_root_len
, plugin_file
,
239 plugin_file_len
+ 1U);
241 return expanded_plugin_file
;
245 plugin_support_new(const char * const plugin_file
)
247 DCPluginSupport
*dcps
;
249 if ((dcps
= calloc((size_t) 1U, sizeof *dcps
)) == NULL
) {
252 if ((dcps
->plugin
= calloc((size_t) 1U, sizeof *dcps
->plugin
)) == NULL
) {
256 assert(plugin_file
!= NULL
&& *plugin_file
!= 0);
257 if ((dcps
->plugin_file
=
258 plugin_support_expand_plugin_file(plugin_file
)) == NULL
) {
264 dcps
->sync_post_filter
= NULL
;
265 dcps
->sync_pre_filter
= NULL
;
271 plugin_support_free(DCPluginSupport
* const dcps
)
273 plugin_support_unload(dcps
);
274 assert(dcps
->plugin_file
!= NULL
&& *dcps
->plugin_file
!= 0);
275 assert(dcps
->plugin
!= NULL
);
277 free(dcps
->plugin_file
);
278 dcps
->plugin_file
= NULL
;
284 DCPluginSupportContext
*
285 plugin_support_context_new(void)
287 DCPluginSupportContext
*dcps_context
;
289 if ((dcps_context
= calloc((size_t) 1U, sizeof *dcps_context
)) == NULL
) {
292 SLIST_INIT(&dcps_context
->dcps_list
);
298 plugin_support_context_insert(DCPluginSupportContext
* const dcps_context
,
299 DCPluginSupport
* const dcps
)
301 assert(dcps_context
!= NULL
);
302 assert(dcps
!= NULL
);
303 SLIST_INSERT_HEAD(&dcps_context
->dcps_list
, dcps
, next
);
309 plugin_support_context_remove(DCPluginSupportContext
* const dcps_context
,
310 DCPluginSupport
* const dcps
)
312 assert(! SLIST_EMPTY(&dcps_context
->dcps_list
));
313 SLIST_REMOVE(&dcps_context
->dcps_list
, dcps
, DCPluginSupport_
, next
);
319 plugin_support_context_free(DCPluginSupportContext
* const dcps_context
)
321 DCPluginSupport
*dcps
;
322 DCPluginSupport
*dcps_tmp
;
324 SLIST_FOREACH_SAFE(dcps
, &dcps_context
->dcps_list
, next
, dcps_tmp
) {
325 plugin_support_free(dcps
);
327 if (dcps_context
->lt_enabled
!= 0) {
334 plugin_support_context_load(DCPluginSupportContext
* const dcps_context
)
336 DCPluginSupport
*dcps
;
339 assert(dcps_context
!= NULL
);
340 if (dcps_context
->lt_enabled
== 0 && lt_dlinit() != 0) {
343 SLIST_FOREACH(dcps
, &dcps_context
->dcps_list
, next
) {
344 if (plugin_support_load(dcps
) != 0) {
354 static DCPluginSyncFilterResult
355 plugin_support_context_get_result_from_dcps(DCPluginSyncFilterResult result
,
356 DCPluginSyncFilterResult result_dcps
)
358 switch (result_dcps
) {
359 case DCP_SYNC_FILTER_RESULT_OK
:
361 case DCP_SYNC_FILTER_RESULT_DIRECT
:
362 if (result
== DCP_SYNC_FILTER_RESULT_OK
) {
363 result
= DCP_SYNC_FILTER_RESULT_DIRECT
;
366 case DCP_SYNC_FILTER_RESULT_KILL
:
367 if (result
== DCP_SYNC_FILTER_RESULT_OK
) {
368 result
= DCP_SYNC_FILTER_RESULT_KILL
;
371 case DCP_SYNC_FILTER_RESULT_ERROR
:
372 if (result
!= DCP_SYNC_FILTER_RESULT_FATAL
) {
373 result
= DCP_SYNC_FILTER_RESULT_ERROR
;
376 case DCP_SYNC_FILTER_RESULT_FATAL
:
378 result
= DCP_SYNC_FILTER_RESULT_FATAL
;
383 DCPluginSyncFilterResult
384 plugin_support_context_apply_sync_post_filters(DCPluginSupportContext
*dcps_context
,
385 DCPluginDNSPacket
*dcp_packet
)
387 DCPluginSupport
*dcps
;
388 const size_t dns_packet_max_len
= dcp_packet
->dns_packet_max_len
;
389 DCPluginSyncFilterResult result
= DCP_SYNC_FILTER_RESULT_OK
;
390 DCPluginSyncFilterResult result_dcps
;
392 assert(dcp_packet
->dns_packet
!= NULL
&&
393 dcp_packet
->dns_packet_len_p
!= NULL
&&
394 *dcp_packet
->dns_packet_len_p
> (size_t) 0U);
395 SLIST_FOREACH(dcps
, &dcps_context
->dcps_list
, next
) {
396 if (dcps
->sync_post_filter
!= NULL
) {
397 result_dcps
= dcps
->sync_post_filter(dcps
->plugin
, dcp_packet
);
398 result
= plugin_support_context_get_result_from_dcps(result
,
400 assert(*dcp_packet
->dns_packet_len_p
<= dns_packet_max_len
);
401 assert(*dcp_packet
->dns_packet_len_p
> (size_t) 0U);
407 DCPluginSyncFilterResult
408 plugin_support_context_apply_sync_pre_filters(DCPluginSupportContext
*dcps_context
,
409 DCPluginDNSPacket
*dcp_packet
)
411 DCPluginSupport
*dcps
;
412 const size_t dns_packet_max_len
= dcp_packet
->dns_packet_max_len
;
413 DCPluginSyncFilterResult result
= DCP_SYNC_FILTER_RESULT_OK
;
414 DCPluginSyncFilterResult result_dcps
;
416 assert(dcp_packet
->dns_packet
!= NULL
&&
417 dcp_packet
->dns_packet_len_p
!= NULL
&&
418 *dcp_packet
->dns_packet_len_p
> (size_t) 0U);
419 SLIST_FOREACH(dcps
, &dcps_context
->dcps_list
, next
) {
420 if (dcps
->sync_pre_filter
!= NULL
) {
421 result_dcps
= dcps
->sync_pre_filter(dcps
->plugin
, dcp_packet
);
422 result
= plugin_support_context_get_result_from_dcps(result
,
425 assert(*dcp_packet
->dns_packet_len_p
<= dns_packet_max_len
);
426 assert(*dcp_packet
->dns_packet_len_p
> (size_t) 0U);