mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
RPKI protocol with integrated RTRLib inside
Add the RPKI protocol (RFC 6810) using the RTRLib (http://rpki.realmv6.org/) that is integrated inside the BIRD's code. Implemeted transports are: - unprotected transport over TCP - secure transport over SSHv2 The code should work properly with one or more cache servers per protocol. Example configuration of bird.conf: ... roa4 table roatable; protocol rpki { table roatable; cache 127.0.0.1; # defaults: port 8282, preference 1, no encryption cache 127.0.0.1 { preference 1; port 2222; ssh encryption { bird private key "/home/birdgeek/.ssh/id_rsa"; cache public key "/home/birdgeek/.ssh/known_hosts"; user "birdgeek"; }; }; cache "rpki-validator.realmv6.org" { preference 2; }; } ...
This commit is contained in:
parent
74d9416763
commit
41f4b5940f
@ -10,6 +10,8 @@ CF_HDR
|
|||||||
|
|
||||||
#define PARSER 1
|
#define PARSER 1
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
@ -26,6 +28,13 @@ CF_HDR
|
|||||||
|
|
||||||
CF_DEFINES
|
CF_DEFINES
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_u8(unsigned val)
|
||||||
|
{
|
||||||
|
if (val > 0xFF)
|
||||||
|
cf_error("Value %d out of range (0-255)", val);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_u16(unsigned val)
|
check_u16(unsigned val)
|
||||||
{
|
{
|
||||||
@ -33,6 +42,16 @@ check_u16(unsigned val)
|
|||||||
cf_error("Value %d out of range (0-65535)", val);
|
cf_error("Value %d out of range (0-65535)", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_file_readability(const char *file_path)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(file_path, "r");
|
||||||
|
if (file)
|
||||||
|
fclose(file);
|
||||||
|
else
|
||||||
|
cf_error("File '%s' cannot be open for read: %m", file_path);
|
||||||
|
}
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
|
@ -175,9 +175,7 @@ fi
|
|||||||
|
|
||||||
AC_SUBST(iproutedir)
|
AC_SUBST(iproutedir)
|
||||||
|
|
||||||
# all_protocols="$proto_bfd bgp ospf pipe radv rip static"
|
all_protocols="$proto_bfd ospf pipe radv rip rpki static" # TODO: add BGP
|
||||||
all_protocols="$proto_bfd ospf pipe radv rip static"
|
|
||||||
|
|
||||||
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
|
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
|
||||||
|
|
||||||
if test "$with_protocols" = all ; then
|
if test "$with_protocols" = all ; then
|
||||||
@ -234,6 +232,10 @@ if test "$enable_debug" = yes ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
BIRD_LIBS=
|
||||||
|
AC_CHECK_LIB(dl, dlopen, BIRD_LIBS="-ldl")
|
||||||
|
AC_SUBST(BIRD_LIBS)
|
||||||
|
|
||||||
CLIENT=
|
CLIENT=
|
||||||
CLIENT_LIBS=
|
CLIENT_LIBS=
|
||||||
if test "$enable_client" = yes ; then
|
if test "$enable_client" = yes ; then
|
||||||
|
@ -34,3 +34,5 @@ checksum.c
|
|||||||
checksum.h
|
checksum.h
|
||||||
alloca.h
|
alloca.h
|
||||||
net.c
|
net.c
|
||||||
|
libssh.c
|
||||||
|
libssh.h
|
126
lib/libssh.c
Normal file
126
lib/libssh.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- Mockup of SSH Library for loading LibSSH using dlopen
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of SSH Library: http://www.libssh.org/
|
||||||
|
* (c) 2003-2009 by Aris Adamantiadis (SSH Library)
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "lib/libssh.h"
|
||||||
|
|
||||||
|
#define FILENAME_OF_SHARED_OBJECT_LIBSSH "libssh.so"
|
||||||
|
|
||||||
|
static void *libssh;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return NULL if success
|
||||||
|
* @return string with error if failed
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
load_libssh(void)
|
||||||
|
{
|
||||||
|
char *err_buf;
|
||||||
|
|
||||||
|
libssh = dlopen(FILENAME_OF_SHARED_OBJECT_LIBSSH, RTLD_LAZY);
|
||||||
|
if (!libssh)
|
||||||
|
{
|
||||||
|
/* This would be probably often repeated problem */
|
||||||
|
char *help_msg = "You have to install libssh library.";
|
||||||
|
err_buf = mb_alloc(&root_pool, 512); /* FIXME: free memory */
|
||||||
|
bsnprintf(err_buf, 512, "%s. %s", dlerror(), help_msg);
|
||||||
|
return err_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlerror(); /* Clear any existing error */
|
||||||
|
|
||||||
|
ssh_new = (ssh_session (*)(void)) dlsym(libssh, "ssh_new");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_set_blocking = (void (*)(ssh_session, int)) dlsym(libssh, "ssh_set_blocking");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_options_set = (int (*)(ssh_session, enum ssh_options_e, const void *)) dlsym(libssh, "ssh_options_set");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_connect = (int (*)(ssh_session)) dlsym(libssh, "ssh_connect");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_get_fd = (socket_t (*)(ssh_session)) dlsym(libssh, "ssh_get_fd");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_is_server_known = (int (*)(ssh_session)) dlsym(libssh, "ssh_is_server_known");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_userauth_publickey_auto = (int (*)(ssh_session, const char *, const char *)) dlsym(libssh, "ssh_userauth_publickey_auto");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_get_error = (const char * (*)(void *)) dlsym(libssh, "ssh_get_error");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_get_error_code = (int (*)(void *)) dlsym(libssh, "ssh_get_error_code");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_disconnect = (void (*)(ssh_session)) dlsym(libssh, "ssh_disconnect");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_free = (void (*)(ssh_session)) dlsym(libssh, "ssh_free");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_new = (ssh_channel (*)(ssh_session)) dlsym(libssh, "ssh_channel_new");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_is_open = (int (*)(ssh_channel)) dlsym(libssh, "ssh_channel_is_open");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_close = (int (*)(ssh_channel)) dlsym(libssh, "ssh_channel_close");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_free = (void (*)(ssh_channel)) dlsym(libssh, "ssh_channel_free");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_open_session = (int (*)(ssh_channel)) dlsym(libssh, "ssh_channel_open_session");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_request_subsystem = (int (*)(ssh_channel, const char *)) dlsym(libssh, "ssh_channel_request_subsystem");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_read_nonblocking = (int (*)(ssh_channel, void *, uint32_t, int)) dlsym(libssh, "ssh_channel_read_nonblocking");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_is_eof = (int (*)(ssh_channel)) dlsym(libssh, "ssh_channel_is_eof");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_select = (int (*)(ssh_channel *, ssh_channel *, ssh_channel *, struct timeval *)) dlsym(libssh, "ssh_channel_select");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
ssh_channel_write = (int (*)(ssh_channel, const void *, uint32_t)) dlsym(libssh, "ssh_channel_write");
|
||||||
|
if ((err_buf = dlerror()) != NULL)
|
||||||
|
return err_buf;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
133
lib/libssh.h
Normal file
133
lib/libssh.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- Mockup headers of SSH Library for loading LibSSH using dlopen
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of SSH Library: http://www.libssh.org/
|
||||||
|
* (c) 2003-2009 by Aris Adamantiadis (SSH Library)
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIRD_LIBSSH_H_
|
||||||
|
#define _BIRD_LIBSSH_H_
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
typedef struct ssh_session_struct* ssh_session;
|
||||||
|
typedef struct ssh_channel_struct* ssh_channel;
|
||||||
|
|
||||||
|
/* Error return codes */
|
||||||
|
#define SSH_OK 0 /* No error */
|
||||||
|
#define SSH_ERROR -1 /* Error of some kind */
|
||||||
|
#define SSH_AGAIN -2 /* The nonblocking call must be repeated */
|
||||||
|
#define SSH_EOF -127 /* We have already a eof */
|
||||||
|
|
||||||
|
enum ssh_server_known_e {
|
||||||
|
SSH_SERVER_ERROR=-1,
|
||||||
|
SSH_SERVER_NOT_KNOWN=0,
|
||||||
|
SSH_SERVER_KNOWN_OK,
|
||||||
|
SSH_SERVER_KNOWN_CHANGED,
|
||||||
|
SSH_SERVER_FOUND_OTHER,
|
||||||
|
SSH_SERVER_FILE_NOT_FOUND
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ssh_auth_e {
|
||||||
|
SSH_AUTH_SUCCESS=0,
|
||||||
|
SSH_AUTH_DENIED,
|
||||||
|
SSH_AUTH_PARTIAL,
|
||||||
|
SSH_AUTH_INFO,
|
||||||
|
SSH_AUTH_AGAIN,
|
||||||
|
SSH_AUTH_ERROR=-1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ssh_error_types_e {
|
||||||
|
SSH_NO_ERROR=0,
|
||||||
|
SSH_REQUEST_DENIED,
|
||||||
|
SSH_FATAL,
|
||||||
|
SSH_EINTR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ssh_options_e {
|
||||||
|
SSH_OPTIONS_HOST,
|
||||||
|
SSH_OPTIONS_PORT,
|
||||||
|
SSH_OPTIONS_PORT_STR,
|
||||||
|
SSH_OPTIONS_FD,
|
||||||
|
SSH_OPTIONS_USER,
|
||||||
|
SSH_OPTIONS_SSH_DIR,
|
||||||
|
SSH_OPTIONS_IDENTITY,
|
||||||
|
SSH_OPTIONS_ADD_IDENTITY,
|
||||||
|
SSH_OPTIONS_KNOWNHOSTS,
|
||||||
|
SSH_OPTIONS_TIMEOUT,
|
||||||
|
SSH_OPTIONS_TIMEOUT_USEC,
|
||||||
|
SSH_OPTIONS_SSH1,
|
||||||
|
SSH_OPTIONS_SSH2,
|
||||||
|
SSH_OPTIONS_LOG_VERBOSITY,
|
||||||
|
SSH_OPTIONS_LOG_VERBOSITY_STR,
|
||||||
|
SSH_OPTIONS_CIPHERS_C_S,
|
||||||
|
SSH_OPTIONS_CIPHERS_S_C,
|
||||||
|
SSH_OPTIONS_COMPRESSION_C_S,
|
||||||
|
SSH_OPTIONS_COMPRESSION_S_C,
|
||||||
|
SSH_OPTIONS_PROXYCOMMAND,
|
||||||
|
SSH_OPTIONS_BINDADDR,
|
||||||
|
SSH_OPTIONS_STRICTHOSTKEYCHECK,
|
||||||
|
SSH_OPTIONS_COMPRESSION,
|
||||||
|
SSH_OPTIONS_COMPRESSION_LEVEL,
|
||||||
|
SSH_OPTIONS_KEY_EXCHANGE,
|
||||||
|
SSH_OPTIONS_HOSTKEYS,
|
||||||
|
SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
|
||||||
|
SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
|
||||||
|
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
|
||||||
|
SSH_OPTIONS_HMAC_C_S,
|
||||||
|
SSH_OPTIONS_HMAC_S_C,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/** No logging at all
|
||||||
|
*/
|
||||||
|
SSH_LOG_NOLOG=0,
|
||||||
|
/** Only warnings
|
||||||
|
*/
|
||||||
|
SSH_LOG_WARNING,
|
||||||
|
/** High level protocol information
|
||||||
|
*/
|
||||||
|
SSH_LOG_PROTOCOL,
|
||||||
|
/** Lower level protocol infomations, packet level
|
||||||
|
*/
|
||||||
|
SSH_LOG_PACKET,
|
||||||
|
/** Every function path
|
||||||
|
*/
|
||||||
|
SSH_LOG_FUNCTIONS
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef socket_t
|
||||||
|
typedef int socket_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssh_session (*ssh_new)(void);
|
||||||
|
void (*ssh_set_blocking)(ssh_session session, int blocking);
|
||||||
|
int (*ssh_options_set)(ssh_session session, enum ssh_options_e type, const void *value);
|
||||||
|
int (*ssh_connect)(ssh_session session);
|
||||||
|
socket_t (*ssh_get_fd)(ssh_session session);
|
||||||
|
int (*ssh_is_server_known)(ssh_session session);
|
||||||
|
int (*ssh_userauth_publickey_auto)(ssh_session session, const char *username, const char *passphrase);
|
||||||
|
const char * (*ssh_get_error)(void *error);
|
||||||
|
int (*ssh_get_error_code)(void *error);
|
||||||
|
void (*ssh_disconnect)(ssh_session session);
|
||||||
|
void (*ssh_free)(ssh_session session);
|
||||||
|
|
||||||
|
ssh_channel (*ssh_channel_new)(ssh_session session);
|
||||||
|
int (*ssh_channel_is_open)(ssh_channel channel);
|
||||||
|
int (*ssh_channel_close)(ssh_channel channel);
|
||||||
|
void (*ssh_channel_free)(ssh_channel channel);
|
||||||
|
int (*ssh_channel_open_session)(ssh_channel channel);
|
||||||
|
int (*ssh_channel_request_subsystem)(ssh_channel channel, const char *subsystem);
|
||||||
|
int (*ssh_channel_read_nonblocking)(ssh_channel channel, void *dest, uint32_t count, int is_stderr);
|
||||||
|
int (*ssh_channel_is_eof)(ssh_channel channel);
|
||||||
|
int (*ssh_channel_select)(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct timeval * timeout);
|
||||||
|
int (*ssh_channel_write)(ssh_channel channel, const void *data, uint32_t len);
|
||||||
|
|
||||||
|
const char *load_libssh(void);
|
||||||
|
|
||||||
|
#endif /* _BIRD_LIBSSH_H_ */
|
25
lib/socket.h
25
lib/socket.h
@ -10,8 +10,27 @@
|
|||||||
#define _BIRD_SOCKET_H_
|
#define _BIRD_SOCKET_H_
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
// #include <sys/socket.h>
|
||||||
|
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
|
#include "lib/libssh.h"
|
||||||
|
|
||||||
|
struct ssh_sock {
|
||||||
|
char *username; /* (Required) SSH user name */
|
||||||
|
char *server_hostkey_path; /* (Optional) Filepath to the SSH public key of remote side, can be knownhost file */
|
||||||
|
char *client_privkey_path; /* (Optional) Filepath to the SSH private key of BIRD */
|
||||||
|
char *subsystem; /* (Optional) Name of SSH subsytem */
|
||||||
|
ssh_session session; /* Internal */
|
||||||
|
ssh_channel channel; /* Internal */
|
||||||
|
int state; /* Internal */
|
||||||
|
#define BIRD_SSH_CONNECT 0 /* Start state */
|
||||||
|
#define BIRD_SSH_IS_SERVER_KNOWN 1
|
||||||
|
#define BIRD_SSH_USERAUTH_PUBLICKEY_AUTO 2
|
||||||
|
#define BIRD_SSH_CHANNEL_NEW 3
|
||||||
|
#define BIRD_SSH_CHANNEL_OPEN_SESSION 4
|
||||||
|
#define BIRD_SSH_CHANNEL_REQUEST_SUBSYSTEM 5
|
||||||
|
#define BIRD_SSH_CONNECTION_ESTABLISHED 6 /* Final state */
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct birdsock {
|
typedef struct birdsock {
|
||||||
resource r;
|
resource r;
|
||||||
@ -19,6 +38,7 @@ typedef struct birdsock {
|
|||||||
int type; /* Socket type */
|
int type; /* Socket type */
|
||||||
void *data; /* User data */
|
void *data; /* User data */
|
||||||
ip_addr saddr, daddr; /* IPA_NONE = unspecified */
|
ip_addr saddr, daddr; /* IPA_NONE = unspecified */
|
||||||
|
char *host; /* Alternative to daddr, NULL = unspecified */
|
||||||
uint sport, dport; /* 0 = unspecified (for IP: protocol type) */
|
uint sport, dport; /* 0 = unspecified (for IP: protocol type) */
|
||||||
int tos; /* TOS / traffic class, -1 = default */
|
int tos; /* TOS / traffic class, -1 = default */
|
||||||
int priority; /* Local socket priority, -1 = default */
|
int priority; /* Local socket priority, -1 = default */
|
||||||
@ -50,7 +70,8 @@ typedef struct birdsock {
|
|||||||
node n;
|
node n;
|
||||||
void *rbuf_alloc, *tbuf_alloc;
|
void *rbuf_alloc, *tbuf_alloc;
|
||||||
char *password; /* Password for MD5 authentication */
|
char *password; /* Password for MD5 authentication */
|
||||||
char *err; /* Error message */
|
const char *err; /* Error message */
|
||||||
|
struct ssh_sock *ssh; /* Used in SK_SSH */
|
||||||
} sock;
|
} sock;
|
||||||
|
|
||||||
sock *sock_new(pool *); /* Allocate new socket */
|
sock *sock_new(pool *); /* Allocate new socket */
|
||||||
@ -114,6 +135,8 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
|
|||||||
#define SK_MAGIC 7 /* Internal use by sysdep code */
|
#define SK_MAGIC 7 /* Internal use by sysdep code */
|
||||||
#define SK_UNIX_PASSIVE 8
|
#define SK_UNIX_PASSIVE 8
|
||||||
#define SK_UNIX 9
|
#define SK_UNIX 9
|
||||||
|
#define SK_SSH_ACTIVE 10 /* - - * * - ? - DA = host */
|
||||||
|
#define SK_SSH 11
|
||||||
|
|
||||||
/* Socket families */
|
/* Socket families */
|
||||||
|
|
||||||
|
@ -877,6 +877,7 @@ proto_build(struct protocol *p)
|
|||||||
|
|
||||||
/* FIXME: convert this call to some protocol hook */
|
/* FIXME: convert this call to some protocol hook */
|
||||||
extern void bfd_init_all(void);
|
extern void bfd_init_all(void);
|
||||||
|
extern void rpki_init_all(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* protos_build - build a protocol list
|
* protos_build - build a protocol list
|
||||||
@ -919,6 +920,10 @@ protos_build(void)
|
|||||||
proto_build(&proto_bfd);
|
proto_build(&proto_bfd);
|
||||||
bfd_init_all();
|
bfd_init_all();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_RPKI
|
||||||
|
proto_build(&proto_rpki);
|
||||||
|
rpki_init_all();
|
||||||
|
#endif
|
||||||
|
|
||||||
proto_pool = rp_new(&root_pool, "Protocols");
|
proto_pool = rp_new(&root_pool, "Protocols");
|
||||||
proto_flush_event = ev_new(proto_pool);
|
proto_flush_event = ev_new(proto_pool);
|
||||||
|
@ -76,7 +76,7 @@ void protos_dump_all(void);
|
|||||||
|
|
||||||
extern struct protocol
|
extern struct protocol
|
||||||
proto_device, proto_radv, proto_rip, proto_static,
|
proto_device, proto_radv, proto_rip, proto_static,
|
||||||
proto_ospf, proto_pipe, proto_bgp, proto_bfd;
|
proto_ospf, proto_pipe, proto_bgp, proto_bfd, proto_rpki;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Routing Protocol Instance
|
* Routing Protocol Instance
|
||||||
|
@ -386,6 +386,7 @@ typedef struct rta {
|
|||||||
#define RTS_OSPF_EXT2 10 /* OSPF external route type 2 */
|
#define RTS_OSPF_EXT2 10 /* OSPF external route type 2 */
|
||||||
#define RTS_BGP 11 /* BGP route */
|
#define RTS_BGP 11 /* BGP route */
|
||||||
#define RTS_PIPE 12 /* Inter-table wormhole */
|
#define RTS_PIPE 12 /* Inter-table wormhole */
|
||||||
|
#define RTS_RPKI 13 /* Route Origin Authorization */
|
||||||
|
|
||||||
#define RTC_UNICAST 0
|
#define RTC_UNICAST 0
|
||||||
#define RTC_BROADCAST 1
|
#define RTC_BROADCAST 1
|
||||||
|
@ -3,7 +3,8 @@ C bfd
|
|||||||
C bgp
|
C bgp
|
||||||
C ospf
|
C ospf
|
||||||
C pipe
|
C pipe
|
||||||
C rip
|
|
||||||
C radv
|
C radv
|
||||||
|
C rip
|
||||||
|
C rpki
|
||||||
C static
|
C static
|
||||||
S ../nest/rt-dev.c
|
S ../nest/rt-dev.c
|
||||||
|
1
proto/rpki/Doc
Normal file
1
proto/rpki/Doc
Normal file
@ -0,0 +1 @@
|
|||||||
|
C rpki.c
|
5
proto/rpki/Makefile
Normal file
5
proto/rpki/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
source=rpki.c packets.c rtr.c tcp_transport.c ssh_transport.c transport.c
|
||||||
|
root-rel=../../
|
||||||
|
dir-name=proto/rpki
|
||||||
|
|
||||||
|
include ../../Rules
|
152
proto/rpki/config.Y
Normal file
152
proto/rpki/config.Y
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CF_HDR
|
||||||
|
|
||||||
|
#include "proto/rpki/rpki.h"
|
||||||
|
|
||||||
|
CF_DEFINES
|
||||||
|
|
||||||
|
#define RPKI_CFG ((struct rpki_config *) this_proto)
|
||||||
|
|
||||||
|
static struct rpki_cache_cfg *this_rpki_cache_cfg;
|
||||||
|
|
||||||
|
CF_DECLS
|
||||||
|
|
||||||
|
CF_KEYWORDS(RPKI, CACHE, LIST, PREFERENCE, BIRD, PRIVATE, PUBLIC, KEY, SSH, ENCRYPTION, USER)
|
||||||
|
CF_KEYWORDS(RETRY, REFRESH, EXPIRE)
|
||||||
|
|
||||||
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
CF_ADDTO(proto, rpki_proto)
|
||||||
|
|
||||||
|
rpki_proto:
|
||||||
|
rpki_proto_start proto_name '{' rpki_proto_opts '}' rpki_proto_finish
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_proto_start:
|
||||||
|
proto_start RPKI {
|
||||||
|
this_proto = proto_config_new(&proto_rpki, $1);
|
||||||
|
init_list(&RPKI_CFG->cache_cfg_list);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_proto_finish:
|
||||||
|
{
|
||||||
|
// if (RPKI_CFG->roa_table_cf == NULL)
|
||||||
|
// cf_error("For the RPKI protocol must be specified a roa table");
|
||||||
|
};
|
||||||
|
|
||||||
|
rpki_proto_opts:
|
||||||
|
/* empty */
|
||||||
|
| rpki_proto_opts rpki_proto_item ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_proto_item:
|
||||||
|
proto_item
|
||||||
|
| CACHE rpki_cache
|
||||||
|
/* | ROA TABLE roa_table_cf { RPKI_CFG->roa_table_cf = $3; } */
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_cache:
|
||||||
|
rpki_cache_init rpki_cache_addr rpki_optional_cache_opts rpki_cache_finish {
|
||||||
|
add_tail(&RPKI_CFG->cache_cfg_list, &this_rpki_cache_cfg->n);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_cache_finish:
|
||||||
|
{
|
||||||
|
if (this_rpki_cache_cfg->port == 0) /* empty? */
|
||||||
|
{
|
||||||
|
if (this_rpki_cache_cfg->ssh != NULL)
|
||||||
|
this_rpki_cache_cfg->port = RPKI_DEFAULT_SSH_PORT;
|
||||||
|
else
|
||||||
|
this_rpki_cache_cfg->port = RPKI_DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_cache_init:
|
||||||
|
{
|
||||||
|
this_rpki_cache_cfg = rpki_new_cache_cfg();
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_cache_addr:
|
||||||
|
text {
|
||||||
|
this_rpki_cache_cfg->hostname = $1;
|
||||||
|
}
|
||||||
|
| ipa {
|
||||||
|
this_rpki_cache_cfg->ip = $1;
|
||||||
|
this_rpki_cache_cfg->hostname = cfg_allocz(sizeof(INET6_ADDRSTRLEN+1));
|
||||||
|
bsnprintf(this_rpki_cache_cfg->hostname, INET6_ADDRSTRLEN+1, "%I", this_rpki_cache_cfg->ip);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_optional_cache_opts:
|
||||||
|
/* empty */
|
||||||
|
| '{' rpki_cache_opts '}'
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_cache_opts:
|
||||||
|
/* empty */
|
||||||
|
| rpki_cache_opts rpki_cache_opts_item ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_cache_opts_item:
|
||||||
|
PORT expr {
|
||||||
|
check_u16($2);
|
||||||
|
this_rpki_cache_cfg->port = $2;
|
||||||
|
}
|
||||||
|
| PREFERENCE expr {
|
||||||
|
if ($2 < 1 || $2 > 0xFF)
|
||||||
|
cf_error("Value %d is out of range (1-255)", $2);
|
||||||
|
this_rpki_cache_cfg->preference = $2;
|
||||||
|
}
|
||||||
|
| REFRESH expr { this_rpki_cache_cfg->refresh_interval = $2; }
|
||||||
|
| RETRY expr { this_rpki_cache_cfg->retry_interval = $2; }
|
||||||
|
| EXPIRE expr { this_rpki_cache_cfg->expire_interval = $2; }
|
||||||
|
| SSH ENCRYPTION rpki_transport_ssh_init '{' rpki_transport_ssh_opts '}' rpki_transport_ssh_finish
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_transport_ssh_init:
|
||||||
|
{
|
||||||
|
this_rpki_cache_cfg->ssh = cfg_allocz(sizeof(struct rpki_cache_ssh_cfg));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_transport_ssh_opts:
|
||||||
|
/* empty */
|
||||||
|
| rpki_transport_ssh_opts rpki_transport_ssh_item ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_transport_ssh_item:
|
||||||
|
BIRD PRIVATE KEY text {
|
||||||
|
check_file_readability($4);
|
||||||
|
this_rpki_cache_cfg->ssh->bird_private_key = $4;
|
||||||
|
}
|
||||||
|
| CACHE PUBLIC KEY text {
|
||||||
|
check_file_readability($4);
|
||||||
|
this_rpki_cache_cfg->ssh->cache_public_key = $4;
|
||||||
|
}
|
||||||
|
| USER text {
|
||||||
|
this_rpki_cache_cfg->ssh->username = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rpki_transport_ssh_finish:
|
||||||
|
{
|
||||||
|
#define RPKI_PARSE_CACHE_MISS_SSH_OPT(what) "Miss '" what ";' option in the %s protocol at cache server %s inside the ssh encryption block"
|
||||||
|
|
||||||
|
if (!this_rpki_cache_cfg->ssh->username)
|
||||||
|
cf_error(RPKI_PARSE_CACHE_MISS_SSH_OPT("user \"ssh_username\""), RPKI_CFG->c.name, this_rpki_cache_cfg->hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
CF_CODE
|
||||||
|
|
||||||
|
CF_END
|
1020
proto/rpki/packets.c
Normal file
1020
proto/rpki/packets.c
Normal file
File diff suppressed because it is too large
Load Diff
38
proto/rpki/packets.h
Normal file
38
proto/rpki/packets.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file is part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTR_PACKETS_H
|
||||||
|
#define RTR_PACKETS_H
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include "rtr.h"
|
||||||
|
|
||||||
|
#define RPKI_RX_BUFFER_SIZE 65536
|
||||||
|
#define RPKI_TX_BUFFER_SIZE 65536
|
||||||
|
#define RPKI_PDU_HEADER_LEN 8
|
||||||
|
#define RPKI_PDU_MAX_LEN 848 /* Error PDU size is the biggest (has encapsulate PDU inside):
|
||||||
|
* header(8) +
|
||||||
|
* len_of_encapsulated_pdu(4) +
|
||||||
|
* encapsulated_pdu_ipv6(32) +
|
||||||
|
* len_of_text(4) +
|
||||||
|
* utf-8 text(400*2) = 848
|
||||||
|
*/
|
||||||
|
#define RPKI_RECV_TIMEOUT 60
|
||||||
|
#define RPKI_SEND_TIMEOUT 60
|
||||||
|
|
||||||
|
int rtr_sync(struct rpki_cache *cache);
|
||||||
|
int rtr_wait_for_sync(struct rpki_cache *cache);
|
||||||
|
int rtr_send_serial_query(struct rpki_cache *cache);
|
||||||
|
int rtr_send_reset_query(struct rpki_cache *cache);
|
||||||
|
int rpki_rx_hook(struct birdsock *sk, int size);
|
||||||
|
void rpki_connected_hook(sock *sk);
|
||||||
|
void rpki_err_hook(struct birdsock *sk, int size);
|
||||||
|
void pfx_table_src_remove(struct rpki_cache *cache);
|
||||||
|
|
||||||
|
#endif
|
645
proto/rpki/rpki.c
Normal file
645
proto/rpki/rpki.c
Normal file
@ -0,0 +1,645 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* Using RTRLib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: RPKI to Router Protocol
|
||||||
|
*
|
||||||
|
* The Resource Public Key Infrastructure (RPKI) to router protocol implementation
|
||||||
|
* is based on the RTRlib (http://rpki.realmv6.org/). The BIRD takes over
|
||||||
|
* |packets.c|, |rtr.c|, |transport.c|, |tcp_transport.c| and |ssh_transport.c| files
|
||||||
|
* from RTRlib.
|
||||||
|
*
|
||||||
|
* A SSH transport requires LibSSH library. LibSSH is loading dynamically using dlopen
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef LOCAL_DEBUG
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include "rpki.h"
|
||||||
|
#include "lib/idm.h"
|
||||||
|
#include "lib/string.h"
|
||||||
|
#include "lib/unix.h"
|
||||||
|
|
||||||
|
static struct idm cache_uniq_id_generator;
|
||||||
|
|
||||||
|
static const char *mgr_str_status[] = {
|
||||||
|
[RTR_MGR_CLOSED] = "RTR_MGR_CLOSED",
|
||||||
|
[RTR_MGR_CONNECTING] = "RTR_MGR_CONNECTING",
|
||||||
|
[RTR_MGR_ESTABLISHED] = "RTR_MGR_ESTABLISHED",
|
||||||
|
[RTR_MGR_ERROR] = "RTR_MGR_ERROR",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *
|
||||||
|
get_group_status(struct rpki_cache_group *group)
|
||||||
|
{
|
||||||
|
return mgr_str_status[group->status];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpki_init_all(void)
|
||||||
|
{
|
||||||
|
idm_init(&cache_uniq_id_generator, &root_pool, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct proto *
|
||||||
|
rpki_init(struct proto_config *C)
|
||||||
|
{
|
||||||
|
struct proto *P = proto_new(C, sizeof(struct rpki_proto));
|
||||||
|
struct rpki_proto *p = (void *) P;
|
||||||
|
p->cf = (void *) C;
|
||||||
|
|
||||||
|
init_list(&p->group_list);
|
||||||
|
|
||||||
|
return P;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
get_cache_ident(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
return tr_ident(cache->rtr_socket->tr_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpki_print_groups(struct rpki_proto *p)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *g;
|
||||||
|
WALK_LIST(g, p->group_list)
|
||||||
|
{
|
||||||
|
DBG("Group(%u) %s \n", g->preference, get_group_status(g));
|
||||||
|
|
||||||
|
struct rpki_cache *c;
|
||||||
|
WALK_LIST(c, g->cache_list)
|
||||||
|
{
|
||||||
|
DBG(" Cache(%s) %s \n", get_cache_ident(c), rtr_state_to_str(c->rtr_socket->state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rpki_cache_group *
|
||||||
|
rpki_cache_group_alloc(struct rpki_proto *p, u8 preference)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *new = mb_allocz(p->p.pool, sizeof(struct rpki_cache_group));
|
||||||
|
init_list(&new->cache_list);
|
||||||
|
new->preference = preference;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rpki_cache_group *
|
||||||
|
rpki_new_cache_group_before(struct rpki_proto *p, struct rpki_cache_group *before, list *group_list, u8 preference)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *new = rpki_cache_group_alloc(p, preference);
|
||||||
|
|
||||||
|
if (&before->n == group_list->head)
|
||||||
|
add_head(group_list, &new->n);
|
||||||
|
else
|
||||||
|
insert_node(&new->n, before->n.prev);
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpki_insert_cache_into_group(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = cache->p;
|
||||||
|
struct rpki_cache_group *group_iter;
|
||||||
|
WALK_LIST(group_iter, p->group_list)
|
||||||
|
{
|
||||||
|
if (group_iter->preference == cache->cfg->preference)
|
||||||
|
{
|
||||||
|
add_tail(&group_iter->cache_list, &cache->n);
|
||||||
|
cache->group = group_iter;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group_iter->preference > cache->cfg->preference)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *new_group = rpki_new_cache_group_before(p, group_iter, &p->group_list, cache->cfg->preference);
|
||||||
|
add_tail(&new_group->cache_list, &cache->n);
|
||||||
|
cache->group = new_group;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rpki_cache_group *new_group = rpki_cache_group_alloc(p, cache->cfg->preference);
|
||||||
|
add_tail(&p->group_list, &new_group->n);
|
||||||
|
add_tail(&new_group->cache_list, &cache->n);
|
||||||
|
cache->group = new_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rpki_cache_cfg *
|
||||||
|
rpki_new_cache_cfg(void)
|
||||||
|
{
|
||||||
|
struct rpki_cache_cfg *cache = cfg_allocz(sizeof(struct rpki_cache_cfg));
|
||||||
|
cache->preference = RPKI_DEFAULT_CACHE_PREFERENCE;
|
||||||
|
cache->ip = IPA_NONE;
|
||||||
|
|
||||||
|
cache->retry_interval = RPKI_DEFAULT_RETRY_INTERVAL;
|
||||||
|
cache->refresh_interval = RPKI_DEFAULT_REFRESH_INTERVAL;
|
||||||
|
cache->expire_interval = RPKI_DEFAULT_EXPIRE_INTERVAL;
|
||||||
|
|
||||||
|
/* The port number will be set afterwards */
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rpki_cache *
|
||||||
|
rpki_new_cache(struct rpki_proto *p, struct rpki_cache_cfg *cache_cfg)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache = mb_allocz(p->p.pool, sizeof(struct rpki_cache));
|
||||||
|
struct rtr_socket *rtr_socket = mb_allocz(p->p.pool, sizeof(struct rtr_socket));
|
||||||
|
struct tr_socket *tr_socket = mb_allocz(p->p.pool, sizeof(struct tr_socket));
|
||||||
|
|
||||||
|
cache->p = p;
|
||||||
|
cache->cfg = cache_cfg;
|
||||||
|
cache->cache_id = idm_alloc(&cache_uniq_id_generator);
|
||||||
|
cache->retry_timer = tm_new_set(p->p.pool, &rpki_retry_hook, cache, 0, 0);
|
||||||
|
cache->refresh_timer = tm_new_set(p->p.pool, &rpki_refresh_hook, cache, 0, 0);
|
||||||
|
cache->expire_timer = tm_new_set(p->p.pool, &rpki_expire_hook, cache, 0, 0);
|
||||||
|
cache->rtr_socket = rtr_socket;
|
||||||
|
cache->rtr_socket->tr_socket = tr_socket;
|
||||||
|
cache->rtr_socket->cache = cache;
|
||||||
|
|
||||||
|
if (cache_cfg->ssh)
|
||||||
|
tr_ssh_init(cache);
|
||||||
|
else
|
||||||
|
tr_tcp_init(cache);
|
||||||
|
|
||||||
|
rtr_init(rtr_socket, cache_cfg->refresh_interval, cache_cfg->expire_interval, cache_cfg->retry_interval);
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close connection without change a status
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rpki_close_connection(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
sock *sk = cache->sk;
|
||||||
|
|
||||||
|
if (sk)
|
||||||
|
{
|
||||||
|
CACHE_TRACE(D_EVENTS, cache, "Close the connection");
|
||||||
|
tr_close(cache->rtr_socket->tr_socket);
|
||||||
|
rfree(sk);
|
||||||
|
cache->sk = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fulfill sock->af and sock->daddr if empty
|
||||||
|
* Return TR_SUCCESS or TR_ERROR
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
rpki_sock_dst_autoresolv(sock *sk)
|
||||||
|
{
|
||||||
|
if (ipa_zero(sk->daddr) && sk->host)
|
||||||
|
{
|
||||||
|
struct addrinfo *res;
|
||||||
|
struct addrinfo *bind_addrinfo = NULL;
|
||||||
|
struct addrinfo hints = {
|
||||||
|
.ai_family = AF_UNSPEC,
|
||||||
|
.ai_socktype = SOCK_STREAM,
|
||||||
|
.ai_flags = AI_ADDRCONFIG,
|
||||||
|
};
|
||||||
|
|
||||||
|
char port[6]; /* max is "65535" + '\0' */
|
||||||
|
bsnprintf(port, sizeof(port), "%u", sk->dport);
|
||||||
|
|
||||||
|
if (getaddrinfo(sk->host, port, &hints, &res) != 0)
|
||||||
|
{
|
||||||
|
CACHE_TRACE(D_EVENTS, (struct rpki_cache *)sk->data, "getaddrinfo error, %s", gai_strerror(errno));
|
||||||
|
return TR_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sk->af = res->ai_family;
|
||||||
|
|
||||||
|
sockaddr sa = {
|
||||||
|
.sa = *res->ai_addr,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint unused;
|
||||||
|
sockaddr_read(&sa, res->ai_family, &sk->daddr, NULL, &unused);
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
}
|
||||||
|
else if (ipa_zero(sk->daddr) && !sk->host)
|
||||||
|
return TR_ERROR;
|
||||||
|
else
|
||||||
|
sk->af = ip6_is_v4mapped(sk->daddr) ? AF_INET : AF_INET6;
|
||||||
|
|
||||||
|
return TR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rpki_open_connection(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = cache->p;
|
||||||
|
struct tr_socket *tr_socket = cache->rtr_socket->tr_socket;
|
||||||
|
CACHE_TRACE(D_EVENTS, cache, "Open a connection");
|
||||||
|
|
||||||
|
ASSERT(cache->sk == NULL);
|
||||||
|
|
||||||
|
cache->sk = sk_new(p->p.pool);
|
||||||
|
sock *sk = cache->sk;
|
||||||
|
rtr_change_socket_state(cache->rtr_socket, RTR_OPENING);
|
||||||
|
|
||||||
|
sk->tx_hook = rpki_connected_hook;
|
||||||
|
sk->err_hook = rpki_err_hook;
|
||||||
|
sk->data = cache;
|
||||||
|
sk->daddr = cache->cfg->ip;
|
||||||
|
sk->dport = cache->cfg->port;
|
||||||
|
sk->host = cache->cfg->hostname;
|
||||||
|
sk->rbsize = RPKI_RX_BUFFER_SIZE;
|
||||||
|
sk->tbsize = RPKI_TX_BUFFER_SIZE;
|
||||||
|
sk->tos = IP_PREC_INTERNET_CONTROL;
|
||||||
|
sk->type = -1; /* must be set in the specific transport layer in tr_open() */
|
||||||
|
rpki_sock_dst_autoresolv(sk);
|
||||||
|
|
||||||
|
if (tr_open(tr_socket) == TR_ERROR)
|
||||||
|
{
|
||||||
|
sk_log_error(sk, p->p.name);
|
||||||
|
rtr_change_socket_state(cache->rtr_socket, RTR_ERROR_TRANSPORT);
|
||||||
|
return TR_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open connections to all caches in group
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rpki_open_group(struct rpki_cache_group *group)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
WALK_LIST(cache, group->cache_list)
|
||||||
|
{
|
||||||
|
if (cache->rtr_socket->state == RTR_SHUTDOWN)
|
||||||
|
rpki_open_connection(cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpki_close_group(struct rpki_cache_group *group)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
WALK_LIST(cache, group->cache_list)
|
||||||
|
{
|
||||||
|
if (cache->rtr_socket->state != RTR_SHUTDOWN)
|
||||||
|
rtr_change_socket_state(cache->rtr_socket, RTR_SHUTDOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpki_remove_cache_from_group(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
rem2_node(&cache->n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpki_free_cache(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
rpki_remove_cache_from_group(cache);
|
||||||
|
rpki_close_connection(cache);
|
||||||
|
pfx_table_src_remove(cache);
|
||||||
|
|
||||||
|
tr_free(cache->rtr_socket->tr_socket);
|
||||||
|
mb_free(cache->rtr_socket->tr_socket);
|
||||||
|
mb_free(cache->rtr_socket);
|
||||||
|
|
||||||
|
/* Timers */
|
||||||
|
tm_stop(cache->retry_timer);
|
||||||
|
tm_stop(cache->refresh_timer);
|
||||||
|
tm_stop(cache->expire_timer);
|
||||||
|
|
||||||
|
rfree(cache->retry_timer);
|
||||||
|
rfree(cache->refresh_timer);
|
||||||
|
rfree(cache->expire_timer);
|
||||||
|
|
||||||
|
idm_free(&cache_uniq_id_generator, cache->cache_id);
|
||||||
|
|
||||||
|
mb_free(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpki_stop_and_free_caches(struct rpki_proto *p)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *group;
|
||||||
|
WALK_LIST_FIRST(group, p->group_list)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
WALK_LIST_FIRST(cache, group->cache_list)
|
||||||
|
{
|
||||||
|
rem_node(NODE cache);
|
||||||
|
rpki_free_cache(cache);
|
||||||
|
}
|
||||||
|
rem_node(NODE group);
|
||||||
|
mb_free(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_notify_state(&p->p, PS_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rpki_shutdown(struct proto *P)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = (struct rpki_proto *) P;
|
||||||
|
|
||||||
|
rpki_stop_and_free_caches(p);
|
||||||
|
|
||||||
|
return PS_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
are_port_and_host_same(struct rpki_cache_cfg *a, struct rpki_cache_cfg *b)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
(a->port == b->port) &&
|
||||||
|
(
|
||||||
|
(a->hostname && b->hostname && strcmp(a->hostname, b->hostname) == 0) ||
|
||||||
|
(ipa_nonzero(a->ip) && (ipa_compare(a->ip, b->ip) == 0))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rpki_cache_cfg *
|
||||||
|
find_cache_cfg_by_host_and_port(list *cache_list, struct rpki_cache_cfg *needle)
|
||||||
|
{
|
||||||
|
struct rpki_cache_cfg *cache_cfg;
|
||||||
|
WALK_LIST(cache_cfg, *cache_list)
|
||||||
|
{
|
||||||
|
if (are_port_and_host_same(needle, cache_cfg))
|
||||||
|
return cache_cfg;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rpki_cache *
|
||||||
|
find_cache_in_proto_by_host_and_port(struct rpki_proto *p, struct rpki_cache_cfg *needle)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *group;
|
||||||
|
WALK_LIST(group, p->group_list)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
WALK_LIST(cache, group->cache_list)
|
||||||
|
{
|
||||||
|
if (are_port_and_host_same(needle, cache->cfg))
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_empty_cache_groups(struct rpki_proto *p)
|
||||||
|
{
|
||||||
|
struct rpki_cache_group *group, *group_nxt;
|
||||||
|
WALK_LIST_DELSAFE(group, group_nxt, p->group_list)
|
||||||
|
{
|
||||||
|
if (EMPTY_LIST(group->cache_list))
|
||||||
|
rem_node(&group->n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move cache into `cache->cfg->preference` preference
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
move_cache_into_group(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
rpki_remove_cache_from_group(cache);
|
||||||
|
rpki_insert_cache_into_group(cache);
|
||||||
|
remove_empty_cache_groups(cache->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go through the group list ordered by priority.
|
||||||
|
* Open the first CLOSED group or stop opening groups if the processed group state is CONNECTING or ESTABLISHED
|
||||||
|
* Then close all groups with the more unimportant priority
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rpki_relax_groups(struct rpki_proto *p)
|
||||||
|
{
|
||||||
|
DBG("Relaxing groups...\n");
|
||||||
|
if (EMPTY_LIST(p->group_list))
|
||||||
|
{
|
||||||
|
RPKI_WARN(p, "No cache in configuration found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool close_all_next_groups = false;
|
||||||
|
|
||||||
|
struct rpki_cache_group *group;
|
||||||
|
WALK_LIST(group, p->group_list)
|
||||||
|
{
|
||||||
|
if (!close_all_next_groups)
|
||||||
|
{
|
||||||
|
switch (group->status)
|
||||||
|
{
|
||||||
|
case RTR_MGR_CLOSED:
|
||||||
|
RPKI_TRACE(D_EVENTS, p, "Open cache group(%u)", group->preference);
|
||||||
|
/* Fall through */
|
||||||
|
case RTR_MGR_CONNECTING:
|
||||||
|
case RTR_MGR_ESTABLISHED:
|
||||||
|
close_all_next_groups = 1;
|
||||||
|
/* Fall through */
|
||||||
|
case RTR_MGR_ERROR:
|
||||||
|
rpki_open_group(group);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RPKI_TRACE(D_EVENTS, p, "Close cache group(%u)", group->preference);
|
||||||
|
rpki_close_group(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpki_print_groups(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rpki_reconfigure_proto(struct rpki_proto *p, struct rpki_config *new_cf, struct rpki_config *old_cf)
|
||||||
|
{
|
||||||
|
if (old_cf->c.table && new_cf->c.table && old_cf->c.table->table != new_cf->c.table->table)
|
||||||
|
{
|
||||||
|
RPKI_TRACE(D_EVENTS, p, "Table changed");
|
||||||
|
return 0; /* Need to restart the protocol */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rpki_cache_cfg *old;
|
||||||
|
WALK_LIST(old, old_cf->cache_cfg_list)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache = find_cache_in_proto_by_host_and_port(p, old);
|
||||||
|
if (!cache)
|
||||||
|
bug("Weird...");
|
||||||
|
|
||||||
|
struct rpki_cache_cfg *new = find_cache_cfg_by_host_and_port(&new_cf->cache_cfg_list, old);
|
||||||
|
if (!new)
|
||||||
|
{
|
||||||
|
/* The cache was in new configuration deleted */
|
||||||
|
rpki_free_cache(cache);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->cfg = new;
|
||||||
|
|
||||||
|
if (old->preference != new->preference)
|
||||||
|
{
|
||||||
|
/* The preference of cache was changed */
|
||||||
|
move_cache_into_group(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!old->ssh != !!new->ssh)
|
||||||
|
{
|
||||||
|
/* toggled SSH enable/disable */
|
||||||
|
return 0; /* Need to restart the protocol */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old->ssh && new->ssh)
|
||||||
|
{
|
||||||
|
/* TODO: RTR_FAST_RECONNECT will be probably enough */
|
||||||
|
|
||||||
|
if (strcmp(old->ssh->bird_private_key, new->ssh->bird_private_key) != 0)
|
||||||
|
return 0; /* Need to restart the protocol */
|
||||||
|
|
||||||
|
if (strcmp(old->ssh->cache_public_key, new->ssh->cache_public_key) != 0)
|
||||||
|
return 0; /* Need to restart the protocol */
|
||||||
|
|
||||||
|
if (strcmp(old->ssh->username, new->ssh->username) != 0)
|
||||||
|
return 0; /* Need to restart the protocol */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rpki_cache_cfg *new;
|
||||||
|
WALK_LIST(new, new_cf->cache_cfg_list)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache = find_cache_in_proto_by_host_and_port(p, new);
|
||||||
|
if (cache)
|
||||||
|
cache->cfg = new;
|
||||||
|
|
||||||
|
struct rpki_cache_cfg *old = find_cache_cfg_by_host_and_port(&old_cf->cache_cfg_list, new);
|
||||||
|
if (!old)
|
||||||
|
{
|
||||||
|
/* Some cache was added to new configuration */
|
||||||
|
struct rpki_cache *new_cache = rpki_new_cache(p, new);
|
||||||
|
rpki_insert_cache_into_group(new_cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpki_print_groups(p);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return 0 if need to restart rtrlib manager
|
||||||
|
* Return 1 if not need to restart rtrlib manager
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
rpki_reconfigure(struct proto *P, struct proto_config *c)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = (struct rpki_proto *) P;
|
||||||
|
struct rpki_config *old_cf = p->cf;
|
||||||
|
struct rpki_config *new_cf = (struct rpki_config *) c;
|
||||||
|
|
||||||
|
int continue_without_restart = rpki_reconfigure_proto(p, new_cf, old_cf);
|
||||||
|
|
||||||
|
p->cf = new_cf;
|
||||||
|
|
||||||
|
if (continue_without_restart)
|
||||||
|
rpki_relax_groups(p);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RPKI_TRACE(D_EVENTS, p, "Have to restart whole protocol");
|
||||||
|
}
|
||||||
|
|
||||||
|
return continue_without_restart;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpki_get_status(struct proto *P, byte *buf)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = (struct rpki_proto *) P;
|
||||||
|
|
||||||
|
uint established_connections = 0;
|
||||||
|
uint cache_servers = 0;
|
||||||
|
uint connecting = 0;
|
||||||
|
|
||||||
|
struct rpki_cache_group *group;
|
||||||
|
WALK_LIST(group, p->group_list)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
WALK_LIST(cache, group->cache_list)
|
||||||
|
{
|
||||||
|
cache_servers++;
|
||||||
|
|
||||||
|
switch (cache->rtr_socket->state)
|
||||||
|
{
|
||||||
|
case RTR_ESTABLISHED:
|
||||||
|
case RTR_SYNC:
|
||||||
|
established_connections++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_SHUTDOWN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
connecting++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (established_connections > 0)
|
||||||
|
bsprintf(buf, "Keep synchronized with %u cache server%s", established_connections, (established_connections > 1) ? "s" : "");
|
||||||
|
else if (connecting > 0)
|
||||||
|
bsprintf(buf, "Connecting to %u cache server%s", connecting, (connecting > 1) ? "s" : "");
|
||||||
|
else if (cache_servers == 0)
|
||||||
|
bsprintf(buf, "No cache server is configured");
|
||||||
|
else if (cache_servers == 1)
|
||||||
|
bsprintf(buf, "Cannot connect to a cache server");
|
||||||
|
else
|
||||||
|
bsprintf(buf, "Cannot connect to any cache servers");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rpki_start(struct proto *P)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = (struct rpki_proto *) P;
|
||||||
|
struct rpki_config *cf = (struct rpki_config *) (P->cf);
|
||||||
|
|
||||||
|
struct rpki_config empty_configuration = {
|
||||||
|
.roa_table_cf = cf->roa_table_cf
|
||||||
|
};
|
||||||
|
init_list(&empty_configuration.cache_cfg_list);
|
||||||
|
rpki_reconfigure_proto(p, cf, &empty_configuration);
|
||||||
|
|
||||||
|
rpki_relax_groups(p);
|
||||||
|
|
||||||
|
return PS_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct protocol proto_rpki = {
|
||||||
|
.name = "RPKI",
|
||||||
|
.template = "rpki%d",
|
||||||
|
.config_size = sizeof(struct rpki_config),
|
||||||
|
.init = rpki_init,
|
||||||
|
.start = rpki_start,
|
||||||
|
// .show_proto_info = rpki_show_proto_info, // TODO: be nice to be implemented
|
||||||
|
.shutdown = rpki_shutdown,
|
||||||
|
.reconfigure = rpki_reconfigure,
|
||||||
|
.get_status = rpki_get_status,
|
||||||
|
};
|
143
proto/rpki/rpki.h
Normal file
143
proto/rpki/rpki.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* Using RTRLib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIRD_RPKI_H_
|
||||||
|
#define _BIRD_RPKI_H_
|
||||||
|
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "nest/route.h"
|
||||||
|
#include "lib/socket.h"
|
||||||
|
#include "lib/ip.h"
|
||||||
|
|
||||||
|
#include "ssh_transport.h"
|
||||||
|
#include "tcp_transport.h"
|
||||||
|
#include "rtr.h"
|
||||||
|
#include "packets.h"
|
||||||
|
|
||||||
|
#define RPKI_DEFAULT_PORT 8282
|
||||||
|
#define RPKI_DEFAULT_SSH_PORT 22
|
||||||
|
#define RPKI_DEFAULT_RETRY_INTERVAL 30
|
||||||
|
#define RPKI_DEFAULT_REFRESH_INTERVAL 600
|
||||||
|
#define RPKI_DEFAULT_EXPIRE_INTERVAL 1200
|
||||||
|
#define RPKI_DEFAULT_CACHE_PREFERENCE 1 /* The most important priority */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-------------------------------------------+
|
||||||
|
* v |
|
||||||
|
* RTR_MGR_CLOSED <--> RTR_MGR_CONNECTING --> RTR_MGR_ESTABLISHED <--> RTR_MGR_ERROR
|
||||||
|
* ^ | ^ |
|
||||||
|
* | +-----------------------------------------+ |
|
||||||
|
* | |
|
||||||
|
* +-----------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
enum rtr_mgr_status {
|
||||||
|
/* RTR sockets are disconnected */
|
||||||
|
RTR_MGR_CLOSED,
|
||||||
|
|
||||||
|
/* RTR sockets trying to establish a connection. */
|
||||||
|
RTR_MGR_CONNECTING,
|
||||||
|
|
||||||
|
/* All RTR sockets of the group are synchronized with the rtr servers. */
|
||||||
|
RTR_MGR_ESTABLISHED,
|
||||||
|
|
||||||
|
/* Error occured on at least one RTR socket. */
|
||||||
|
RTR_MGR_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpki_cache_ssh_cfg {
|
||||||
|
char *bird_private_key; /* Filepath to the BIRD server private key */
|
||||||
|
char *cache_public_key; /* Filepath to the public key of cache server, can be file known_hosts */
|
||||||
|
char *username; /* Username for SSH connection */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Used in parsing of configuration file */
|
||||||
|
struct rpki_cache_cfg {
|
||||||
|
node n;
|
||||||
|
char *hostname; /* Full domain name of cache server or NULL */
|
||||||
|
ip_addr ip; /* IP address of cache server or IPA_NONE */
|
||||||
|
u16 port; /* Port of cache server */
|
||||||
|
u8 preference; /* Preference: the most prioritized are the lowest numbers and starts with 1 */
|
||||||
|
uint refresh_interval; /* Time interval (in seconds) for refreshing ROA from server */
|
||||||
|
uint expire_interval; /* Time interval (in seconds) */
|
||||||
|
uint retry_interval; /* Time interval (in seconds) for an unreachable server */
|
||||||
|
struct rpki_cache_ssh_cfg *ssh; /* SSH configuration or NULL */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpki_cache {
|
||||||
|
node n;
|
||||||
|
struct rpki_proto *p;
|
||||||
|
struct rpki_cache_cfg *cfg;
|
||||||
|
struct rpki_cache_group *group;
|
||||||
|
struct rtr_socket *rtr_socket; /* RTRlib's socket data structure */
|
||||||
|
sock *sk; /* BIRD's socket data structure */
|
||||||
|
timer *retry_timer; /* Timer for Cache server */
|
||||||
|
timer *refresh_timer; /* Timer for Cache server */
|
||||||
|
timer *expire_timer; /* Timer for Cache server */
|
||||||
|
u32 cache_id; /* For purge ROAs learned only from this cache */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpki_cache_group {
|
||||||
|
node n;
|
||||||
|
u8 preference; /* Preference: the most prioritized are the lowest numbers and starts with 1 */
|
||||||
|
list cache_list; /* List of cache servers (struct rpki_cache) * */
|
||||||
|
enum rtr_mgr_status status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpki_config {
|
||||||
|
struct proto_config c;
|
||||||
|
list cache_cfg_list; /* Unordered list of cache servers configurations (struct rpki_cache_cfg) */
|
||||||
|
struct roa_table_config *roa_table_cf;/* The ROA table for routes importing from cache servers */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpki_proto {
|
||||||
|
struct proto p;
|
||||||
|
struct rpki_config *cf;
|
||||||
|
list group_list; /* Sorted list of cache groups (struct rpki_cache_group) */
|
||||||
|
timer *timer; /* Main timer */
|
||||||
|
};
|
||||||
|
|
||||||
|
void rpki_init_all(void);
|
||||||
|
struct rpki_cache_cfg *rpki_new_cache_cfg(void);
|
||||||
|
void rpki_init_all(void);
|
||||||
|
void rpki_close_connection(struct rpki_cache *cache);
|
||||||
|
int rpki_open_connection(struct rpki_cache *cache);
|
||||||
|
const char *get_cache_ident(struct rpki_cache *cache);
|
||||||
|
void rpki_relax_groups(struct rpki_proto *p);
|
||||||
|
void rpki_print_groups(struct rpki_proto *p);
|
||||||
|
|
||||||
|
#define RPKI_LOG(log_level, rpki, msg, args...) \
|
||||||
|
do { \
|
||||||
|
log(log_level "%s: " msg, (rpki)->p.name , ## args); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#if defined(LOCAL_DEBUG) || defined(GLOBAL_DEBUG)
|
||||||
|
#define CACHE_DBG(cache,msg,args...) \
|
||||||
|
do { \
|
||||||
|
RPKI_LOG(L_DEBUG, (cache)->p, "%s: %s() " msg, get_cache_ident(cache),__func__, ## args); \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
#define CACHE_DBG(cache,msg,args...) do { } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RPKI_TRACE(level,rpki,msg,args...) \
|
||||||
|
do { \
|
||||||
|
if ((rpki)->p.debug & level) \
|
||||||
|
RPKI_LOG(L_TRACE, rpki, msg, ## args); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define CACHE_TRACE(level,cache,msg,args...) \
|
||||||
|
do { \
|
||||||
|
if ((cache)->p->p.debug & level) \
|
||||||
|
RPKI_LOG(L_TRACE, (cache)->p, "%s: " msg, get_cache_ident(cache), ## args); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define RPKI_WARN(p, msg, args...) RPKI_LOG(L_WARN, p, msg, ## args);
|
||||||
|
|
||||||
|
#endif /* _BIRD_RPKI_H_ */
|
338
proto/rpki/rtr.c
Normal file
338
proto/rpki/rtr.c
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef LOCAL_DEBUG
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "rpki.h"
|
||||||
|
|
||||||
|
#include "packets.h"
|
||||||
|
#include "rtr.h"
|
||||||
|
#include "lib/timer.h"
|
||||||
|
|
||||||
|
static const char *rtr_socket_str_states[] = {
|
||||||
|
[RTR_OPENING] = "RTR_OPENING",
|
||||||
|
[RTR_CONNECTING] = "RTR_CONNECTING",
|
||||||
|
[RTR_ESTABLISHED] = "RTR_ESTABLISHED",
|
||||||
|
[RTR_RESET] = "RTR_RESET",
|
||||||
|
[RTR_SYNC] = "RTR_SYNC",
|
||||||
|
[RTR_FAST_RECONNECT] = "RTR_FAST_RECONNECT",
|
||||||
|
[RTR_ERROR_NO_DATA_AVAIL] = "RTR_ERROR_NO_DATA_AVAIL",
|
||||||
|
[RTR_ERROR_NO_INCR_UPDATE_AVAIL] = "RTR_ERROR_NO_INCR_UPDATE_AVAIL",
|
||||||
|
[RTR_ERROR_FATAL] = "RTR_ERROR_FATAL",
|
||||||
|
[RTR_ERROR_TRANSPORT] = "RTR_ERROR_TRANSPORT",
|
||||||
|
[RTR_SHUTDOWN] = "RTR_SHUTDOWN"
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_init(struct rtr_socket *rtr_socket, const unsigned int refresh_interval, const unsigned int expire_interval, const unsigned int retry_interval)
|
||||||
|
{
|
||||||
|
if(refresh_interval == 0)
|
||||||
|
rtr_socket->refresh_interval = 300;
|
||||||
|
else if (refresh_interval > 3600)
|
||||||
|
{
|
||||||
|
CACHE_TRACE(D_EVENTS, rtr_socket->cache, "The refresh interval %u is too big, setting it to 3600 seconds", refresh_interval);
|
||||||
|
rtr_socket->refresh_interval = 3600;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rtr_socket->refresh_interval = (refresh_interval > (3600 - RPKI_RECV_TIMEOUT) ? (3600 - RPKI_RECV_TIMEOUT) : refresh_interval);
|
||||||
|
|
||||||
|
rtr_socket->expire_interval = (expire_interval == 0 ? (rtr_socket->refresh_interval * 2) : expire_interval);
|
||||||
|
rtr_socket->retry_interval = (retry_interval == 0) ? 600 : retry_interval;
|
||||||
|
|
||||||
|
rtr_socket->state = RTR_SHUTDOWN;
|
||||||
|
rtr_socket->request_session_id = true;
|
||||||
|
rtr_socket->serial_number = 0;
|
||||||
|
rtr_socket->last_update = 0;
|
||||||
|
rtr_socket->version = RTR_PROTOCOL_MAX_SUPPORTED_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_purge_records_if_outdated(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rtr_socket *rtr_socket = cache->rtr_socket;
|
||||||
|
|
||||||
|
if (rtr_socket->last_update == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((rtr_socket->last_update + rtr_socket->expire_interval) < now)
|
||||||
|
{
|
||||||
|
switch (rtr_socket->state)
|
||||||
|
{
|
||||||
|
case RTR_ESTABLISHED:
|
||||||
|
case RTR_SYNC:
|
||||||
|
CACHE_DBG(cache, "There are obsolete roa records, but cache is in ESTABLISHED/SYNC state. Bad timing...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfx_table_src_remove(cache);
|
||||||
|
CACHE_TRACE(D_EVENTS, cache, "Remove outdated records from pfx_table");
|
||||||
|
rtr_socket->request_session_id = true;
|
||||||
|
rtr_socket->serial_number = 0;
|
||||||
|
rtr_socket->last_update = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CACHE_DBG(cache, "There are no outdated roa records, it remains %u seconds to become obsolete", (now - (rtr_socket->last_update + rtr_socket->expire_interval)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_stop(struct rtr_socket *rtr_socket)
|
||||||
|
{
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_SHUTDOWN);
|
||||||
|
CACHE_TRACE(D_EVENTS, rtr_socket->cache, "Socket shut down");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
rtr_state_to_str(enum rtr_socket_state state)
|
||||||
|
{
|
||||||
|
return rtr_socket_str_states[state];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set group status to @mgr_status if all sockets of caches in the @group are @socket_state
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_group_status_to_if_all_sockets_are(struct rpki_cache_group *group, const enum rtr_mgr_status mgr_status, const enum rtr_socket_state socket_state)
|
||||||
|
{
|
||||||
|
bool do_all_sockets_pass = true;
|
||||||
|
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
WALK_LIST(cache, group->cache_list)
|
||||||
|
{
|
||||||
|
if (cache->rtr_socket->state != socket_state)
|
||||||
|
do_all_sockets_pass = false;
|
||||||
|
}
|
||||||
|
if (do_all_sockets_pass)
|
||||||
|
group->status = mgr_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_state new_state)
|
||||||
|
{
|
||||||
|
const enum rtr_socket_state old_state = rtr_socket->state;
|
||||||
|
|
||||||
|
if (old_state == new_state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rtr_socket->state = new_state;
|
||||||
|
|
||||||
|
struct rpki_cache *cache = rtr_socket->cache;
|
||||||
|
CACHE_TRACE(D_EVENTS, cache, "Change state %s -> %s", rtr_state_to_str(old_state), rtr_state_to_str(new_state));
|
||||||
|
|
||||||
|
switch (new_state)
|
||||||
|
{
|
||||||
|
case RTR_CONNECTING:
|
||||||
|
if (old_state == RTR_SHUTDOWN)
|
||||||
|
cache->group->status = RTR_MGR_CONNECTING;
|
||||||
|
|
||||||
|
if (cache->sk == NULL || cache->sk->fd < 0)
|
||||||
|
{
|
||||||
|
if (rpki_open_connection(cache) == TR_SUCCESS)
|
||||||
|
cache->rtr_socket->state = RTR_SYNC; /* Need call a setup the bird socket in io.c loop */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_SYNC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_ESTABLISHED:
|
||||||
|
/* set status of group to RTR_MGR_ESTABLISHED if all caches in the common group are RTR_ESTABLISHED */
|
||||||
|
set_group_status_to_if_all_sockets_are(cache->group, RTR_MGR_ESTABLISHED, RTR_ESTABLISHED);
|
||||||
|
rpki_relax_groups(cache->p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_RESET:
|
||||||
|
/* Resetting RTR connection. */
|
||||||
|
rtr_socket->request_session_id = true;
|
||||||
|
rtr_socket->serial_number = 0;
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_SYNC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_SYNC:
|
||||||
|
/* Requesting for receive validation records from the RTR server. */
|
||||||
|
if (rtr_socket->request_session_id)
|
||||||
|
{
|
||||||
|
//change to state RESET, if socket dont has a session_id
|
||||||
|
if (rtr_send_reset_query(cache) != RTR_SUCCESS)
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//if we already have a session_id, send a serial query and start to sync
|
||||||
|
if (rtr_send_serial_query(cache) != RTR_SUCCESS)
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_ERROR_NO_INCR_UPDATE_AVAIL:
|
||||||
|
/* Server was unable to answer the last serial or reset query. */
|
||||||
|
rtr_purge_records_if_outdated(cache);
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case RTR_ERROR_NO_DATA_AVAIL:
|
||||||
|
/* No validation records are available on the RTR server. */
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_RESET);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_ERROR_FATAL:
|
||||||
|
/* Fatal protocol error occurred. */
|
||||||
|
rtr_socket->request_session_id = true;
|
||||||
|
rtr_socket->serial_number = 0;
|
||||||
|
rtr_socket->last_update = 0;
|
||||||
|
pfx_table_src_remove(cache);
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case RTR_ERROR_TRANSPORT:
|
||||||
|
/* Error on the transport socket occurred. */
|
||||||
|
rpki_close_connection(cache);
|
||||||
|
rtr_schedule_next_retry(cache);
|
||||||
|
cache->group->status = RTR_MGR_ERROR;
|
||||||
|
rpki_relax_groups(cache->p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_FAST_RECONNECT:
|
||||||
|
/* Reconnect without any waiting period */
|
||||||
|
rpki_close_connection(cache);
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_CONNECTING);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_SHUTDOWN:
|
||||||
|
/* RTR Socket is stopped. */
|
||||||
|
rpki_close_connection(cache);
|
||||||
|
rtr_socket->request_session_id = true;
|
||||||
|
rtr_socket->serial_number = 0;
|
||||||
|
rtr_socket->last_update = 0;
|
||||||
|
pfx_table_src_remove(cache);
|
||||||
|
|
||||||
|
/* set status of group to RTR_MGR_CLOSED if all caches in the common group are RTR_SHUTDOWN */
|
||||||
|
set_group_status_to_if_all_sockets_are(cache->group, RTR_MGR_CLOSED, RTR_SHUTDOWN);
|
||||||
|
rpki_relax_groups(cache->p);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timers
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_schedule_next_refresh(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rtr_socket *rtr_socket = cache->rtr_socket;
|
||||||
|
|
||||||
|
if (cache->rtr_socket->state == RTR_SHUTDOWN)
|
||||||
|
{
|
||||||
|
CACHE_DBG(cache, "Stop refreshing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned time_to_wait = MAX(((int)rtr_socket->refresh_interval - (int)(now - rtr_socket->last_update)), 1);
|
||||||
|
|
||||||
|
CACHE_DBG(cache, "Next refresh of cache(%s) will be after %u seconds", tr_ident(rtr_socket->tr_socket), time_to_wait);
|
||||||
|
tm_start(cache->refresh_timer, time_to_wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_schedule_next_retry(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
switch (cache->rtr_socket->state)
|
||||||
|
{
|
||||||
|
case RTR_ESTABLISHED:
|
||||||
|
case RTR_SYNC:
|
||||||
|
case RTR_RESET:
|
||||||
|
CACHE_DBG(cache, "Stop retrying connection");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CACHE_TRACE(D_EVENTS, cache, "Connection will retry after %u seconds again", cache->rtr_socket->retry_interval);
|
||||||
|
tm_start(cache->retry_timer, cache->rtr_socket->retry_interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtr_schedule_next_expire_check(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rtr_socket *rtr_socket = cache->rtr_socket;
|
||||||
|
|
||||||
|
unsigned time_to_wait = MAX(((int)rtr_socket->expire_interval - (int)(now - rtr_socket->last_update))+3, 1);
|
||||||
|
|
||||||
|
CACHE_DBG(cache, "Next ROA expiration check will be after %u seconds again", time_to_wait);
|
||||||
|
tm_stop(cache->expire_timer);
|
||||||
|
tm_start(cache->expire_timer, time_to_wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpki_refresh_hook(struct timer *tm)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache = tm->data;
|
||||||
|
struct rtr_socket *rtr_socket = cache->rtr_socket;
|
||||||
|
|
||||||
|
switch (rtr_socket->state)
|
||||||
|
{
|
||||||
|
case RTR_ESTABLISHED:
|
||||||
|
CACHE_DBG(cache, "Refreshing");
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_SYNC);
|
||||||
|
rtr_schedule_next_refresh(cache);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTR_CONNECTING:
|
||||||
|
case RTR_SYNC:
|
||||||
|
/* Wait small amout of time to transite state */
|
||||||
|
tm_start(tm, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CACHE_DBG(cache, "Stop Refreshing (%s)", rtr_socket_str_states[rtr_socket->state]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpki_retry_hook(struct timer *tm)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache = tm->data;
|
||||||
|
struct rtr_socket *rtr_socket = cache->rtr_socket;
|
||||||
|
struct rpki_proto *p = cache->p;
|
||||||
|
|
||||||
|
switch (rtr_socket->state)
|
||||||
|
{
|
||||||
|
case RTR_ESTABLISHED:
|
||||||
|
case RTR_CONNECTING:
|
||||||
|
case RTR_SYNC:
|
||||||
|
case RTR_SHUTDOWN:
|
||||||
|
CACHE_DBG(cache, "Stop Retry Connecting (%s)", rtr_socket_str_states[rtr_socket->state]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CACHE_DBG(cache, "Retry Connecting (%s)", rtr_socket_str_states[rtr_socket->state]);
|
||||||
|
rtr_change_socket_state(rtr_socket, RTR_CONNECTING);
|
||||||
|
rpki_print_groups(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rpki_expire_hook(struct timer *tm)
|
||||||
|
{
|
||||||
|
struct rpki_cache *cache = tm->data;
|
||||||
|
struct rtr_socket *rtr_socket = cache->rtr_socket;
|
||||||
|
|
||||||
|
if (rtr_socket->last_update == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CACHE_DBG(cache, "Expire Hook");
|
||||||
|
|
||||||
|
rtr_purge_records_if_outdated(cache);
|
||||||
|
rtr_schedule_next_expire_check(cache);
|
||||||
|
}
|
140
proto/rpki/rtr.h
Normal file
140
proto/rpki/rtr.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTR_H
|
||||||
|
#define RTR_H
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "transport.h"
|
||||||
|
|
||||||
|
#include "nest/bird.h"
|
||||||
|
|
||||||
|
static const uint8_t RTR_PROTOCOL_VERSION_0 = 0;
|
||||||
|
static const uint8_t RTR_PROTOCOL_VERSION_1 = 1;
|
||||||
|
|
||||||
|
static const uint8_t RTR_PROTOCOL_MIN_SUPPORTED_VERSION = 0;
|
||||||
|
static const uint8_t RTR_PROTOCOL_MAX_SUPPORTED_VERSION = 1;
|
||||||
|
|
||||||
|
enum rtr_rtvals {
|
||||||
|
RTR_SUCCESS = 0,
|
||||||
|
RTR_ERROR = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief States of the RTR socket.
|
||||||
|
*/
|
||||||
|
enum rtr_socket_state {
|
||||||
|
/* State between request for open new socket and asynchronous finish the opening socket */
|
||||||
|
RTR_OPENING,
|
||||||
|
|
||||||
|
/** Socket is establishing the transport connection. */
|
||||||
|
RTR_CONNECTING,
|
||||||
|
|
||||||
|
/** Connection is established, socket is waiting for a Serial Notify or expiration of the refresh_interval timer */
|
||||||
|
RTR_ESTABLISHED,
|
||||||
|
|
||||||
|
/** Resetting RTR connection. */
|
||||||
|
RTR_RESET,
|
||||||
|
|
||||||
|
/** Receiving validation records from the RTR server. */
|
||||||
|
RTR_SYNC,
|
||||||
|
|
||||||
|
/** Reconnect without any waiting period */
|
||||||
|
RTR_FAST_RECONNECT,
|
||||||
|
|
||||||
|
/** No validation records are available on the RTR server. */
|
||||||
|
RTR_ERROR_NO_DATA_AVAIL,
|
||||||
|
|
||||||
|
/** Server was unable to answer the last serial or reset query. */
|
||||||
|
RTR_ERROR_NO_INCR_UPDATE_AVAIL,
|
||||||
|
|
||||||
|
/** Fatal protocol error occurred. */
|
||||||
|
RTR_ERROR_FATAL,
|
||||||
|
|
||||||
|
/** Error on the transport socket occurred. */
|
||||||
|
RTR_ERROR_TRANSPORT,
|
||||||
|
|
||||||
|
/** RTR Socket is stopped. */
|
||||||
|
RTR_SHUTDOWN,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rtr_socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A function pointer that is called if the state of the rtr socket has changed.
|
||||||
|
*/
|
||||||
|
typedef void (*rtr_connection_state_fp)(const struct rtr_socket *rtr_socket, const enum rtr_socket_state state, void *connection_state_fp_param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A RTR socket.
|
||||||
|
* @param tr_socket Pointer to an initialized tr_socket that will be used to communicate with the RTR server.
|
||||||
|
* @param refresh_interval Time period in seconds. Tells the router how long to wait before next attempting to poll the cache, using a Serial Query or
|
||||||
|
* Reset Query PDU.
|
||||||
|
* @param last_update Timestamp of the last validation record update. Is 0 if the pfx_table doesn't stores any
|
||||||
|
* validation reords from this rtr_socket.
|
||||||
|
* @param expire_interval Time period in seconds. Received records are deleted if the client was unable to refresh data for this time period.
|
||||||
|
* If 0 is specified, the expire_interval is twice the refresh_interval.
|
||||||
|
* @param retry_interval Time period in seconds between a faild quary and the next attempt.
|
||||||
|
* @param state Current state of the socket.
|
||||||
|
* @param session_id session_id of the RTR session.
|
||||||
|
* @param request_session_id True, if the rtr_client have to request a new none from the server.
|
||||||
|
* @param serial_number Last serial number of the obtained validation records.
|
||||||
|
*/
|
||||||
|
struct rtr_socket {
|
||||||
|
struct tr_socket *tr_socket;
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
bird_clock_t last_update;
|
||||||
|
unsigned int retry_interval; /* Use if the cache server is down */
|
||||||
|
unsigned int refresh_interval;
|
||||||
|
unsigned int expire_interval; /* After this period from last refresh will be ROAs discard */
|
||||||
|
enum rtr_socket_state state;
|
||||||
|
uint32_t session_id;
|
||||||
|
bool request_session_id;
|
||||||
|
uint32_t serial_number;
|
||||||
|
unsigned int version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a rtr_socket.
|
||||||
|
* @param[out] rtr_socket Pointer to the allocated rtr_socket that will be initialized.
|
||||||
|
* @param[in] refresh_interval Interval in seconds between serial queries that are sent to the server. Must be <= 3600
|
||||||
|
* @param[in] expire_interval Stored validation records will be deleted if cache was unable to refresh data for this period.\n
|
||||||
|
* The default value is twice the refresh_interval.
|
||||||
|
*/
|
||||||
|
void rtr_init(struct rtr_socket *rtr_socket, const unsigned int refresh_interval, const unsigned int expire_interval, const unsigned int retry_interval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the RTR connection and terminate the transport connection.
|
||||||
|
* @param[in] rtr_socket rtr_socket that will be used.
|
||||||
|
*/
|
||||||
|
void rtr_stop(struct rtr_socket *rtr_socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a rtr_socket_state to a String.
|
||||||
|
* @param[in] state state to convert to a string
|
||||||
|
* @return NULL If state isn't a valid rtr_socket_state
|
||||||
|
* @return !=NULL The rtr_socket_state as String.
|
||||||
|
*/
|
||||||
|
const char *rtr_state_to_str(enum rtr_socket_state state);
|
||||||
|
|
||||||
|
void rtr_purge_records_if_outdated(struct rpki_cache *cache);
|
||||||
|
void rtr_change_socket_state(struct rtr_socket *rtr_socket, const enum rtr_socket_state new_state);
|
||||||
|
|
||||||
|
void rpki_retry_hook(struct timer *tm);
|
||||||
|
void rpki_expire_hook(struct timer *tm);
|
||||||
|
void rpki_refresh_hook(struct timer *tm);
|
||||||
|
|
||||||
|
void rtr_schedule_next_refresh(struct rpki_cache *cache);
|
||||||
|
void rtr_schedule_next_retry(struct rpki_cache *cache);
|
||||||
|
void rtr_schedule_next_expire_check(struct rpki_cache *cache);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* @} */
|
131
proto/rpki/ssh_transport.c
Normal file
131
proto/rpki/ssh_transport.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "ssh_transport.h"
|
||||||
|
#include "lib/libssh.h"
|
||||||
|
|
||||||
|
#include "rpki.h"
|
||||||
|
|
||||||
|
static int tr_ssh_open(void *tr_ssh_sock);
|
||||||
|
static void tr_ssh_close(void *tr_ssh_sock);
|
||||||
|
static void tr_ssh_free(struct tr_socket *tr_sock);
|
||||||
|
static const char *tr_ssh_ident(void *tr_ssh_sock);
|
||||||
|
|
||||||
|
int tr_ssh_open(void *socket)
|
||||||
|
{
|
||||||
|
struct tr_ssh_socket *ssh_socket = socket;
|
||||||
|
struct rpki_cache *cache = ssh_socket->cache;
|
||||||
|
|
||||||
|
const char *err_msg;
|
||||||
|
if ((err_msg = load_libssh()) != NULL)
|
||||||
|
{
|
||||||
|
CACHE_TRACE(D_EVENTS, cache, "%s", err_msg);
|
||||||
|
return TR_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock *sk = cache->sk;
|
||||||
|
sk->type = SK_SSH_ACTIVE;
|
||||||
|
sk->ssh = mb_allocz(sk->pool, sizeof(struct ssh_sock));
|
||||||
|
sk->ssh->username = cache->cfg->ssh->username;
|
||||||
|
sk->ssh->client_privkey_path = cache->cfg->ssh->bird_private_key;
|
||||||
|
sk->ssh->server_hostkey_path = cache->cfg->ssh->cache_public_key;
|
||||||
|
sk->ssh->subsystem = "rpki-rtr";
|
||||||
|
sk->ssh->state = BIRD_SSH_CONNECT;
|
||||||
|
|
||||||
|
if (sk_open(sk) != 0)
|
||||||
|
return TR_ERROR;
|
||||||
|
|
||||||
|
return TR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tr_ssh_close(void *tr_ssh_sock)
|
||||||
|
{
|
||||||
|
struct tr_ssh_socket *socket = tr_ssh_sock;
|
||||||
|
struct rpki_cache *cache = socket->cache;
|
||||||
|
|
||||||
|
sock *sk = cache->sk;
|
||||||
|
if (sk && sk->ssh)
|
||||||
|
{
|
||||||
|
if (sk->ssh->channel)
|
||||||
|
{
|
||||||
|
if (ssh_channel_is_open(sk->ssh->channel))
|
||||||
|
ssh_channel_close(sk->ssh->channel);
|
||||||
|
ssh_channel_free(sk->ssh->channel);
|
||||||
|
sk->ssh->channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sk->ssh->session)
|
||||||
|
{
|
||||||
|
ssh_disconnect(sk->ssh->session);
|
||||||
|
ssh_free(sk->ssh->session);
|
||||||
|
sk->ssh->session = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tr_ssh_free(struct tr_socket *tr_sock)
|
||||||
|
{
|
||||||
|
struct tr_ssh_socket *tr_ssh_sock = tr_sock->socket;
|
||||||
|
|
||||||
|
if (tr_ssh_sock)
|
||||||
|
{
|
||||||
|
if (tr_ssh_sock->ident != NULL)
|
||||||
|
mb_free(tr_ssh_sock->ident);
|
||||||
|
mb_free(tr_ssh_sock);
|
||||||
|
tr_sock->socket = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *tr_ssh_ident(void *tr_ssh_sock)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
struct tr_ssh_socket *ssh_sock = tr_ssh_sock;
|
||||||
|
struct rpki_cache *cache = ssh_sock->cache;
|
||||||
|
|
||||||
|
assert(ssh_sock != NULL);
|
||||||
|
|
||||||
|
if (ssh_sock->ident != NULL)
|
||||||
|
return ssh_sock->ident;
|
||||||
|
|
||||||
|
const char *username = cache->cfg->ssh->username;
|
||||||
|
const char *host = cache->cfg->hostname;
|
||||||
|
|
||||||
|
len = strlen(username) + 1 + strlen(host) + 1 + 5 + 1; /* <user> + '@' + <host> + ':' + <port> + '\0' */
|
||||||
|
ssh_sock->ident = mb_alloc(cache->p->p.pool, len);
|
||||||
|
if (ssh_sock->ident == NULL)
|
||||||
|
return NULL;
|
||||||
|
snprintf(ssh_sock->ident, len, "%s@%s:%u", username, host, cache->cfg->port);
|
||||||
|
return ssh_sock->ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tr_ssh_init(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = cache->p;
|
||||||
|
struct tr_socket *tr_socket = cache->rtr_socket->tr_socket;
|
||||||
|
|
||||||
|
tr_socket->close_fp = &tr_ssh_close;
|
||||||
|
tr_socket->free_fp = &tr_ssh_free;
|
||||||
|
tr_socket->open_fp = &tr_ssh_open;
|
||||||
|
tr_socket->ident_fp = &tr_ssh_ident;
|
||||||
|
|
||||||
|
tr_socket->socket = mb_allocz(p->p.pool, sizeof(struct tr_ssh_socket));
|
||||||
|
struct tr_ssh_socket *ssh = tr_socket->socket;
|
||||||
|
|
||||||
|
ssh->cache = cache;
|
||||||
|
|
||||||
|
return TR_SUCCESS;
|
||||||
|
}
|
63
proto/rpki/ssh_transport.h
Normal file
63
proto/rpki/ssh_transport.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup mod_ssh_transport_h SSH transport socket
|
||||||
|
* @ingroup mod_transport_h
|
||||||
|
* @brief An implementation of the SSH protocol for the RTR transport.
|
||||||
|
* @details This transport implementation uses libssh
|
||||||
|
* (http://www.libssh.org/) for all ssh specific operations.\n
|
||||||
|
* See @ref mod_transport_h "transport interface" for a list of supported
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @example ssh_tr.c
|
||||||
|
* Example of how to open a SSH transport connection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SSH_TRANSPORT_H
|
||||||
|
#define SSH_TRANSPORT_H
|
||||||
|
#include "transport.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A tr_ssh_config struct holds configuration data for an tr_ssh socket.
|
||||||
|
* @param host Hostname or IP address to connect to.
|
||||||
|
* @param port Port to connect to.
|
||||||
|
* @param bindaddr Hostname or IP address to connect from. NULL for
|
||||||
|
* determination by OS.
|
||||||
|
* @param username Username for authentication.
|
||||||
|
* @param server_hostkey_path Path to public SSH key of the server or NULL to
|
||||||
|
don't verify host authenticity.
|
||||||
|
* @param client_privkey_path Path to private key of the authentication keypair
|
||||||
|
* or NULL to use ~/.ssh/id_rsa.
|
||||||
|
*/
|
||||||
|
struct tr_ssh_config {
|
||||||
|
char *host;
|
||||||
|
unsigned int port;
|
||||||
|
char *username;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tr_ssh_socket {
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
char *ident;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the tr_socket struct for a SSH connection.
|
||||||
|
* @param[in] config SSH configuration for the connection.
|
||||||
|
* @param[out] socket Initialized transport socket.
|
||||||
|
* @returns TR_SUCCESS On success.
|
||||||
|
* @returns TR_ERROR On error.
|
||||||
|
*/
|
||||||
|
int tr_ssh_init(struct rpki_cache *cache);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* @} */
|
121
proto/rpki/tcp_transport.c
Normal file
121
proto/rpki/tcp_transport.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "rpki.h"
|
||||||
|
|
||||||
|
#include "tcp_transport.h"
|
||||||
|
#include "lib/unix.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int tr_tcp_open(void *tr_tcp_sock);
|
||||||
|
static void tr_tcp_close(void *tr_tcp_sock);
|
||||||
|
static void tr_tcp_free(struct tr_socket *tr_sock);
|
||||||
|
static const char *tr_tcp_ident(void *socket);
|
||||||
|
|
||||||
|
int tr_tcp_open(void *tr_tcp_sock)
|
||||||
|
{
|
||||||
|
struct tr_tcp_socket *tcp_socket = tr_tcp_sock;
|
||||||
|
struct rpki_cache *cache = tcp_socket->cache;
|
||||||
|
|
||||||
|
sock *sk = cache->sk;
|
||||||
|
sk->type = SK_TCP_ACTIVE;
|
||||||
|
sk->daddr = tcp_socket->config.ip;
|
||||||
|
|
||||||
|
if (sk_open(sk) != 0)
|
||||||
|
return TR_ERROR;
|
||||||
|
|
||||||
|
return TR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tr_tcp_close(void *tr_tcp_sock)
|
||||||
|
{
|
||||||
|
struct tr_tcp_socket *tcp_socket = tr_tcp_sock;
|
||||||
|
struct rpki_cache *cache = tcp_socket->cache;
|
||||||
|
|
||||||
|
sock *sk = cache->sk;
|
||||||
|
if (sk && sk->fd > 0)
|
||||||
|
{
|
||||||
|
/* TODO: ??? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tr_tcp_free(struct tr_socket *tr_sock)
|
||||||
|
{
|
||||||
|
struct tr_tcp_socket *tcp_sock = tr_sock->socket;
|
||||||
|
|
||||||
|
if (tcp_sock)
|
||||||
|
{
|
||||||
|
if (tcp_sock->ident != NULL)
|
||||||
|
mb_free(tcp_sock->ident);
|
||||||
|
tr_sock->socket = NULL;
|
||||||
|
mb_free(tcp_sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *tr_tcp_ident(void *socket)
|
||||||
|
{
|
||||||
|
assert(socket != NULL);
|
||||||
|
|
||||||
|
struct tr_tcp_socket *sock = socket;
|
||||||
|
struct rpki_proto *p = sock->cache->p;
|
||||||
|
|
||||||
|
if (sock->ident != NULL)
|
||||||
|
return sock->ident;
|
||||||
|
|
||||||
|
size_t colon_and_port_len = 6; /* max ":65535" */
|
||||||
|
size_t ident_len;
|
||||||
|
if (sock->config.host)
|
||||||
|
ident_len = strlen(sock->config.host) + colon_and_port_len + 1;
|
||||||
|
else
|
||||||
|
ident_len = IPA_MAX_TEXT_LENGTH + colon_and_port_len + 1;
|
||||||
|
|
||||||
|
sock->ident = mb_allocz(p->p.pool, ident_len);
|
||||||
|
if (sock->ident == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (sock->config.host)
|
||||||
|
bsnprintf(sock->ident, ident_len, "%s:%u", sock->config.host, sock->config.port);
|
||||||
|
else
|
||||||
|
bsnprintf(sock->ident, ident_len, "%I:%u", sock->config.ip, sock->config.port);
|
||||||
|
|
||||||
|
return sock->ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tr_tcp_init(struct rpki_cache *cache)
|
||||||
|
{
|
||||||
|
struct rpki_proto *p = cache->p;
|
||||||
|
struct rpki_cache_cfg *cache_cfg = cache->cfg;
|
||||||
|
struct tr_socket *tr_socket = cache->rtr_socket->tr_socket;
|
||||||
|
|
||||||
|
tr_socket->close_fp = &tr_tcp_close;
|
||||||
|
tr_socket->free_fp = &tr_tcp_free;
|
||||||
|
tr_socket->open_fp = &tr_tcp_open;
|
||||||
|
tr_socket->ident_fp = &tr_tcp_ident;
|
||||||
|
|
||||||
|
tr_socket->socket = mb_allocz(p->p.pool, sizeof(struct tr_tcp_socket));
|
||||||
|
struct tr_tcp_socket *tcp = tr_socket->socket;
|
||||||
|
|
||||||
|
tcp->cache = cache;
|
||||||
|
tcp->config.host = cache_cfg->hostname;
|
||||||
|
tcp->config.ip = cache_cfg->ip;
|
||||||
|
tcp->config.port = cache_cfg->port;
|
||||||
|
|
||||||
|
return TR_SUCCESS;
|
||||||
|
}
|
55
proto/rpki/tcp_transport.h
Normal file
55
proto/rpki/tcp_transport.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup mod_tcp_transport_h TCP transport socket
|
||||||
|
* @ingroup mod_transport_h
|
||||||
|
* @brief An implementation of the TCP protocol for the RTR transport.
|
||||||
|
* See @ref mod_transport_h "transport interface" for a list of supported operations.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTR_TCP_TRANSPORT_H
|
||||||
|
#define RTR_TCP_TRANSPORT_H
|
||||||
|
#include "transport.h"
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "lib/ip.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A tr_tcp_config struct holds configuration for a TCP connection.
|
||||||
|
* @param host Hostname or IP address to connect to.
|
||||||
|
* @param port Port to connect to.
|
||||||
|
* @param bindaddr Hostname or IP address to connect from. NULL for
|
||||||
|
* determination by OS.
|
||||||
|
* to use the source address of the system's default route to the server
|
||||||
|
*/
|
||||||
|
struct tr_tcp_config {
|
||||||
|
ip_addr ip; char *host; /* at least one of @ip or @host must be defined */
|
||||||
|
uint port;
|
||||||
|
char *bindaddr; /* TODO: NEED THIS? */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tr_tcp_socket {
|
||||||
|
struct rpki_cache *cache;
|
||||||
|
struct tr_tcp_config config;
|
||||||
|
char *ident;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the tr_socket struct for a TCP connection.
|
||||||
|
* @param[in] config TCP configuration for the connection.
|
||||||
|
* @param[out] socket Initialized transport socket.
|
||||||
|
* @returns TR_SUCCESS On success.
|
||||||
|
* @returns TR_ERROR On error.
|
||||||
|
*/
|
||||||
|
int tr_tcp_init(struct rpki_cache *cache);
|
||||||
|
#endif
|
||||||
|
/* @} */
|
32
proto/rpki/transport.c
Normal file
32
proto/rpki/transport.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rpki.h"
|
||||||
|
#include "transport.h"
|
||||||
|
|
||||||
|
inline int tr_open(struct tr_socket *socket)
|
||||||
|
{
|
||||||
|
return socket->open_fp(socket->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void tr_close(struct tr_socket *socket)
|
||||||
|
{
|
||||||
|
socket->close_fp(socket->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void tr_free(struct tr_socket *socket)
|
||||||
|
{
|
||||||
|
socket->free_fp(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *tr_ident(struct tr_socket *socket)
|
||||||
|
{
|
||||||
|
return socket->ident_fp(socket->socket);
|
||||||
|
}
|
96
proto/rpki/transport.h
Normal file
96
proto/rpki/transport.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
|
||||||
|
*
|
||||||
|
* (c) 2015 CZ.NIC
|
||||||
|
*
|
||||||
|
* This file was part of RTRlib: http://rpki.realmv6.org/
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup mod_transport_h Transport sockets
|
||||||
|
* @brief The RTR transport sockets implement the communication channel
|
||||||
|
* (e.g., SSH, TCP, TCP-AO) between an RTR server and client.
|
||||||
|
* @details Before using the transport socket, a tr_socket must be
|
||||||
|
* initialized based on a protocol-dependent init function (e.g.,
|
||||||
|
* tr_tcp_init()).\n
|
||||||
|
* The tr_* functions call the corresponding function pointers, which are
|
||||||
|
* passed in the tr_socket struct, and forward the remaining arguments.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTR_TRANSPORT_H
|
||||||
|
#define RTR_TRANSPORT_H
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The return values for tr_ functions.
|
||||||
|
*/
|
||||||
|
enum tr_rtvals {
|
||||||
|
/** @brief Operation was successfull. */
|
||||||
|
TR_SUCCESS = 0,
|
||||||
|
|
||||||
|
/** Error occured. */
|
||||||
|
TR_ERROR = -1,
|
||||||
|
|
||||||
|
/** No data is available on the socket. */
|
||||||
|
TR_WOULDBLOCK = -2,
|
||||||
|
|
||||||
|
/** Call was interrupted from a signal */
|
||||||
|
TR_INTR = -3,
|
||||||
|
|
||||||
|
/** Connection closed */
|
||||||
|
TR_CLOSED = -4
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tr_socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A transport socket datastructure.
|
||||||
|
*
|
||||||
|
* @param socket A pointer to a technology specific socket.
|
||||||
|
* @param open_fp Pointer to a function that establishes the socket connection.
|
||||||
|
* @param close_fp Pointer to a function that closes the socket.
|
||||||
|
* @param free_fp Pointer to a function that frees all memory allocated with this socket.
|
||||||
|
*/
|
||||||
|
struct tr_socket {
|
||||||
|
void *socket;
|
||||||
|
int (*open_fp)(void *socket) ;
|
||||||
|
void (*close_fp)(void *socket) ;
|
||||||
|
void (*free_fp)(struct tr_socket *tr_sock);
|
||||||
|
const char *(*ident_fp)(void *socket);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Establish the connection.
|
||||||
|
* @param[in] socket Socket that will be used.
|
||||||
|
* @return TR_SUCCESS On success.
|
||||||
|
* @return TR_ERROR On error.
|
||||||
|
*/
|
||||||
|
int tr_open(struct tr_socket *socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Close the socket connection.
|
||||||
|
* @param[in] socket Socket that will be closed.
|
||||||
|
*/
|
||||||
|
void tr_close(struct tr_socket *socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deallocates all memory that the passed socket uses.
|
||||||
|
* Socket have to be closed before.
|
||||||
|
* @param[in] socket which will be freed.
|
||||||
|
*/
|
||||||
|
void tr_free(struct tr_socket *socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an identifier for the socket endpoint, eg host:port.
|
||||||
|
* @param[in] socket
|
||||||
|
* return Pointer to a \0 terminated String
|
||||||
|
* return NULL on error
|
||||||
|
*/
|
||||||
|
const char *tr_ident(struct tr_socket *socket);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* @} */
|
@ -43,6 +43,7 @@
|
|||||||
#undef CONFIG_BGP
|
#undef CONFIG_BGP
|
||||||
#undef CONFIG_OSPF
|
#undef CONFIG_OSPF
|
||||||
#undef CONFIG_PIPE
|
#undef CONFIG_PIPE
|
||||||
|
#undef CONFIG_RPKI
|
||||||
|
|
||||||
/* We use multithreading */
|
/* We use multithreading */
|
||||||
#undef USE_PTHREADS
|
#undef USE_PTHREADS
|
||||||
|
342
sysdep/unix/io.c
342
sysdep/unix/io.c
@ -35,6 +35,7 @@
|
|||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
|
#include "lib/libssh.h"
|
||||||
#include "nest/iface.h"
|
#include "nest/iface.h"
|
||||||
|
|
||||||
#include "lib/unix.h"
|
#include "lib/unix.h"
|
||||||
@ -1060,12 +1061,42 @@ sk_free_bufs(sock *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sk_ssh_free(sock *s)
|
||||||
|
{
|
||||||
|
struct ssh_sock *ssh = s->ssh;
|
||||||
|
|
||||||
|
if (s->ssh == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ssh->channel)
|
||||||
|
{
|
||||||
|
if (ssh_channel_is_open(ssh->channel))
|
||||||
|
ssh_channel_close(ssh->channel);
|
||||||
|
ssh_channel_free(ssh->channel);
|
||||||
|
ssh->channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh->session)
|
||||||
|
{
|
||||||
|
ssh_disconnect(ssh->session);
|
||||||
|
ssh_free(ssh->session);
|
||||||
|
ssh->session = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mb_free(ssh);
|
||||||
|
s->ssh = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sk_free(resource *r)
|
sk_free(resource *r)
|
||||||
{
|
{
|
||||||
sock *s = (sock *) r;
|
sock *s = (sock *) r;
|
||||||
|
|
||||||
sk_free_bufs(s);
|
sk_free_bufs(s);
|
||||||
|
if (s->type == SK_SSH || s->type == SK_SSH_ACTIVE)
|
||||||
|
sk_ssh_free(s);
|
||||||
|
|
||||||
if (s->fd >= 0)
|
if (s->fd >= 0)
|
||||||
{
|
{
|
||||||
close(s->fd);
|
close(s->fd);
|
||||||
@ -1182,6 +1213,9 @@ sk_setup(sock *s)
|
|||||||
int y = 1;
|
int y = 1;
|
||||||
int fd = s->fd;
|
int fd = s->fd;
|
||||||
|
|
||||||
|
if (s->type == SK_SSH_ACTIVE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||||
ERR("O_NONBLOCK");
|
ERR("O_NONBLOCK");
|
||||||
|
|
||||||
@ -1295,6 +1329,14 @@ sk_tcp_connected(sock *s)
|
|||||||
s->tx_hook(s);
|
s->tx_hook(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sk_ssh_connected(sock *s)
|
||||||
|
{
|
||||||
|
sk_alloc_bufs(s);
|
||||||
|
s->type = SK_SSH;
|
||||||
|
s->tx_hook(s);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sk_passive_connected(sock *s, int type)
|
sk_passive_connected(sock *s, int type)
|
||||||
{
|
{
|
||||||
@ -1359,6 +1401,193 @@ sk_passive_connected(sock *s, int type)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return SSH_OK or SSH_AGAIN or SSH_ERROR
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
sk_ssh_connect(sock *s)
|
||||||
|
{
|
||||||
|
s->fd = ssh_get_fd(s->ssh->session);
|
||||||
|
|
||||||
|
/* Big fall thru automat */
|
||||||
|
switch (s->ssh->state)
|
||||||
|
{
|
||||||
|
case BIRD_SSH_CONNECT:
|
||||||
|
{
|
||||||
|
switch (ssh_connect(s->ssh->session))
|
||||||
|
{
|
||||||
|
case SSH_AGAIN:
|
||||||
|
return SSH_AGAIN;
|
||||||
|
|
||||||
|
case SSH_OK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case BIRD_SSH_IS_SERVER_KNOWN:
|
||||||
|
{
|
||||||
|
s->ssh->state = BIRD_SSH_IS_SERVER_KNOWN;
|
||||||
|
|
||||||
|
if (s->ssh->server_hostkey_path)
|
||||||
|
{
|
||||||
|
int server_identity_is_ok = 1;
|
||||||
|
|
||||||
|
/* Check server identity */
|
||||||
|
switch (ssh_is_server_known(s->ssh->session))
|
||||||
|
{
|
||||||
|
#define LOG_WARN_ABOUT_SSH_SERVER_VALIDATION(s,msg,args...) log(L_WARN "SSH Identity %s@%s:%u: " msg, (s)->ssh->username, (s)->host, (s)->dport, ## args);
|
||||||
|
case SSH_SERVER_KNOWN_OK:
|
||||||
|
/* The server is known and has not changed. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SERVER_NOT_KNOWN:
|
||||||
|
LOG_WARN_ABOUT_SSH_SERVER_VALIDATION(s, "The server is unknown, its public key was not found in the known host file %s", s->ssh->server_hostkey_path);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SERVER_KNOWN_CHANGED:
|
||||||
|
LOG_WARN_ABOUT_SSH_SERVER_VALIDATION(s, "The server key has changed. Either you are under attack or the administrator changed the key.");
|
||||||
|
server_identity_is_ok = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SERVER_FILE_NOT_FOUND:
|
||||||
|
LOG_WARN_ABOUT_SSH_SERVER_VALIDATION(s, "The known host file %s does not exist", s->ssh->server_hostkey_path);
|
||||||
|
server_identity_is_ok = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SERVER_ERROR:
|
||||||
|
LOG_WARN_ABOUT_SSH_SERVER_VALIDATION(s, "Some error happened");
|
||||||
|
server_identity_is_ok = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_SERVER_FOUND_OTHER:
|
||||||
|
LOG_WARN_ABOUT_SSH_SERVER_VALIDATION(s, "The server gave use a key of a type while we had an other type recorded. " \
|
||||||
|
"It is a possible attack.");
|
||||||
|
server_identity_is_ok = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server_identity_is_ok)
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case BIRD_SSH_USERAUTH_PUBLICKEY_AUTO:
|
||||||
|
{
|
||||||
|
s->ssh->state = BIRD_SSH_USERAUTH_PUBLICKEY_AUTO;
|
||||||
|
switch (ssh_userauth_publickey_auto(s->ssh->session, NULL, NULL))
|
||||||
|
{
|
||||||
|
case SSH_AUTH_AGAIN:
|
||||||
|
return SSH_AGAIN;
|
||||||
|
|
||||||
|
case SSH_AUTH_SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case BIRD_SSH_CHANNEL_NEW:
|
||||||
|
{
|
||||||
|
s->ssh->state = BIRD_SSH_CHANNEL_NEW;
|
||||||
|
s->ssh->channel = ssh_channel_new(s->ssh->session);
|
||||||
|
if (s->ssh->channel == NULL)
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BIRD_SSH_CHANNEL_OPEN_SESSION:
|
||||||
|
{
|
||||||
|
s->ssh->state = BIRD_SSH_CHANNEL_OPEN_SESSION;
|
||||||
|
switch (ssh_channel_open_session(s->ssh->channel))
|
||||||
|
{
|
||||||
|
case SSH_AGAIN:
|
||||||
|
return SSH_AGAIN;
|
||||||
|
|
||||||
|
case SSH_OK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case BIRD_SSH_CHANNEL_REQUEST_SUBSYSTEM:
|
||||||
|
{
|
||||||
|
s->ssh->state = BIRD_SSH_CHANNEL_REQUEST_SUBSYSTEM;
|
||||||
|
if (s->ssh->subsystem)
|
||||||
|
{
|
||||||
|
switch (ssh_channel_request_subsystem(s->ssh->channel, s->ssh->subsystem))
|
||||||
|
{
|
||||||
|
case SSH_AGAIN:
|
||||||
|
return SSH_AGAIN;
|
||||||
|
|
||||||
|
case SSH_OK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case BIRD_SSH_CONNECTION_ESTABLISHED:
|
||||||
|
s->ssh->state = BIRD_SSH_CONNECTION_ESTABLISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return file descriptor number if success
|
||||||
|
* Return -1 if failed
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
sk_open_ssh(sock *s)
|
||||||
|
{
|
||||||
|
if (!s->ssh)
|
||||||
|
bug("sk_open() sock->ssh is not allocated");
|
||||||
|
|
||||||
|
s->ssh->session = ssh_new();
|
||||||
|
if (s->ssh->session == NULL)
|
||||||
|
ERR2("Cannot create a ssh session");
|
||||||
|
|
||||||
|
const int verbosity = SSH_LOG_NOLOG;
|
||||||
|
ssh_options_set(s->ssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||||
|
ssh_options_set(s->ssh->session, SSH_OPTIONS_HOST, s->host);
|
||||||
|
ssh_options_set(s->ssh->session, SSH_OPTIONS_PORT, &(s->dport));
|
||||||
|
ssh_options_set(s->ssh->session, SSH_OPTIONS_USER, s->ssh->username);
|
||||||
|
|
||||||
|
if (s->ssh->server_hostkey_path)
|
||||||
|
ssh_options_set(s->ssh->session, SSH_OPTIONS_KNOWNHOSTS, s->ssh->server_hostkey_path);
|
||||||
|
|
||||||
|
if (s->ssh->client_privkey_path)
|
||||||
|
ssh_options_set(s->ssh->session, SSH_OPTIONS_IDENTITY, s->ssh->client_privkey_path);
|
||||||
|
|
||||||
|
ssh_set_blocking(s->ssh->session, 0);
|
||||||
|
|
||||||
|
switch (sk_ssh_connect(s))
|
||||||
|
{
|
||||||
|
case SSH_AGAIN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_OK:
|
||||||
|
sk_ssh_connected(s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_ERROR:
|
||||||
|
ERR2(ssh_get_error(s->ssh->session));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssh_get_fd(s->ssh->session);
|
||||||
|
|
||||||
|
err:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sk_open - open a socket
|
* sk_open - open a socket
|
||||||
* @s: socket
|
* @s: socket
|
||||||
@ -1390,6 +1619,11 @@ sk_open(sock *s)
|
|||||||
do_bind = bind_port || ipa_nonzero(bind_addr);
|
do_bind = bind_port || ipa_nonzero(bind_addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SK_SSH_ACTIVE:
|
||||||
|
s->ttx = ""; /* Force s->ttx != s->tpos */
|
||||||
|
fd = sk_open_ssh(s);
|
||||||
|
break;
|
||||||
|
|
||||||
case SK_UDP:
|
case SK_UDP:
|
||||||
fd = socket(fam_to_af[s->fam], SOCK_DGRAM, IPPROTO_UDP);
|
fd = socket(fam_to_af[s->fam], SOCK_DGRAM, IPPROTO_UDP);
|
||||||
bind_port = s->sport;
|
bind_port = s->sport;
|
||||||
@ -1472,6 +1706,7 @@ sk_open(sock *s)
|
|||||||
ERR2("listen");
|
ERR2("listen");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SK_SSH_ACTIVE:
|
||||||
case SK_MAGIC:
|
case SK_MAGIC:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1481,6 +1716,7 @@ sk_open(sock *s)
|
|||||||
|
|
||||||
if (!(s->flags & SKF_THREAD))
|
if (!(s->flags & SKF_THREAD))
|
||||||
sk_insert(s);
|
sk_insert(s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -1663,6 +1899,26 @@ sk_maybe_write(sock *s)
|
|||||||
reset_tx_buffer(s);
|
reset_tx_buffer(s);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case SK_SSH:
|
||||||
|
while (s->ttx != s->tpos)
|
||||||
|
{
|
||||||
|
e = ssh_channel_write(s->ssh->channel, s->ttx, s->tpos - s->ttx);
|
||||||
|
|
||||||
|
if (e < 0)
|
||||||
|
{
|
||||||
|
s->err = ssh_get_error(s->ssh->session);
|
||||||
|
s->err_hook(s, ssh_get_error_code(s->ssh->session));
|
||||||
|
|
||||||
|
reset_tx_buffer(s);
|
||||||
|
/* EPIPE is just a connection close notification during TX */
|
||||||
|
s->err_hook(s, (errno != EPIPE) ? errno : 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s->ttx += e;
|
||||||
|
}
|
||||||
|
reset_tx_buffer(s);
|
||||||
|
return 1;
|
||||||
|
|
||||||
case SK_UDP:
|
case SK_UDP:
|
||||||
case SK_IP:
|
case SK_IP:
|
||||||
{
|
{
|
||||||
@ -1687,6 +1943,7 @@ sk_maybe_write(sock *s)
|
|||||||
reset_tx_buffer(s);
|
reset_tx_buffer(s);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
bug("sk_maybe_write: unknown socket type %d", s->type);
|
bug("sk_maybe_write: unknown socket type %d", s->type);
|
||||||
}
|
}
|
||||||
@ -1773,6 +2030,62 @@ sk_send_full(sock *s, unsigned len, struct iface *ifa,
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
call_rx_hook(sock *s, int size)
|
||||||
|
{
|
||||||
|
if (s->rx_hook(s, size))
|
||||||
|
{
|
||||||
|
/* We need to be careful since the socket could have been deleted by the hook */
|
||||||
|
if (current_sock == s)
|
||||||
|
s->rpos = s->rbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sk_read_ssh(sock *s)
|
||||||
|
{
|
||||||
|
ssh_channel rchans[2] = { s->ssh->channel, NULL };
|
||||||
|
struct timeval timev = { 1, 0 };
|
||||||
|
|
||||||
|
if (ssh_channel_select(rchans, NULL, NULL, &timev) == SSH_EINTR)
|
||||||
|
return 1; /* Try again */
|
||||||
|
|
||||||
|
if (ssh_channel_is_eof(s->ssh->channel) != 0)
|
||||||
|
{
|
||||||
|
/* The remote side is closing the connection */
|
||||||
|
s->err_hook(s, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rchans[0] == NULL)
|
||||||
|
return 0; /* No data is available on the socket */
|
||||||
|
|
||||||
|
const uint used_bytes = s->rpos - s->rbuf;
|
||||||
|
const int read_bytes = ssh_channel_read_nonblocking(s->ssh->channel, s->rpos, s->rbsize - used_bytes, 0);
|
||||||
|
if (read_bytes > 0)
|
||||||
|
{
|
||||||
|
/* Received data */
|
||||||
|
s->rpos += read_bytes;
|
||||||
|
call_rx_hook(s, used_bytes + read_bytes);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (read_bytes == 0)
|
||||||
|
{
|
||||||
|
if (ssh_channel_is_eof(s->ssh->channel) != 0)
|
||||||
|
{
|
||||||
|
/* The remote side is closing the connection */
|
||||||
|
s->err_hook(s, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s->err = ssh_get_error(s->ssh->session);
|
||||||
|
s->err_hook(s, ssh_get_error_code(s->ssh->session));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* No data is available on the socket */
|
||||||
|
}
|
||||||
|
|
||||||
/* sk_read() and sk_write() are called from BFD's event loop */
|
/* sk_read() and sk_write() are called from BFD's event loop */
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1801,17 +2114,15 @@ sk_read(sock *s)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
s->rpos += c;
|
s->rpos += c;
|
||||||
if (s->rx_hook(s, s->rpos - s->rbuf))
|
call_rx_hook(s, s->rpos - s->rbuf);
|
||||||
{
|
|
||||||
/* We need to be careful since the socket could have been deleted by the hook */
|
|
||||||
if (current_sock == s)
|
|
||||||
s->rpos = s->rbuf;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SK_SSH:
|
||||||
|
return sk_read_ssh(s);
|
||||||
|
|
||||||
case SK_MAGIC:
|
case SK_MAGIC:
|
||||||
return s->rx_hook(s, 0);
|
return s->rx_hook(s, 0);
|
||||||
|
|
||||||
@ -1850,6 +2161,25 @@ sk_write(sock *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SK_SSH_ACTIVE:
|
||||||
|
{
|
||||||
|
switch (sk_ssh_connect(s))
|
||||||
|
{
|
||||||
|
case SSH_OK:
|
||||||
|
sk_ssh_connected(s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSH_AGAIN:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case SSH_ERROR:
|
||||||
|
s->err = ssh_get_error(s->ssh->session);
|
||||||
|
s->err_hook(s, ssh_get_error_code(s->ssh->session));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (s->ttx != s->tpos && sk_maybe_write(s) > 0)
|
if (s->ttx != s->tpos && sk_maybe_write(s) > 0)
|
||||||
{
|
{
|
||||||
|
@ -37,8 +37,8 @@ subdir: sysdep/paths.h .dir-stamp .dep-stamp
|
|||||||
set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done
|
set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done
|
||||||
|
|
||||||
$(exedir)/bird: $(bird-dep)
|
$(exedir)/bird: $(bird-dep)
|
||||||
@echo LD $(LDFLAGS) -o $@ $^ $(LIBS)
|
@echo LD $(LDFLAGS) -o $@ $^ $(LIBS) $(BIRD_LIBS)
|
||||||
@$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
@$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(BIRD_LIBS)
|
||||||
|
|
||||||
$(exedir)/birdc: $(birdc-dep)
|
$(exedir)/birdc: $(birdc-dep)
|
||||||
@echo LD $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS)
|
@echo LD $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS)
|
||||||
|
@ -23,6 +23,7 @@ CPPFLAGS=-I$(root-rel) -I$(srcdir) @CPPFLAGS@
|
|||||||
CFLAGS=$(CPPFLAGS) @CFLAGS@
|
CFLAGS=$(CPPFLAGS) @CFLAGS@
|
||||||
LDFLAGS=@LDFLAGS@
|
LDFLAGS=@LDFLAGS@
|
||||||
LIBS=@LIBS@
|
LIBS=@LIBS@
|
||||||
|
BIRD_LIBS=@BIRD_LIBS@
|
||||||
CLIENT_LIBS=@CLIENT_LIBS@
|
CLIENT_LIBS=@CLIENT_LIBS@
|
||||||
CC=@CC@
|
CC=@CC@
|
||||||
M4=@M4@
|
M4=@M4@
|
||||||
|
Loading…
Reference in New Issue
Block a user