Merge pull request #4639 from opensourcerouting/c-ares-lib

make c-ares DNS resolver available as lib
This commit is contained in:
Quentin Young 2019-07-03 16:49:19 -04:00 committed by GitHub
commit c682502cd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 131 additions and 61 deletions

View File

@ -1560,7 +1560,7 @@ if test "${NHRPD}" != ""; then
AC_MSG_ERROR([trying to build nhrpd, but libcares not found. install c-ares and its -dev headers.]) AC_MSG_ERROR([trying to build nhrpd, but libcares not found. install c-ares and its -dev headers.])
]) ])
fi fi
AM_CONDITIONAL([CARES], [test "${NHRPD}" != ""])
dnl ------------------ dnl ------------------
dnl check Net-SNMP library dnl check Net-SNMP library

1
debian/frr.install vendored
View File

@ -2,6 +2,7 @@ etc/
usr/bin/vtysh usr/bin/vtysh
usr/bin/mtracebis usr/bin/mtracebis
usr/lib/*/frr/libfrr.* usr/lib/*/frr/libfrr.*
usr/lib/*/frr/libfrrcares.*
usr/lib/*/frr/libfrrospfapiclient.* usr/lib/*/frr/libfrrospfapiclient.*
usr/lib/frr/*.sh usr/lib/frr/*.sh
usr/lib/frr/*d usr/lib/frr/*d

View File

@ -85,6 +85,7 @@ const char *node_names[] = {
"northbound debug", // NORTHBOUND_DEBUG_NODE, "northbound debug", // NORTHBOUND_DEBUG_NODE,
"vnc debug", // DEBUG_VNC_NODE, "vnc debug", // DEBUG_VNC_NODE,
"route-map debug", /* RMAP_DEBUG_NODE */ "route-map debug", /* RMAP_DEBUG_NODE */
"resolver debug", /* RESOLVER_DEBUG_NODE */
"aaa", // AAA_NODE, "aaa", // AAA_NODE,
"keychain", // KEYCHAIN_NODE, "keychain", // KEYCHAIN_NODE,
"keychain key", // KEYCHAIN_KEY_NODE, "keychain key", // KEYCHAIN_KEY_NODE,

View File

@ -94,6 +94,7 @@ enum node_type {
NORTHBOUND_DEBUG_NODE, /* Northbound Debug node. */ NORTHBOUND_DEBUG_NODE, /* Northbound Debug node. */
DEBUG_VNC_NODE, /* Debug VNC node. */ DEBUG_VNC_NODE, /* Debug VNC node. */
RMAP_DEBUG_NODE, /* Route-map debug node */ RMAP_DEBUG_NODE, /* Route-map debug node */
RESOLVER_DEBUG_NODE, /* Resolver debug node */
AAA_NODE, /* AAA node. */ AAA_NODE, /* AAA node. */
KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_NODE, /* Key-chain node. */
KEYCHAIN_KEY_NODE, /* Key-chain key node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */

View File

@ -356,6 +356,12 @@ static struct log_ref ferr_lib_err[] = {
.description = "A callback used to process a configuration change has returned an error while applying the changes", .description = "A callback used to process a configuration change has returned an error while applying the changes",
.suggestion = "Gather log data and open an Issue.", .suggestion = "Gather log data and open an Issue.",
}, },
{
.code = EC_LIB_RESOLVER,
.title = "DNS Resolution",
.description = "An error was detected while attempting to resolve a hostname",
.suggestion = "Ensure that DNS is working properly and the hostname is configured in dns. If you are still seeing this error, open an issue"
},
{ {
.code = END_FERR, .code = END_FERR,
} }

View File

@ -84,6 +84,7 @@ enum lib_log_refs {
EC_LIB_GRPC_INIT, EC_LIB_GRPC_INIT,
EC_LIB_ID_CONSISTENCY, EC_LIB_ID_CONSISTENCY,
EC_LIB_ID_EXHAUST, EC_LIB_ID_EXHAUST,
EC_LIB_RESOLVER,
}; };
extern void lib_error_init(void); extern void lib_error_init(void);

View File

