forked from Mirror/frr
bgpd: create cache server socket in vrf
Create cache server socket in vrf Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
This commit is contained in:
parent
a3bd9bad37
commit
a951752d4a
230
bgpd/bgp_rpki.c
230
bgpd/bgp_rpki.c
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
#include "bgpd/bgp_rpki_clippy.c"
|
#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, "BGP RPKI Cache server");
|
||||||
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
|
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
|
||||||
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib");
|
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib");
|
||||||
|
@ -75,6 +76,7 @@ struct cache {
|
||||||
} tr_config;
|
} tr_config;
|
||||||
struct rtr_socket *rtr_socket;
|
struct rtr_socket *rtr_socket;
|
||||||
uint8_t preference;
|
uint8_t preference;
|
||||||
|
struct rpki_vrf *rpki_vrf;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum return_values { SUCCESS = 0, ERROR = -1 };
|
enum return_values { SUCCESS = 0, ERROR = -1 };
|
||||||
|
@ -287,6 +289,99 @@ static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled)
|
||||||
return 1;
|
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)
|
static struct rpki_vrf *find_rpki_vrf(const char *vrfname)
|
||||||
{
|
{
|
||||||
struct listnode *rpki_vrf_nnode;
|
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;
|
struct rpki_vrf *rpki_vrf;
|
||||||
const char *msg;
|
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) {
|
if (!rpki_vrf) {
|
||||||
msg = "could not find rpki_vrf";
|
msg = "could not find rpki_vrf";
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -1068,11 +1178,16 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
|
||||||
return RPKI_NOT_BEING_USED;
|
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;
|
uint8_t preference = cache->preference;
|
||||||
struct rtr_mgr_group group;
|
struct rtr_mgr_group group;
|
||||||
struct list *cache_list;
|
struct list *cache_list;
|
||||||
|
struct rpki_vrf *rpki_vrf;
|
||||||
|
|
||||||
|
rpki_vrf = cache->rpki_vrf;
|
||||||
|
if (!rpki_vrf)
|
||||||
|
return ERROR;
|
||||||
|
|
||||||
group.preference = preference;
|
group.preference = preference;
|
||||||
group.sockets_len = 1;
|
group.sockets_len = 1;
|
||||||
|
@ -1097,6 +1212,105 @@ static int add_cache(struct cache *cache, struct rpki_vrf *rpki_vrf)
|
||||||
return SUCCESS;
|
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,
|
static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host,
|
||||||
const char *port, const uint8_t preference,
|
const char *port, const uint8_t preference,
|
||||||
const char *bindaddr)
|
const char *bindaddr)
|
||||||
|
@ -1116,16 +1330,20 @@ static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host,
|
||||||
else
|
else
|
||||||
tcp_config->bindaddr = NULL;
|
tcp_config->bindaddr = NULL;
|
||||||
|
|
||||||
|
tcp_config->data = cache;
|
||||||
|
tcp_config->new_socket = rpki_create_socket;
|
||||||
rtr_socket = create_rtr_socket(tr_socket);
|
rtr_socket = create_rtr_socket(tr_socket);
|
||||||
|
|
||||||
|
cache->rpki_vrf = rpki_vrf;
|
||||||
cache->type = TCP;
|
cache->type = TCP;
|
||||||
cache->tr_socket = tr_socket;
|
cache->tr_socket = tr_socket;
|
||||||
cache->tr_config.tcp_config = tcp_config;
|
cache->tr_config.tcp_config = tcp_config;
|
||||||
cache->rtr_socket = rtr_socket;
|
cache->rtr_socket = rtr_socket;
|
||||||
cache->preference = preference;
|
cache->preference = preference;
|
||||||
|
|
||||||
int ret = add_cache(cache, rpki_vrf);
|
int ret = add_cache(cache);
|
||||||
if (ret != SUCCESS) {
|
if (ret != SUCCESS) {
|
||||||
|
tcp_config->data = NULL;
|
||||||
free_cache(cache);
|
free_cache(cache);
|
||||||
}
|
}
|
||||||
return ret;
|
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);
|
ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr);
|
||||||
else
|
else
|
||||||
ssh_config->bindaddr = NULL;
|
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->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username);
|
||||||
ssh_config->client_privkey_path =
|
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);
|
rtr_socket = create_rtr_socket(tr_socket);
|
||||||
|
|
||||||
|
cache->rpki_vrf = rpki_vrf;
|
||||||
cache->type = SSH;
|
cache->type = SSH;
|
||||||
cache->tr_socket = tr_socket;
|
cache->tr_socket = tr_socket;
|
||||||
cache->tr_config.ssh_config = ssh_config;
|
cache->tr_config.ssh_config = ssh_config;
|
||||||
cache->rtr_socket = rtr_socket;
|
cache->rtr_socket = rtr_socket;
|
||||||
cache->preference = preference;
|
cache->preference = preference;
|
||||||
|
|
||||||
int ret = add_cache(cache, rpki_vrf);
|
int ret = add_cache(cache);
|
||||||
if (ret != SUCCESS) {
|
if (ret != SUCCESS) {
|
||||||
|
ssh_config->data = NULL;
|
||||||
free_cache(cache);
|
free_cache(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#ifndef __BGP_RPKI_H__
|
#ifndef __BGP_RPKI_H__
|
||||||
#define __BGP_RPKI_H__
|
#define __BGP_RPKI_H__
|
||||||
|
|
||||||
|
extern struct zebra_privs_t bgpd_privs;
|
||||||
|
|
||||||
enum rpki_states {
|
enum rpki_states {
|
||||||
RPKI_NOT_BEING_USED,
|
RPKI_NOT_BEING_USED,
|
||||||
RPKI_VALID,
|
RPKI_VALID,
|
||||||
|
|
Loading…
Reference in a new issue