summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_rpki.c230
-rw-r--r--bgpd/bgp_rpki.h2
2 files changed, 228 insertions, 4 deletions
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 458677b8ad..83ba5419d9 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -44,6 +44,7 @@
#include "bgpd/bgp_rpki_clippy.c"
+DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_TEMP, "BGP RPKI Intermediate Buffer");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib");
@@ -75,6 +76,7 @@ struct cache {
} tr_config;
struct rtr_socket *rtr_socket;
uint8_t preference;
+ struct rpki_vrf *rpki_vrf;
};
enum return_values { SUCCESS = 0, ERROR = -1 };
@@ -287,6 +289,99 @@ static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled)
return 1;
}
+/* tcp identifier : <HOST>:<PORT>
+ * ssh identifier : <user>@<HOST>:<PORT>
+ */
+static struct rpki_vrf *find_rpki_vrf_from_ident(const char *ident)
+{
+#if defined(FOUND_SSH)
+ struct tr_ssh_config *ssh_config;
+#endif
+ struct tr_tcp_config *tcp_config;
+ struct listnode *rpki_vrf_nnode;
+ unsigned int cache_port, port;
+ struct listnode *cache_node;
+ struct rpki_vrf *rpki_vrf;
+ struct cache *cache;
+ bool is_tcp = true;
+ size_t host_len;
+ char *endptr;
+ char *host;
+ char *ptr;
+ char *buf;
+
+ /* extract the <SOCKET> */
+ ptr = strrchr(ident, ':');
+ if (!ptr)
+ return NULL;
+
+ ptr++;
+ /* extract port */
+ port = atoi(ptr);
+ if (port == 0)
+ /* not ours */
+ return NULL;
+
+ /* extract host */
+ ptr--;
+ host_len = (size_t)(ptr - ident);
+ buf = XCALLOC(MTYPE_BGP_RPKI_TEMP, host_len + 1);
+ memcpy(buf, ident, host_len);
+ buf[host_len] = '\0';
+ endptr = strrchr(buf, '@');
+
+ /* ssh session */
+ if (endptr) {
+ host = XCALLOC(MTYPE_BGP_RPKI_TEMP,
+ (size_t)(buf + host_len - endptr) + 1);
+ memcpy(host, endptr + 1, (size_t)(buf + host_len - endptr) + 1);
+ is_tcp = false;
+ } else {
+ host = buf;
+ buf = NULL;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) {
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node,
+ cache)) {
+ if ((cache->type == TCP && !is_tcp)
+#if defined(FOUND_SSH)
+ || (cache->type == SSH && is_tcp)
+#endif
+ )
+ continue;
+
+ if (is_tcp) {
+ tcp_config = cache->tr_config.tcp_config;
+ cache_port = atoi(tcp_config->port);
+ if (cache_port != port)
+ continue;
+ if (strlen(tcp_config->host) != strlen(host))
+ continue;
+ if (memcmp(tcp_config->host, host, host_len) ==
+ 0)
+ break;
+ }
+#if defined(FOUND_SSH)
+ else {
+ ssh_config = cache->tr_config.ssh_config;
+ if (port != ssh_config->port)
+ continue;
+ if (strmatch(ssh_config->host, host))
+ break;
+ }
+#endif
+ }
+ if (cache)
+ break;
+ }
+ if (host)
+ XFREE(MTYPE_BGP_RPKI_TEMP, host);
+ if (buf)
+ XFREE(MTYPE_BGP_RPKI_TEMP, buf);
+ return rpki_vrf;
+}
+
static struct rpki_vrf *find_rpki_vrf(const char *vrfname)
{
struct listnode *rpki_vrf_nnode;
@@ -608,8 +703,23 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
{
struct rpki_vrf *rpki_vrf;
const char *msg;
+ const struct rtr_socket *rtr = rec.socket;
+ const char *ident;
- rpki_vrf = find_rpki_vrf(NULL);
+ if (!rtr) {
+ msg = "could not find rtr_socket from cb_sync_rtr";
+ goto err;
+ }
+ if (!rtr->tr_socket) {
+ msg = "could not find tr_socket from cb_sync_rtr";
+ goto err;
+ }
+ ident = rtr->tr_socket->ident_fp(rtr->tr_socket->socket);
+ if (!ident) {
+ msg = "could not find ident from cb_sync_rtr";
+ goto err;
+ }
+ rpki_vrf = find_rpki_vrf_from_ident(ident);
if (!rpki_vrf) {
msg = "could not find rpki_vrf";
goto err;
@@ -1068,11 +1178,16 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
return RPKI_NOT_BEING_USED;
}
-static int add_cache(struct cache *cache, struct rpki_vrf *rpki_vrf)
+static int add_cache(struct cache *cache)
{
uint8_t preference = cache->preference;
struct rtr_mgr_group group;
struct list *cache_list;
+ struct rpki_vrf *rpki_vrf;
+
+ rpki_vrf = cache->rpki_vrf;
+ if (!rpki_vrf)
+ return ERROR;
group.preference = preference;
group.sockets_len = 1;
@@ -1097,6 +1212,105 @@ static int add_cache(struct cache *cache, struct rpki_vrf *rpki_vrf)
return SUCCESS;
}
+static int rpki_create_socket(void *_cache)
+{
+ struct timeval prev_snd_tmout, prev_rcv_tmout, timeout;
+ struct cache *cache = (struct cache *)_cache;
+ struct rpki_vrf *rpki_vrf = cache->rpki_vrf;
+ struct tr_tcp_config *tcp_config;
+ struct addrinfo *res = NULL;
+ struct addrinfo hints = {};
+ socklen_t optlen;
+ char *host, *port;
+ struct vrf *vrf;
+ int cancel_state;
+ int socket;
+ int ret;
+#if defined(FOUND_SSH)
+ struct tr_ssh_config *ssh_config;
+ char s_port[10];
+#endif
+
+ if (!cache)
+ return -1;
+
+ if (rpki_vrf->vrfname == NULL)
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ else
+ vrf = vrf_lookup_by_name(rpki_vrf->vrfname);
+ if (!vrf)
+ return -1;
+
+ if (!CHECK_FLAG(vrf->status, VRF_ACTIVE) || vrf->vrf_id == VRF_UNKNOWN)
+ return -1;
+
+ if (cache->type == TCP) {
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ tcp_config = cache->tr_config.tcp_config;
+ host = tcp_config->host;
+ port = tcp_config->port;
+ }
+#if defined(FOUND_SSH)
+ else {
+ ssh_config = cache->tr_config.ssh_config;
+ host = ssh_config->host;
+ snprintf(s_port, sizeof(s_port), "%hu", ssh_config->port);
+ port = s_port;
+
+ hints.ai_flags |= AI_NUMERICHOST;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ }
+#endif
+
+ frr_with_privs (&bgpd_privs) {
+ ret = vrf_getaddrinfo(host, port, &hints, &res, vrf->vrf_id);
+ }
+ if (ret != 0)
+ return -1;
+
+ frr_with_privs (&bgpd_privs) {
+ socket = vrf_socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol, vrf->vrf_id, NULL);
+ }
+ if (socket < 0)
+ return -1;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancel_state);
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ optlen = sizeof(prev_rcv_tmout);
+ getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout, &optlen);
+ getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout, &optlen);
+
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+
+ if (connect(socket, res->ai_addr, res->ai_addrlen) == -1) {
+ if (res)
+ freeaddrinfo(res);
+ close(socket);
+ pthread_setcancelstate(cancel_state, NULL);
+ return -1;
+ }
+
+ if (res)
+ freeaddrinfo(res);
+ pthread_setcancelstate(cancel_state, NULL);
+
+ setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout,
+ sizeof(prev_rcv_tmout));
+ setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout,
+ sizeof(prev_snd_tmout));
+
+ return socket;
+}
+
static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host,
const char *port, const uint8_t preference,
const char *bindaddr)
@@ -1116,16 +1330,20 @@ static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host,
else
tcp_config->bindaddr = NULL;
+ tcp_config->data = cache;
+ tcp_config->new_socket = rpki_create_socket;
rtr_socket = create_rtr_socket(tr_socket);
+ cache->rpki_vrf = rpki_vrf;
cache->type = TCP;
cache->tr_socket = tr_socket;
cache->tr_config.tcp_config = tcp_config;
cache->rtr_socket = rtr_socket;
cache->preference = preference;
- int ret = add_cache(cache, rpki_vrf);
+ int ret = add_cache(cache);
if (ret != SUCCESS) {
+ tcp_config->data = NULL;
free_cache(cache);
}
return ret;
@@ -1152,6 +1370,8 @@ static int add_ssh_cache(struct rpki_vrf *rpki_vrf, const char *host,
ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
else
ssh_config->bindaddr = NULL;
+ ssh_config->data = cache;
+ ssh_config->new_socket = rpki_create_socket;
ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username);
ssh_config->client_privkey_path =
@@ -1161,14 +1381,16 @@ static int add_ssh_cache(struct rpki_vrf *rpki_vrf, const char *host,
rtr_socket = create_rtr_socket(tr_socket);
+ cache->rpki_vrf = rpki_vrf;
cache->type = SSH;
cache->tr_socket = tr_socket;
cache->tr_config.ssh_config = ssh_config;
cache->rtr_socket = rtr_socket;
cache->preference = preference;
- int ret = add_cache(cache, rpki_vrf);
+ int ret = add_cache(cache);
if (ret != SUCCESS) {
+ ssh_config->data = NULL;
free_cache(cache);
}
diff --git a/bgpd/bgp_rpki.h b/bgpd/bgp_rpki.h
index de28715d1b..4f2f87d2ef 100644
--- a/bgpd/bgp_rpki.h
+++ b/bgpd/bgp_rpki.h
@@ -8,6 +8,8 @@
#ifndef __BGP_RPKI_H__
#define __BGP_RPKI_H__
+extern struct zebra_privs_t bgpd_privs;
+
enum rpki_states {
RPKI_NOT_BEING_USED,
RPKI_VALID,