@ -17,17 +17,18 @@
#include "vector.h" #include "vector.h"
#include "thread.h" #include "thread.h"
#include "lib_errors.h" #include "lib_errors.h"
#include "resolver.h"
#include "nhrpd.h" #include "command.h"
#include "nhrp_errors.h"
struct resolver_state { struct resolver_state {
ares_channel channel; ares_channel channel;
struct thread_master *master;
struct thread *timeout; struct thread *timeout;
vector read_threads, write_threads; vector read_threads, write_threads;
}; };
static struct resolver_state state; static struct resolver_state state;
static bool resolver_debug;
#define THREAD_RUNNING ((struct thread *)-1) #define THREAD_RUNNING ((struct thread *)-1)
@ -54,7 +55,8 @@ static int resolver_cb_socket_readable(struct thread *t)
ares_process_fd(r->channel, fd, ARES_SOCKET_BAD); ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) { if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
t = NULL; t = NULL;
thread_add_read(master, resolver_cb_socket_readable, r, fd, &t); thread_add_read(r->master, resolver_cb_socket_readable, r, fd,
&t);
vector_set_index(r->read_threads, fd, t); vector_set_index(r->read_threads, fd, t);
} }
resolver_update_timeouts(r); resolver_update_timeouts(r);
@ -71,7 +73,7 @@ static int resolver_cb_socket_writable(struct thread *t)
ares_process_fd(r->channel, ARES_SOCKET_BAD, fd); ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) { if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
t = NULL; t = NULL;
thread_add_write(master, resolver_cb_socket_writable, r, fd, thread_add_write(r->master, resolver_cb_socket_writable, r, fd,
&t); &t);
vector_set_index(r->write_threads, fd, t); vector_set_index(r->write_threads, fd, t);
} }
@ -91,8 +93,8 @@ static void resolver_update_timeouts(struct resolver_state *r)
tv = ares_timeout(r->channel, NULL, &tvbuf); tv = ares_timeout(r->channel, NULL, &tvbuf);
if (tv) { if (tv) {
unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000; unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
thread_add_timer_msec(master, resolver_cb_timeout, r, timeoutms, thread_add_timer_msec(r->master, resolver_cb_timeout, r,
&r->timeout); timeoutms, &r->timeout);
} }
} }
@ -105,8 +107,8 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
if (readable) { if (readable) {
t = vector_lookup_ensure(r->read_threads, fd); t = vector_lookup_ensure(r->read_threads, fd);
if (!t) { if (!t) {
thread_add_read(master, resolver_cb_socket_readable, r, thread_add_read(r->master, resolver_cb_socket_readable,
fd, &t); r, fd, &t);
vector_set_index(r->read_threads, fd, t); vector_set_index(r->read_threads, fd, t);
} }
} else { } else {
@ -122,8 +124,8 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
if (writable) { if (writable) {
t = vector_lookup_ensure(r->write_threads, fd); t = vector_lookup_ensure(r->write_threads, fd);
if (!t) { if (!t) {
thread_add_read(master, resolver_cb_socket_writable, r, thread_add_read(r->master, resolver_cb_socket_writable,
fd, &t); r, fd, &t);
vector_set_index(r->write_threads, fd, t); vector_set_index(r->write_threads, fd, t);
} }
} else { } else {
@ -137,37 +139,23 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
} }
} }
void resolver_init(void)
{
struct ares_options ares_opts;
state.read_threads = vector_init(1);
state.write_threads = vector_init(1);
ares_opts = (struct ares_options){
.sock_state_cb = &ares_socket_cb,
.sock_state_cb_data = &state,
.timeout = 2,
.tries = 3,
};
ares_init_options(&state.channel, &ares_opts,
ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT
| ARES_OPT_TRIES);
}
static void ares_address_cb(void *arg, int status, int timeouts, static void ares_address_cb(void *arg, int status, int timeouts,
struct hostent *he) struct hostent *he)
{ {
struct resolver_query *query = (struct resolver_query *)arg; struct resolver_query *query = (struct resolver_query *)arg;
union sockunion addr[16]; union sockunion addr[16];
void (*callback)(struct resolver_query *, int, union sockunion *);
size_t i; size_t i;
callback = query->callback;
query->callback = NULL;
if (status != ARES_SUCCESS) { if (status != ARES_SUCCESS) {
debugf(NHRP_DEBUG_COMMON, "[%p] Resolving failed", query); if (resolver_debug)
query->callback(query, -1, NULL); zlog_debug("[%p] Resolving failed", query);
query->callback = NULL;
callback(query, -1, NULL);
return; return;
} }
@ -186,10 +174,10 @@ static void ares_address_cb(void *arg, int status, int timeouts,
} }
} }
debugf(NHRP_DEBUG_COMMON, "[%p] Resolved with %d results", query, if (resolver_debug)
(int)i); zlog_debug("[%p] Resolved with %d results", query, (int)i);
query->callback(query, i, &addr[0]);
query->callback = NULL; callback(query, i, &addr[0]);
} }
void resolver_resolve(struct resolver_query *query, int af, void resolver_resolve(struct resolver_query *query, int af,
@ -199,15 +187,61 @@ void resolver_resolve(struct resolver_query *query, int af,
{ {
if (query->callback != NULL) { if (query->callback != NULL) {
flog_err( flog_err(
EC_NHRP_RESOLVER, EC_LIB_RESOLVER,
"Trying to resolve '%s', but previous query was not finished yet", "Trying to resolve '%s', but previous query was not finished yet",
hostname); hostname);
return; return;
} }
debugf(NHRP_DEBUG_COMMON, "[%p] Resolving '%s'", query, hostname); if (resolver_debug)
zlog_debug("[%p] Resolving '%s'", query, hostname);
query->callback = callback; query->callback = callback;
ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query); ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query);
resolver_update_timeouts(&state); resolver_update_timeouts(&state);
} }
DEFUN(debug_resolver,
debug_resolver_cmd,
"[no] debug resolver",
NO_STR
DEBUG_STR
"Debug DNS resolver actions\n")
{
resolver_debug = (argc == 2);
return CMD_SUCCESS;
}
static struct cmd_node resolver_debug_node = {RESOLVER_DEBUG_NODE, "", 1};
static int resolver_config_write_debug(struct vty *vty)
{
if (resolver_debug)
vty_out(vty, "debug resolver\n");
return 1;
}
void resolver_init(struct thread_master *tm)
{
struct ares_options ares_opts;
state.master = tm;
state.read_threads = vector_init(1);
state.write_threads = vector_init(1);
ares_opts = (struct ares_options){
.sock_state_cb = &ares_socket_cb,
.sock_state_cb_data = &state,
.timeout = 2,
.tries = 3,
};
ares_init_options(&state.channel, &ares_opts,
ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT
| ARES_OPT_TRIES);
install_node(&resolver_debug_node, resolver_config_write_debug);
install_element(CONFIG_NODE, &debug_resolver_cmd);
install_element(ENABLE_NODE, &debug_resolver_cmd);
}

25
lib/resolver.h Normal file
View File

@ -0,0 +1,25 @@
/* C-Ares integration to Quagga mainloop
* Copyright (c) 2014-2015 Timo Teräs
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _FRR_RESOLVER_H
#define _FRR_RESOLVER_H
#include "thread.h"
#include "sockunion.h"
struct resolver_query {
void (*callback)(struct resolver_query *, int n, union sockunion *);
};
void resolver_init(struct thread_master *tm);
void resolver_resolve(struct resolver_query *query, int af,
const char *hostname, void (*cb)(struct resolver_query *,
int, union sockunion *));
#endif /* _FRR_RESOLVER_H */

View File

@ -285,6 +285,21 @@ lib_libfrrsnmp_la_SOURCES = \
lib/snmp.c \ lib/snmp.c \
# end # end
#
# c-ares support
#
if CARES
lib_LTLIBRARIES += lib/libfrrcares.la
pkginclude_HEADERS += lib/resolver.h
endif
lib_libfrrcares_la_CFLAGS = $(WERROR) $(CARES_CFLAGS)
lib_libfrrcares_la_LDFLAGS = -version-info 0:0:0
lib_libfrrcares_la_LIBADD = $(CARES_LIBS)
lib_libfrrcares_la_SOURCES = \
lib/resolver.c \
#end
# #
# ZeroMQ support # ZeroMQ support
# #

View File

@ -31,12 +31,6 @@ static struct log_ref ferr_nhrp_err[] = {
.description = "NHRP has detected a error with the Strongswan code", .description = "NHRP has detected a error with the Strongswan code",
.suggestion = "Ensure that StrongSwan is configured correctly. Restart StrongSwan and FRR" .suggestion = "Ensure that StrongSwan is configured correctly. Restart StrongSwan and FRR"
}, },
{
.code = EC_NHRP_RESOLVER,
.title = "NHRP DNS Resolution",
.description = "NHRP has detected an error in an attempt to resolve a hostname",
.suggestion = "Ensure that DNS is working properly and the hostname is configured in dns. If you are still seeing this error, open an issue"
},
{ {
.code = END_FERR, .code = END_FERR,
} }

