Skip to content

Commit

Permalink
bgpd: create cache server socket in vrf
Browse files Browse the repository at this point in the history
Create cache server socket in vrf

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
  • Loading branch information
pguibert6WIND authored and louis-6wind committed Jan 18, 2024
1 parent a3bd9ba commit a951752
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 4 deletions.
230 changes: 226 additions & 4 deletions bgpd/bgp_rpki.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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 };
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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 =
Expand All @@ -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);
}

Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_rpki.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit a951752

Please sign in to comment.