View File

@ -25,7 +25,6 @@
enum nhrp_log_refs { enum nhrp_log_refs {
EC_NHRP_SWAN = NHRP_FERR_START, EC_NHRP_SWAN = NHRP_FERR_START,
EC_NHRP_RESOLVER,
}; };
extern void nhrp_error_init(void); extern void nhrp_error_init(void);

View File

@ -141,7 +141,7 @@ int main(int argc, char **argv)
nhrp_error_init(); nhrp_error_init();
vrf_init(NULL, NULL, NULL, NULL, NULL); vrf_init(NULL, NULL, NULL, NULL, NULL);
nhrp_interface_init(); nhrp_interface_init();
resolver_init(); resolver_init(master);
/* Run with elevated capabilities, as for all netlink activity /* Run with elevated capabilities, as for all netlink activity
* we need privileges anyway. */ * we need privileges anyway. */

View File

@ -16,6 +16,7 @@
#include "zclient.h" #include "zclient.h"
#include "debug.h" #include "debug.h"
#include "memory.h" #include "memory.h"
#include "resolver.h"
DECLARE_MGROUP(NHRPD) DECLARE_MGROUP(NHRPD)
@ -84,15 +85,6 @@ static inline int notifier_active(struct notifier_list *l)
return !list_empty(&l->notifier_head); return !list_empty(&l->notifier_head);
} }
struct resolver_query {
void (*callback)(struct resolver_query *, int n, union sockunion *);
};
void resolver_init(void);
void resolver_resolve(struct resolver_query *query, int af,
const char *hostname, void (*cb)(struct resolver_query *,
int, union sockunion *));
void nhrp_zebra_init(void); void nhrp_zebra_init(void);
void nhrp_zebra_terminate(void); void nhrp_zebra_terminate(void);

View File

@ -8,8 +8,7 @@ vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c
man8 += $(MANBUILD)/nhrpd.8 man8 += $(MANBUILD)/nhrpd.8
endif endif
nhrpd_nhrpd_LDADD = lib/libfrr.la $(LIBCAP) $(CARES_LIBS) nhrpd_nhrpd_LDADD = lib/libfrr.la lib/libfrrcares.la $(LIBCAP)
nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS)
nhrpd_nhrpd_SOURCES = \ nhrpd_nhrpd_SOURCES = \
nhrpd/linux.c \ nhrpd/linux.c \
nhrpd/netlink_arp.c \ nhrpd/netlink_arp.c \
@ -27,7 +26,6 @@ nhrpd_nhrpd_SOURCES = \
nhrpd/nhrp_vc.c \ nhrpd/nhrp_vc.c \
nhrpd/nhrp_vty.c \ nhrpd/nhrp_vty.c \
nhrpd/reqid.c \ nhrpd/reqid.c \
nhrpd/resolver.c \
nhrpd/vici.c \ nhrpd/vici.c \
nhrpd/zbuf.c \ nhrpd/zbuf.c \
nhrpd/znl.c \ nhrpd/znl.c \

View File

@ -377,6 +377,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
strlen("debug route-map")) strlen("debug route-map"))
== 0) == 0)
config = config_get(RMAP_DEBUG_NODE, line); config = config_get(RMAP_DEBUG_NODE, line);
else if (strncmp(line, "debug resolver",
strlen("debug resolver")) == 0)
config = config_get(RESOLVER_DEBUG_NODE, line);
else if (strncmp(line, "debug", strlen("debug")) == 0) else if (strncmp(line, "debug", strlen("debug")) == 0)
config = config_get(DEBUG_NODE, line); config = config_get(DEBUG_NODE, line);
else if (strncmp(line, "password", strlen("password")) == 0 else if (strncmp(line, "password", strlen("password")) == 0
@ -423,7 +426,7 @@ void vtysh_config_parse_line(void *arg, const char *line)
|| (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \ || (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \
|| (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \ || (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \
|| (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \ || (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \
|| (I) == MPLS_NODE) || (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE)
/* Display configuration to file pointer. */ /* Display configuration to file pointer. */
void vtysh_config_dump(void) void vtysh_config_dump(void)